Support --type enhancement as an alias for --type feature when creating
issues. The normalization happens before validation to ensure consistency
across all code paths.
Closes gt-hzanoe
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The acquireStartLock function would recursively call itself after
attempting to remove a stale lock file. If os.Remove failed (due to
permissions, race conditions, etc.), the error was silently ignored
with `_`, causing infinite recursion until the 1GB stack limit was
exceeded.
Changes:
- Convert recursive calls to a bounded retry loop (max 3 attempts)
- Check removeFileFn return value before retrying
- Apply same fix to handleStaleLock which had the same issue
- Add test to verify function returns false when remove fails
Fixes the stack overflow crash that occurred when running any bd
command with a stale or problematic lock file.
Co-authored-by: Steven Syrek <steven.syrek@deepl.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Fix infinite recursion bug in computeJSONLHashForHook (was calling
itself instead of computeJSONLHash)
- Update pre-commit, post-merge, post-checkout templates to use
`bd hook <name>` instead of `bd hooks run <name>`, routing to the
Dolt-aware implementations in hook.go
- Update all hook template versions to 0.48.0 for consistency
The hook infrastructure added in 15d74a9a had a critical bug where
the hash computation function recursed infinitely, and the templates
still pointed to the old hook implementations in hooks.go instead
of the new Dolt-aware ones in hook.go.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit implements the git hook infrastructure for Dolt storage backend
as specified in the design document.
Changes:
- Add `bd hook` command (singular) for git hooks to call directly
- Implement per-worktree export state tracking in .beads/export-state/
- Add post-checkout guard to only import if JSONL changed
- Add hook chaining configuration (chain_strategy, chain_timeout_ms)
- Support hooks in .beads/hooks/ directory with git config core.hooksPath
- Implement branch-then-merge import pattern for Dolt storage
- Update bd init to install hooks to .beads/hooks/ for Dolt backend
- Add --beads flag to `bd hooks install` command
The new `bd hook` command supports:
- pre-commit: Export database to JSONL, stage changes
- post-merge: Import JSONL to database after pull/merge
- post-checkout: Import JSONL after branch checkout (with guard)
For Dolt backend, uses branch-then-merge pattern:
1. Create jsonl-import branch
2. Import JSONL data to branch
3. Merge branch to main (cell-level conflict resolution)
4. Delete branch on success
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Git hooks are shared across all worktrees and live in the common git
directory (e.g., /repo/.git/hooks), not the worktree-specific directory
(e.g., /repo/.git/worktrees/feature/hooks).
The core issue was in GetGitHooksDir() which used GetGitDir() instead
of GetGitCommonDir(). This caused hooks to be installed to/read from
the wrong location when running in a worktree.
Additionally, several places in the codebase manually constructed
hooks paths using gitDir + "hooks" instead of calling GetGitHooksDir().
These have been updated to use the proper worktree-aware path.
Affected areas:
- GetGitHooksDir() now uses GetGitCommonDir()
- CheckGitHooks() uses GetGitHooksDir()
- installHooks/uninstallHooks use GetGitHooksDir()
- runChainedHook() uses GetGitHooksDir()
- Doctor checks use git-common-dir for hooks paths
- Reset command uses GetGitCommonDir() for hooks and beads-worktrees
Symptoms that this fixes:
- Chained hooks (pre-commit.old) not running in worktrees
- bd hooks install not finding/installing hooks correctly in worktrees
- bd hooks list showing incorrect status in worktrees
- bd doctor reporting incorrect hooks status in worktrees
Co-authored-by: Zain Rizvi <4468967+ZainRizvi@users.noreply.github.com>
The JSONL file hash mismatch warning was appearing consistently after
git commit operations, even when no actual data inconsistency existed.
Root Cause:
Two code paths export to JSONL but only one updated jsonl_file_hash:
- flushToJSONLWithState() (used by bd update/create): Updated both
jsonl_content_hash AND jsonl_file_hash
- finalizeExport() (used by bd sync --flush-only): Updated only
jsonl_content_hash, NOT jsonl_file_hash
Since validateJSONLIntegrity() checks jsonl_file_hash, any bd command
after a git commit would see a mismatch and trigger the warning.
Steps to Reproduce (before fix):
1. cd /path/to/beads-project
2. bd update -p 3 some-issue-id # Works fine, stores hash H1
3. git add .beads/issues.jsonl && git commit --amend --no-edit
# Pre-commit hook runs bd sync --flush-only
# This updates jsonl_content_hash to H2 but leaves jsonl_file_hash as H1
4. bd update -p 3 some-issue-id # WARNING appears!
# validateJSONLIntegrity() compares file (H2) with jsonl_file_hash (H1)
5. Repeat steps 3-4 indefinitely - warning always appears
The fix adds SetJSONLFileHash() call to finalizeExport(), ensuring both
export paths update the same metadata consistently.
WSL doesn't fully respect Unix file permission semantics - the file
owner can bypass read-only restrictions, similar to macOS. Add isWSL()
helper and skip TestMergeDriverWithLockedConfig_E2E on WSL.
Fixes bd-srv
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
The dolt storage backend requires CGO due to its gozstd dependency.
This change makes the dolt backend optional using build tags, allowing
`go install` to work on Windows where CGO is disabled by default.
Changes:
- Add BackendFactory registration pattern to factory package
- Create factory_dolt.go with `//go:build cgo` constraint that
registers the dolt backend only when CGO is available
- Update init.go to use factory instead of direct dolt import
- When dolt backend is requested without CGO, provide helpful error
message directing users to pre-built binaries
The sqlite backend (default) works without CGO and covers the majority
of use cases. Users who need dolt can either:
1. Use pre-built binaries from GitHub releases
2. Enable CGO by installing a C compiler
Fixes#1116
Add "__complete" to noDbCommands list so that Cobra's internal completion
command can run without requiring a beads database to be present.
Previously, running shell completions (e.g., `bd show <TAB>`) in a directory
without a .beads database would fail with "no beads database found" error.
Now completions return empty results gracefully when no database exists,
allowing basic command completion to work everywhere while issue ID
completion still requires a database.
Added integration test that verifies __complete command works without a database.
Remove dead code that was inadvertently orphaned when PR #918 refactored
the sync flow. The function was never called since v0.47.0.
The function caused GH#1100 by running `git checkout HEAD -- .beads/`
which restored the entire .beads/ directory, overwriting uncommitted
config.yaml changes.
Add regression test (TestConfigPreservedDuringSync) to prevent similar
restoration logic from being reintroduced.
Fixes#1100
When routing issues to other repos (via contributor routing or --rig flag),
the code was hardcoding sqlite.New instead of using the storage factory.
This meant Dolt-configured repos would fail when receiving routed issues.
Changed two locations:
- Contributor routing (line 357): use factory.NewFromConfig
- createInRig --rig flag (line 789): use factory.NewFromConfig
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changes:
- Save issue-prefix in config.yaml when using --no-db mode
(previously only saved in database which doesn't exist in no-db mode)
- Add config.ResetForTesting() to allow reloading config in tests
- Simplify test to verify config values rather than execute subsequent
commands (cobra's flag caching makes multi-Execute() testing complex)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
setupGitRepo now creates an empty issues.jsonl for RepoContext,
which triggers 'JSONL changed since import' validation in tests
that set up their own .beads/ directory.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Centralizes repository context resolution via RepoContext API, fixing bugs where git commands run in the wrong repo when BEADS_DIR points elsewhere or in worktree scenarios.
Update all documentation to use the new subcommand syntax:
- `bd daemon --start` → `bd daemon start`
- `bd daemon --stop` → `bd daemon stop`
- `bd daemon --status` → `bd daemon status`
- `bd daemon --health` → `bd daemon status --all`
- `--global=false` → `--local`
The old flag syntax is deprecated but still works with warnings.
Closes: bd-734vd
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 2 of Dolt integration - enables runtime backend selection:
- Add --backend flag to bd init (sqlite|dolt)
- Create storage factory for backend instantiation
- Update daemon and main.go to use factory with config detection
- Update database discovery to find Dolt backends via metadata.json
- Fix Dolt schema init to split statements for MySQL compatibility
- Add ReadOnly mode to skip schema init for read-only commands
Usage: bd init --backend dolt --prefix myproject
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Apply same fix as #1091 to isMCPServerInstalled(): check all three
settings locations (user-level, project-level, and project-local).
- Extract checkMCPInSettings() helper function
- Check ~/.claude/settings.json, .claude/settings.json, and
.claude/settings.local.json
- Add TestIsMCPServerInstalledProjectLevel with positive and negative cases
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
The variable was declared and set but never actually used for anything,
just assigned to blank identifier. Clean up dead code from PR #1088.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(doctor): detect beads plugin in project-level settings
isBeadsPluginInstalled() now checks project-level settings files
(.claude/settings.json and .claude/settings.local.json) in addition
to user-level settings (~/.claude/settings.json).
This fixes the contradictory bd doctor output where the plugin check
passes but the integration check warns "Not configured" when the
plugin is enabled at project scope.
Fixes#1090
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(doctor): detect Claude hooks in project-level settings.json
hasClaudeHooks() was missing .claude/settings.json - it only checked
.claude/settings.local.json for project-level hooks.
Now checks all three locations:
- ~/.claude/settings.json (user-level)
- .claude/settings.json (project-level)
- .claude/settings.local.json (project-level, gitignored)
Also uses filepath.Join consistently for cross-platform compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
When a crew worker's .beads/ is redirected to another repo, bd sync
now detects this and skips all git operations (sync-branch worktree
manipulation). Instead, it just exports to JSONL and lets the target
repo's owner handle the git sync.
Changes:
- sync.go: Detect redirect early, skip git operations when active
- beads.go: Update GetRedirectInfo() to check git repo even when
BEADS_DIR is pre-set (findLocalBdsDirInRepo helper)
- validation.go: Add doctor check for redirect + sync-branch conflict
- doctor.go: Register new check, remove undefined CheckMisclassifiedWisps
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Executed-By: beads/crew/dave
Rig: beads
Role: crew
The bd edit command opens an interactive editor ($EDITOR) which AI agents
cannot use. Added warnings to AGENTS.md, AGENT_INSTRUCTIONS.md, and
cmd/bd/AGENTS.md directing agents to use bd update with flags instead.
Fixes: bd-3ft33
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When beads directory is redirected to a different repository (via bd-arjb),
gitCommitBeadsDir() was running git add from the current working directory's
repo root instead of the beads directory's repo root, causing exit status 128.
This fix adds the same redirect handling already present in gitHasBeadsChanges()
and gitHasUncommittedBeadsChanges() - checking GetRedirectInfo() and using
filepath.Dir(beadsDir) as the repo root when redirected.
Fixes: git add failed: exit status 128 errors during bd sync
The --children flag would produce no output for issues without children.
Initialize the map entry in processIssue so the display loop can show
"No children found" message.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds a --children flag to the bd show command that displays only the
children of the specified issue. This is useful for quickly viewing
child steps of an epic without the full issue details.
The flag supports:
- Default mode: shows children with full dependency line formatting
- --short mode: shows compact one-liner per child
- --json mode: outputs children in JSON format
Fixes gt-lzf3.5
Co-authored-by: toast <julianknutsen@users.noreply.github>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add support for JetBrains Junie AI agent:
- Create .junie/guidelines.md with workflow instructions
- Create .junie/mcp/mcp.json for MCP server configuration
- Add 'junie' to BuiltinRecipes in recipes.go
- Add runJunieRecipe() handler in setup.go
- Add website documentation
- Add integrations/junie/README.md
Usage: bd setup junie
Add daemonClient.ResolveID() calls before AddComment and ListComments
operations in daemon mode, following the pattern from update.go.
Previously, short IDs (e.g., "5wbm") worked with most bd commands but
failed with `comments add` and `comments list` when using the daemon.
The short ID was passed directly to the RPC server which expected full
IDs (e.g., "prefix-5wbm").
Changes:
- cmd/bd/comments.go: Add ID resolution before daemon RPC calls
- internal/rpc/comments_test.go: Update tests to reflect client-side
resolution pattern (RPC server expects full IDs, CLI resolves first)
Fixes: https://github.com/steveyegge/beads/issues/1070
Add tests demonstrating that `bd comments add` and `bd comments list`
don't accept short IDs in daemon mode, while other commands do.
Tests added:
- TestCLI_CommentsAddShortID (cli_fast_test.go)
- Tests short ID, partial ID, and comment alias in direct mode (passes)
- TestCommentAddWithShortID (internal/rpc/comments_test.go)
- Tests RPC layer with short ID (FAILS - demonstrates bug)
- TestCommentListWithShortID (internal/rpc/comments_test.go)
- Tests listing comments with short ID (FAILS - demonstrates bug)
The fix should add daemonClient.ResolveID() before AddComment/ListComments,
following the pattern in update.go and label.go.
Refs: https://github.com/steveyegge/beads/issues/1070
Previously, displayGates() always showed 'Open Gates' header even when
closed gates were included via --all flag. Also, closed gates would
appear mixed with open gates under the misleading 'Open Gates' header.
Changes:
- Modified displayGates() to accept showAll parameter
- Separates gates into 'Open Gates' and 'Closed Gates' sections
- Closed gates only shown when --all flag is used
- Fixed handleGateList RPC handler to use ExcludeStatus instead of
Status filter for consistency with CLI behavior
Fixes gas-town issue go-47m
The test guard was flagging false positives when SQLite shm/wal files
had their mtime updated from read-only operations (config loading, etc.)
without any actual content modification.
Now only reports when file size changes, which indicates actual content
modification rather than just file access.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add multiple layers of defense against misclassified wisps:
- Importer auto-detects -wisp- pattern and sets ephemeral flag
- GetReadyWork excludes -wisp- IDs via SQL LIKE clause
- Doctor check 26d detects misclassified wisps in JSONL
This addresses recurring issue where wisps with missing ephemeral
flag would pollute bd ready output after JSONL import.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- sync_git_test.go: getCurrentBranchOrHEAD now returns 1 value (not 2)
- daemon_basics_test.go: getPIDFileForSocket uses dbPath not socketPath
- daemon_autostart.go: mark unused socketPath param with underscore
These tests were broken by recent refactors that changed function signatures
but didn't update the corresponding test files.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When using short socket paths (workspaces with paths >103 chars),
filepath.Dir(socketPath) returns /tmp/beads-XXXXX/ instead of the
actual .beads/ directory. This caused TryDaemonLock to look in the
wrong location, always return false, clean up the startlock, and
recurse infinitely causing stack overflow.
Changed 4 occurrences in acquireStartLock, handleStaleLock,
handleExistingSocket, and getPIDFileForSocket to use
filepath.Dir(dbPath) which correctly points to .beads/.
Fixes: gt-qlt
Co-authored-by: furiosa <mayor@gastown.local>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
The function always returns nil for error since it is designed to
return HEAD on detached HEAD state. Simplify signature to just
return string.
Fixes golangci-lint unparam warning.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add bd doctor check that detects legacy gastown merge queue JSON files
in .beads/mq/. These files are local-only remnants from the old mrqueue
implementation and can safely be deleted since gt done already creates
merge-request wisps in beads.
- CheckStaleMQFiles() detects .beads/mq/*.json files
- FixStaleMQFiles() removes the entire mq directory
- Comprehensive tests for check and fix
This is the first step toward removing the mrqueue side-channel from
gastown. The follow-up convoy will update Refinery/Witness to use
beads exclusively.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add bd doctor check that warns if .beads/last-touched is tracked by git.
This file is local runtime state that should never be committed, as it
causes spurious diffs in other clones.
- CheckLastTouchedNotTracked() detects if file is git-tracked
- FixLastTouchedTracking() untracks with git rm --cached
- Comprehensive tests for all scenarios
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
prek (https://prek.j178.dev) is a faster Rust-based alternative to
pre-commit that uses the same .pre-commit-config.yaml config files.
Changes:
- Add prek detection pattern in hookManagerPatterns (before pre-commit
to ensure correct detection since prek hooks may contain 'pre-commit')
- Handle prek in checkManagerBdIntegration using same config parser
- Update init_git_hooks.go to recognize prek-installed hooks
- Rename isPreCommit field to isPreCommitFramework for clarity
- Use regex pattern matching all pre-commit/prek signatures consistently
- Add test cases for prek run and prek hook-impl signatures
Co-authored-by: Ismar Iljazovic <ismar@gmail.com>
macOS allows file owners to write to their own read-only (0444) files,
so TestSetupGlobalGitIgnore_ReadOnly cannot exercise the "Unable to write"
code path on this platform.
Skip both test cases on darwin with an explanatory message.
The test was failing because it called 'git config --global core.excludesfile'
which returned the real user's gitignore path instead of using the test's
temp directory.
Fix: Set GIT_CONFIG_GLOBAL env var to an empty temp config file, ensuring
the test uses the temp directory's .config/git/ignore path as intended.
Also extracted the isolation logic into a reusable setupIsolatedGitConfig helper.
Co-authored-by: Ismar Iljazovic <ismar@gmail.com>
Fixes#1041
The pre-push hook was not passing arguments to chained hooks,
causing them to fail. This change:
1. Changes runPrePushHook() to accept args []string parameter
2. Passes args to runChainedHook() instead of nil
3. Updates call site to pass hookArgs
4. Renames local 'args' to 'statusArgs' to avoid variable shadowing
Co-authored-by: Ismar Iljazovic <ismar@gmail.com>