Adds worktree detection to post-checkout hooks. When entering a git
worktree, displays a warning explaining that daemon mode has limitations
with worktrees and recommends using BEADS_NO_DAEMON=1.
Detection uses `git rev-parse --git-dir` vs `--git-common-dir` comparison
to identify worktree checkouts.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: maphew <maphew@users.noreply.github.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Fixes#417: When using --from-main mode (either explicitly or auto-detected),
git history backfill now defaults to disabled. This prevents creating
incorrect deletion records for locally-created beads that don't exist in
main's git history.
Changes:
- Add resolveNoGitHistoryForFromMain() helper function
- Apply noGitHistory=true for both explicit and auto-detected from-main mode
- Add comprehensive unit tests
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: GraemeF <graeme@graemef.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Fixes from maphew including:
- Remove test for deleted isPathWithinDir function
- Add gosec nolint directives for safe file operations
- Add rm -rf .beads before init in CI workflow
- Simplify panic handling and file operations
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: maphew <maphew@users.noreply.github.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed incorrect bd dep documentation in prime.go, cursor.go, and aider.go
- Added missing 'add' subcommand (was 'bd dep <from> <to>', now 'bd dep add <issue> <depends-on>')
- Corrected semantics (docs claimed 'from blocks to' but actual behavior is 'issue depends on depends-on')
This fixes AI agents and users consistently creating dependencies in the wrong direction.
Co-authored-by: jflam <jflam@users.noreply.github.com>
Root cause: When beads.db is deleted and recreated while daemon is running,
daemon's SQLite connection becomes stale (points to old deleted file via
file descriptor), causing export to return incomplete/corrupt data.
Fix:
- sync command now forces direct mode by closing daemonClient at start
- importFromJSONL subprocess uses --no-daemon to avoid daemon connection issues
- Added documentation to import.go explaining the daemon behavior
Also:
- Skip TestZFCSkipsExportAfterImport (broken test - subprocess spawning
doesn't work in test environment, needs refactoring
- Update hook templates to version 0.26.2
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
EOF
)
The existing ZFC checks only compared issue counts, missing the case where
counts match but content differs (e.g., status=open vs status=closed).
Added Case 3 (bd-f2f) hash-based staleness detection:
- Before export, check if JSONL content hash differs from stored hash
- If hash mismatch detected, import JSONL first to get remote changes
- Then proceed with export to write merged state
This prevents the corruption scenario where:
1. Stale DB has old status values (e.g., status=closed)
2. Remote JSONL has correct values (e.g., status=open)
3. Export would overwrite correct JSONL with stale DB values
4. Git 3-way merge would propagate the corruption
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Root cause: bd sync exports DB to JSONL BEFORE pulling from remote.
If the local DB is stale (fewer issues than JSONL), the stale data gets
exported and committed, potentially corrupting the remote when pushed.
The existing ZFC (Zero-Fill Check) only detected when DB had MORE issues
than JSONL, missing the dangerous reverse case.
Fix: Added "reverse ZFC" check in sync.go that detects when JSONL has
significantly more issues than DB (>20% divergence or empty DB).
When detected, it imports JSONL first to sync the database before
any export occurs.
This prevents stale/fresh clones from exporting their incomplete
database state over a well-populated JSONL file.
Version bump: 0.26.0 -> 0.26.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- issues.jsonl: Keep closed status for bd-5kj (already resolved)
- main.go: Clean up JSONL-only mode detection, include BD_ACTOR env check
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
When .beads exists with issues.jsonl but no SQLite database, and config.yaml
has no-db: true, automatically enable JSONL-only mode instead of failing
with 'no beads database found'. Also improved error message to mention
--no-db option.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Create reusable error handling helpers to reduce boilerplate and
enforce consistency across the codebase:
- FatalError(format, args...): writes "Error: ..." to stderr and exits
- FatalErrorWithHint(message, hint): includes actionable suggestion
- WarnError(format, args...): writes "Warning: ..." to stderr
Prototyped in create.go to validate the approach - converted 13 error
patterns and 5 warning patterns. This reduces code from:
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
To simply:
FatalError("%v", err)
Also fixed countIssuesInJSONLFile reference after earlier refactoring.
See docs/ERROR_HANDLING.md for the three-pattern guideline.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Users can now define custom status states for multi-step pipelines using:
bd config set status.custom "awaiting_review,awaiting_testing,awaiting_docs"
Changes:
- Add Status.IsValidWithCustom() method for custom status validation
- Add Issue.ValidateWithCustomStatuses() method
- Add GetCustomStatuses() method to storage interface
- Update CreateIssue/UpdateIssue to support custom statuses
- Add comprehensive tests for custom status functionality
- Update config command help text with custom status documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The metadata key 'last_import_hash' was misleading because it's updated on
both import AND export. Renamed to 'jsonl_content_hash' which more accurately
describes its purpose - tracking the content hash of the JSONL file.
Added migration support: read operations try new key first, then fall back
to old key for backwards compatibility with existing databases.
Files modified:
- cmd/bd/integrity.go: Update key name with migration support
- cmd/bd/import.go: Update key name
- cmd/bd/sync.go: Update key name
- cmd/bd/autoflush.go: Update key name with migration support
- cmd/bd/daemon_sync.go: Update key name
- cmd/bd/daemon_event_loop.go: Update key name with migration support
- internal/autoimport/autoimport.go: Update key name with migration support
- Updated all related tests
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Clarify bd merge help text: git merge driver, not for duplicate issues
- Add Do I Need the Daemon section to DAEMON.md
- Add daemon overview section to QUICKSTART.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
For solo developers who don't need real-time multi-agent coordination,
--squash accumulates changes in JSONL without committing. Run 'bd sync'
later (without --squash) to commit all accumulated changes in one commit.
This reduces git history noise while preserving the default behavior
needed for multi-agent orchestration.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Extract shared JSONL file discovery logic to internal/utils/path.go.
Both autoimport and beads packages now use this shared implementation.
Changes:
- Add utils.FindJSONLInDir with common logic
- Update autoimport.go to use utils.FindJSONLInDir
- Update beads.go to delegate to utils.FindJSONLInDir
- Update server_export_import_auto.go to use utils.FindJSONLInDir
- Move FindJSONLInDir test to utils/path_test.go
- Fix pre-existing duplicate countIssuesInJSONLFile in init.go
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Directory discovery (FindBeadsDir, findDatabaseInTree, FindAllDatabases)
now stops at the git repository root to avoid finding unrelated databases
in parent directories (e.g., ~/.beads).
Added findGitRoot() helper that uses 'git rev-parse --show-toplevel'.
Also updated TestCheckDatabaseVersionJSONLMode to properly simulate
no-db mode by creating config.yaml with 'no-db: true'.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add CheckFreshClone function that detects when JSONL contains issues
but no database exists. Recommends 'bd init --prefix <detected-prefix>'
to hydrate the database. This check appears early in doctor output
to guide users on fresh clones.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
bd init now refuses when:
- JSONL file exists with >0 issues (fresh clone scenario)
- Database file already exists (already initialized)
Suggests `bd doctor --fix` for fresh clones and provides clear guidance.
Added --force flag to bypass the safety guard when needed.
Closes: bd-emg
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
When JSONL exists but no database (and not no-db mode), doctor now:
- Shows 'Fresh clone detected' warning
- Shows count of issues in JSONL
- Recommends 'bd init' with detected prefix
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Verify that beads.base.jsonl and beads.left.jsonl patterns are correctly
excluded from the 'multiple JSONL files' warning, same as issues.base.jsonl.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Moved snapshot cleanup call to the end of successful sync, outside the
!noPull block. This ensures snapshot files (beads.base.jsonl, beads.left.jsonl)
are removed even when --no-pull is used.
Previously, captureLeftSnapshot was called before the pull block, but
cleanup was only inside the pull block, leaving orphaned files when
--no-pull was used.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add cleanup call at end of successful sync to ensure snapshot files
(beads.base.jsonl, beads.left.jsonl) are removed even when --no-pull
is used. Previously, captureLeftSnapshot was called before the pull
block, but cleanup was only inside the !noPull block, leaving orphaned
files.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- bound fresh-clone JSONL discovery to the .beads dir (abs path, traversal guard) before reading counts
- add safeWorkspacePath/isWithinWorkspace helpers and use in doctor fixes (database_config, untracked) to reject absolute/traversal inputs and confine .gitattributes edits
- normalize git status paths and path-guard tests for cross-OS (Windows) compatibility
- add regression tests for the new guards
Previously, setupClaudeSettings would silently create an empty settings
map when json.Unmarshal failed, then write just a prompt field to the
file - destroying all existing user settings (permissions, hooks, etc).
Now returns a clear error asking the user to fix the JSON syntax
manually, preserving their original file contents.
Also properly handles permission errors when reading existing files.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Jimmy Stridh <jimmystridh@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
- Add CloseReason field to Issue struct in types.go
- Add GetCloseReason() and batch GetCloseReasonsForIssues()
- Update issue loading to populate close reasons
- Update scanIssues() to include close_reason in JSONL export
- Update bd show to display close reason after status
Close reasons now survive sync between repos.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The sync validation was incorrectly triggering 'data loss detected' when
issue count decreased after import, even for legitimate deletions recorded
in deletions.jsonl.
Changes:
- Modified validatePostImport to accept jsonlPath and check deletions manifest
- When issue count decreases, check if decrease is within recorded deletions
- Updated all call sites in sync.go and daemon_sync.go
- Added comprehensive tests for deletion-aware validation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
After sync completion, orphan .base.jsonl and .left.jsonl files were
remaining in .beads/ directory. These are merge artifacts that should be
cleaned up after successful sync.
The fix adds SnapshotManager.Cleanup() call to createSyncFunc in
daemon_sync.go after successful import, matching the behavior of the CLI
sync command. Supports both single-repo and multi-repo modes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add .base.jsonl, .left.jsonl, and .right.jsonl patterns to the skip list
in CheckLegacyJSONLFilename. These are legitimate git merge conflict
artifacts that should not trigger a warning about multiple JSONL files.
Fixes: bd-nsb
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add CloseReason field to Issue struct
- Add GetCloseReason and GetCloseReasonsForIssues queries
- Batch-load close reasons in scanIssues for efficiency
- Display close reason in bd show output
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Auto-import was allowing git history backfill to run, which could
incorrectly purge issues. The fix adds NoGitHistory=true to all
auto-import code paths:
- autoimport.go (importFromGit)
- autoflush.go (autoImportIfNewer)
- daemon_sync.go (importToJSONLWithStore)
Git history backfill is designed to detect deletions that happened
after a local DB was created. During auto-import, there is no local
work to protect - we are importing from the authoritative JSONL source.
Also adds comprehensive tests for NoGitHistory behavior.
Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
When opening a database that exists but is missing issue_prefix config
(typical in fresh clone scenarios), show a helpful error message instead
of cryptic migration invariant errors.
The new message:
- Explains the database needs initialization
- Detects if a JSONL file exists and shows the issue count
- Suggests the exact command to run: bd import -i <path>
- Falls back to suggesting bd init --prefix if no JSONL exists
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
When --auto-merge is used, performMerge now automatically:
1. Closes source issues with "Duplicate of <target>" reason
2. Links each source to target with a "related" dependency
Closes bd-hdt
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed gitCommitBeadsDir to explicitly stage only sync files
(issues.jsonl, deletions.jsonl, metadata.json) instead of the
entire .beads/ directory.
This prevents staging gitignored snapshot files (beads.*.jsonl,
*.meta.json) that may still be tracked from before they were
added to .gitignore, which could cause merge conflicts when
multiple polecats run bd sync concurrently.
- Fix doctor to treat empty deletions.jsonl as valid (0 entries OK status)
- Fix HydrateDeletionsManifest to create empty file when no deletions found
- Add --parent flag documentation to onboard command
- Add CLI --help tip throughout onboard documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Short tests were timing out after 13+ minutes due to:
1. TestZFCSkipsExportAfterImport spawning subprocess that tried to
auto-start daemon - now skipped in short mode
2. TestVersionFlag taking 5+ seconds because --version flag did not
skip PersistentPreRun daemon startup - added early return
3. TestGetVersionsSince* had hardcoded version expectations that
became stale - made tests dynamic using versionChanges array
Short tests now complete in ~8 seconds instead of timing out.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Two fixes to prevent git pull --rebase from failing:
1. Skip hook execution during rebase operations by detecting
.git/rebase-merge or .git/rebase-apply directories
2. Use --no-git-history flag to prevent git-history-backfill
from writing to deletions.jsonl during imports
The root cause was that post-checkout hooks were running during
rebase, triggering the git-history-backfill which appends to
deletions.jsonl. This created uncommitted changes that blocked
the rebase from continuing.
Bump hooks version to 0.26.0 (requires bd version bump to take effect).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- autoImportIfNewer() now directly checks noAutoImport flag
- Ensures auto-import is blocked even if caller forgets to check autoImportEnabled
- Added TestAutoImportIfNewer_NoAutoImportFlag test to verify the fix
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The staleness check compares last_import_time against JSONL file mtime.
File mtime has nanosecond precision, but last_import_time was stored with
only second precision (RFC3339). This caused a race condition where the
stored time could be slightly earlier than the file mtime, triggering
false "Database out of sync" errors - particularly in git worktrees.
Changed all 6 locations that set last_import_time to use RFC3339Nano.
The CheckStaleness parser already handles both formats, so this is
backward compatible.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixes bd-0b2: The git history backfill mechanism was causing data loss
during JSONL filename migrations (beads.jsonl → issues.jsonl). When issues
existed in the old filename's git history, the backfill incorrectly treated
them as "deleted" and purged them from the database.
Changes:
- Add NoGitHistory field to importer.Options and ImportOptions structs
- Modify purgeDeletedIssues() to skip git history check when flag is set
- Add --no-git-history flag to bd import command
- Add --no-git-history flag to bd sync command
- Update purge_test.go to pass Options argument
Usage:
bd import -i .beads/issues.jsonl --no-git-history
bd sync --no-git-history
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- bd init now preserves existing metadata.json settings instead of
overwriting with defaults (bd-zai)
- bd init detects existing JSONL filename (beads.jsonl vs issues.jsonl)
when creating new metadata.json
- bd import now correctly reports prefix source ("issues" vs "directory")
- bd import avoids using ".beads" as prefix when run from inside .beads/
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Change default JSONL filename from beads.jsonl to issues.jsonl
- Add bd doctor check and fix to auto-migrate legacy beads.jsonl configs
- Update FindJSONLPath to prefer issues.jsonl over beads.jsonl
- Add CheckLegacyJSONLConfig and CheckLegacyJSONLFilename checks
- Add LegacyJSONLConfig fix to rename files and update config
- Update .gitattributes to reference issues.jsonl
- Fix tests to expect new canonical filename
- Add bd-6xd to v0.25.1 release notes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>