- Provides comprehensive workflow patterns and decision criteria
- Includes quick reference (SKILL.md) and detailed references
- Teaches when to use bd vs markdown/TodoWrite
- Covers dependency types and issue lifecycle management
- Complements existing plugin with usage philosophy
The show command was crashing with a nil pointer dereference when
accessing issue.CompactionLevel. This occurred due to two issues in
the daemon mode response handling:
1. The IssueDetails struct incorrectly embedded *types.Issue as a
pointer, causing the JSON unmarshaling to leave it nil. Changed
to embed types.Issue directly.
2. Missing null check for non-existent issues. The daemon returns
null when an issue is not found, which wasn't handled properly.
Added explicit null checking before parsing the response to provide
a clear error message when issues don't exist.
Fixes panic when running: bd show <non-existent-id>
- Removed invalid 'version: 2' field (must be string)
- Ran golangci-lint migrate to update to v2 schema
- Moved linters-settings -> linters.settings
- Moved issues.exclude-rules -> linters.exclusions.rules
- Moved issues.exclude -> linters.exclusions.rules with text field
- Config now validates successfully with golangci-lint v2.x
Amp-Thread-ID: https://ampcode.com/threads/T-d5fb1beb-0350-4a49-b8fa-ab752a82ef8e
Co-authored-by: Amp <amp@ampcode.com>
- Split platform-specific daemon process configuration into separate files
- daemon_unix.go: Uses Setsid for Unix/Linux/macOS
- daemon_windows.go: Uses CREATE_NEW_PROCESS_GROUP for Windows
- Fixes compilation error: "unknown field Setsid in struct literal"
This allows bd.exe to build successfully on Windows while maintaining
proper daemon behavior on all platforms.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Auto-starts daemon on first bd command (unless --no-daemon or BEADS_AUTO_START_DAEMON=false)
- Exponential backoff on failures: 5s, 10s, 20s, 40s, 80s, 120s (max)
- Lockfile prevents race conditions when multiple commands start daemon simultaneously
- Stdio redirected to /dev/null to prevent daemon output in foreground
- Uses os.Executable() for security (prevents PATH hijacking)
- Socket readiness verified with actual connection test
- Accepts multiple falsy values: false, 0, no, off (case-insensitive)
- Working directory set to database directory for local daemon context
- Comprehensive test coverage including backoff math and concurrent starts
Fixes:
- Closes bd-1 (won't fix - compaction keeps DBs small)
- Closes bd-124 (daemon auto-start implemented)
Documentation updated in README.md and AGENTS.md
Amp-Thread-ID: https://ampcode.com/threads/T-b10fe866-ab85-417f-9c4c-5d1f044c5796
Co-authored-by: Amp <amp@ampcode.com>
- bd-159: Global daemon now runs in routing mode without opening DB
- bd-158: Set socket permissions to 0600 for security
- bd-160: Reject --auto-commit/--auto-push with --global
- bd-157: Verified stale socket cleanup (already working)
- bd-56: Closed as won't-do (cycle prevention is better)
- bd-73: Multi-repo support complete
Implements bd-122: Document how to use beads across multiple projects
Added comprehensive multi-repo documentation:
- README.md: Global daemon section with architecture diagram
- AGENTS.md: MCP multi-repo configuration (global daemon + per-project)
- integrations/beads-mcp/README.md: BEADS_WORKING_DIR usage
- Mermaid diagram showing one daemon serving multiple repos
Documentation covers:
- Global daemon (bd daemon --global) for system-wide usage
- Per-project MCP instances with BEADS_WORKING_DIR
- Comparison table (local vs global)
- When to use each approach
- Example workflows for multi-project setups
Benefits of global daemon:
- One daemon process for all repos
- Automatic socket discovery (local -> global fallback)
- Better resource usage
- Per-request context routing to correct database
Amp-Thread-ID: https://ampcode.com/threads/T-ea606216-b886-4af0-bba8-56d000362d01
Co-authored-by: Amp <amp@ampcode.com>
Implements bd-121: Global daemon with system-wide socket
Changes:
- Add --global flag to daemon command
- Use ~/.beads/bd.sock when --global is set
- Skip git repo validation for global daemon
- Update daemon discovery to check ~/.beads/ as fallback
- Both Go CLI and Python MCP client check global socket
- Update all tests to pass global parameter
Benefits:
- Single daemon serves all repos on system
- No per-repo daemon management needed
- Better resource usage for users with many repos
- Automatic fallback when local daemon not running
Usage:
bd daemon --global # Start global daemon
bd daemon --status --global # Check global status
bd daemon --stop --global # Stop global daemon
Related: bd-73 (multi-repo epic)
Amp-Thread-ID: https://ampcode.com/threads/T-ea606216-b886-4af0-bba8-56d000362d01
Co-authored-by: Amp <amp@ampcode.com>
Closes bd-155
When daemon is running, store is nil because PersistentPreRun returns
early after connecting to daemon. The delete command (both single and
batch) now falls back to direct storage access when store is nil,
following the pattern used by other commands like ready and blocked.
Amp-Thread-ID: https://ampcode.com/threads/T-4e1ac6f1-7465-442a-a385-adaa98b539ad
Co-authored-by: Amp <amp@ampcode.com>
The status filter was treating 'all' as a literal status value instead of
a special case meaning 'show all statuses'. This caused the SQL query to
filter for 'WHERE status = all' which matched no issues.
Fixed by checking if status is 'all' and skipping the filter in that case.
- Fix list.go to skip status filter when status == 'all'
- Update CHANGELOG with fix details
- All tests pass
This PR fixes three bugs that prevented the MCP plugin from working:
1. **Fixed parameter name mismatch in tools.py**
- Changed `workspace_root=workspace_root` to `working_dir=workspace_root`
- The `create_bd_client()` function expects `working_dir` parameter,
but tools.py was passing `workspace_root`
- This caused "got an unexpected keyword argument 'workspace_root'" error
2. **Added version check guard for daemon client**
- Added `hasattr(_client, '_check_version')` check before calling
- BdDaemonClient doesn't have `_check_version()` method, only BdCliClient does
- This caused "'BdDaemonClient' object has no attribute '_check_version'" error
3. **Implemented proper daemon socket detection for fallback**
- Added synchronous socket file existence check before creating daemon client
- Walks up directory tree looking for `.beads/bd.sock` file
- Only creates daemon client if socket exists, otherwise falls back to CLI
- Previously, daemon client was created but failed on first method call
- This enables the documented "prefer_daemon with automatic CLI fallback" behavior
**Testing:**
- Verified MCP tools work correctly with single-repo setup
- Confirmed automatic fallback to CLI when daemon isn't running
- Tested on macOS with bd v0.9.9
**Related Issues:**
- Addresses symptoms similar to #65 (Windows BEADS_WORKING_DIR issue)
Since our implementation uses `async` IO for subprocess communication, it's
crucial to utilize the `fastMCP.run_async()` entry-point of FastMCP.
This should fix crashes on Windows.
ref: steveyegge/beads#53
- Add DeleteIssues() method in sqlite.go for atomic batch deletion
- Support multiple issue IDs as arguments or from file
- Add --from-file flag to read IDs from file (supports comments)
- Add --dry-run mode for safe preview without deleting
- Add --cascade flag for recursive deletion of dependents
- Add --force flag to orphan dependents instead of failing
- Pre-collect connected issues before deletion for text reference updates
- Add orphan deduplication to prevent duplicate IDs
- Add rows.Err() checks in all row iteration loops
- Full transaction safety - all deletions succeed or none do
- Comprehensive statistics tracking (deleted, dependencies, labels, events)
- Update README and CHANGELOG with batch deletion docs
Fixed critical code review issues:
- Dry-run mode now properly uses dryRun parameter instead of deleting data
- Text references are pre-collected before deletion so they update correctly
- Added orphan deduplication and error checks
- Updated defer rollback pattern per Go best practices
- MCP server now uses daemon client by default with CLI fallback
- Added BEADS_USE_DAEMON environment variable (default: enabled)
- Created multi-repo integration test (all tests pass)
- Updated .gitignore for daemon runtime files
- Added SETUP_DAEMON.md with migration instructions
- Closed bd-105 (investigation complete) and bd-114 (multi-server confusion)
This enables single MCP server to handle multiple repos via daemon
with per-request context routing. No more multiple MCP server configs!
Amp-Thread-ID: https://ampcode.com/threads/T-c222692e-f6ef-4649-9726-db59470b82ef
Co-authored-by: Amp <amp@ampcode.com>
- Added per-request storage routing in daemon server
- Server now supports Cwd field in requests for database discovery
- Tree-walking to find .beads/*.db from any working directory
- Storage caching for performance across requests
- Created Python daemon client (bd_daemon_client.py)
- RPC over Unix socket communication
- Implements full BdClientBase interface
- Auto-discovery of daemon socket from working directory
- Refactored bd_client.py with abstract interface
- BdClientBase abstract class for common interface
- BdCliClient for CLI-based operations (renamed from BdClient)
- create_bd_client() factory with daemon/CLI fallback
- Backwards-compatible BdClient alias
Next: Update MCP server to use daemon client when available
The 'blocked' command doesn't have RPC support in the daemon yet.
When the daemon is running, store is nil, causing a panic.
This fix detects when daemon is running but store is nil, and opens
a direct database connection as a fallback. This allows the command
to work even when the daemon is active, until proper RPC support
is added.
The statsCmd was not checking if a daemon client was available before
trying to access the store directly. When the daemon is running, store
is nil, causing a panic.
This fix adds a check for daemonClient and uses RPC to get statistics
when the daemon is available, falling back to direct store access only
when running in direct mode.
Multiple dep commands were directly accessing store without checking if
daemon was available, causing nil pointer dereferences when daemon was
running.
Fixed commands:
- dep add: Now uses RPC when daemon is available
- dep remove: Now uses RPC when daemon is available
- dep tree: Added fallback to direct storage when daemon lacks RPC support
- dep cycles: Added fallback to direct storage when daemon lacks RPC support
The commands with RPC support (add/remove) now use the daemon client
when available. Commands without RPC support (tree/cycles) fall back
to opening a direct database connection when the daemon is running.
The vendorHash in the flake was outdated, causing build failures.
Updated to match current Go module dependencies.
Also bumped version to 0.9.9 to match current project version.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
The daemon command was failing to find the database while other commands
like 'bd list' could find it. This was because ensureBeadsDir() was not
using the same database discovery logic as other commands.
This fix updates ensureBeadsDir() to use beads.FindDatabasePath() API,
the same discovery mechanism used by all other commands, ensuring
consistent behavior across the CLI.
- Add 'bd epic status' to show epic completion with child progress
- Add 'bd epic close-eligible' to bulk-close completed epics
- Add GetEpicsEligibleForClosure() storage method
- Update 'bd stats' to show count of epics ready to close
- Add EpicStatus type for tracking epic/child relationships
- Support --eligible-only, --dry-run, and --json flags
- Fix golangci-lint config version requirement
Addresses GitHub issue #62 - epics now have visibility and
management tools for closure when all children are complete.
Amp-Thread-ID: https://ampcode.com/threads/T-e8ac3f48-f0cf-4858-8e8f-aace2481c30d
Co-authored-by: Amp <amp@ampcode.com>
Use _time_format=sqlite parameter in modernc.org/sqlite connection
string to ensure DATETIME columns use SQLite's native time format
(format 7 with timezone) instead of Go's default String() format.
This improves compatibility with SQLite's date/time functions and
ensures consistent time representation across the database.
- Create .gitignore file in .beads/ when running bd init
- Ignores *.db and *.db-* patterns to prevent database commits
- Add test coverage to verify .gitignore creation
- Add .claude/settings.local.json to project .gitignore
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: Ben Madore <madorb@users.noreply.github.com>
- Remove ~/.beads/default.db fallback from FindDatabasePath()
- Update daemon to error if no database found instead of falling back
- Update main.go to require explicit database initialization
- Add help/version/quickstart to commands that don't need database
- Add MCP client debug logging for database routing
Amp-Thread-ID: https://ampcode.com/threads/T-2b757a14-cf10-400e-a83c-30349182dd82
Co-authored-by: Amp <amp@ampcode.com>
- Add TestInitCommand with subtests for default prefix, custom prefix, quiet flag, and prefix normalization
- Add TestInitAlreadyInitialized to verify re-initialization works correctly
- Tests verify database creation, config storage, and metadata
- Tests verify -q/--quiet flag suppresses output correctly
- All tests pass
The -q flag was already working correctly; this just adds test coverage.