The _find_beads_db_in_tree() function now follows .beads/redirect files
to find shared beads databases. This is essential for polecat/crew
directories that use redirect files to share a central database.
Changes:
- Added _resolve_beads_redirect() helper function
- Updated _find_beads_db_in_tree() to check for redirect files before
looking for local .db files
- Added comprehensive tests for redirect functionality
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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>
* feat(ready,blocked): Add --parent flag for scoping by epic/bead descendants
Add --parent flag to `bd ready` and `bd blocked` CLI commands and MCP tools
to filter results to all descendants of a specific epic or bead.
## Backward Compatibility
- CLI: New optional --parent flag; existing usage unchanged
- RPC: New `blocked` operation added (was missing); existing operations unchanged
- MCP: New optional `parent` parameter; existing calls work as before
- Storage interface: GetBlockedIssues signature changed to accept WorkFilter
- All callers updated to pass empty filter for existing behavior
- Empty WorkFilter{} returns identical results to previous implementation
## Implementation Details
SQLite uses recursive CTE to traverse parent-child hierarchy:
WITH RECURSIVE descendants AS (
SELECT issue_id FROM dependencies
WHERE type = 'parent-child' AND depends_on_id = ?
UNION ALL
SELECT d.issue_id FROM dependencies d
JOIN descendants dt ON d.depends_on_id = dt.issue_id
WHERE d.type = 'parent-child'
)
SELECT issue_id FROM descendants
MemoryStorage implements equivalent recursive traversal with visited-set
cycle protection via collectDescendants helper.
Parent filter composes with existing filters (priority, labels, assignee, etc.)
as an additional WHERE clause - all filters are AND'd together.
## RPC Blocked Support
MCP beads_blocked() existed but daemon client raised NotImplementedError.
Added OpBlocked and handleBlocked to enable daemon RPC path, which was
previously broken. Now both CLI and daemon clients work for blocked queries.
## Changes
- internal/types/types.go: Add ParentID *string to WorkFilter
- internal/storage/sqlite/ready.go: Add recursive CTE for parent filtering
- internal/storage/memory/memory.go: Add getAllDescendants/collectDescendants
- internal/storage/storage.go: Update GetBlockedIssues interface signature
- cmd/bd/ready.go: Add --parent flag to ready and blocked commands
- internal/rpc/protocol.go: Add OpBlocked constant and BlockedArgs type
- internal/rpc/server_issues_epics.go: Add handleBlocked RPC handler
- internal/rpc/client.go: Add Blocked client method
- integrations/beads-mcp/: Add BlockedParams model and parent parameter
## Usage
bd ready --parent bd-abc # All ready descendants
bd ready --parent bd-abc --priority 1 # Combined with other filters
bd blocked --parent bd-abc # All blocked descendants
## Testing
Added 4 test cases for parent filtering:
- TestParentIDFilterDescendants: Verifies recursive traversal (grandchildren)
- TestParentIDWithOtherFilters: Verifies composition with priority filter
- TestParentIDWithBlockedDescendants: Verifies blocked issues excluded from ready
- TestParentIDEmptyParent: Verifies empty result for childless parent
* fix: Correct blockedCmd indentation and suppress gosec false positive
- Fix syntax error from incorrect indentation in blockedCmd Run function
- Add nolint:gosec comment for GetBlockedIssues SQL formatting (G201)
The filterSQL variable contains only parameterized WHERE clauses with
? placeholders, not user input
Add 'deferred' as a valid issue status for issues that are deliberately
put on ice - not blocked by dependencies, just postponed for later.
Changes:
- Add StatusDeferred constant and update IsValid() validation
- Add DeferredIssues to Statistics struct with counting in both SQLite
and memory storage
- Add 'bd defer' command to set status to deferred
- Add 'bd undefer' command to restore status to open
- Update help text across list, search, count, dep, stale, and config
- Update MCP server models and tools to accept deferred status
- Add deferred to blocker status checks (schema, cache, ready, compact)
- Add StatusDeferred to public API exports (beads.go, internal/beads)
- Add snowflake styling for deferred in dep tree and graph views
Semantics:
- deferred vs blocked: deferred is a choice, blocked is forced
- deferred vs closed: deferred will be revisited, closed is done
- Deferred issues excluded from 'bd ready' (already works since
default filter only includes open/in_progress)
- Deferred issues still block dependents (they are not done!)
- Deferred issues visible in 'bd list' and 'bd stale'
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Merge set_context, where_am_i, and init into a single 'context' tool
with action parameter (set, show, init).
- set: Set the workspace root directory (default when workspace_root provided)
- show: Show current workspace context (default when no args)
- init: Initialize beads in the current workspace directory
This reduces tool count from 3 to 1 while maintaining all functionality.
Closes beads-eub
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When running as an MCP server, subprocesses must not inherit stdin because
MCP uses stdin for JSON-RPC protocol communication. Inherited stdin causes
subprocesses to block indefinitely waiting for input or steal bytes from
the MCP protocol stream.
Added stdin=subprocess.DEVNULL (or asyncio.subprocess.DEVNULL for async)
to all subprocess calls:
- server.py: _resolve_workspace_root() git subprocess
- tools.py: _resolve_workspace_root() git subprocess
- bd_client.py: _run_command(), _check_version(), add_dependency(),
quickstart(), and init() async subprocess calls
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Type Safety Improvements:
- Change dict → dict[str, Any] throughout codebase for explicit typing
- Add PEP 561 py.typed marker file to export type information
- Add types-requests to dev dependencies
- Improve signal handler typing (FrameType | None)
- Improve decorator typing (Callable[..., Awaitable[T]])
- Add quickstart() abstract method to BdClientBase for interface completeness
Bug Fixes:
- Fix variable shadowing: beads_dir → local_beads_dir in bd_client.py
- Improve error handling in mail.py:_call_agent_mail() to prevent undefined error
- Make working_dir required (not Optional) in BdDaemonClient
- Remove unnecessary 'or' defaults for required Pydantic fields
Validation:
- mypy passes with no errors
- All unit tests passing
- Daemon quickstart returns helpful static text (RPC doesn't support this command)
- Add _find_beads_db_in_tree() to walk up looking for .beads/*.db
- Update _get_client() to auto-detect when workspace not set
- Matches CLI behavior (no manual set_context needed after restart)
- Add 8 comprehensive tests for auto-detection
- Update existing tests to mock auto-detection in error cases
Fixes silent failures after Amp restart.
Amp-Thread-ID: https://ampcode.com/threads/T-c47f524d-c101-40d5-839a-659f52b9be48
Co-authored-by: Amp <amp@ampcode.com>
- Add repair_deps(fix=False) for orphaned dependencies
- Add detect_pollution(clean=False) for test issue detection
- Add validate(checks=None, fix_all=False) for health checks
- Implemented in BdCliClient, stubs in BdDaemonClient
- Registered as MCP tools in server.py
Amp-Thread-ID: https://ampcode.com/threads/T-9ce04c75-201b-4019-b9f1-0cf10663557c
Co-authored-by: Amp <amp@ampcode.com>
- Add shell=True for subprocess.run() on Windows platform
- Improves git command PATH resolution on Windows
- Add debug logging for git detection failures
- Fixes GH#245 timeout issue where git rev-parse times out in MCP server
Amp-Thread-ID: https://ampcode.com/threads/T-71b3ce65-87cb-451a-a30d-162d76d92f9c
Co-authored-by: Amp <amp@ampcode.com>
- Add ping() and health() methods to BdDaemonClient for connection verification
- Implement _health_check_client() to verify cached client connections
- Add _reconnect_client() with exponential backoff (0.1s, 0.2s, 0.4s, max 3 retries)
- Update _get_client() to health-check before returning cached clients
- Automatically detect and remove stale connections from pool
- Add comprehensive test suite with 14 tests covering all scenarios
- Handle daemon restarts, upgrades, and long-idle connections gracefully
Amp-Thread-ID: https://ampcode.com/threads/T-2366ef1b-389c-4293-8145-7613037c9dfa
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>
Fixes#114 and #122 by adding --description/-d flag to bd update CLI
and description parameter to MCP update_issue tool.
Changes:
- CLI: Added --description flag to updateCmd
- RPC: Added Description field to UpdateArgs
- Daemon: Updated updatesFromArgs to handle description
- MCP: Added description to update_issue, UpdateIssueParams, and clients
- Storage: description already supported in allowedUpdateFields
Tested in both daemon and direct modes.
- Register atexit handler to close daemon connections
- Add signal handlers for SIGTERM/SIGINT for graceful shutdown
- Implement cleanup() to close all daemon client connections
- Track daemon clients globally for cleanup
- Add close() method to BdDaemonClient (no-op since connections are per-request)
- Register client on first use via _get_client()
- Add comprehensive lifecycle tests
This prevents MCP server processes from accumulating without cleanup.
Each tool invocation will now properly clean up on exit.
Amp-Thread-ID: https://ampcode.com/threads/T-05d76b8e-dac9-472b-bfd0-afe10e3457cd
Co-authored-by: Amp <amp@ampcode.com>
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)
- 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>
Implements the `bd` reopen command across the entire MCP stack, enabling
agents to reopen closed issues with optional reason tracking for audit
trails. This addresses the need to handle regressions and incorrectly
closed issues without manual `bd` CLI intervention.
The reopen command is more explicit than `bd update --status open` and
emits a dedicated Reopened event in the audit log, making it easier to
track why issues were reopened during analysis.
Changes:
- `models.py`: Add ReopenIssueParams with issue_ids list and optional reason
- `bd_client.py`: Implement reopen() method with JSON response parsing
- `tools.py`: Add beads_reopen_issue() wrapper with Annotated types for MCP
- `server.py`: Register 'reopen' MCP tool with description and parameters
Testing (10 new):
- `test_bd_client.py`: 4 unit tests (mocked subprocess)
- `test_bd_client_integration.py`: 3 integration tests (real `bd` CLI)
- `test_mcp_server_integration.py`: 3 MCP integration tests (FastMCP Client)
- `test_tools.py`: 3 tools wrapper tests (mocked BdClient)
Also updated `README.md`.
1. Fix `test_default_beads_path_auto_detection`
- Changed beads_path to use `Field(default_factory=_default_beads_path)` so the default is evaluated at instance
creation time, not class definition time
- Updated test to mock both `shutil.which` and `os.access`
2. Fix `test_init_creates_beads_directory`
- Fixed test to pass `working_dir=temp_dir` to `BdClient` instead of using `os.chdir()`
- The `_get_working_dir()` method checks `PWD` env var first, which isn't updated by `os.chdir()`
3. Fix minor linting errors reported by `ruff` tool
4. Update `beads` version to `0.9.6` in `uv.lock` file
MCP Server test coverage is now excellent, at 92% overall maintaining our high-standards of production level quality.
```
Name Stmts Miss Cover
------------------------------------------------
src/beads_mcp/__init__.py 1 0 100%
src/beads_mcp/__main__.py 3 3 0%
src/beads_mcp/bd_client.py 214 14 93%
src/beads_mcp/config.py 51 2 96%
src/beads_mcp/models.py 92 1 99%
src/beads_mcp/server.py 58 16 72%
src/beads_mcp/tools.py 59 0 100%
------------------------------------------------
TOTAL 478 36 92%
```
Fixes Claude Code marketplace plugin installation failure (bd-183).
Problem: The plugin.json manifest included an engines field (borrowed from npm)
to specify minimum bd CLI version requirements. However, Claude Code's plugin
manifest schema doesn't recognize this field, causing validation errors when
installing via /plugin marketplace add.
Solution:
1. Remove the engines field from plugin.json
2. Add runtime version checking in the MCP server startup
3. Update documentation to reflect automatic version checking
Changes:
- .claude-plugin/plugin.json: Remove unsupported engines field
- integrations/beads-mcp/src/beads_mcp/bd_client.py:
- Add BdVersionError exception class
- Add _check_version() method to validate bd CLI >= 0.9.0
- Use bd version command (not bd --version)
- integrations/beads-mcp/src/beads_mcp/tools.py:
- Make _get_client() async to support version checking
- Update all tool functions to await _get_client()
- Add version check on first MCP server use
- .claude-plugin/commands/bd-version.md: Update to mention automatic checking
- PLUGIN.md: Document automatic version validation at startup
Benefits:
- Plugin installs successfully via Claude Code marketplace
- Clear error messages if bd CLI version is too old
- Version check happens once per MCP server lifetime (not per command)
- Users get actionable update instructions in error messages
Closes bd-183