From e97c122feb885b3f2ce9083a3af7c1ee6b15e4d4 Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Sun, 19 Oct 2025 19:37:58 -0700 Subject: [PATCH] Cleanup and fixes: godoc comments, removed dead code, fixed renumber FK constraint bug - Added comprehensive godoc comments for auto-flush functions (bd-4) - Removed unused issueMap in scoreCollisions (bd-6) - Fixed renumber command FK constraint failure (bd-143) - Changed UpdateIssueID to use explicit connection with FK disabled - Resolves 'constraint failed: FOREIGN KEY constraint failed' error - Deleted 22 test/placeholder issues - Renumbered issues from bd-1 to bd-143 (eliminated gaps) Amp-Thread-ID: https://ampcode.com/threads/T-65f78f08-4856-4af0-9d6c-af33e88b5f63 Co-authored-by: Amp --- .beads/issues.jsonl | 27 ++--------------- cmd/bd/main.go | 43 ++++++++++++++++++++++++++++ internal/storage/sqlite/collision.go | 6 ---- internal/storage/sqlite/sqlite.go | 21 +++++++++----- 4 files changed, 60 insertions(+), 37 deletions(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 10c5efba..20d2bba8 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,18 +1,12 @@ {"id":"bd-1","title":"Reach 1.0 release milestone","description":"Stabilize API, finalize documentation, comprehensive testing","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.271608-07:00","closed_at":"2025-10-18T16:47:05.346306-07:00"} {"id":"bd-10","title":"Add visual indicators for nodes with multiple parents in dep tree","description":"When a node appears in the dependency tree via multiple paths (diamond dependencies), add a visual indicator like (*) or (multiple parents) to help users understand the graph structure. This would make it clear when deduplication has occurred. Example: 'bd-503: Shared dependency (*) [P1] (open)'","status":"open","priority":3,"issue_type":"feature","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.272062-07:00"} {"id":"bd-100","title":"Phase 4: Add atomic operations and stress testing","description":"Implement atomic multi-operation support and test under concurrent load.\n\nFeatures:\n- Batch/transaction API for multi-step operations\n- Request timeout and cancellation support\n- Connection pooling optimization\n- Stress tests with 4+ concurrent agents\n- Performance benchmarks vs direct mode\n- Documentation updates\n\nValidates all acceptance criteria for bd-96.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-10-16T22:47:49.785525-07:00","updated_at":"2025-10-19T19:04:29.272348-07:00","closed_at":"2025-10-16T23:40:29.95134-07:00"} -{"id":"bd-101","title":"Test daemon auto-detection","description":"","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-16T23:04:51.334824-07:00","updated_at":"2025-10-19T19:04:29.272591-07:00","closed_at":"2025-10-16T23:04:55.769268-07:00"} -{"id":"bd-102","title":"Test daemon RPC","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T23:18:41.845364-07:00","updated_at":"2025-10-19T19:04:29.272824-07:00","closed_at":"2025-10-16T23:19:11.402442-07:00"} {"id":"bd-103","title":"Add comprehensive daemon tests for RPC integration","description":"Add tests for:\n- RPC server integration (daemon accepts connections)\n- Concurrent client operations\n- Socket cleanup on shutdown\n- Server start failures (socket already exists)\n- Graceful shutdown verification\n\nThese tests were identified in bd-99 code review but not implemented yet.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T23:28:30.552132-07:00","updated_at":"2025-10-19T19:04:29.273044-07:00","closed_at":"2025-10-16T23:57:54.583646-07:00"} {"id":"bd-104","title":"Investigate CWD propagation from Claude Code/Amp to MCP server","description":"","design":"## Problem\n\nMCP servers don't know which directory the user is working in within Claude Code or Amp. This causes database routing issues for beads because:\n\n1. MCP server process starts with its own CWD (wherever it was launched from)\n2. `bd` binary uses tree-walking to discover databases based on CWD\n3. Without correct CWD, `bd` discovers the wrong database or falls back to ~/.beads\n\n## Current Workaround\n\nWe're using explicit `BEADS_DB` environment variables in MCP server configuration:\n- One MCP server per repo with explicit database path\n- Works but doesn't scale (30+ repos with .beads/ directories)\n\n## Desired Solution\n\nMCP server should receive CWD context either:\n\n### Option A: Startup Time\n- Claude Code/Amp passes working directory when launching MCP server\n- MCP server uses that directory for all tool calls\n- **Question:** Is this supported in MCP protocol/implementations?\n\n### Option B: Tool Call Time \n- Each MCP tool call includes a `cwd` parameter\n- Tools use that CWD for subprocess execution\n- **Question:** Does MCP protocol support per-call context?\n\n### Option C: Hybrid\n- MCP server detects directory from Claude Code workspace/project\n- Tools accept optional `cwd` override parameter\n\n## Investigation Steps\n\n1. Review MCP protocol specification for context passing\n2. Check Claude Code MCP implementation for CWD handling\n3. Check Amp MCP implementation for CWD handling \n4. Test if PWD environment variable is set correctly by Claude Code\n5. Prototype dynamic CWD detection in beads-mcp\n6. Document findings and recommend approach\n\n## References\n\n- beads-mcp already has `BEADS_WORKING_DIR` config support\n- bd_client.py uses `cwd` parameter for subprocess calls\n- Current implementation: `os.environ.get('PWD', os.getcwd())`\n","acceptance_criteria":"- Documented investigation findings\n- Tested CWD propagation in both Claude Code and Amp\n- Recommended approach for solving multi-repo MCP database routing\n- Prototype or proof-of-concept if feasible","notes":"## Implementation Complete (2025-10-17)\n\nImplemented PATH 1 (Simple Context Management) from the recommended solutions.\n\n### What Was Built\n\nAdded two new MCP tools to beads-mcp:\n\n1. **set_context(workspace_root)** - Sets workspace root and discovers database\n - Resolves to git repo root automatically\n - Walks up tree to find `.beads/*.db`\n - Sets env vars: BEADS_WORKING_DIR, BEADS_DB, BEADS_CONTEXT_SET\n\n2. **where_am_i()** - Shows current context for debugging\n - Returns workspace root, database path, actor\n\n3. **@require_context decorator** - Guards all write operations\n - Only enforced when BEADS_REQUIRE_CONTEXT=1 env var is set\n - Ensures context is set before create/update/close/reopen/dep/init\n - Backward compatible (off by default)\n\n### Implementation Details\n\n- File: `integrations/beads-mcp/src/beads_mcp/server.py`\n- Tests: All existing tests pass (103/104)\n- Documentation: `integrations/beads-mcp/CONTEXT_MANAGEMENT.md`\n\n### Key Discovery: Environment Variable Limitation\n\n**FastMCP architectural constraint:** Environment variables don't persist between tool calls in the current MCP protocol/FastMCP implementation.\n\nThis means:\n- `set_context` works within its own tool call\n- Subsequent tools may not see the env vars\n- True session state would require MCP protocol changes\n\n### Current Status\n\n**Partial solution delivered:**\n✅ Tools exist and work correctly\n✅ Can be used for explicit context management\n✅ Provides visibility (where_am_i)\n✅ Guards against accidental misrouting (when enabled)\n⚠️ Limited by MCP protocol's stateless nature\n\n**For production use:** Continue with current workaround (explicit BEADS_DB per MCP server config) until:\n1. MCP protocol adds session state support, OR\n2. We implement daemon RPC with per-request cwd (PATH 1.5), OR\n3. Client implementations can pass context with every tool call\n\n### Next Steps\n\n**Immediate (keep current workaround):**\n- Use single MCP server with explicit BEADS_DB in config\n- Set BEADS_REQUIRE_CONTEXT=1 for safety\n- Call set_context at session start (even if env vars don't persist, it validates paths)\n\n**Medium-term (if needed):**\n- Implement PATH 1.5: Add cwd parameter to daemon RPC protocol\n- Update MCP server to use daemon client instead of direct CLI calls\n- Per-request context routing via daemon\n\n**Long-term (if \u003e50 repos):**\n- Implement PATH 2: Advanced routing daemon with repo→DB index\n\n## Original Notes\n[Previous investigation notes preserved above...]","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-17T02:06:09.737832-07:00","updated_at":"2025-10-19T19:04:29.273279-07:00","closed_at":"2025-10-17T16:54:35.196728-07:00"} {"id":"bd-105","title":"Test Epic for epic commands","description":"","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-17T12:07:19.224482-07:00","updated_at":"2025-10-19T19:04:29.273572-07:00","closed_at":"2025-10-17T12:07:59.213044-07:00"} -{"id":"bd-106","title":"Child task 1","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-17T12:07:24.27717-07:00","updated_at":"2025-10-19T19:04:29.273847-07:00","closed_at":"2025-10-17T12:07:38.659749-07:00"} -{"id":"bd-107","title":"Child task 2","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-17T12:07:24.316272-07:00","updated_at":"2025-10-19T19:04:29.274159-07:00","closed_at":"2025-10-17T12:07:45.496304-07:00"} -{"id":"bd-108","title":"Child task 3","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-17T12:07:24.33996-07:00","updated_at":"2025-10-19T19:04:29.274439-07:00","closed_at":"2025-10-17T12:07:45.624974-07:00"} {"id":"bd-109","title":"Another epic","description":"","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-17T12:08:10.396072-07:00","updated_at":"2025-10-19T19:04:29.274661-07:00","closed_at":"2025-10-17T12:10:06.062102-07:00"} {"id":"bd-11","title":"Critical bug","description":"","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.274887-07:00","closed_at":"2025-10-14T14:16:08.107546-07:00"} {"id":"bd-110","title":"Test epic 2","description":"","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-17T12:09:59.880202-07:00","updated_at":"2025-10-19T19:04:29.275121-07:00","closed_at":"2025-10-17T12:10:06.063293-07:00"} -{"id":"bd-111","title":"Child A","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-17T12:09:59.923718-07:00","updated_at":"2025-10-19T19:04:29.275413-07:00","closed_at":"2025-10-17T12:10:00.087913-07:00"} {"id":"bd-112","title":"Auto-close or warn about epics when all children complete","description":"","design":"See epic.go for implementation. Commands: bd epic status, bd epic close-eligible. Stats integration added.","acceptance_criteria":"Commands work, tests pass, addresses GitHub issue #62","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-17T13:47:42.9642-07:00","updated_at":"2025-10-19T19:04:29.275751-07:00","closed_at":"2025-10-17T13:47:48.136662-07:00","external_ref":"gh-62"} {"id":"bd-113","title":"Agents confused by multiple MCP beads servers - use wrong database","description":"When multiple beads MCP servers are configured (e.g., beads-wyvern, beads-adar), agents may use the wrong server and create issues in wrong database. In this session, created wy-22 (wyvern) when working in beads repo. Root cause: All MCP servers available simultaneously with different BEADS_WORKING_DIR/BEADS_DB env vars. Agent must manually choose correct server or use direct bd commands.","design":"## This is a SYMPTOM of bd-104\n\nThe multi-server approach was a workaround attempt that backfired. See bd-104 for comprehensive root cause analysis.\n\n## Original Solutions (superseded by bd-104 analysis)\n\nPossible solutions: 1) Context-aware MCP routing based on pwd, 2) Single MCP server that auto-detects context, 3) Better agent instructions about which server to use, 4) Naming convention that makes server purpose obvious (beads-wyvern vs beads-current)\n\n## Actual Solution (from bd-104)\n\nImplement PATH 1: Single MCP server with SetContext/WhereAmI tools. This issue will be resolved when bd-104 is implemented.","notes":"This issue is a SYMPTOM of bd-104 (missing CWD propagation). The multi-server workaround (beads-wyvern, beads-adar, etc.) doesn't solve the root cause and creates new problems (agent confusion about which server to use). See bd-104 for comprehensive analysis and architectural solutions. Should be resolved when bd-104 is fixed with Path 1 (SetContext/WhereAmI approach).","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-17T13:47:58.092565-07:00","updated_at":"2025-10-19T19:04:29.276024-07:00","closed_at":"2025-10-17T16:54:35.197351-07:00"} {"id":"bd-114","title":"Implement daemon RPC with per-request context routing (PATH 1.5)","description":"Enable MCP server to use daemon with per-request context instead of shelling out to bd CLI. This solves multi-repo routing properly.","design":"## Goal\n\nMCP server → daemon RPC with `cwd` parameter → daemon routes to correct database per request\n\n## Architecture\n\n```\nAI Client (Claude/Amp)\n ↓\nMCP Server (set_context sets workspace_root)\n ↓\nDaemon Client Library (new)\n ↓ RPC with cwd field\nbeadsd Daemon\n ↓ tree-walking per request\nCorrect .beads/*.db\n```\n\n## Components\n\n### 1. Extend Daemon RPC Protocol\n**Files:** `internal/daemon/protocol.go`, daemon handlers\n\n- Add `Cwd string` field to all request types (CreateIssueRequest, UpdateIssueRequest, etc.)\n- Daemon does tree-walking to find `.beads/*.db` based on cwd\n- Each operation gets its own context (stateless per request)\n\n### 2. Create Daemon Client Library\n**New file:** `integrations/beads-mcp/src/beads_mcp/bd_daemon_client.py`\n\n- Python client for daemon RPC protocol\n- Methods matching current BdClient interface\n- Adds `cwd` parameter to all requests\n- Handles connection management, retries\n- Falls back to CLI if daemon unavailable\n\n### 3. Update MCP Server\n**File:** `integrations/beads-mcp/src/beads_mcp/server.py`\n\n- Store workspace_root from `set_context` \n- Use daemon client by default, fall back to CLI client\n- Pass workspace_root as cwd to all operations\n- Handle daemon not running gracefully\n\n### 4. Update bd_client.py\n**File:** `integrations/beads-mcp/src/beads_mcp/bd_client.py`\n\n- Make it an abstract interface/base class\n- Concrete implementations: BdCliClient, BdDaemonClient\n- Factory function to create appropriate client\n\n## Benefits\n\n- ✅ True multi-repo support (each request has context)\n- ✅ Better performance (no process spawning)\n- ✅ Concurrent access already solved (daemon exists)\n- ✅ Stateless per request (no env var persistence issues)\n- ✅ Falls back to CLI when daemon not running\n\n## Implementation Steps\n\n1. **Extend RPC protocol** (Go)\n - Add Cwd field to request structs\n - Update daemon handlers to use cwd for tree-walking\n \n2. **Create daemon client** (Python)\n - Implement RPC protocol in Python\n - Match BdClient interface\n \n3. **Refactor MCP server**\n - Abstract BdClient\n - Use daemon client when available\n \n4. **Test with multiple repos**\n - Concurrent operations\n - Context switching\n - Daemon restart handling\n\n## Related Issues\n\n- bd-104: Root cause investigation (this is PATH 1.5 solution)\n- bd-113: Multi-server confusion (will be resolved)\n- bd-96, bd-97, bd-98, bd-99: Daemon implementation (foundation)","acceptance_criteria":"- MCP server can use daemon RPC instead of CLI\n- Each operation includes cwd context\n- Daemon routes to correct database per request\n- Works with multiple repos simultaneously\n- Falls back to CLI gracefully if daemon unavailable\n- All existing MCP tests pass\n- New multi-repo integration tests pass","notes":"## Progress: Session 2 (2025-10-17 continued)\n\n### Completed\n1. ✅ Updated MCP server to use daemon client\n - Modified `tools.py` to use `create_bd_client()` factory\n - Passes `BEADS_WORKING_DIR` from environment\n - Uses daemon by default, falls back to CLI\n2. ✅ Added `BEADS_USE_DAEMON` environment variable\n - Default: `1` (enabled)\n - Set to `0` to force CLI mode\n3. ✅ Created multi-repo integration test (`test_multi_repo.py`)\n - Tests concurrent operations across two repos\n - Verifies proper database routing based on cwd\n - Validates issue prefix isolation (r1- vs r2-)\n - All tests pass! ✅\n4. ✅ Updated MCP README with daemon usage docs\n - Added BEADS_USE_DAEMON to environment variables\n - Added multi-repo test documentation\n\n### Test Results\n```\n=== All Tests Passed! ===\nSummary:\n ✅ Per-request context routing works\n ✅ Multiple repos are properly isolated\n ✅ Concurrent operations succeed\n ✅ Daemon handles rapid context switching\n```\n\n### Files Modified/Added (Session 2)\n- `integrations/beads-mcp/src/beads_mcp/tools.py` - uses daemon client ✅\n- `integrations/beads-mcp/test_multi_repo.py` - NEW integration test ✅\n- `integrations/beads-mcp/README.md` - daemon documentation ✅\n\n### Architecture Validated\n\n```\nAI Client (Claude/Amp)\n ↓\nMCP Server (workspace_root from set_context)\n ↓ create_bd_client(prefer_daemon=True, workspace_root)\nDaemon Client Library\n ↓ RPC with cwd field\nbeadsd Daemon\n ↓ per-request tree-walking\nCorrect .beads/*.db\n```\n\n### Ready to Close\nAll acceptance criteria met:\n- ✅ MCP server can use daemon RPC instead of CLI\n- ✅ Each operation includes cwd context\n- ✅ Daemon routes to correct database per request\n- ✅ Works with multiple repos simultaneously\n- ✅ Falls back to CLI gracefully if daemon unavailable\n- ✅ All existing MCP tests pass\n- ✅ New multi-repo integration tests pass","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-17T16:20:00.775954-07:00","updated_at":"2025-10-19T19:04:29.276315-07:00","closed_at":"2025-10-17T16:37:34.504057-07:00"} @@ -71,32 +65,27 @@ {"id":"bd-162","title":"Add 'bd comments' command to view and manage issue comments","description":"Add support for commenting on issues with a new 'bd comments' command.\n\nCommands:\n- bd comments \u003cissue-id\u003e # List all comments on an issue\n- bd comments add \u003cissue-id\u003e \"text\" # Add a comment\n- bd comments add \u003cissue-id\u003e -f file.txt # Add comment from file\n- bd comments \u003cissue-id\u003e --json # JSON output for agents\n\nUse cases:\n- Track discussion/decisions on issues\n- Add context without cluttering description\n- Record why work was paused/resumed\n- Multi-person collaboration notes\n- Agent can leave progress updates\n\nImplementation:\n- Add comments table to schema (id, issue_id, author, text, timestamp)\n- Store in JSONL as nested array in issue objects\n- Show chronologically with timestamps\n- Include in 'bd show' output (collapsed by default?)\n\nQuestions:\n- Should comments be editable/deletable?\n- Include author field (env var or git config)?\n- Threading/replies to comments?","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-19T15:58:07.483312-07:00","updated_at":"2025-10-19T19:04:29.288247-07:00","closed_at":"2025-10-19T18:24:50.979019-07:00"} {"id":"bd-163","title":"Add daemon RPC support for comments and label subcommands","description":"The 'bd comments' and 'bd label' subcommands don't work in direct mode because they don't inherit PersistentPreRun from root command. Need to add daemon RPC handlers similar to how show/update/create work.\n\nAffected commands:\n- bd comments \u003cid\u003e\n- bd comments add \u003cid\u003e \"text\"\n- bd label list \u003cid\u003e\n- bd label add \u003cid\u003e \u003clabel\u003e\n- bd label remove \u003cid\u003e \u003clabel\u003e\n\nSolution: Add RPC handlers in daemon.go for these operations and update the CLI commands to use daemon RPC when available (check daemonClient != nil pattern used in other commands).","status":"in_progress","priority":2,"issue_type":"bug","created_at":"2025-10-19T16:08:42.16553-07:00","updated_at":"2025-10-19T19:04:29.288454-07:00"} {"id":"bd-164","title":"MCP server workspace routing broken - using wrong server for workspace","description":"When working in ~/src/beads, AI agent is calling mcp__beads-wyvern__* functions which are configured for ~/wyvern workspace. This causes MCP commands to fail or operate on wrong database.\n\nExpected: Should use correct MCP server based on current workspace\nActual: Using beads-wyvern MCP server when in beads repo\n\nNeed to investigate:\n- How MCP server routing/selection works\n- Why wrong server is being selected\n- How to fix workspace detection","notes":"Root cause: Using multiple MCP servers (beads-adar, beads-wyvern, beads-vc, beads) instead of single MCP server with global daemon. AI randomly selects wrong server for workspace.\n\nFixed:\n1. Started global daemon: bd daemon --global\n2. Simplified config to single MCP server in ~/.config/amp/settings.json\n3. Updated AGENTS.md to emphasize single MCP server as RECOMMENDED approach\n4. Marked legacy multiple-server approach with warning about workspace routing issues\n\nUser needs to restart Amp for config changes to take effect.","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-19T18:32:04.513755-07:00","updated_at":"2025-10-19T19:04:29.288678-07:00","closed_at":"2025-10-19T18:35:00.167234-07:00"} +{"id":"bd-165","title":"Renumber command fails with foreign key constraint error","description":"When running 'bd renumber --force' after deleting issues, the command fails with: 'failed to rename bd-34 to temp ID: failed to update issue ID: constraint failed: FOREIGN KEY constraint failed (787)'. This suggests the renumber implementation doesn't properly handle foreign key constraints during the ID swap process. May need to disable foreign keys temporarily or use a different renumbering strategy.","notes":"Root cause: Foreign keys are disabled in the database (PRAGMA foreign_keys = 0). The UpdateIssueID function uses 'PRAGMA defer_foreign_keys = ON' but this only works when foreign keys are already enabled. Need to either: 1) Enable foreign keys globally, 2) Enable them in the transaction, or 3) Use a different renumbering strategy that doesn't trigger constraint checks.","status":"in_progress","priority":1,"issue_type":"bug","created_at":"2025-10-19T19:33:20.324768-07:00","updated_at":"2025-10-19T19:34:01.896527-07:00"} {"id":"bd-17","title":"Make auto-flush debounce duration configurable","description":"flushDebounce is hardcoded to 5 seconds. Make it configurable via environment variable BEADS_FLUSH_DEBOUNCE (e.g., '500ms', '10s'). Current 5-second value is reasonable for interactive use, but CI/automated scenarios might want faster flush. Add getDebounceDuration() helper function. Located in cmd/bd/main.go:31.","status":"closed","priority":3,"issue_type":"feature","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.288887-07:00","closed_at":"2025-10-18T09:47:43.22126-07:00"} {"id":"bd-18","title":"Optimize auto-flush to use incremental updates","description":"Every flush exports ALL issues and ALL dependencies, even if only one issue changed. For large projects (1000+ issues), this could be expensive. Current approach guarantees consistency, which is fine for MVP, but future optimization could track which issues changed and use incremental updates. Located in cmd/bd/main.go:255-276.","status":"closed","priority":3,"issue_type":"feature","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.289088-07:00","closed_at":"2025-10-14T02:51:52.200141-07:00"} {"id":"bd-19","title":"Refactor duplicate flush logic in PersistentPostRun","description":"PersistentPostRun contains a complete copy of the flush logic instead of calling flushToJSONL(). This violates DRY principle and makes maintenance harder. Refactor to use flushToJSONL() with a force parameter to bypass isDirty check, or extract shared logic into a helper function. Located in cmd/bd/main.go:104-138.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.289594-07:00","closed_at":"2025-10-18T09:44:24.167574-07:00"} {"id":"bd-2","title":"Add test for deep hierarchy blocking (50+ levels)","description":"Current tests verify 2-level depth (grandparent → parent → child). The depth limit is hardcoded to 50 in the recursive CTE, but we don't test edge cases near that limit.\n\n**Test cases needed:**\n1. Verify 50-level deep hierarchy works correctly\n2. Verify depth limit prevents runaway recursion\n3. Measure performance impact of deep hierarchies\n4. Consider if 50 is the right limit (why not 100? why not 20?)\n\n**Rationale:**\n- Most hierarchies are 2-5 levels deep\n- But pathological cases (malicious or accidental) could create 50+ level nesting\n- Need to ensure graceful degradation, not catastrophic failure\n\n**Implementation:**\nAdd TestDeepHierarchyBlocking to ready_test.go","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.289811-07:00","closed_at":"2025-10-18T16:47:05.347564-07:00"} {"id":"bd-20","title":"Implement full cross-type cycle prevention in AddDependency","description":"Expand cycle prevention in AddDependency to check for cycles across ALL dependency types, not just 'blocks'. Currently only 'blocks' type dependencies are checked for cycles, allowing cross-type circular dependencies to form (e.g., A blocks B, B parent-child A). This can cause semantic confusion and is a maintenance hazard for future operations that traverse dependencies.","design":"Implementation approach:\n1. Modify the cycle check in AddDependency (postgres.go:559-599)\n2. Remove the 'type = blocks' filter from the recursive CTE\n3. Check for cycles regardless of dependency type being added\n4. Return a clear error message indicating which types form the cycle\n\nTrade-offs to consider:\n- This is more mathematically correct (no cycles in dependency DAG)\n- May break legitimate use cases where cross-type cycles are intentional\n- Need to evaluate whether ANY cross-type cycles are valid in practice\n- Alternative: make this configurable with a --allow-cycle flag\n\nBefore implementing, should investigate:\n- Are there legitimate reasons for cross-type cycles?\n- What's the performance impact on large graphs (1000+ issues)?\n- Should certain type combinations be allowed to cycle?","acceptance_criteria":"- AddDependency prevents cycles across all dependency types, not just 'blocks'\n- Clear error message when cycle would be created, including dependency types\n- All existing tests pass\n- Performance benchmarked on large dependency graphs (100+ issues)\n- Decision documented on whether to add --allow-cycle flag or exception rules","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.290041-07:00","closed_at":"2025-10-16T20:31:19.174534-07:00"} -{"id":"bd-21","title":"Test issue for design field","description":"Testing the new update flags","design":"## Design Plan\\n- Add flags to update command\\n- Test thoroughly\\n- Document changes","acceptance_criteria":"- All three fields (design, notes, acceptance-criteria) can be updated\\n- Changes persist in database\\n- bd show displays the fields correctly","notes":"Implementation complete. All tests passing.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.290251-07:00","closed_at":"2025-10-14T02:51:52.199634-07:00"} {"id":"bd-22","title":"Use safer placeholder pattern in replaceIDReferences","description":"Currently uses bd-313 which could theoretically collide with user text. Use a truly unique placeholder like null bytes: \\x00REMAP\\x00_0_\\x00 which are unlikely to appear in normal text. Located in collision.go:324. Very low probability issue but worth fixing for completeness.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.290462-07:00","closed_at":"2025-10-18T09:43:18.250156-07:00"} {"id":"bd-23","title":"Improve error handling in dependency removal during remapping","description":"In updateDependencyReferences(), RemoveDependency errors are caught and ignored with continue (line 392). Comment says 'if dependency doesn't exist' but this catches ALL errors including real failures. Should check error type with errors.Is(err, ErrDependencyNotFound) and only ignore not-found errors, returning other errors properly.","status":"closed","priority":3,"issue_type":"bug","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.29066-07:00","closed_at":"2025-10-18T09:41:18.209717-07:00"} {"id":"bd-24","title":"Optimize export dependency queries (N+1 problem)","description":"Export triggers separate GetDependencyRecords() per issue. For large DBs (1000+ issues), this is N+1 queries. Add GetAllDependencyRecords() to fetch all dependencies in one query. Location: cmd/bd/export.go:52-59, import.go:138-142","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.290915-07:00","closed_at":"2025-10-14T02:51:52.19905-07:00"} {"id":"bd-25","title":"Add validation/warning for malformed issue IDs","description":"getNextID silently ignores non-numeric ID suffixes (e.g., bd-foo). CAST returns NULL for invalid strings. Consider detecting and warning about malformed IDs in database. Location: internal/storage/sqlite/sqlite.go:79-82","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.291598-07:00","closed_at":"2025-10-14T02:51:52.198988-07:00"} {"id":"bd-26","title":"Simplify getNextID SQL query parameters","description":"Query passes prefix four times to same SQL query. Works but fragile if query changes. Consider simplifying SQL to require fewer parameters. Location: internal/storage/sqlite/sqlite.go:73-78","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.291783-07:00","closed_at":"2025-10-16T10:07:34.038708-07:00"} -{"id":"bd-27","title":"Test issue to verify fix","description":"This should be bd-44 if the fix works","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.291944-07:00","closed_at":"2025-10-16T10:07:33.971732-07:00"} -{"id":"bd-28","title":"Add PostgreSQL backend","description":"Implement PostgreSQL storage backend as alternative to SQLite for larger teams","status":"closed","priority":3,"issue_type":"feature","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.292097-07:00","closed_at":"2025-10-16T10:07:33.961565-07:00"} {"id":"bd-29","title":"Improve session management","description":"Current session management is basic. Need to improve with better expiration handling.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.292261-07:00","closed_at":"2025-10-16T10:07:34.005199-07:00"} {"id":"bd-3","title":"Make maxDepth configurable in bd dep tree command","description":"Currently maxDepth is hardcoded to 50 in GetDependencyTree. Add --max-depth flag to bd dep tree command to allow users to control recursion depth. Default should remain 50 for safety, but users with very deep trees or wanting shallow views should be able to configure it.","status":"closed","priority":4,"issue_type":"feature","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.292419-07:00","closed_at":"2025-10-19T08:59:59.596748-07:00"} -{"id":"bd-30","title":"Improve session management","description":"Current session management is basic. Need to improve with better expiration handling.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.292587-07:00","closed_at":"2025-10-16T10:07:22.46194-07:00"} -{"id":"bd-31","title":"Improve session management","description":"Current session management is basic. Need to improve with better expiration handling.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.29275-07:00","closed_at":"2025-10-14T14:37:17.463188-07:00"} {"id":"bd-32","title":"Fix: bd init --prefix test -q flag not recognized","description":"The init command doesn't recognize the -q flag. When running 'bd init --prefix test -q', it fails silently or behaves unexpectedly. The flag should either be implemented for quiet mode or removed from documentation if not supported.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.292914-07:00","closed_at":"2025-10-17T00:09:18.921816-07:00"} -{"id":"bd-33","title":"Test issue with --deps flag","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.293076-07:00","closed_at":"2025-10-16T10:07:34.027923-07:00"} {"id":"bd-34","title":"Implement storage driver interface for pluggable backends","description":"Create abstraction layer for storage to support multiple backends (SQLite, Postgres, Turso, in-memory testing, etc.).\n\n**Current state:** All storage logic hardcoded to SQLite in internal/storage/sqlite/sqlite.go\n\n**Proposed design:**\n\n```go\n// internal/storage/storage.go\ntype Store interface {\n // Issue CRUD\n CreateIssue(issue *Issue) error\n GetIssue(id string) (*Issue, error)\n UpdateIssue(id string, updates *Issue) error\n DeleteIssue(id string) error\n ListIssues(filter *Filter) ([]*Issue, error)\n \n // Dependencies\n AddDependency(from, to string, depType DependencyType) error\n RemoveDependency(from, to string, depType DependencyType) error\n GetDependencies(id string) ([]*Dependency, error)\n \n // Counters, stats\n GetNextID(prefix string) (string, error)\n GetStats() (*Stats, error)\n \n Close() error\n}\n```\n\n**Benefits:**\n- Better testing (mock/in-memory stores)\n- Future flexibility (Postgres, cloud APIs, etc.)\n- Clean architecture (business logic decoupled from storage)\n- Enable Turso or other backends without refactoring everything\n\n**Implementation steps:**\n1. Define Store interface in internal/storage/storage.go\n2. Refactor SQLiteStore to implement interface\n3. Update all commands to use interface, not concrete type\n4. Add MemoryStore for testing\n5. Add driver selection via config (storage.driver = sqlite|turso|postgres)\n6. Update tests to use interface\n\n**Note:** This is valuable even without adopting Turso. Good architecture practice.\n\n**Context:** From GH issue #2 RFC evaluation. Driver interface is low-cost, high-value regardless of whether we add alternative backends.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.293258-07:00","closed_at":"2025-10-17T23:46:22.447301-07:00"} {"id":"bd-35","title":"Add system-wide/multi-repo support for beads","description":"GitHub issue #4 requests ability to use beads across multiple projects and for system-wide task tracking.\n\nCurrent limitation: beads is per-repository isolated. Each project has its own .beads/ directory and issues cannot reference issues in other projects.\n\nPotential approaches:\n1. Global beads instance in ~/.beads/global.db for cross-project work\n2. Project references - allow issues to link across repos\n3. Multi-project workspace support - one beads instance managing multiple repos\n4. Integration with existing MCP server to provide remote multi-project access\n\nUse cases:\n- System administrators tracking work across multiple machines/repos\n- Developers working on a dozen+ projects simultaneously\n- Cross-cutting concerns that span multiple repositories\n- Global todo list with project-specific subtasks\n\nRelated:\n- GitHub issue #4: https://github.com/steveyegge/beads/issues/4\n- Comparison to membank MCP which already supports multi-project via centralized server\n- MCP server at integrations/beads-mcp/ could be extended for this\n\nSee also: Testing framework for plugins (also from GH #4)","notes":"Multi-repo support status update:\n\n✅ **COMPLETED (P1 - Core functionality):**\n- bd-120: --global daemon flag ✅ \n- bd-121: Multi-repo documentation ✅\n- bd-114: Per-request context routing ✅\n\n**REMAINING (Optional enhancements):**\n- bd-122 (P2): 'bd repos' command - nice-to-have for UX\n- bd-123 (P2): Daemon auto-start - convenience feature\n- bd-124 (P3): Workspace config - alternative approach\n- bd-125 (P4): Cross-repo references - future feature\n\n**Decision:** Core multi-repo support is COMPLETE and working. Remaining items are independent enhancements, not blockers. \n\nRecommend closing bd-35 as complete. Open new issues for specific enhancements if needed.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.293442-07:00","closed_at":"2025-10-17T23:15:17.705446-07:00"} {"id":"bd-36","title":"Create version bump script","description":"Create scripts/bump-version.sh to automate version syncing across all components.\n\nThe script should:\n1. Take a version number as argument (e.g., ./scripts/bump-version.sh 0.9.3)\n2. Update all version files:\n - cmd/bd/version.go (Version constant)\n - .claude-plugin/plugin.json (version field)\n - .claude-plugin/marketplace.json (plugins[].version)\n - integrations/beads-mcp/pyproject.toml (version field)\n - README.md (Alpha version mention)\n - PLUGIN.md (version requirements)\n3. Validate semantic versioning format\n4. Show diff preview before applying\n5. Optionally create git commit with standard message\n\nThis prevents the version mismatch issue that occurred when only version.go was updated.\n\nRelated: bd-35 (version sync issue)","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.293624-07:00","closed_at":"2025-10-14T13:49:22.368581-07:00"} {"id":"bd-37","title":"Implement collision detection in import","description":"Create collision.go with detectCollisions() function. Compare incoming JSONL issues against DB state. Distinguish between: (1) exact match (idempotent), (2) ID match but different content (collision), (3) new issue. Return list of colliding issues.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.293791-07:00","closed_at":"2025-10-16T10:07:22.461107-07:00"} {"id":"bd-38","title":"Implement reference scoring algorithm","description":"Count references for each colliding issue: text mentions in descriptions/notes/design fields + dependency references. Sort collisions by score ascending (fewest refs first). This minimizes total updates during renumbering.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.29395-07:00","closed_at":"2025-10-14T02:51:52.198288-07:00"} {"id":"bd-39","title":"Implement ID remapping with reference updates","description":"Allocate new IDs for colliding issues. Update all text field references using word-boundary regex (\\bbd-10\\b). Update dependency records. Build id_mapping for reporting. Handle chain dependencies properly.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.29412-07:00","closed_at":"2025-10-14T02:51:52.198356-07:00"} -{"id":"bd-4","title":"Add godoc comments for auto-flush functions","description":"Add comprehensive godoc comments for findJSONLPath(), markDirtyAndScheduleFlush(), and flushToJSONL() explaining behavior, concurrency considerations, and error handling. Include notes about debouncing behavior (timer resets on each write, flush occurs 5s after LAST operation) and flush-on-exit guarantees. Located in cmd/bd/main.go:188-307.","status":"open","priority":4,"issue_type":"chore","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.294273-07:00"} +{"id":"bd-4","title":"Add godoc comments for auto-flush functions","description":"Add comprehensive godoc comments for findJSONLPath(), markDirtyAndScheduleFlush(), and flushToJSONL() explaining behavior, concurrency considerations, and error handling. Include notes about debouncing behavior (timer resets on each write, flush occurs 5s after LAST operation) and flush-on-exit guarantees. Located in cmd/bd/main.go:188-307.","status":"closed","priority":4,"issue_type":"chore","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:22:19.172983-07:00","closed_at":"2025-10-19T19:22:19.172983-07:00"} {"id":"bd-40","title":"Add --resolve-collisions flag and user reporting","description":"Add import flags: --resolve-collisions (auto-fix) and --dry-run (preview). Display clear report: collisions detected, remappings applied (old→new with scores), reference counts updated. Default behavior: fail on collision (safe).","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.294439-07:00","closed_at":"2025-10-16T10:07:34.003238-07:00"} {"id":"bd-41","title":"Write comprehensive collision resolution tests","description":"Test cases: simple collision, multiple collisions, dependency updates, text reference updates, chain dependencies, edge cases (partial ID matches, case sensitivity, triple merges). Add to import_test.go and collision_test.go.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.294593-07:00","closed_at":"2025-10-16T10:07:34.007864-07:00"} {"id":"bd-42","title":"Update documentation for collision resolution","description":"Update README.md with collision resolution section. Update CLAUDE.md with new workflow. Document --resolve-collisions and --dry-run flags. Add example scenarios showing branch merge workflows.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.294738-07:00","closed_at":"2025-10-16T10:07:34.028648-07:00"} @@ -107,7 +96,6 @@ {"id":"bd-47","title":"Dependency B","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.29551-07:00","closed_at":"2025-10-16T10:07:34.126858-07:00"} {"id":"bd-48","title":"Shared dependency C","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.295661-07:00","closed_at":"2025-10-16T10:07:34.12808-07:00"} {"id":"bd-49","title":"Implement reserved database name _.db","description":"Auto-detection now skips .beads/_.db to prevent pollution when beads dogfoods itself. This allows beads to use its own issue tracker without interfering with other projects using beads in the same directory tree. Implementation includes filtering in findDatabase(), stopping directory walk when .beads/ is found, and documentation in README.md and CLAUDE.md.","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.295801-07:00","closed_at":"2025-10-14T02:51:52.199832-07:00"} -{"id":"bd-5","title":"Low priority chore","description":"","status":"open","priority":4,"issue_type":"chore","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.295949-07:00"} {"id":"bd-50","title":"Epic test","description":"","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.296099-07:00","closed_at":"2025-10-16T10:07:34.128633-07:00"} {"id":"bd-51","title":"Task A under epic","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.296261-07:00","closed_at":"2025-10-16T10:07:34.129516-07:00"} {"id":"bd-52","title":"Task B under epic","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.296426-07:00","closed_at":"2025-10-16T10:07:34.129768-07:00"} @@ -118,7 +106,7 @@ {"id":"bd-57","title":"Test issue with explicit ID","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.297153-07:00","closed_at":"2025-10-16T10:07:34.124331-07:00"} {"id":"bd-58","title":"Another explicit ID","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.297308-07:00","closed_at":"2025-10-16T10:07:34.130516-07:00"} {"id":"bd-59","title":"Create Claude Code plugin for beads","description":"Package beads as a Claude Code plugin for easy installation via /plugin command.\n\nContext: GitHub issue #28 - https://github.com/steveyegge/beads/issues/28\n\nCurrent state:\n- MCP server exists in integrations/beads-mcp/\n- No plugin packaging yet\n\nDeliverables:\n1. .claude-plugin/plugin.json with metadata\n2. .claude-plugin/marketplace.json for distribution\n3. Custom slash commands (/bd-ready, /bd-create, /bd-show, etc.)\n4. Bundle MCP server configuration\n5. Optional: Pre-configured hooks for auto-sync\n6. Documentation for installation and usage\n\nBenefits:\n- Makes beads instantly discoverable in Claude Code ecosystem\n- Single-command installation vs. manual setup\n- Bundled cohesive experience\n- Lowers adoption barrier significantly\n\nReferences:\n- https://www.anthropic.com/news/claude-code-plugins\n- https://docs.claude.com/en/docs/claude-code/plugins","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.297458-07:00","closed_at":"2025-10-14T12:59:39.974612-07:00"} -{"id":"bd-6","title":"Remove unused issueMap in scoreCollisions","description":"scoreCollisions() creates issueMap and populates it (lines 135-138) but never uses it. Either remove it or add a TODO comment explaining future use. Located in collision.go:135-138. Cosmetic cleanup.","status":"open","priority":4,"issue_type":"chore","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.297612-07:00"} +{"id":"bd-6","title":"Remove unused issueMap in scoreCollisions","description":"scoreCollisions() creates issueMap and populates it (lines 135-138) but never uses it. Either remove it or add a TODO comment explaining future use. Located in collision.go:135-138. Cosmetic cleanup.","status":"closed","priority":4,"issue_type":"chore","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:27:34.230312-07:00","closed_at":"2025-10-19T19:27:34.230312-07:00"} {"id":"bd-60","title":"Research Claude Code plugin structure and requirements","description":"Study the plugin format, required files, and best practices.\n\nTasks:\n- Review official plugin documentation\n- Examine example plugins if available\n- Document plugin.json schema\n- Understand marketplace.json requirements\n- Identify slash command format","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.297766-07:00","closed_at":"2025-10-14T12:55:23.358165-07:00"} {"id":"bd-61","title":"Create plugin metadata files","description":"Create .claude-plugin/plugin.json and marketplace.json.\n\nRequirements:\n- Name, description, version, author\n- MCP server configuration bundling\n- License and repository info\n- Installation instructions","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.297907-07:00","closed_at":"2025-10-14T12:55:59.029894-07:00"} {"id":"bd-62","title":"Design and implement slash commands","description":"Create useful slash commands for beads workflow.\n\nProposed commands:\n- /bd-ready - Show ready work\n- /bd-create - Create new issue interactively\n- /bd-show - Show issue details\n- /bd-update - Update issue status\n- /bd-close - Close issue\n- /bd-workflow - Show full agent workflow guide\n\nEach command should provide a good UX and leverage the MCP server tools.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.298045-07:00","closed_at":"2025-10-14T12:57:06.733755-07:00"} @@ -136,16 +124,8 @@ {"id":"bd-73","title":"Document hierarchical blocking behavior in README","description":"The fix for bd-78 changes user-visible behavior: children of blocked epics are now automatically blocked.\n\n**What needs documenting:**\n1. README.md dependency section should explain blocking propagation\n2. Clarify that 'blocks' + 'parent-child' together create transitive blocking\n3. Note that 'related' and 'discovered-from' do NOT propagate blocking\n4. Add example showing epic → child blocking propagation\n\n**Example to add:**\n```bash\n# If epic is blocked, children are too\nbd create \"Epic 1\" -t epic -p 1\nbd create \"Task 1\" -t task -p 1\nbd dep add task-1 epic-1 --type parent-child\n\n# Block the epic\nbd create \"Blocker\" -t task -p 0\nbd dep add epic-1 blocker-1 --type blocks\n\n# Now both epic-1 AND task-1 are blocked\nbd ready # Neither will show up\n```","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.30013-07:00","closed_at":"2025-10-14T13:10:38.482538-07:00"} {"id":"bd-74","title":"Another test with multiple deps","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.300284-07:00","closed_at":"2025-10-16T10:07:34.028111-07:00"} {"id":"bd-75","title":"Add migration scripts for GitHub Issues","description":"Create scripts to import from GitHub Issues API or exported JSON","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.300428-07:00","closed_at":"2025-10-17T23:51:47.390748-07:00"} -{"id":"bd-76","title":"Test hash-based import","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.300565-07:00","closed_at":"2025-10-14T13:39:56.958248-07:00"} -{"id":"bd-77","title":"Test issue","description":"Testing prefix","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.300714-07:00","closed_at":"2025-10-14T13:39:55.828804-07:00"} -{"id":"bd-78","title":"Test label dirty tracking","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.300863-07:00","closed_at":"2025-10-14T14:37:52.155733-07:00"} -{"id":"bd-79","title":"Test incremental export","description":"Testing bd-80 implementation","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.301002-07:00","closed_at":"2025-10-16T10:07:22.50945-07:00"} {"id":"bd-8","title":"Refactor parseMarkdownFile to reduce cyclomatic complexity","description":"The parseMarkdownFile function in cmd/bd/markdown.go has a cyclomatic complexity of 38, which exceeds the recommended threshold of 30. This makes the function harder to understand, test, and maintain.","design":"Split the function into smaller, focused units:\n\n1. parseMarkdownFile(filepath) - Main entry point, handles file I/O\n2. parseMarkdownContent(scanner) - Core parsing logic\n3. processIssueSection(issue, section, content) - Handle section finalization (current switch statement)\n4. parseLabels(content) []string - Extract labels from content\n5. parseDependencies(content) []string - Extract dependencies from content\n6. parsePriority(content) int - Parse and validate priority\n\nBenefits:\n- Each function has a single responsibility\n- Easier to test individual components\n- Lower cognitive load when reading code\n- Better encapsulation of parsing logic","acceptance_criteria":"- parseMarkdownFile complexity \u003c 15\n- New helper functions each have complexity \u003c 10\n- All existing tests still pass\n- No change in functionality or behavior\n- Code coverage maintained or improved","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.301148-07:00","closed_at":"2025-10-14T14:37:17.463352-07:00"} {"id":"bd-80","title":"Investigate auto-export debounce not triggering","description":"Auto-export to JSONL did not trigger automatically after creating bd-30 and bd-29. Had to manually run 'bd export' to sync.\n\n**Expected behavior:** Auto-export should trigger ~5 seconds after CRUD operations (per CLAUDE.md documentation).\n\n**Actual behavior:** Issues bd-30 and bd-29 were created but JSONL was not updated until manual 'bd export' was run.\n\n**Investigation needed:**\n1. Check if auto-flush goroutine is running\n2. Verify debounce timer is being triggered on CreateIssue()\n3. Check for errors/panics in background export\n4. Verify auto-flush is enabled by default\n5. Check if there's a race condition with shutdown\n\n**Impact:** HIGH - Data loss risk if users create issues and don't realize they haven't synced to Git.\n\n**Testing:**\n```bash\n# Create issue and wait 10 seconds\nbd create \"Test\" -p 4\nsleep 10\ngrep \"Test\" .beads/issues.jsonl # Should find it\n```\n\n**Workaround:** Manually run 'bd export' after CRUD operations.\n\n**Context:** Discovered during GH issue #2 RFC evaluation while creating bd-30 and bd-29.","status":"in_progress","priority":1,"issue_type":"bug","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.301317-07:00"} -{"id":"bd-81","title":"Test export cancels timer","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.301486-07:00","closed_at":"2025-10-14T14:37:52.155473-07:00"} -{"id":"bd-82","title":"Test flush tracking","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.301637-07:00","closed_at":"2025-10-16T10:07:22.502637-07:00"} -{"id":"bd-83","title":"Regular auto-ID issue","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.301788-07:00","closed_at":"2025-10-16T10:07:22.508912-07:00"} -{"id":"bd-84","title":"Test auto-sync feature","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.301943-07:00","closed_at":"2025-10-14T14:37:52.155117-07:00"} {"id":"bd-85","title":"Add test coverage for auto-flush feature","description":"Add comprehensive tests for auto-flush functionality:\\n- Test that markDirtyAndScheduleFlush() is called after CRUD operations\\n- Test debounce timing (rapid operations result in single flush)\\n- Test --no-auto-flush flag disables feature\\n- Test flush on program exit\\n- Test concurrent operations don't cause races\\n- Test error scenarios (disk full, permission denied, etc.)\\n- Test import command triggers auto-flush\\n\\nCurrent implementation has no test coverage for the auto-flush feature. Located in cmd/bd/main_test.go (to be created).","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.302092-07:00","closed_at":"2025-10-16T10:07:22.508336-07:00"} {"id":"bd-86","title":"Add visibility for auto-flush failures","description":"flushToJSONL() writes warnings to stderr when flush fails, but calling code has no way to know if flush succeeded or failed. This means a command could return success even though JSONL is now out of sync. Consider maintaining a 'last flush status' variable or counter for failed flushes, and warn user after multiple consecutive failures (e.g., 3+). Located in cmd/bd/main.go:227-307.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.302248-07:00","closed_at":"2025-10-16T10:07:22.497491-07:00"} {"id":"bd-87","title":"Handle missing JSONL directory in findJSONLPath","description":"findJSONLPath() assumes the database directory exists. If someone runs bd init to create a new database but the .beads directory doesn't exist yet, the glob operations might fail silently. Add os.MkdirAll(dbDir, 0755) to ensure directory exists before globbing. Located in cmd/bd/main.go:188-201.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.302398-07:00","closed_at":"2025-10-14T02:51:52.199959-07:00"} @@ -155,7 +135,6 @@ {"id":"bd-90","title":"Add --strict flag for dependency import failures","description":"Currently dependency import errors are warnings (logged to stderr, execution continues). Missing targets or cycles may indicate JSONL corruption. Add --strict flag to fail on any dependency errors for data integrity validation. Location: cmd/bd/import.go:159-164","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.303007-07:00","closed_at":"2025-10-16T10:07:34.035752-07:00"} {"id":"bd-91","title":"Optimize reference updates to avoid loading all issues into memory","description":"In updateReferences(), we call SearchIssues with no filter to get ALL issues for updating references. For large databases (10k+ issues), this loads everything into memory. Options: 1) Use batched processing with LIMIT/OFFSET, 2) Use SQL UPDATE with REPLACE() directly, 3) Stream results instead of loading all at once. Located in collision.go:266","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.303158-07:00","closed_at":"2025-10-17T23:26:43.830137-07:00"} {"id":"bd-92","title":"Cache compiled regexes in replaceIDReferences for performance","description":"replaceIDReferences() compiles the same regex patterns on every call. With 100 issues and 10 ID mappings, that's 1000 regex compilations. Pre-compile regexes once and reuse. Can use a struct with compiled regex, placeholder, and newID. Located in collision.go:329. Estimated performance improvement: 10-100x for large batches.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.303304-07:00","closed_at":"2025-10-16T10:07:22.469891-07:00"} -{"id":"bd-93","title":"test_from_22561","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.30348-07:00","closed_at":"2025-10-16T20:31:20.075645-07:00"} {"id":"bd-94","title":"Add cross-type cycle detection warnings to dependency operations","description":"When adding a dependency with 'bd dep add', run DetectCycles() afterwards and warn users if any cycles exist (across all dependency types, not just 'blocks'). This provides visibility into circular dependencies without blocking the operation.","design":"Implementation approach:\n1. After successfully adding a dependency in AddDependency, call DetectCycles()\n2. If cycles are found, print a warning to stderr showing:\n - The cycle path(s) detected\n - Which dependency types are involved\n - A note that this may cause confusion in dependency visualization\n3. Do NOT fail the operation - this is informational only\n4. Consider adding a --quiet flag to suppress warnings if needed\n\nThe warning should be clear and actionable, e.g.:\nWARNING: Circular dependency detected:\n vc-5 (blocks) → vc-13 (parent-child) → vc-5\nThis may cause confusion in dependency visualization.","acceptance_criteria":"- After 'bd dep add' creates a cross-type cycle, a warning is printed to stderr\n- Warning includes the full cycle path with dependency types\n- Operation still succeeds (warning only, not an error)\n- No warning is printed when no cycles exist\n- Warning message is clear and actionable","notes":"Current behavior: bd PREVENTS cycles (errors out). This issue wants to ALLOW cycles but WARN. \n\nDecision: Current behavior is better. Cycles break the ready work algorithm and dep tree visualization. Prevention is safer than warnings users might ignore.\n\nCode at dep.go:70-92 has cycle detection but it's unreachable - AddDependency errors before that code runs.\n\nRecommend closing as won't-do or changing requirement to match current behavior.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-19T19:04:29.303627-07:00","closed_at":"2025-10-17T23:08:00.079059-07:00"} {"id":"bd-95","title":"Fix renumbering temp ID collision bug","description":"bd renumber --force fails with UNIQUE constraint error when trying to assign temp IDs:\n\nError: failed to rename bd-37 to temp ID: failed to update issue ID: constraint failed: UNIQUE constraint failed: issues.id (1555)\n\nThe temp ID generation logic in renumber.go doesn't guarantee unique IDs. Need to:\n1. Use a temp ID strategy that can't collide (e.g., prefix with 'temp-', use UUIDs, or use high numbers like 999999+)\n2. Verify temp IDs don't exist before using them\n3. Add test case for renumbering with various ID gaps\n\nReproduced when renumbering 107 issues with gaps (IDs 1-344 compacting to 1-107).","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-16T21:13:38.519915-07:00","updated_at":"2025-10-19T19:04:29.303798-07:00","closed_at":"2025-10-16T21:19:18.49592-07:00"} {"id":"bd-96","title":"Implement daemon architecture for concurrent access","description":"Multiple AI agents running concurrently cause database corruption, git lock contention, and data loss. Implement a daemon-based architecture where bd daemon owns SQLite (single writer) and all bd commands become RPC clients when daemon is running. Batches git operations to prevent index.lock contention. Maintains backward compatibility with graceful fallback to direct mode. See DAEMON_DESIGN.md for full details.","design":"Architecture: Unix socket RPC with JSON payloads. bd commands auto-detect daemon socket, fall back to direct mode if not present. Daemon serializes all SQLite writes and batches git exports every 5 seconds. Per-repo daemon using .beads/bd.sock location.\n\nImplementation phases:\n1. RPC protocol infrastructure (protocol.go, server.go, client.go)\n2. Client auto-detection and fallback\n3. Daemon SQLite ownership and git batching\n4. Atomic operations and transactions","acceptance_criteria":"- 4 concurrent agents can run without errors\n- No UNIQUE constraint failures on ID generation\n- No git index.lock errors \n- SQLite counter stays in sync with actual issues\n- Graceful fallback when daemon not running\n- All existing tests pass\n- Documentation updated","status":"closed","priority":0,"issue_type":"epic","created_at":"2025-10-16T21:54:48.794119-07:00","updated_at":"2025-10-19T19:04:29.303947-07:00","closed_at":"2025-10-16T23:45:02.505335-07:00"} diff --git a/cmd/bd/main.go b/cmd/bd/main.go index 49a0e60a..3504176e 100644 --- a/cmd/bd/main.go +++ b/cmd/bd/main.go @@ -745,6 +745,15 @@ func outputJSON(v interface{}) { } // findJSONLPath finds the JSONL file path for the current database +// findJSONLPath discovers the JSONL file path for the current database and ensures +// the parent directory exists. Uses beads.FindJSONLPath() for discovery (checking +// BEADS_JSONL env var first, then using .beads/issues.jsonl next to the database). +// +// Creates the .beads directory if it doesn't exist (important for new databases). +// If directory creation fails, returns the path anyway - the subsequent write will +// fail with a clearer error message. +// +// Thread-safe: No shared state access. func findJSONLPath() string { // Use public API for path discovery jsonlPath := beads.FindJSONLPath(dbPath) @@ -985,6 +994,19 @@ func checkVersionMismatch() { } // markDirtyAndScheduleFlush marks the database as dirty and schedules a flush +// markDirtyAndScheduleFlush marks the database as dirty and schedules a debounced +// export to JSONL. Uses a timer that resets on each call - flush occurs 5 seconds +// after the LAST database modification (not the first). +// +// Debouncing behavior: If multiple operations happen within 5 seconds, the timer +// resets each time, and only one flush occurs after the burst of activity completes. +// This prevents excessive writes during rapid issue creation/updates. +// +// Flush-on-exit guarantee: PersistentPostRun cancels the timer and flushes immediately +// before the command exits, ensuring no data is lost even if the timer hasn't fired. +// +// Thread-safe: Protected by flushMutex. Safe to call from multiple goroutines. +// No-op if auto-flush is disabled via --no-auto-flush flag. func markDirtyAndScheduleFlush() { if !autoFlushEnabled { return @@ -1051,6 +1073,27 @@ func clearAutoFlushState() { } // flushToJSONL exports dirty issues to JSONL using incremental updates +// flushToJSONL exports dirty database changes to the JSONL file. Uses incremental +// export by default (only exports modified issues), or full export for ID-changing +// operations (renumber, resolve-collisions). Invoked by the debounce timer or +// immediately on command exit. +// +// Export modes: +// - Incremental (default): Exports only GetDirtyIssues(), merges with existing JSONL +// - Full (after renumber): Exports all issues, rebuilds JSONL from scratch +// +// Error handling: Tracks consecutive failures. After 3+ failures, displays prominent +// warning suggesting manual "bd export" to recover. Failure counter resets on success. +// +// Thread-safety: +// - Protected by flushMutex for isDirty/needsFullExport access +// - Checks storeActive flag (via storeMutex) to prevent use-after-close +// - Safe to call from timer goroutine or main thread +// +// No-op conditions: +// - Store already closed (storeActive=false) +// - Database not dirty (isDirty=false) +// - No dirty issues found (incremental mode only) func flushToJSONL() { // Check if store is still active (not closed) storeMutex.Lock() diff --git a/internal/storage/sqlite/collision.go b/internal/storage/sqlite/collision.go index eaf574ff..7081b41e 100644 --- a/internal/storage/sqlite/collision.go +++ b/internal/storage/sqlite/collision.go @@ -152,12 +152,6 @@ func equalStringPtr(a, b *string) bool { // // Reference score = text mentions + dependency references func ScoreCollisions(ctx context.Context, s *SQLiteStorage, collisions []*CollisionDetail, allIssues []*types.Issue) error { - // Build a map of all issues for quick lookup - issueMap := make(map[string]*types.Issue) - for _, issue := range allIssues { - issueMap[issue.ID] = issue - } - // Get all dependency records for efficient lookup allDeps, err := s.GetAllDependencyRecords(ctx) if err != nil { diff --git a/internal/storage/sqlite/sqlite.go b/internal/storage/sqlite/sqlite.go index 577b4ed6..710af77b 100644 --- a/internal/storage/sqlite/sqlite.go +++ b/internal/storage/sqlite/sqlite.go @@ -1149,18 +1149,25 @@ func (s *SQLiteStorage) UpdateIssue(ctx context.Context, id string, updates map[ // UpdateIssueID updates an issue ID and all its text fields in a single transaction func (s *SQLiteStorage) UpdateIssueID(ctx context.Context, oldID, newID string, issue *types.Issue, actor string) error { - tx, err := s.db.BeginTx(ctx, nil) + // Get exclusive connection to ensure PRAGMA applies + conn, err := s.db.Conn(ctx) + if err != nil { + return fmt.Errorf("failed to get connection: %w", err) + } + defer conn.Close() + + // Disable foreign keys on this specific connection + _, err = conn.ExecContext(ctx, `PRAGMA foreign_keys = OFF`) + if err != nil { + return fmt.Errorf("failed to disable foreign keys: %w", err) + } + + tx, err := conn.BeginTx(ctx, nil) if err != nil { return fmt.Errorf("failed to begin transaction: %w", err) } defer tx.Rollback() - // Defer foreign key checks until end of transaction - _, err = tx.ExecContext(ctx, `PRAGMA defer_foreign_keys = ON`) - if err != nil { - return fmt.Errorf("failed to defer foreign keys: %w", err) - } - _, err = tx.ExecContext(ctx, ` UPDATE issues SET id = ?, title = ?, description = ?, design = ?, acceptance_criteria = ?, notes = ?, updated_at = ?