Add auto-commit, auto-push, local mode, sync interval, and daemon mode
to the status output when querying a running daemon.
This helps users understand the current daemon configuration without
having to check logs or remember what flags were used at startup.
Changes:
- Add config fields to StatusResponse in protocol.go
- Add SetConfig() method to Server for daemon to set its config
- Update handleStatus() to include config in response
- Update showDaemonStatus() to query and display config via RPC
- Add comprehensive test coverage for new functionality
Co-authored-by: Christian Catalan <crcatala@gmail.com>
Adds --foreground flag to 'bd daemon --start' that runs the daemon in
foreground instead of forking to background. This enables management by
process supervisors like systemd, supervisord, or similar tools.
Usage: bd daemon --start --foreground
Closes#438🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat(daemon): add --local flag for git-free operation
Add --local mode to the daemon that allows it to run without a git
repository. This decouples the daemon's core functionality (auto-flush
to JSONL, auto-import from JSONL) from git synchronization.
Changes:
- Add --local flag to daemon command
- Skip git repo check when --local is set
- Add validation that --auto-commit and --auto-push cannot be used with --local
- Create local-only sync functions that skip git operations:
- createLocalSyncFunc: export-only for polling mode
- createLocalExportFunc: export without git commit/push
- createLocalAutoImportFunc: import without git pull
- Update startup message to indicate LOCAL mode
- Update event loop to use local functions when in local mode
This enables use cases like:
- Single-machine issue tracking without git
- Auto-flush to JSONL for backup purposes
- Running daemon in environments without git access
Multi-machine sync still requires git (as expected).
* fix(daemon): skip fingerprint validation in local mode
validateDatabaseFingerprint() calls beads.ComputeRepoID() which
executes git commands. This fails in non-git directories even
with --local flag.
Skip fingerprint validation entirely when running in local mode
since there's no git repository to validate against.
* test(daemon): add comprehensive test coverage for --local mode
Add tests for:
- Flag validation (--local incompatible with --auto-commit/--auto-push)
- Git check skip logic in local mode
- createLocalSyncFunc, createLocalExportFunc, createLocalAutoImportFunc
- Fingerprint validation skip in local mode
- Full integration test in non-git directory
- Export/import round-trip test
---------
Co-authored-by: Claude <noreply@anthropic.com>
Global daemon support has been deprecated for most of the project's
lifetime. This change removes the dead code entirely:
- Remove --global and --migrate-to-global daemon flags
- Remove runGlobalDaemon() and migrateToGlobalDaemon() functions
- Remove shouldUseGlobalDaemon() and getGlobalBeadsDir() functions
- Simplify functions that had global bool parameters
- Remove warning about old global socket in getSocketPath()
This reduces code complexity and removes 238 net lines of unused code.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Currently 'bd daemon' with no args immediately starts the daemon. This is
inconsistent with other daemon management commands like --stop, --status,
etc. and makes the command less discoverable for new users.
Changes:
- Add --start flag to explicitly start daemon
- Show help text when no operation flags provided
- Update auto-start logic to use --start flag
- Update startDaemon() to pass --start when forking
- Update all documentation to use 'bd daemon --start'
- Update MCP Python client error messages
The MCP docs already incorrectly showed 'bd daemon start' which doesn't
work, so this change fixes that documentation bug while improving UX.
Auto-start still works correctly - it now passes --start internally.
Fixes bd-gfu
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixes#358
The daemon was ignoring daemon.auto_commit and daemon.auto_push configuration values stored in the database unless the corresponding CLI flags were explicitly provided. This prevented bd init --team configuration from working as expected.
Changes:
- Modified cmd/bd/daemon.go to check database config when flags are not explicitly set
- Uses beads.FindDatabasePath() to locate the database and sqlite.New() to read config
- Only applies when starting daemon (skips for --stop, --status, --health, etc.)
Co-authored-by: Charles P. Cross <cpdata@users.noreply.github.com>
Complete implementation of signal-aware context propagation for graceful
cancellation across all commands and storage operations.
Key changes:
1. Signal-aware contexts (bd-rtp):
- Added rootCtx/rootCancel in main.go using signal.NotifyContext()
- Set up in PersistentPreRun, cancelled in PersistentPostRun
- Daemon uses same pattern in runDaemonLoop()
- Handles SIGINT/SIGTERM for graceful shutdown
2. Context propagation (bd-yb8):
- All commands now use rootCtx instead of context.Background()
- sqlite.New() receives context for cancellable operations
- Database operations respect context cancellation
- Storage layer propagates context through all queries
3. Cancellation tests (bd-2o2):
- Added import_cancellation_test.go with comprehensive tests
- Added export cancellation test in export_test.go
- Tests verify database integrity after cancellation
- All cancellation tests passing
Fixes applied during review:
- Fixed rootCtx lifecycle (removed premature defer from PersistentPreRun)
- Fixed test context contamination (reset rootCtx in test cleanup)
- Fixed export tests missing context setup
Impact:
- Pressing Ctrl+C during import/export now cancels gracefully
- No database corruption or hanging transactions
- Clean shutdown of all operations
Tested:
- go build ./cmd/bd ✓
- go test ./cmd/bd -run TestImportCancellation ✓
- go test ./cmd/bd -run TestExportCommand ✓
- Manual Ctrl+C testing verified
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Improvements:
1. Added top-level panic recovery in runDaemonLoop
- Captures stack trace and logs to daemon.log
- Writes daemon-error file with crash details for user visibility
- Cleans up PID file on panic
2. Replaced os.Exit calls with return statements where possible
- Allows deferred cleanup to run (lock release, socket removal, etc)
- Improves graceful shutdown on errors
3. Enhanced stopDaemon forced-kill path
- Removes stale socket file after process.Kill()
- Prevents socket artifacts from accumulating
4. Added integration tests for crash recovery
Closes bd-vcg5
- Add ParentPID field to DaemonLockInfo struct
- Daemon monitors parent process every 10 seconds
- Gracefully exits when parent process dies
- Prevents accumulation of orphaned daemons from dead sessions
- Fixes race conditions from multiple daemons on same database
Closes bd-zpnq
- Add nolint:gosec comments for safe file operations
- G304: File reads from validated/secure paths
- G306/G302: JSONL/error files need 0644 for sharing/debugging
- G204: Subprocess launches with validated arguments
- G104: Deferred file close errors are non-critical
- G115: Safe integer conversions in backoff
- G201: SQL placeholders for IN clause expansion
All warnings are for intentional behavior that is safe in context.
Amp-Thread-ID: https://ampcode.com/threads/T-d78f2780-4709-497f-97b0-035ca8c809e1
Co-authored-by: Amp <amp@ampcode.com>
When daemon detects multiple .db files (after filtering .backup and vc.db),
it now writes detailed error to .beads/daemon-error file before exiting.
The error file is checked and displayed when:
- Daemon discovery fails to connect
- Auto-start fails to yield a running daemon
- User runs 'bd daemons list'
This makes the error immediately visible without requiring users to check
daemon logs.
Changes:
- cmd/bd/daemon.go: Write daemon-error file on multiple .db detection
- internal/daemon/discovery.go: Read and surface daemon-error in DaemonInfo.Error
- cmd/bd/main.go: Display daemon-error when auto-start fails
Amp-Thread-ID: https://ampcode.com/threads/T-1005a8d1-7a5a-4844-ad2d-2b8a6145825f
Co-authored-by: Amp <amp@ampcode.com>
- Changed backup file filtering from checking file extension (.backup) to checking if filename contains '.backup'
- This now properly filters files like 'beads.backup-pre-hash-20251030-171258.db'
- Also exclude vc.db from database detection
- Add strings import to beads.go
- Improve error message to suggest manual removal
Fixes bd-373c
Event-driven daemon is now production-ready after hardening fixes in
commit 349b892. Making it the default for v0.21.0.
Users can still opt back to polling mode with BEADS_DAEMON_MODE=poll
if needed.
Benefits:
- <500ms sync latency (vs 5000ms with polling)
- ~60% less CPU usage
- Instant reactivity to mutations and file changes
- Fallback polling when file watcher unavailable
Amp-Thread-ID: https://ampcode.com/threads/T-a9a67394-37ca-4b79-aa23-c5c011f9c0cd
Co-authored-by: Amp <amp@ampcode.com>
Three critical fixes to make event-driven mode production-ready:
1. Skip redundant imports: Check JSONL mtime vs DB mtime to avoid
self-triggered import loops after export writes JSONL
2. Add server.Stop() in serverErrChan case: Ensures clean RPC
server shutdown on errors
3. Fallback ticker (60s): When file watcher unavailable (e.g., network
filesystems), fall back to periodic polling to detect remote changes
These minimal fixes address Oracle's concerns without over-engineering.
Event-driven mode is now safe for default.
Amp-Thread-ID: https://ampcode.com/threads/T-a9a67394-37ca-4b79-aa23-c5c011f9c0cd
Co-authored-by: Amp <amp@ampcode.com>
Hash-based IDs make collision resolution unnecessary. The flag was
already non-functional (handleCollisions returns error on collision
regardless of flag value).
Removed:
- --resolve-collisions flag from bd import
- ResolveCollisions field from ImportOptions and importer.Options
- All references in daemon, auto-import, and tests
- Updated error messages to reflect hash IDs don't collide
All import tests pass.
Amp-Thread-ID: https://ampcode.com/threads/T-47dfa0cc-bb71-4467-ac86-f0966a7c5d58
Co-authored-by: Amp <amp@ampcode.com>
- Created global daemon registry at ~/.beads/registry.json
- Daemons auto-register on start, unregister on graceful shutdown
- DiscoverDaemons() now uses registry instead of filesystem scan
- Instant daemon discovery (35ms vs indefinite hang)
- Auto-cleanup of stale registry entries
- Full test coverage
Closes bd-07b8c8, bd-acb971c7
- Add mutation events for label/dep/comment operations
- Create separate export-only and import-only functions
- Add dropped events counter with safety net export
- Complete bd-80 mutation channel implementation
Event-driven mode now:
- Emits mutation events for ALL write operations (not just create/update/close)
- Uses createExportFunc() for mutations (export+commit/push only, no pull)
- Uses createAutoImportFunc() for file changes (pull+import only, no export)
- Tracks dropped events and triggers safety export every 60s if any dropped
- Achieves <500ms latency target by avoiding full sync on each trigger
Behind BEADS_DAEMON_MODE=events flag (poll is still default)
- Added CanonicalDatabaseName constant (beads.db) and LegacyDatabaseNames list
- Updated bd init to use canonical name via constant
- Added daemon validation to reject non-canonical database names
- Updated bd migrate to use canonical name constant
- Enhanced FindDatabasePath to warn when using legacy database names
- All database discovery now prefers beads.db with backward compatibility
Closes bd-165
- Added validatePreExport to prevent data loss
- Added checkDuplicateIDs to detect corruption
- Added checkOrphanedDeps to find orphaned dependencies (both sides)
- Added validatePostImport to ensure imports don't lose data
- CRITICAL FIX: Removed post-pull export that clobbered fresh JSONL
- Conservative checks when JSONL is unreadable
- Efficient COUNT(*) SQL path instead of loading all issues
- Comprehensive test coverage including edge cases
Replace the NO-OP importToJSONLWithStore() stub with full implementation:
- Reads and parses JSONL file line by line using bufio.Scanner
- Uses importIssuesCore() with auto-collision resolution enabled
- Integrates with existing import infrastructure
- Fixes PRIMARY root cause of bd-160 multi-clone sync failure
The daemon now properly imports remote changes pulled from git instead
of ignoring them, allowing databases to converge across clones.
Amp-Thread-ID: https://ampcode.com/threads/T-9b92c2dc-e0e2-4d77-b562-136da8c3f64e
Co-authored-by: Amp <amp@ampcode.com>
- Implement bd migrate command with detection, version checking, and cleanup
- Update daemon to suggest bd migrate for version mismatches
- Enhance CLI version warnings to recommend bd migrate
- Add comprehensive tests for migration scenarios
- Document migration workflow in QUICKSTART.md and AGENTS.md
Completes bd-164 and epic bd-159
Amp-Thread-ID: https://ampcode.com/threads/T-34ea4682-8c48-44c2-8421-dc40f867773b
Co-authored-by: Amp <amp@ampcode.com>
- Add JSON format to daemon.lock with database path, version, PID, and timestamp
- Validate database path on client connection (fail if mismatch)
- Backward compatible with old plain-PID lock files
- Add comprehensive tests for JSON format and validation
- Update all lock acquisition callsites to pass database path
Amp-Thread-ID: https://ampcode.com/threads/T-137e6a9c-b690-4ade-9bec-13fcd7d0e4ed
Co-authored-by: Amp <amp@ampcode.com>
- Added version validation on daemon startup
- Daemon checks bd_version metadata matches current version
- Clear error messages for version mismatches with 3 resolution options
- Auto-sets missing version metadata for old databases
- Added BEADS_IGNORE_VERSION_MISMATCH=1 override for emergencies
- Tested version mismatch detection, override flag, and missing metadata handling
- Changed bd init to always create beads.db instead of {prefix}.db
- Added migration logic to detect and rename old databases
- Updated findDatabaseInTree to prefer beads.db and warn on multiple .db files
- Daemon now refuses to start if multiple .db files exist (ambiguity error)
- Updated tests to expect beads.db instead of prefix-based naming
- Tested migration, ambiguity detection, and warning messages
- Add OpStatus operation and StatusResponse type to RPC protocol
- Add workspacePath and dbPath fields to Server struct
- Implement handleStatus() handler with daemon metadata
- Track last activity time with atomic.Value
- Add client.Status() method
- Check for exclusive locks via ShouldSkipDatabase()
- Update all test files to use new NewServer signature
- Add comprehensive status endpoint test
Closes bd-148
- Increase flush debounce from 1s to 30s (provides transaction window for batch operations)
- Increase daemon poll from 2s to 5s (reduces commit spam)
- Agents should run 'bd sync' at end of session to force immediate commit
- Prevents creating dozens of commits when making multiple issue changes
- Reduce flush debounce from 5s to 1s (BEADS_FLUSH_DEBOUNCE)
- Reduce daemon poll interval from 10s to 2s
- Makes issue changes sync much faster to JSONL and git
- bd-155: Add pre-import flush in daemon sync cycle to prevent deleted issues from being re-imported
- bd-155: Reduce default daemon polling interval from 5 minutes to 10 seconds
- bd-156: Fix hardcoded 'vc.db' - now properly detects existing .db files in local .beads/ directory
- Set rpc.ServerVersion from Version in daemon startup
- Set rpc.ClientVersion from Version in main.go startup
- Eliminates need to manually update RPC versions
- Both now use 0.0.0 placeholder, overridden at runtime
Amp-Thread-ID: https://ampcode.com/threads/T-03c37f7f-f41e-4b87-8700-d346c21bad30
Co-authored-by: Amp <amp@ampcode.com>
- Added safety check to exportToJSONLWithStore (daemon path)
- Refuses to export 0 issues over non-empty JSONL file
- Added --force flag to override safety check when intentional
- Added test coverage for empty database export protection
- Prevents data loss when daemon has wrong/empty database
Amp-Thread-ID: https://ampcode.com/threads/T-de18e0ad-bd17-46ec-994b-0581e257dcde
Co-authored-by: Amp <amp@ampcode.com>
- Run initial sync in background so daemon becomes responsive immediately
- Skip daemon-running check for forked child process (BD_DAEMON_FOREGROUND=1)
- Fix PID file conflict between acquireDaemonLock and runDaemonLoop
- Daemon now starts reliably even with slow/failing git pulls
Fixes issue where daemon would timeout during auto-start because it was
blocked on git pull in the initial sync cycle. Now the RPC server starts
immediately and sync runs asynchronously.
Amp-Thread-ID: https://ampcode.com/threads/T-57f3c00a-02b4-4878-adba-c7d1649759b4
Co-authored-by: Amp <amp@ampcode.com>
Fixes silent data loss when .beads/ directory removed and daemon auto-starts.
Root cause: checkGitForIssues() hardcoded 'issues.jsonl' but git tracks 'beads.jsonl'
Changes:
- Fix A (bd-131): checkGitForIssues() tries beads.jsonl first, then issues.jsonl
- Fix B (bd-132): Immediate export after import in bd init to prevent daemon race
- Fix C (bd-133): Safety check that fails loudly if import fails
- Fix D (bd-134): Daemon startup auto-import when DB empty but git has issues
- Tests (bd-135): Comprehensive integration test suite
Oracle-recommended improvements:
- Export to exact git-relative path (prevents path drift)
- filepath.ToSlash for Windows git compatibility
- 64MB scanner buffer for large JSONL lines
- Improved safety check messages (only suggest local file if exists)
All tests passing. No regressions.
Amp-Thread-ID: https://ampcode.com/threads/T-0e31dc6a-a0d9-46c6-87b2-cfdebe829a52
Co-authored-by: Amp <amp@ampcode.com>