Add bd sync --check command that performs pre-sync integrity checks
without modifying state:
1. Force push detection: Detects when sync branch has diverged from
remote, indicating a potential force push
2. Prefix mismatch detection: Scans JSONL for issues that don't match
the configured prefix
3. Orphaned children detection: Finds issues with parent references
to non-existent issues
Outputs diagnostic with actionable suggestions for each problem found.
Exits with code 1 if any problems are detected.
Implements bd-hlsw.1: Pre-sync integrity check
The ExtractIssuePrefix function was falling back to first-hyphen
extraction when the suffix didn't look like a hash (e.g., 4+ char
words without digits). This broke prefixes like 'hacker-news' where
an issue ID 'hacker-news-test' would incorrectly extract 'hacker'.
Fix: Always use last-hyphen extraction for alphanumeric suffixes.
Only fall back to first-hyphen for non-alphanumeric suffixes.
Examples:
- 'hacker-news-test' -> 'hacker-news' (was: 'hacker')
- 'me-py-toolkit-abc' -> 'me-py-toolkit' (was: 'me')
- 'vc-baseline-hello' -> 'vc-baseline' (was: 'vc')
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When sync.branch is set to the current branch (e.g., main), bd sync
now commits directly instead of failing with a worktree error.
Changes:
- sync.go: Detect when current branch == sync branch and skip worktree
- sync.go: Show appropriate messages for direct-mode commits/pulls
- doctor.go: Change from Error to OK status when on sync branch
The fix allows users to work directly on the sync branch without
having to switch to a different branch for bd sync to work.
Closes: GH#519
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a truly silent quick-capture command that outputs only the issue ID,
enabling seamless script integration and reducing noise in AI conversations.
Changes:
- Add --silent flag to 'bd create' command
- Create new 'bd q' alias for quick capture
- Suppress warnings in silent/quiet mode
Usage:
bd q "Fix login bug" # Outputs only: bd-a1b2
ISSUE=$(bd q "New feature") # Capture ID in variable
bd create "Task" --silent # Same as bd q
Closes#540🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When `bd doctor --fix` fails to apply a fix, it was showing
"Manual fix: Run 'bd doctor --fix' ..." which is circular and unhelpful.
Now extracts just the manual command from the fix message:
- "..., or manually: <cmd>" -> extracts <cmd>
- "bd doctor --fix or <alt>" -> extracts <alt>
- No alternative available -> shows nothing
Closes GH#403
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Allow changing an issue type (bug, feature, task, epic, chore) via the
bd update command. The storage layer already supported issue_type in
allowedUpdateFields, this just exposes it through the CLI.
Changes:
- Add --type/-t flag to updateCmd in show.go
- Add IssueType field to UpdateArgs in protocol.go
- Handle issue_type in updatesFromArgs in server_issues_epics.go
- Add validation using ParseIssueType before update
Example usage:
bd update ab-xyz --type epic
Fixes: #522
Claude was using word-based priorities like "medium" instead of numeric
values (0-4 or P0-P4), causing bd create commands to fail in a loop.
Changes:
- Update bd prime output to clearly document priority format with example
- Add explicit note: NOT "high"/"medium"/"low"
- Improve error message to mention that words are not valid
Closes#517🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Two fixes to make pre-commit hook more resilient:
1. Check if beads is actually initialized (has db, config, or jsonl)
- Empty .beads directory no longer triggers sync attempt
- Handles case where .beads was removed from git but dir lingers
2. Make sync failure a warning instead of blocking error
- Beads issues shouldn't prevent code commits
- User can still run 'bd sync --flush-only' manually
Also synced examples/git-hooks/pre-commit with template (worktree handling).
Closes#483🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When sync branch diverges significantly from remote, provide clear
recovery options instead of a confusing rebase conflict error.
- Add CheckDivergence() to detect and report sync branch divergence
- Add ResetToRemote() to reset local sync branch to remote state
- Add --reset-remote and --force-push flags for recovery
- Improve error message when rebase fails to include recovery steps
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed all user-facing documentation and help text to use `in_progress`
(underscore) instead of `in-progress` (hyphen) to match the canonical
status value.
Files updated:
- cmd/bd/ready.go - Short description
- cmd/bd/status.go - Long description
- commands/stats.md - Action suggestion
- README.md - Workflow description
Note: CSS class names, HTML IDs, and GitHub label mappings intentionally
kept with hyphens as they follow different conventions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Only treat issue IDs as hierarchical (parent.child) when the dot appears
AFTER the first hyphen. This prevents false positives when the project
directory name contains a dot (e.g., "my.project-abc123" was incorrectly
being treated as having parent "my").
Fixes GH#508
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- bd-6pni: Auto-filter tombstoned issues with mismatched prefixes during
import instead of failing. Tombstones from contributor PRs with different
test prefixes are pollution and safe to ignore.
- bd-ffr9: Stop recreating deletions.jsonl after tombstone migration.
Added IsTombstoneMigrationComplete() check to all code paths that write
to the legacy deletions manifest.
- bd-admx: Fix perpetual "JSONL file hash mismatch" warning. Now clears
both export_hashes AND jsonl_file_hash when mismatch detected, so the
warning doesn't repeat.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes 46 broken relative links across 20 documentation files in docs/.
Changes:
- Added ../ prefix for root files (README.md, AGENTS.md)
- Removed ../ prefix for sibling docs files
- Removed dead links to non-existent files
- Fixed subdirectory paths
Based on PR #574 by chrisvaillancourt.
Co-Authored-By: Chris Vaillancourt <chrisvaillancourt@users.noreply.github.com>
- bd-8v5o: When doctor --fix hydrates issues from git history, also
remove them from the deletions manifest to prevent perpetual skip
warnings during sync
- bd-wsqt: Remove verbose per-issue "Skipping bd-xxx" messages during
sync. Caller already shows summary of skipped issues.
Added RemoveDeletions() function to deletions package with tests.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When importing issues, if an incoming issue has the same content hash as an
existing issue but a DIFFERENT prefix, this should not be treated as a rename.
Cross-prefix content matches occur when importing issues from other projects
that happen to have identical content.
Previously, the importer would call handleRename which tries to create an issue
with the incoming prefix, failing prefix validation ("does not match configured
prefix" error).
The fix checks if prefixes differ before calling handleRename:
- Same prefix, different ID suffix → true rename, call handleRename
- Different prefix → skip incoming issue, keep existing unchanged
Added test: TestImportCrossPrefixContentMatch reproduces the bug scenario
where alpha-* issues exist but beta-* issues are imported with same content.
Document the intent and nuances of recent fixes:
internal/importer/utils.go:
- RenameImportedIssuePrefixes: explain the three ID formats (sequential,
hash-based, hierarchical) and how prefix renaming preserves identity
- isValidIDSuffix: document why dots are allowed (hierarchical parent-child
relationships) and what characters are rejected
cmd/bd/deletion_tracking.go:
- isIssueNotFoundError: explain why "not found" is success during merge
(issue may be tombstoned, never existed locally, or manually deleted)
- Deletion loop: document what "accepted deletions" means and why we
tolerate missing issues during the pruning phase
During sync, the 3-way merge logic tries to delete issues that were
removed remotely. If an issue is already gone (tombstoned or never
existed locally), that shouldn't be an error - the goal is just to
ensure the issue is deleted.
Changes:
- Add isIssueNotFoundError helper to detect missing issue errors
- Skip "issue not found" errors during merge deletion (count as success)
- Update stats output to show already-gone count when relevant
Update bd show command to include status information for all dependency
types (children, blocks, related, discovered). Issues now display with
format [P1 - closed] instead of just [P1].
This provides better visibility into the state of dependent issues
without needing to run bd show on each individual issue.
Changes:
- Updated daemon mode formatting for all dependency types (lines 208, 214, 220, 226)
- Updated direct mode formatting for all dependency types (lines 400, 406, 412, 418)
- Changed format from "[P%d]" to "[P%d - %s]" with dash separator
Example output:
Children (9):
↳ pma-an8: Create config.py module [P1 - closed]
↳ pma-38g: Create utils.py module [P1 - open]
Blocks (1):
← pma-uzm: Adapt validate_outputs.py [P1 - blocked]
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
The isNumeric function was rejecting valid hierarchical hash IDs like
'6we.2' that contain dots for parent.child notation. This caused
`bd import --rename-on-import` to fail with "non-numeric suffix" errors.
Changes:
- Rename isNumeric to isValidIDSuffix for clarity
- Accept dots (.) in addition to alphanumeric for hierarchical IDs
- Update test cases to cover hierarchical ID formats
* feat: auto-disable daemon in git worktrees for safety
Implement worktree daemon compatibility as proposed in the analysis.
The daemon is now automatically disabled when running in a git worktree
unless sync-branch is configured.
Git worktrees share the same .beads directory, and the daemon commits
to whatever branch its working directory has checked out. This causes
commits to go to the wrong branch when using daemon in worktrees.
- Add shouldDisableDaemonForWorktree() helper that checks:
1. If current directory is a git worktree (via git rev-parse)
2. If sync-branch is configured (env var or config.yaml)
- Modify shouldAutoStartDaemon() to call the helper
- Modify daemon connection logic in main.go to skip connection
- Add FallbackWorktreeSafety constant for daemon status reporting
- Update warnWorktreeDaemon() to skip warning when sync-branch configured
- In worktree WITHOUT sync-branch: daemon auto-disabled, direct mode used
- In worktree WITH sync-branch: daemon enabled (commits go to dedicated branch)
- In regular repo: no change (daemon works as before)
- Added comprehensive unit tests for shouldDisableDaemonForWorktree()
- Added integration tests for shouldAutoStartDaemon() in worktree contexts
- Manual E2E testing verified correct behavior
- Updated WORKTREES.md with new automatic safety behavior
- Updated DAEMON.md with Git Worktrees section
* feat: check database config for sync-branch in worktree safety logic
Previously, the worktree daemon safety check only looked at:
- BEADS_SYNC_BRANCH environment variable
- sync-branch in config.yaml
This meant users who configured sync-branch via `bd config set sync-branch`
(which stores in the database) would still have daemon disabled in worktrees.
Now the check also reads sync.branch from the database config table,
making daemon work in worktrees when sync-branch is configured via any method.
Changes:
- Add IsConfiguredWithDB() function that checks env, config.yaml, AND database
- Add findBeadsDB() to locate database (worktree-aware via git-common-dir)
- Add getMainRepoRoot() helper using git rev-parse
- Add getConfigFromDB() for lightweight database reads
- Update shouldDisableDaemonForWorktree() to use IsConfiguredWithDB()
- Update warnWorktreeDaemon() to use IsConfiguredWithDB()
- Add test case for database config path
* refactor: use existing beads.FindDatabasePath() instead of duplicating code
Remove duplicate getMainRepoRoot() and findBeadsDB() functions from
syncbranch.go and use the existing beads.FindDatabasePath() which is
already worktree-aware.
Changes:
- Replace custom findBeadsDB() with beads.FindDatabasePath()
- Remove duplicate getMainRepoRoot() (git.GetMainRepoRoot() exists)
- Remove unused imports (exec, strings, filepath)
- Clean up debug logging in tests
---------
Co-authored-by: Charles P. Cross <cpdata@users.noreply.github.com>
The --repair flag was generating sequential IDs (sageox-9895, sageox-9896)
instead of hash-based IDs (sageox-jwnv, sageox-urtm). This fix uses the
proper GenerateIssueID function from sqlite package to generate consistent
hash-based IDs during prefix repair operations.
Changes:
- Import sqlite package for hash ID generation
- Add generateRepairHashID helper that uses sqlite.GenerateIssueID
- Track used IDs within batch to avoid collisions
- Update test to verify hash IDs instead of sequential
Contributors frequently fork the repo and accidentally include their local
.beads/issues.jsonl changes in PRs. This adds:
1. A new CI job that fails PRs containing .beads/issues.jsonl changes
2. Clear error message with fix instructions
3. Updated CONTRIBUTING.md with guidance
This should prevent the common issue of PRs including unintended database changes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>