- Add dolt_mode, dolt_server_host, dolt_server_port fields to configfile.Config
- Add IsDoltServerMode(), GetDoltServerHost(), GetDoltServerPort() helpers
- Update factory to read server mode config and set Options accordingly
- Skip bootstrap in server mode (database lives on server)
- Pass Database name to dolt.Config for USE statement after connecting
- Disable dolt stats collection to avoid lock issues in embedded mode
This enables bd to connect to a running dolt sql-server (started via
'gt dolt start') instead of using embedded mode, allowing multi-client
access without file locking conflicts.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Code review fix: In server mode, Dolt connects to an external sql-server
and should NOT be single-process-only. The whole point of server mode is
to enable multi-writer access.
Changes:
- Add Config.GetCapabilities() method that considers server mode
- Update daemon_guard, daemon_autostart, daemons, main to use GetCapabilities()
- Add TestGetCapabilities test
- Update init command help text to document server mode flags
The existing CapabilitiesForBackend(string) is kept for backward compatibility
but now includes a note to use Config.GetCapabilities() when the full config
is available.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds Dolt auto-commit functionality for write commands and sets explicit commit authors.
Includes fix for race condition in commandDidWrite (converted to atomic.Bool).
Original PR: #1267 by @coffeegoddd
Co-authored-by: Dustin Brown <dustin@dolthub.com>
When bd runs with --no-daemon or during init in a directory that has a
.beads/redirect file, it now correctly follows the redirect to create
the database in the target location instead of locally.
The bug occurred because:
1. init.go hardcoded .beads/beads.db without checking for redirects
2. main.go's fallback path for auto-bootstrap also used local .beads
Both code paths now call beads.FollowRedirect() to resolve the correct
.beads directory before constructing the database path.
Added TestInitWithRedirect to verify the fix.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Track whether the store was actually opened read-only (vs just requested)
since the fallback logic may change opts.ReadOnly. Use this to skip
auto-import in staleness checks - importing would fail anyway if the
store is read-only.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes#1093: `bd version` was spawning 5-7 git subprocesses before
checking if it even needed database access.
Moved the noDbCommands early-return check to run BEFORE:
- ensureForkProtection() (spawns ~5 git commands)
- signalOrchestratorActivity() (spawns git config)
This eliminates unnecessary process churn for simple commands like
`bd version`, `bd help`, `bd completion`, etc.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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.
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>
The export command was incorrectly listed in readOnlyCommands, causing the SQLite database to be opened in read-only mode. This prevented export from clearing dirty issues and updating the JSONL file hash.
Add 'owner' field to Issue struct for tracking the human responsible
for the issue, distinct from 'created_by' which tracks the executor.
Owner is populated from git author email (GIT_AUTHOR_EMAIL or git
config user.email), per Decision 008 for CV accumulation.
Changes:
- Add Owner field to types.Issue with omitempty JSON tag
- Include Owner in content hash computation
- Add owner column migration (036_owner_column.go)
- Update all SQL queries to include owner field
- Add getOwner() helper using git author email fallback chain
- Populate owner in bd create command
- Add owner to RPC CreateArgs protocol
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Executed-By: beads/crew/dave
Rig: beads
Role: crew
- Insert git config user.name in fallback chain before final $USER default
- Consolidate duplicate actor resolution logic into single function
- Add BEADS_ACTOR as env var alias for MCP compatibility
- Add tests for actor resolution priority
- Update CONFIG.md with Actor Identity Resolution section
The new fallback order is:
--actor flag > BD_ACTOR > BEADS_ACTOR > git user.name > $USER > "unknown"
Co-authored-by: Ohffs <ohffsnotnow@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
After devcontainer restart (cold-start), `bd --no-daemon show` failed to
find beads because:
1. Read-only commands skipped auto-import
2. Newly created DB had no issue_prefix set, causing import to fail
This fix enables seamless cold-start recovery by:
- Allowing read-only commands (show, list, etc.) to auto-bootstrap when
JSONL exists but DB doesn't
- Setting needsBootstrap flag when falling back from read-only to
read-write mode for missing DB
- Auto-detecting and setting issue_prefix from JSONL during auto-import
when DB is uninitialized
Fixes: gt-b09
Co-authored-by: Claude <noreply@anthropic.com>
Problem:
- When dbPath is set to relative fallback (".beads/beads.db"),
findJSONLPath() returns a relative path
- daemon_sync_branch.go calls filepath.Rel(absolutePath, relativePath)
which fails with: "Rel: can't make .beads/issues.jsonl relative to ..."
Solution:
- Canonicalize dbPath at assignment in main.go:471 (source fix)
- Add defensive guard in findJSONLPath() (defense-in-depth)
- Use utils.CanonicalizePath() for OS-agnostic handling
(symlinks, case normalization on macOS)
Testing:
- Add TestFindJSONLPath_RelativeDbPath (tracer bullet for bug)
- Add edge case tests for BEADS_JSONL and empty dbPath
- All sync mode tests pass including daemon E2E
Implements a new command to resolve git merge conflict markers in JSONL files.
Features:
- Mechanical mode (default): deterministic merge using updated_at timestamps
- Closed status wins over open
- Higher priority (lower number) wins
- Notes are concatenated when different
- Dependencies are unioned
- Dry-run mode to preview changes
- JSON output for agent integration
- Automatic backup creation before changes
The command defaults to resolving .beads/beads.jsonl but accepts any file path.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Users could not run 'bd config set no-db true' without already having a
database, creating a chicken-and-egg problem. The PersistentPreRunE
would fail with 'no beads database found' before the config command
could even run.
The fix detects when a yaml-only config operation is being attempted
(config set/get with keys like no-db, no-daemon, sync.branch, etc.)
and allows it to proceed without requiring a database.
Before:
$ bd config set no-db true
Error: no beads database found
After:
$ bd config set no-db true
Set no-db = true (in config.yaml)
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>
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>
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>
Added actor field to RPC client and set it before daemon requests.
This ensures status changes (like pinned events) show who performed
the action in bd activity output.
Changes:
- Added actor field to Client struct
- Added SetActor method to set actor for audit trail
- Modified ExecuteWithCwd to include actor in RPC requests
- Updated main.go to call SetActor after daemon connection
Fixes gt-1ydd9
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
bd has 70+ commands, which can be overwhelming for human users who just
want to track issues. The new `bd human` command displays a curated list
of ~15 essential commands organized by workflow:
- Working With Issues: create, list, show, update, close, reopen, comment
- Finding Work: ready, search, status, stats
- Dependencies: dep add/remove/tree, graph, blocked
- Setup & Sync: init, sync, doctor
- Getting Help: quickstart, help, --help
Also includes quick examples showing common workflows.
Changes:
- Add cmd/bd/human.go with curated help output
- Add "human" to noDbCommands list in main.go (no database needed)
When the database has orphaned dependencies or labels, the migration
invariant check fails and prevents the database from opening. This
creates a chicken-and-egg problem where bd doctor --fix cannot run.
The new bd repair command:
- Opens SQLite directly, bypassing invariant checks
- Deletes orphaned dependencies (issue_id or depends_on_id not in issues)
- Deletes orphaned labels (issue_id not in issues)
- Runs WAL checkpoint to persist changes
- Supports --dry-run to preview what would be cleaned
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Strip (bd-xxx), (gt-xxx) suffixes from code comments and changelog
entries. The descriptions remain meaningful without the ephemeral
issue IDs.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Wisp operations (mol wisp *, mol burn, mol squash) and commands operating on
ephemeral issue IDs (bd-eph-*, gt-eph-*, eph-*) now auto-bypass the daemon.
Since wisps are ephemeral (Ephemeral=true) and never exported to JSONL,
the daemon cannot help with them anyway. This eliminates the need to manually
add --no-daemon for every wisp operation.
Changes:
- Add isWispOperation() helper to detect wisp commands and ephemeral IDs
- Add FallbackWispOperation constant for daemon status tracking
- Insert wisp detection in PersistentPreRunE daemon connection logic
- Update error messages in wisp.go, mol_burn.go, mol_squash.go
- Add comprehensive unit tests for isWispOperation()
Analysis found these commands are dead code:
- gt never calls `bd pin` - uses `bd update --status=pinned` instead
- Beads.Pin() wrapper exists but is never called
- bd hook functionality duplicated by gt mol status
- Code comment says "pinned field is cosmetic for bd hook visibility"
Removed:
- cmd/bd/pin.go
- cmd/bd/unpin.go
- cmd/bd/hook.go
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Writes activity.json to ~/gt/daemon/ when bd runs inside a Gas Town
workspace. This enables the daemon to detect bd usage and adjust its
polling frequency with exponential backoff.
Best-effort: silently skips if not in Gas Town or on any error.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove dual code paths in the autoflush system. FlushManager is now the
only code path for auto-flush operations.
Changes:
- Remove legacy globals: isDirty, needsFullExport, flushTimer
- Remove flushToJSONL() wrapper function (was backward-compat shim)
- Simplify markDirtyAndScheduleFlush/FullExport to just call FlushManager
- Update tests to use FlushManager or flushToJSONLWithState directly
FlushManager handles all flush state internally in its run() goroutine,
eliminating the need for global state. Sandbox mode and tests that do
not need flushing get a no-op when FlushManager is nil.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add semantic coloring to help output (section headers, flags, types)
- Reorganize commands into clearer categories:
- "Views & Reports" for readonly queries (ready, stats, blocked, etc.)
- "Maintenance" for health/repair tasks (doctor, validate, migrate, etc.)
- Merge "Issue Metadata" back into "Working With Issues"
- Highlight "doctor" as primary maintenance entry point with "(start here)"
- Create docs/UI_PHILOSOPHY.md documenting Tufte-inspired design principles
- Add guidance for PR to not include .beads/issues.jsonl
Implements gt-0ei3: Template molecules now live in a separate molecules.jsonl
file, distinct from work items in issues.jsonl.
Key changes:
- Add internal/molecules package for loading molecule catalogs
- Implement hierarchical loading: built-in → town → user → project
- Molecules use their own ID namespace (mol-*) with prefix validation skipped
- Templates are marked with is_template: true and are read-only
- bd list excludes templates by default (existing functionality)
The hierarchical loading allows:
- Built-in molecules shipped with bd binary (placeholder for future)
- Town-level: ~/gt/.beads/molecules.jsonl (Gas Town)
- User-level: ~/.beads/molecules.jsonl
- Project-level: .beads/molecules.jsonl
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When bd detects it's running in a fork (origin != steveyegge/beads),
automatically add .beads/issues.jsonl to .git/info/exclude.
This prevents contributors from accidentally including issue database
changes in their PRs. The exclusion is:
- Per-clone (doesn't modify tracked files
- One-time setup (checks if already excluded)
- Silent (only logs in debug mode)
Maintainers (origin = steveyegge/beads) are not affected.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
EOF
)
- bd mail reply: reply to messages with thread linking via replies_to
- bd show --thread: display full conversation threads
- bd relate/unrelate: bidirectional relates_to links for knowledge graph
- bd duplicate --of: mark issues as duplicates with auto-close
- bd supersede --with: mark issues as superseded with auto-close
- Hooks system: on_create, on_update, on_close, on_message in .beads/hooks/
- RPC protocol: added Sender, Ephemeral, RepliesTo fields to CreateArgs/UpdateArgs
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* 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>
Added onboard and hooks commands to the noDbCommands list so they
skip database and daemon initialization. These commands don't need
database access - they just output documentation or manage git hooks.
On Windows, if no .beads directory exists, the PersistentPreRun
would attempt database discovery (including git worktree detection)
which could hang due to git command issues.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements single-shot mode improvements for Windows and Docker scenarios:
- Add --lock-timeout global flag (default 30s, 0 = fail immediately)
- Add config file support: lock-timeout: 100ms
- Parameterize SQLite busy_timeout via NewWithTimeout() function
- In --sandbox mode: default lock-timeout to 100ms
- In --sandbox mode: skip FlushManager creation (no background goroutines)
This addresses bd.exe hanging on Windows and locking conflicts when
using beads across host + Docker containers.
Closes: bd-59er, bd-r4od, bd-dh8a
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add JSONL-only mode detection in ensureStoreActive() with context-aware
error messages that suggest correct actions based on project state
- Improve error messages in main.go to detect JSONL presence and suggest
appropriate solutions (bd init, --no-db flag, or config.yaml setting)
- Update documentation to use issues.jsonl as canonical filename:
- AGENT_INSTRUCTIONS.md, README.md, resolve-beads-conflict.md
- docs/GIT_INTEGRATION.md
- Update hook template comments to clarify issues.jsonl is canonical
while maintaining backward compatibility for beads.jsonl
Fixes#534🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace fragile strings.Contains("no-db: true") with proper YAML parsing
to avoid false matches in comments or nested keys.
Changes:
- Add NoDb field to localConfig struct
- Add isNoDbModeConfigured() helper function
- Update main.go and doctor.go to use the helper
- Add 8 test cases for isNoDbModeConfigured
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a --readonly flag that blocks all write operations, allowing workers
to read beads state without modifying it. Workers can use:
- bd show, bd list, bd ready (read operations)
Workers cannot use:
- bd create, bd update, bd close, bd sync, etc. (write operations)
The flag can be set via:
- --readonly flag on command line
- BD_READONLY=true environment variable
- readonly: true in config file
This enables swarm workers to see their assigned work from a static
snapshot of the beads database without accidentally modifying it.
Commands protected by readonly mode:
- create, update, close, delete, edit
- sync, import, reopen
- comment add, dep add/remove, label add/remove
- repair-deps, compact, migrate, migrate-hash-ids, migrate-issues
- rename-prefix, validate --fix-all, duplicates --auto-merge
- epic close-eligible, jira sync
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
When sync.branch is configured, the sync command:
1. Exports changes to JSONL
2. Commits to sync branch via worktree
3. Pulls from sync branch
4. Restores .beads/ from HEAD to keep working directory clean
But PersistentPostRun's flushManager.Shutdown() was re-exporting to JSONL,
undoing the restore and leaving modified files.
Fix: Set skipFinalFlush flag when sync.branch mode completes successfully.
This prevents the final export in PersistentPostRun.
Also: Skip push to main branch when sync.branch is configured - all
pushes should go through the sync branch worktree.
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>
- 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>