When .beads/redirect points to another location that crosses directory
boundaries, isExternalBeadsDir() can return true even when both paths
are in the same git repo. Previously, this would trigger the direct
commit mode, bypassing the configured sync.branch workflow.
Now we check hasSyncBranchConfig before entering the external path.
When sync.branch is configured, we skip direct-commit mode and use
the sync.branch worktree workflow instead, which properly handles
copying JSONL files regardless of where the source .beads lives.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Two fixes:
1. `bd init` chaining was broken - the code referenced `.old` hooks but
never actually renamed the existing hooks. Added the missing os.Rename().
2. `bd hooks install` now supports --chain flag to chain with existing hooks
(e.g., pre-commit framework). When used, existing hooks are renamed to
.old and bd hooks run will call them before the bd logic.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add redirect to GitignoreTemplate with explanatory comment
- Add redirect to requiredPatterns for outdated gitignore detection
- Add CheckRedirectNotTracked() to detect already-tracked redirect files
- Add FixRedirectTracking() to untrack via git rm --cached
- Register check in bd doctor under Git Integration category
- Add 6 tests for the new functionality
The redirect file contains a relative path that only works in the
original worktree. When committed, it causes warnings in other clones:
"Warning: redirect target does not exist"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Cherry-picked website/, scripts/generate-llms-full.sh, and deploy-docs.yml
from joyshmitz's PR. Fixed workflow to trigger on main branch instead of
docs/docusaurus-site.
Features:
- Docusaurus documentation site with llms.txt support
- Environment-variable driven config (defaults to steveyegge org)
- Automated llms-full.txt generation from docs
- GitHub Pages deployment workflow
Co-authored-by: joyshmitz <joyshmitz@users.noreply.github.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Executed-By: beads/crew/dave
Rig: beads
Role: crew
Follow-up to #812 fix. When useSyncBranch is true, we always call
CommitToSyncBranch (bypassing gitHasBeadsChanges). If the worktree
has no actual changes, we now show "→ No changes to commit" for
consistent UX with the non-sync-branch code path.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add TestSet cases for main/master rejection in syncbranch_test.go
- Add TestInitWithSyncBranch to verify --branch flag works
- Add TestInitWithoutBranchFlag to verify no auto-detection (root cause)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Agent beads are identity/state tracking beads for agents, not actionable work items.
Cherry-picked from fix/actor-on-status-events
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Scaffolds bd preflight for PR readiness checks. Currently prints a
static checklist of common pre-PR validation items:
- Tests pass
- Lint passes
- No beads pollution
- Nix hash current
- Version sync
--check and --fix flags are documented but not yet implemented
(see bd-lfak.2 through bd-lfak.5 for roadmap).
(bd-lfak.1)
Cherry-picked from polecat/amber-1767146829144
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The root cause was isExternalBeadsDir() incorrectly identifying bare repo
worktrees as "external" repos. This caused bd sync to take the "external
beads dir" code path instead of the worktree-based sync branch path.
The bug: isExternalBeadsDir() compared syncbranch.GetRepoRoot() (which returns
incorrect values for bare repo worktrees) with getRepoRootFromPath() (which
uses --show-toplevel). These returned different values for bare repo
worktrees, causing local worktrees to be treated as external.
The fix: Use git rev-parse --git-common-dir for comparison instead of repo
root. This correctly identifies that worktrees of the same repo share the
same git directory, regardless of bare repo setup.
Also added:
- getGitCommonDir() helper function
- Tests for both getGitCommonDir and isExternalBeadsDir
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds atomic claim operation for work queue messages:
- New --claim flag on bd update command
- Sets assignee to claimer and status to in_progress
- Fails with clear error if already claimed by someone else
- Works in both daemon and direct modes
- Includes comprehensive tests for claim functionality
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When using sync-branch with aggressive gitignore on code branches
(.beads/* ignored), gitHasBeadsChanges() returns false because git
does not track the files. This caused bd sync to skip CommitToSyncBranch
entirely, even though CommitToSyncBranch has its own internal change
detection that checks the worktree where gitignore is different.
The fix bypasses gitHasBeadsChanges when useSyncBranch is true, letting
CommitToSyncBranch determine if there are actual changes in the worktree.
Closes#812🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Completes the work from #813 by actually calling the new functions:
- Add Check 14b in doctor.go for redirect file tracking detection
- Add Redirect Not Tracked case in doctor_fix.go switch statement
Without this wiring, bd doctor would not detect or fix already-tracked
redirect files, only prevent new ones via the updated .gitignore template.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Executed-By: beads/crew/dave
Rig: beads
Role: crew
When bd worktree creates a worktree, it writes a .beads/redirect file
pointing back to the main repo's .beads/. If this file is accidentally
committed (e.g., via git add .), it causes "redirect target does not exist"
warnings when cloned or used in other worktrees.
Changes:
- Add 'redirect' to GitignoreTemplate to prevent future accidental commits
- Add 'redirect' to requiredPatterns so bd doctor detects outdated .gitignore
- Add CheckRedirectNotTracked() to detect already-tracked redirect files
- Add FixRedirectTracking() to untrack accidentally committed redirects
Tests: 8 new tests covering template, detection, and fix scenarios
The prefix mismatch check in bd doctor was reporting warnings when
issues were created via molecule workflows (bd mol pour), which
intentionally use a different prefix pattern (<base>-mol instead
of just <base>).
Added recognition of valid workflow prefix variants:
- <prefix>-mol (molecules from bd mol pour)
- <prefix>-wisp (ephemeral wisps)
- <prefix>-eph (ephemeral issues)
These are intentional prefix extensions for visual distinction, not
actual mismatches. The check now only warns for truly mismatched
prefixes (e.g., different project entirely).
Added comprehensive regression tests for all prefix variant cases.
Fixes#811
Generated with Claude Code
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added 479 lines of new tests:
- utils_unit_test.go: Tests for utility functions (truncateString,
pluralize, formatTimeAgo, containsLabel, extractIDSuffix, truncate,
truncateDescription, showCleanupDeprecationHint, clearAutoFlushState)
- hooks_test.go: Tests for FormatHookWarnings, isRebaseInProgress,
hasBeadsJSONL
- list_test.go: Tests for formatIssueLong, formatIssueCompact
- version_tracking_test.go: Fixed flaky tests by setting BEADS_DIR
env var to prevent git worktree detection from finding the actual
.beads directory instead of the temp directory
Coverage increased from 21.6% to 22.0%. The remaining 78% of untested
code involves daemon/RPC operations, command handlers requiring
database/daemon setup, and git operations that would require
integration tests with mocked dependencies.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This implements sync branch integrity guards that detect when the remote
sync branch has been force-pushed since the last sync, preventing silent
data corruption.
Changes:
- Add internal/syncbranch/integrity.go with:
- CheckForcePush() - detects force-push via stored remote SHA comparison
- UpdateStoredRemoteSHA() - stores current remote SHA after successful sync
- ClearStoredRemoteSHA() - clears stored SHA when resetting
- GetStoredRemoteSHA() - retrieves stored SHA for inspection
- Update cmd/bd/sync.go to:
- Add --accept-rebase flag for non-interactive reset to remote
- Add force-push detection before sync branch pull operations
- Prompt user for confirmation when force-push detected
- Update stored remote SHA after successful sync
The implementation:
1. Tracks the remote sync branch commit SHA in config after each sync
2. On subsequent syncs, checks if stored SHA is ancestor of current remote
3. If not (force-push detected), warns user with details and prompts
4. User can accept reset or abort to investigate manually
5. --accept-rebase flag allows scripted/non-interactive recovery
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Addresses the self-hosting recursion problem where contributors using
beads-the-tool on beads-the-project leak personal issues into PRs.
Design recommends auto-routing (Approach 4):
- Detect user role via git remote URL (SSH=maintainer, HTTPS=contributor)
- Route contributor issues to ~/.beads-planning automatically
- Zero-friction default with explicit override available
Key finding: bd-6x6g needs implementation - routing is calculated but
not actually used to switch target repo in bd create.
Enables bd-lfak (PR preflight checks) to implement pollution detection.
(bd-umbf)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add comprehensive JSONL Issue Schema section to docs/ARCHITECTURE.md
documenting all exported fields including close_reason
- Add TestCloseReasonRoundTrip test in export_import_test.go to verify
close_reason is preserved through JSONL export/import cycle
Closes: bd-lxzx
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When no issue ID is provided to `bd update` or `bd close`, use the last
touched issue from the most recent create, update, show, or close operation.
This addresses the common workflow where you create an issue and then
immediately want to add more details (like changing priority from P2 to P4)
without re-typing the issue ID.
Implementation:
- New file last_touched.go with Get/Set/Clear functions
- Store last touched ID in .beads/last-touched (gitignored)
- Track on create, update, show, and close operations
- Allow update/close with zero args to use last touched
(bd-s2t)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
BUG: BD_ACTOR env var was only read in --no-db mode (lines 352-360)
and daemon RPC path. Normal direct mode and JSONL-only mode detection
paths fell back to $USER without checking BD_ACTOR.
Fix: Add explicit os.Getenv("BD_ACTOR") check in both:
- JSONL-only mode detection path (lines 393-402)
- Normal direct mode path (lines 440-450)
(gt-6r18e.2)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When config.yaml has malformed YAML, getLocalSyncBranch and
isNoDbModeConfigured were silently returning empty/false with no
feedback, making debugging difficult. Now they log a warning via
debug.Logf when YAML parsing fails.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
BUG: BD_ACTOR env var was only read in --no-db mode (lines 352-360)
and daemon RPC path. Normal direct mode and JSONL-only mode detection
paths fell back to $USER without checking BD_ACTOR.
Fix: Add explicit os.Getenv("BD_ACTOR") check in both:
- JSONL-only mode detection path (lines 393-402)
- Normal direct mode path (lines 440-450)
(gt-6r18e.2)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The bug: In a bare repo + worktrees setup, jsonlRelPath was calculated
relative to the project root (containing all worktrees), resulting in
paths like "main/.beads/issues.jsonl". But the sync branch worktree uses
sparse checkout for .beads/*, so files are at ".beads/issues.jsonl".
This caused SyncJSONLToWorktreeWithOptions to write to the wrong location
(e.g., worktree/main/.beads/ instead of worktree/.beads/), so changes
made locally never reached the sync branch worktree.
#785 fixed the reverse direction (worktree → local) by adding
normalizeBeadsRelPath(), but the local → worktree direction was missed.
Fix:
- Export NormalizeBeadsRelPath() (uppercase) for cross-package use
- Apply normalization in SyncJSONLToWorktreeWithOptions for dstPath
- Apply normalization in daemon_sync_branch.go for worktreeJSONLPath
in both commit and pull paths
- Add unit tests for the normalization function
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add SQLite read-only mode for commands that only query data (list, ready,
show, stats, blocked, count, search, graph, duplicates, comments, export).
Changes:
- Add NewReadOnly() and NewReadOnlyWithTimeout() to sqlite package
- Opens with mode=ro to prevent any file writes
- Skips WAL pragma, schema init, and migrations
- Skips WAL checkpoint on Close()
- Update main.go to detect read-only commands and use appropriate opener
- Skip auto-migrate, FlushManager, and auto-import for read-only commands
- Add tests verifying file mtime is unchanged after read operations
This fixes the issue where file watchers (like beads-ui) would go into
infinite loops because bd list/show/ready modified the database file.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Two issues fixed:
1. `bd init` was auto-detecting current branch (e.g., main) as sync.branch
when no --branch flag was specified. This caused worktree conflicts.
2. Added validation to reject main/master as sync.branch values.
When sync.branch is set to main, the worktree mechanism creates a checkout
of main at .git/beads-worktrees/main/, which prevents git checkout main
from working in the user's working directory.
The sync branch feature should use a dedicated branch like 'beads-sync'.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Executed-By: beads/crew/dave
Rig: beads
Role: crew
db.Exec was being passed %s format specifiers directly in the SQL
string, but db.Exec does not do printf-style formatting - it uses the
variadic args as SQL parameter bindings. This caused the literal %s
to be sent to SQLite, which failed with near percent: syntax error.
Fixed by using fmt.Sprintf to interpolate the column expressions into
the SQL string before passing to db.Exec.
Added regression test that creates an old-schema database with edge
columns (replies_to, relates_to, duplicate_of, superseded_by) and
verifies migration 022 completes successfully.
Fixes#809
Generated with Claude Code
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This addresses the code smell of 20+ global variables in main.go by:
1. Creating CommandContext struct in context.go that groups all runtime state:
- Configuration (DBPath, Actor, JSONOutput, etc.)
- Runtime state (Store, DaemonClient, HookRunner, etc.)
- Auto-flush/import state
- Version tracking
- Profiling handles
2. Adding accessor functions (getStore, getActor, getDaemonClient, etc.)
that provide backward-compatible access to the state while allowing
gradual migration to CommandContext.
3. Updating direct_mode.go to demonstrate the migration pattern using
accessor functions instead of direct global access.
4. Adding test isolation helpers (ensureCleanGlobalState, enableTestModeGlobals)
to prevent test interference when multiple tests manipulate global state.
Benefits:
- Reduces global count from 20+ to 1 (cmdCtx)
- Better testability (can inject mock contexts)
- Clearer state ownership (all state in one place)
- Thread safety (mutexes grouped with the data they protect)
Note: Two pre-existing test failures (TestTrackBdVersion_*) are unrelated to
this change and fail both with and without these modifications.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>