Files
beads/.saved-stashes/beads-stash1-log-rotation.patch
2025-11-28 10:50:49 -08:00

855 lines
168 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
diff --git a/.beads/BUG-FOUND-getNextID.md b/.beads/BUG-FOUND-getNextID.md
deleted file mode 100644
index cf392a9..0000000
--- a/.beads/BUG-FOUND-getNextID.md
+++ /dev/null
@@ -1,96 +0,0 @@
-# BUG FOUND: getNextID() uses alphabetical MAX instead of numerical
-
-## Location
-`internal/storage/sqlite/sqlite.go:60-84`, function `getNextID()`
-
-## The Bug
-```go
-err := db.QueryRow("SELECT MAX(id) FROM issues").Scan(&maxID)
-```
-
-This uses alphabetical MAX on the text `id` column, not numerical MAX.
-
-## Impact
-When you have bd-1 through bd-10:
-- Alphabetical sort: bd-1, bd-10, bd-2, bd-3, ... bd-9
-- MAX(id) returns "bd-9" (alphabetically last)
-- nextID is calculated as 10
-- Creating a new issue tries to use bd-10, which already exists
-- Result: UNIQUE constraint failed
-
-## Reproduction
-```bash
-# After creating bd-1 through bd-10
-./bd create "Test issue" -t task -p 1
-# Error: failed to insert issue: UNIQUE constraint failed: issues.id
-```
-
-## The Fix
-
-Option 1: Cast to integer in SQL (BEST)
-```sql
-SELECT MAX(CAST(SUBSTR(id, INSTR(id, '-') + 1) AS INTEGER)) FROM issues WHERE id LIKE 'bd-%'
-```
-
-Option 2: Pad IDs with zeros
-- Change ID format from "bd-10" to "bd-0010"
-- Alphabetical and numerical order match
-- Breaks existing IDs
-
-Option 3: Query all IDs and find max in Go
-- Less efficient but more flexible
-- Works with any ID format
-
-## Recommended Solution
-
-Option 1 with proper prefix handling:
-
-```go
-func getNextID(db *sql.DB) int {
- // Get prefix from config (default "bd")
- var prefix string
- err := db.QueryRow("SELECT value FROM config WHERE key = 'issue_prefix'").Scan(&prefix)
- if err != nil || prefix == "" {
- prefix = "bd"
- }
-
- // Find max numeric ID for this prefix
- var maxNum sql.NullInt64
- query := `
- SELECT MAX(CAST(SUBSTR(id, LENGTH(?) + 2) AS INTEGER))
- FROM issues
- WHERE id LIKE ? || '-%'
- `
- err = db.QueryRow(query, prefix, prefix).Scan(&maxNum)
- if err != nil || !maxNum.Valid {
- return 1
- }
-
- return int(maxNum.Int64) + 1
-}
-```
-
-## Workaround for Now
-
-Manually specify IDs when creating issues:
-```bash
-# This won't work because auto-ID fails:
-./bd create "Title" -t task -p 1
-
-# Workaround - manually calculate next ID:
-./bd list | grep -oE 'bd-[0-9]+' | sed 's/bd-//' | sort -n | tail -1
-# Then add 1 and create with explicit ID in code
-```
-
-Or fix the bug first before continuing!
-
-## Related to bd-9
-
-This bug is EXACTLY the kind of distributed ID collision problem that bd-9 is designed to solve! But we should also fix the root cause.
-
-## Created Issue
-
-Should create: "Fix getNextID() to use numerical MAX instead of alphabetical"
-- Type: bug
-- Priority: 0 (critical - blocks all new issue creation)
-- Blocks: bd-9 (can't create child issues)
diff --git a/.beads/bd-9-child-issues.txt b/.beads/bd-9-child-issues.txt
deleted file mode 100644
index dd9a3e6..0000000
--- a/.beads/bd-9-child-issues.txt
+++ /dev/null
@@ -1,86 +0,0 @@
-# Child Issues for BD-9: Collision Resolution
-
-## Issues to Create
-
-These issues break down bd-9 into implementable chunks. Link them all to bd-9 as parent-child dependencies.
-
-### Issue 1: Extend export to include dependencies
-**Title**: Extend export to include dependencies in JSONL
-**Type**: task
-**Priority**: 1
-**Description**: Modify export.go to include dependencies array in each issue's JSONL output. This makes JSONL self-contained and enables proper collision resolution. Format: {"id":"bd-10","dependencies":[{"depends_on_id":"bd-5","type":"blocks"}]}
-**Command**: `bd create "Extend export to include dependencies in JSONL" -t task -p 1 -d "Modify export.go to include dependencies array in each issue's JSONL output. This makes JSONL self-contained and enables proper collision resolution. Format: {\"id\":\"bd-10\",\"dependencies\":[{\"depends_on_id\":\"bd-5\",\"type\":\"blocks\"}]}"`
-
-### Issue 2: Implement collision detection
-**Title**: Implement collision detection in import
-**Type**: task
-**Priority**: 1
-**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.
-**Command**: `bd create "Implement collision detection in import" -t task -p 1 -d "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."`
-
-### Issue 3: Implement reference scoring
-**Title**: Implement reference scoring algorithm
-**Type**: task
-**Priority**: 1
-**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.
-**Command**: `bd create "Implement reference scoring algorithm" -t task -p 1 -d "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."`
-
-### Issue 4: Implement ID remapping
-**Title**: Implement ID remapping with reference updates
-**Type**: task
-**Priority**: 1
-**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.
-**Command**: `bd create "Implement ID remapping with reference updates" -t task -p 1 -d "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."`
-
-### Issue 5: Add CLI flags
-**Title**: Add --resolve-collisions flag and user reporting
-**Type**: task
-**Priority**: 1
-**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).
-**Command**: `bd create "Add --resolve-collisions flag and user reporting" -t task -p 1 -d "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)."`
-
-### Issue 6: Write tests
-**Title**: Write comprehensive collision resolution tests
-**Type**: task
-**Priority**: 1
-**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.
-**Command**: `bd create "Write comprehensive collision resolution tests" -t task -p 1 -d "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."`
-
-### Issue 7: Update docs
-**Title**: Update documentation for collision resolution
-**Type**: task
-**Priority**: 1
-**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.
-**Command**: `bd create "Update documentation for collision resolution" -t task -p 1 -d "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."`
-
-## Additional Feature Issue
-
-### Issue: Add design field support to update command
-**Title**: Add design/notes/acceptance_criteria fields to update command
-**Type**: feature
-**Priority**: 2
-**Description**: Currently bd update only supports status, priority, title, assignee. Add support for --design, --notes, --acceptance-criteria flags. This makes it easier to add detailed designs to issues after creation.
-**Command**: `bd create "Add design/notes/acceptance_criteria fields to update command" -t feature -p 2 -d "Currently bd update only supports status, priority, title, assignee. Add support for --design, --notes, --acceptance-criteria flags. This makes it easier to add detailed designs to issues after creation."`
-
-## Dependency Linking
-
-After creating all child issues, link them to bd-9:
-```bash
-# Assuming the issues are bd-10 through bd-16 (or whatever IDs were assigned)
-bd dep add <child-id> bd-9 --type parent-child
-```
-
-Example:
-```bash
-bd dep add bd-10 bd-9 --type parent-child
-bd dep add bd-11 bd-9 --type parent-child
-bd dep add bd-12 bd-9 --type parent-child
-# etc.
-```
-
-## Current State
-
-- bd-10 was created successfully ("Extend export to include dependencies")
-- bd-11+ attempts failed with UNIQUE constraint errors
-- This suggests those IDs already exist in the DB but may not be in the JSONL file
-- Need to investigate DB/JSONL sync issue before creating more issues
diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl
index 54f4c64..d0efa81 100644
--- a/.beads/issues.jsonl
+++ b/.beads/issues.jsonl
@@ -1,18 +1,18 @@
-{"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-18T09:57:27.538218-07:00","closed_at":"2025-10-16T21:03:25.526789-07:00"}
+{"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-18T16:47:05.346306-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-18T09:57:27.564776-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-18T09:57:28.112352-07:00","closed_at":"2025-10-16T23:40:29.95134-07:00","dependencies":[{"issue_id":"bd-100","depends_on_id":"bd-96","type":"parent-child","created_at":"2025-10-16T22:47:49.787472-07:00","created_by":"stevey"}]}
+{"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-18T09:57:28.112352-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-18T09:57:27.947326-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-18T09:57:27.956806-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-18T09:57:28.113292-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-18T09:57:27.957985-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-18T09:57:27.958823-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-18T09:57:27.960412-07:00","closed_at":"2025-10-17T12:07:38.659749-07:00","dependencies":[{"issue_id":"bd-106","depends_on_id":"bd-105","type":"parent-child","created_at":"2025-10-17T12:07:29.09999-07:00","created_by":"stevey"}]}
-{"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-18T09:57:27.960949-07:00","closed_at":"2025-10-17T12:07:45.496304-07:00","dependencies":[{"issue_id":"bd-107","depends_on_id":"bd-105","type":"parent-child","created_at":"2025-10-17T12:07:29.133888-07:00","created_by":"stevey"}]}
-{"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-18T09:57:27.961513-07:00","closed_at":"2025-10-17T12:07:45.624974-07:00","dependencies":[{"issue_id":"bd-108","depends_on_id":"bd-105","type":"parent-child","created_at":"2025-10-17T12:07:29.169846-07:00","created_by":"stevey"}]}
+{"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-18T09:57:27.960412-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-18T09:57:27.960949-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-18T09:57:27.961513-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-18T09:57:27.962851-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-18T09:57:27.570477-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-18T09:57:27.963392-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-18T09:57:27.964133-07:00","closed_at":"2025-10-17T12:10:00.087913-07:00","dependencies":[{"issue_id":"bd-111","depends_on_id":"bd-110","type":"parent-child","created_at":"2025-10-17T12:09:59.965897-07:00","created_by":"stevey"}]}
+{"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-18T09:57:27.964133-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-18T09:57:27.964942-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-18T09:57:28.114142-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-18T09:57:28.114683-07:00","closed_at":"2025-10-17T16:37:34.504057-07:00"}
@@ -22,12 +22,12 @@
{"id":"bd-118","title":"Issue in repo1","description":"This should go to repo1 database","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-17T16:35:02.535742-07:00","updated_at":"2025-10-18T09:57:27.968887-07:00","closed_at":"2025-10-17T18:13:19.394276-07:00"}
{"id":"bd-119","title":"Fix nil pointer crash in bd export command","description":"When running `bd export -o .beads/issues.jsonl`, the command crashes with a nil pointer dereference.\n\n## Error\n```\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x108 pc=0x1034456fc]\n\ngoroutine 1 [running]:\nmain.init.func14(0x103c24380, {0x1034a9695?, 0x4?, 0x1034a95c9?})\n /Users/stevey/src/vc/adar/beads/cmd/bd/export.go:74 +0x15c\n```\n\n## Context\n- This happened after closing bd-104, bd-113, bd-114\n- Auto-export from daemon still works fine\n- Only the manual `bd export` command crashes\n- Data was already synced via auto-export, so no data loss\n\n## Location\nFile: `cmd/bd/export.go` line 74","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-17T17:34:05.014619-07:00","updated_at":"2025-10-18T09:57:28.115127-07:00","closed_at":"2025-10-17T17:35:41.414218-07:00"}
{"id":"bd-12","title":"Verify auto-export works","description":"","status":"closed","priority":0,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T09:57:27.582926-07:00","closed_at":"2025-10-14T14:16:09.268591-07:00"}
-{"id":"bd-120","title":"Add --global flag to daemon for multi-repo support","description":"Currently daemon creates socket at .beads/bd.sock in each repo. For multi-repo support, add --global flag to create socket in ~/.beads/bd.sock that can serve requests from any repository.\n\nImplementation:\n- Add --global flag to daemon command\n- When --global is set, use ~/.beads/bd.sock instead of ./.beads/bd.sock \n- Don't require being in a git repo when --global is used\n- Update daemon discovery logic to check ~/.beads/bd.sock as fallback\n- Document that global daemon can serve multiple repos simultaneously\n\nBenefits:\n- Single daemon serves all repos on the system\n- No need to start daemon per-repo\n- Better resource usage\n- Enables system-wide task tracking\n\nContext: Per-request context routing (bd-114) already implemented - daemon can handle multiple repos. This issue is about making the UX better.\n\nRelated: bd-35 (parent issue for multi-repo support)","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-17T20:43:47.080685-07:00","updated_at":"2025-10-18T09:57:28.115562-07:00","closed_at":"2025-10-17T22:45:42.411986-07:00","dependencies":[{"issue_id":"bd-120","depends_on_id":"bd-35","type":"parent-child","created_at":"2025-10-17T20:44:02.2335-07:00","created_by":"daemon"}]}
-{"id":"bd-121","title":"Document multi-repo workflow with daemon","description":"The daemon already supports multi-repo via per-request context routing (bd-114), but this isn't documented. Users need to know how to use beads across multiple projects.\n\nAdd documentation for:\n1. How daemon serves multiple repos simultaneously\n2. Starting daemon in one repo, using from others\n3. MCP server multi-repo configuration\n4. Example: tracking work across a dozen projects\n5. Comparison to workspace/global instance approaches\n\nDocumentation locations:\n- README.md (Multi-repo section)\n- AGENTS.md (MCP multi-repo config)\n- integrations/beads-mcp/README.md (working_dir parameter)\n\nInclude:\n- Architecture diagram showing one daemon, many repos\n- Example MCP config with BEADS_WORKING_DIR\n- CLI workflow example\n- Reference to test_multi_repo.py as proof of concept\n\nContext: Feature already works (proven by test_multi_repo.py), just needs user-facing docs.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-17T20:43:48.91315-07:00","updated_at":"2025-10-18T09:57:28.116187-07:00","closed_at":"2025-10-17T22:49:32.514372-07:00","dependencies":[{"issue_id":"bd-121","depends_on_id":"bd-35","type":"parent-child","created_at":"2025-10-17T20:44:03.261924-07:00","created_by":"daemon"}]}
-{"id":"bd-122","title":"Add 'bd repos' command for multi-repo aggregation","description":"When using daemon in multi-repo mode, users need commands to view/manage work across all active repositories.\n\nAdd 'bd repos' subcommand with:\n\n1. bd repos list\n - Show all repositories daemon has cached\n - Display: path, prefix, issue count, last activity\n - Example output:\n ~/src/project1 [p1-] 45 issues (active)\n ~/src/project2 [p2-] 12 issues (2m ago)\n\n2. bd repos ready --all \n - Aggregate ready work across all repos\n - Group by repo or show combined list\n - Support priority/assignee filters\n\n3. bd repos stats\n - Combined statistics across all repos\n - Total issues, breakdown by status/priority\n - Per-repo breakdown\n\n4. bd repos clear-cache\n - Close all cached storage connections\n - Useful for freeing resources\n\nImplementation notes:\n- Requires daemon to track active storage instances\n- May need RPC protocol additions for multi-repo queries\n- Should gracefully handle repos that no longer exist\n\nDepends on: Global daemon flag (makes this more useful)\n\nContext: This provides the UX layer on top of existing multi-repo support. The daemon can already serve multiple repos - this makes it easy to work with them.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-17T20:43:49.816998-07:00","updated_at":"2025-10-18T09:57:27.972631-07:00","closed_at":"2025-10-18T00:04:42.197247-07:00","dependencies":[{"issue_id":"bd-122","depends_on_id":"bd-35","type":"parent-child","created_at":"2025-10-17T20:44:04.407138-07:00","created_by":"daemon"},{"issue_id":"bd-122","depends_on_id":"bd-120","type":"blocks","created_at":"2025-10-17T20:44:13.681626-07:00","created_by":"daemon"}]}
-{"id":"bd-123","title":"Add daemon auto-start on first use","description":"Currently users must manually start daemon with 'bd daemon'. For better UX, auto-start daemon when first bd command is run.\n\nImplementation:\n\n1. In PersistentPreRun, check if daemon is running\n2. If not, check if auto-start is enabled (default: true)\n3. Start daemon with appropriate flags (--global if configured)\n4. Wait for socket to be ready (with timeout)\n5. Retry connection to newly-started daemon\n6. Silently fail back to direct mode if daemon won't start\n\nConfiguration:\n- BEADS_AUTO_START_DAEMON env var (default: true)\n- --no-auto-daemon flag to disable\n- Config file option: auto_start_daemon = true\n\nSafety considerations:\n- Don't auto-start if daemon failed recently (exponential backoff)\n- Log auto-start to daemon.log\n- Clear error messages if auto-start fails\n- Never auto-start if --no-daemon flag is set\n\nBenefits:\n- Zero-configuration experience\n- Daemon benefits (speed, multi-repo) automatic\n- Still supports direct mode as fallback\n\nDepends on: Global daemon flag would make this more useful","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-17T20:43:50.961453-07:00","updated_at":"2025-10-18T09:57:27.973611-07:00","closed_at":"2025-10-17T23:33:57.173903-07:00","dependencies":[{"issue_id":"bd-123","depends_on_id":"bd-35","type":"parent-child","created_at":"2025-10-17T20:44:05.502634-07:00","created_by":"daemon"},{"issue_id":"bd-123","depends_on_id":"bd-120","type":"blocks","created_at":"2025-10-17T20:44:14.987308-07:00","created_by":"daemon"}]}
-{"id":"bd-124","title":"Add workspace config file for multi-repo management (optional enhancement)","description":"For users who want explicit control over multi-repo setup without daemon, add optional workspace config file.\n\nConfig file: ~/.beads/workspaces.toml\n\nExample:\n[workspaces]\ncurrent = \"global\"\n\n[workspace.global]\ndb = \"~/.beads/global.db\"\ndescription = \"System-wide tasks\"\n\n[workspace.project1] \ndb = \"~/src/project1/.beads/db.sqlite\"\ndescription = \"Main product\"\n\n[workspace.project2]\ndb = \"~/src/project2/.beads/db.sqlite\"\ndescription = \"Internal tools\"\n\nCommands:\nbd workspace list # Show all workspaces\nbd workspace add NAME PATH # Add workspace\nbd workspace remove NAME # Remove workspace \nbd workspace use NAME # Switch active workspace\nbd workspace current # Show current workspace\nbd --workspace NAME \u003ccommand\u003e # Override for single command\n\nImplementation:\n- Load config in PersistentPreRun\n- Override dbPath based on current workspace\n- Store workspace state in config file\n- Support both workspace config AND auto-discovery\n- Workspace config takes precedence over auto-discovery\n\nPriority rationale:\n- Priority 3 (low) because daemon approach already solves this\n- Only implement if users request explicit workspace management\n- Adds complexity vs daemon's automatic discovery\n\nAlternative: Users can use BEADS_DB env var for manual workspace switching today.","status":"open","priority":3,"issue_type":"feature","created_at":"2025-10-17T20:43:52.348572-07:00","updated_at":"2025-10-18T09:57:27.975868-07:00","dependencies":[{"issue_id":"bd-124","depends_on_id":"bd-35","type":"parent-child","created_at":"2025-10-17T20:44:06.411344-07:00","created_by":"daemon"}]}
-{"id":"bd-125","title":"Add cross-repo issue references (future enhancement)","description":"Support referencing issues across different beads repositories. Useful for tracking dependencies between separate projects.\n\nProposed syntax:\n- Local reference: bd-122 (current behavior)\n- Cross-repo by path: ~/src/other-project#bd-456\n- Cross-repo by workspace name: @project2:bd-789\n\nUse cases:\n1. Frontend project depends on backend API issue\n2. Shared library changes blocking multiple projects\n3. System administrator tracking work across machines\n4. Monorepo with separate beads databases per component\n\nImplementation challenges:\n- Storage layer needs to query external databases\n- Dependency resolution across repos\n- What if external repo not available?\n- How to handle in JSONL export/import?\n- Security: should repos be able to read others?\n\nDesign questions to resolve first:\n1. Read-only references vs full cross-repo dependencies?\n2. How to handle repo renames/moves?\n3. Absolute paths vs workspace names vs git remotes?\n4. Should bd-35 auto-discover related repos?\n\nRecommendation: \n- Gather user feedback first\n- Start with read-only references\n- Implement as plugin/extension?\n\nContext: This is mentioned in bd-35 as approach #2. Much more complex than daemon multi-repo approach. Only implement if there's strong user demand.\n\nPriority: Backlog (4) - wait for user feedback before designing","status":"open","priority":4,"issue_type":"feature","created_at":"2025-10-17T20:43:54.04594-07:00","updated_at":"2025-10-18T09:57:28.116864-07:00","dependencies":[{"issue_id":"bd-125","depends_on_id":"bd-35","type":"parent-child","created_at":"2025-10-17T20:44:07.576103-07:00","created_by":"daemon"}]}
+{"id":"bd-120","title":"Add --global flag to daemon for multi-repo support","description":"Currently daemon creates socket at .beads/bd.sock in each repo. For multi-repo support, add --global flag to create socket in ~/.beads/bd.sock that can serve requests from any repository.\n\nImplementation:\n- Add --global flag to daemon command\n- When --global is set, use ~/.beads/bd.sock instead of ./.beads/bd.sock \n- Don't require being in a git repo when --global is used\n- Update daemon discovery logic to check ~/.beads/bd.sock as fallback\n- Document that global daemon can serve multiple repos simultaneously\n\nBenefits:\n- Single daemon serves all repos on the system\n- No need to start daemon per-repo\n- Better resource usage\n- Enables system-wide task tracking\n\nContext: Per-request context routing (bd-114) already implemented - daemon can handle multiple repos. This issue is about making the UX better.\n\nRelated: bd-35 (parent issue for multi-repo support)","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-17T20:43:47.080685-07:00","updated_at":"2025-10-18T09:57:28.115562-07:00","closed_at":"2025-10-17T22:45:42.411986-07:00"}
+{"id":"bd-121","title":"Document multi-repo workflow with daemon","description":"The daemon already supports multi-repo via per-request context routing (bd-114), but this isn't documented. Users need to know how to use beads across multiple projects.\n\nAdd documentation for:\n1. How daemon serves multiple repos simultaneously\n2. Starting daemon in one repo, using from others\n3. MCP server multi-repo configuration\n4. Example: tracking work across a dozen projects\n5. Comparison to workspace/global instance approaches\n\nDocumentation locations:\n- README.md (Multi-repo section)\n- AGENTS.md (MCP multi-repo config)\n- integrations/beads-mcp/README.md (working_dir parameter)\n\nInclude:\n- Architecture diagram showing one daemon, many repos\n- Example MCP config with BEADS_WORKING_DIR\n- CLI workflow example\n- Reference to test_multi_repo.py as proof of concept\n\nContext: Feature already works (proven by test_multi_repo.py), just needs user-facing docs.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-17T20:43:48.91315-07:00","updated_at":"2025-10-18T09:57:28.116187-07:00","closed_at":"2025-10-17T22:49:32.514372-07:00"}
+{"id":"bd-122","title":"Add 'bd repos' command for multi-repo aggregation","description":"When using daemon in multi-repo mode, users need commands to view/manage work across all active repositories.\n\nAdd 'bd repos' subcommand with:\n\n1. bd repos list\n - Show all repositories daemon has cached\n - Display: path, prefix, issue count, last activity\n - Example output:\n ~/src/project1 [p1-] 45 issues (active)\n ~/src/project2 [p2-] 12 issues (2m ago)\n\n2. bd repos ready --all \n - Aggregate ready work across all repos\n - Group by repo or show combined list\n - Support priority/assignee filters\n\n3. bd repos stats\n - Combined statistics across all repos\n - Total issues, breakdown by status/priority\n - Per-repo breakdown\n\n4. bd repos clear-cache\n - Close all cached storage connections\n - Useful for freeing resources\n\nImplementation notes:\n- Requires daemon to track active storage instances\n- May need RPC protocol additions for multi-repo queries\n- Should gracefully handle repos that no longer exist\n\nDepends on: Global daemon flag (makes this more useful)\n\nContext: This provides the UX layer on top of existing multi-repo support. The daemon can already serve multiple repos - this makes it easy to work with them.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-17T20:43:49.816998-07:00","updated_at":"2025-10-18T09:57:27.972631-07:00","closed_at":"2025-10-18T00:04:42.197247-07:00"}
+{"id":"bd-123","title":"Add daemon auto-start on first use","description":"Currently users must manually start daemon with 'bd daemon'. For better UX, auto-start daemon when first bd command is run.\n\nImplementation:\n\n1. In PersistentPreRun, check if daemon is running\n2. If not, check if auto-start is enabled (default: true)\n3. Start daemon with appropriate flags (--global if configured)\n4. Wait for socket to be ready (with timeout)\n5. Retry connection to newly-started daemon\n6. Silently fail back to direct mode if daemon won't start\n\nConfiguration:\n- BEADS_AUTO_START_DAEMON env var (default: true)\n- --no-auto-daemon flag to disable\n- Config file option: auto_start_daemon = true\n\nSafety considerations:\n- Don't auto-start if daemon failed recently (exponential backoff)\n- Log auto-start to daemon.log\n- Clear error messages if auto-start fails\n- Never auto-start if --no-daemon flag is set\n\nBenefits:\n- Zero-configuration experience\n- Daemon benefits (speed, multi-repo) automatic\n- Still supports direct mode as fallback\n\nDepends on: Global daemon flag would make this more useful","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-17T20:43:50.961453-07:00","updated_at":"2025-10-18T09:57:27.973611-07:00","closed_at":"2025-10-17T23:33:57.173903-07:00"}
+{"id":"bd-124","title":"Add workspace config file for multi-repo management (optional enhancement)","description":"For users who want explicit control over multi-repo setup without daemon, add optional workspace config file.\n\nConfig file: ~/.beads/workspaces.toml\n\nExample:\n[workspaces]\ncurrent = \"global\"\n\n[workspace.global]\ndb = \"~/.beads/global.db\"\ndescription = \"System-wide tasks\"\n\n[workspace.project1] \ndb = \"~/src/project1/.beads/db.sqlite\"\ndescription = \"Main product\"\n\n[workspace.project2]\ndb = \"~/src/project2/.beads/db.sqlite\"\ndescription = \"Internal tools\"\n\nCommands:\nbd workspace list # Show all workspaces\nbd workspace add NAME PATH # Add workspace\nbd workspace remove NAME # Remove workspace \nbd workspace use NAME # Switch active workspace\nbd workspace current # Show current workspace\nbd --workspace NAME \u003ccommand\u003e # Override for single command\n\nImplementation:\n- Load config in PersistentPreRun\n- Override dbPath based on current workspace\n- Store workspace state in config file\n- Support both workspace config AND auto-discovery\n- Workspace config takes precedence over auto-discovery\n\nPriority rationale:\n- Priority 3 (low) because daemon approach already solves this\n- Only implement if users request explicit workspace management\n- Adds complexity vs daemon's automatic discovery\n\nAlternative: Users can use BEADS_DB env var for manual workspace switching today.","status":"open","priority":3,"issue_type":"feature","created_at":"2025-10-17T20:43:52.348572-07:00","updated_at":"2025-10-18T09:57:27.975868-07:00"}
+{"id":"bd-125","title":"Add cross-repo issue references (future enhancement)","description":"Support referencing issues across different beads repositories. Useful for tracking dependencies between separate projects.\n\nProposed syntax:\n- Local reference: bd-122 (current behavior)\n- Cross-repo by path: ~/src/other-project#bd-456\n- Cross-repo by workspace name: @project2:bd-789\n\nUse cases:\n1. Frontend project depends on backend API issue\n2. Shared library changes blocking multiple projects\n3. System administrator tracking work across machines\n4. Monorepo with separate beads databases per component\n\nImplementation challenges:\n- Storage layer needs to query external databases\n- Dependency resolution across repos\n- What if external repo not available?\n- How to handle in JSONL export/import?\n- Security: should repos be able to read others?\n\nDesign questions to resolve first:\n1. Read-only references vs full cross-repo dependencies?\n2. How to handle repo renames/moves?\n3. Absolute paths vs workspace names vs git remotes?\n4. Should bd-35 auto-discover related repos?\n\nRecommendation: \n- Gather user feedback first\n- Start with read-only references\n- Implement as plugin/extension?\n\nContext: This is mentioned in bd-35 as approach #2. Much more complex than daemon multi-repo approach. Only implement if there's strong user demand.\n\nPriority: Backlog (4) - wait for user feedback before designing","status":"open","priority":4,"issue_type":"feature","created_at":"2025-10-17T20:43:54.04594-07:00","updated_at":"2025-10-18T09:57:28.116864-07:00"}
{"id":"bd-126","title":"Add batch deletion command for issues","description":"Support deleting multiple issues efficiently instead of one at a time.\n\n**Use Cases:**\n- Cleaning up duplicate/spam issues (e.g., bd-99 to bd-115 watchdog spam)\n- Removing test-only issues after feature removal\n- Bulk cleanup of obsolete/spurious bugs\n- Renumbering prep: delete ranges before compaction\n\n**Proposed Syntax Options:**\n\n**Option 1: Multiple IDs as arguments**\n```bash\nbd delete vc-1 vc-2 vc-3 --force\nbd delete vc-{1..20} --force # Shell expansion\n```\n\n**Option 2: Read from file (RECOMMENDED)**\n```bash\nbd delete --from-file deletions.txt --force --dry-run # Preview\nbd delete --from-file deletions.txt --force # Execute\n# File format: one issue ID per line\n```\n\n**Option 3: Query-based deletion**\n```bash\nbd delete --where \"priority=3 AND type=chore\" --force\nbd delete --label test-only --force\nbd delete --prefix bd- --status open --force\n```\n\n**Must-Have Features:**\n\n1. **Dry-run mode**: `--dry-run` to preview what would be deleted\n - Show issue IDs, titles, dependency counts\n - Warn about issues with dependents\n\n2. **Dependency handling**:\n - `--cascade`: Delete dependents recursively\n - `--force`: Delete even if dependents exist (orphans them)\n - Default: Fail if any issue has dependents\n\n3. **Summary output**:\n ```\n Deleted 162 issues\n Removed 347 dependencies\n Removed 89 labels\n Orphaned 5 issues (use --cascade to delete)\n ```\n\n4. **Transaction safety**: All-or-nothing for file/query input\n - Either all deletions succeed or none do\n - Rollback on error\n\n**Nice-to-Have Features:**\n\n1. **Interactive confirmation** for large batches (\u003e10 issues)\n ```\n About to delete 162 issues. Continue? [y/N]\n (Use --force to skip confirmation)\n ```\n\n2. **Progress indicator** for large batches (\u003e50 deletions)\n ```\n Deleting issues... [####------] 42/162 (26%)\n ```\n\n3. **Undo support**:\n ```bash\n bd undelete --last-batch # Restore from snapshots\n bd undelete bd-99 # Restore single issue\n ```\n\n**Implementation Notes:**\n\n- Leverage existing `DeleteIssue()` in storage layer\n- Wrap in transaction for atomicity\n- Consider adding `DeleteIssues(ctx, []string)` for efficiency\n- May need to query dependents before deletion\n- File format should support comments (#) and blank lines\n- JSON output mode should list all deleted IDs\n\n**Example Workflow:**\n```bash\n# Identify issues to delete\nbd list --label test-only --json | jq -r '.[].id' \u003e /tmp/delete.txt\n\n# Preview deletion\nbd delete --from-file /tmp/delete.txt --dry-run\n\n# Execute with cascade\nbd delete --from-file /tmp/delete.txt --cascade --force\n\n# Verify\nbd stats\n```\n\n**Security Considerations:**\n- Require explicit `--force` flag to prevent accidents\n- Warn when deleting issues with dependencies\n- Log deletions to audit trail\n- Consider requiring confirmation for \u003e100 deletions even with --force\n\n**Requested by:** Another agent during cleanup of bd-99 to bd-115 watchdog spam","notes":"Fixed critical issues found in code review:\n1. Dry-run mode now properly uses dryRun parameter instead of deleting data\n2. Text references are pre-collected before deletion so they update correctly\n3. Added orphan deduplication to prevent duplicate IDs\n4. Added rows.Err() checks in all row iteration loops\n5. Updated defer to ignore rollback error per Go best practices","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-17T20:49:30.921943-07:00","updated_at":"2025-10-18T09:57:28.117657-07:00","closed_at":"2025-10-17T21:03:29.165515-07:00"}
{"id":"bd-127","title":"bd list shows 0 issues despite database containing 115 issues","description":"When running 'bd list --status all' it shows 'Found 0 issues' even though 'bd stats' shows 115 total issues and 'sqlite3 .beads/vc.db \"SELECT COUNT(*) FROM issues\"' returns 115.\n\nReproduction:\n1. cd ~/src/vc/vc\n2. bd stats # Shows 115 issues\n3. bd list --status all # Shows 0 issues\n4. sqlite3 .beads/vc.db 'SELECT COUNT(*) FROM issues;' # Shows 115\n\nExpected: bd list should show all 115 issues\nActual: Shows 'Found 0 issues:'\n\nThis occurs with both /opt/homebrew/bin/bd (v0.9.9) and ~/src/vc/adar/beads/bd (v0.9.10)","design":"Possible causes:\n- Default filter excluding all issues\n- Database query issue in list command\n- Auto-discovery finding wrong database (but stats works?)\n- Recent deletion operation corrupted some index","acceptance_criteria":"bd list --status all shows all issues that bd stats counts","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-17T21:19:08.225181-07:00","updated_at":"2025-10-18T09:57:27.984926-07:00","closed_at":"2025-10-17T21:55:40.788625-07:00"}
{"id":"bd-128","title":"Confusing version mismatch warnings with contradictory messages","description":"The version mismatch warning shows contradictory messages depending on which binary version is used:\n\nWhen using v0.9.10 binary with v0.9.9 database:\n'Your bd binary (v0.9.10) differs from the database version (v0.9.9)'\n'Your binary appears to be OUTDATED.'\n\nWhen using v0.9.9 binary with v0.9.10 database:\n'Your bd binary (v0.9.9) differs from the database version (v0.9.10)'\n'Your binary appears NEWER than the database.'\n\nThe first message is incorrect - v0.9.10 \u003e v0.9.9, so the binary is NEWER, not outdated.\n\nReproduction:\n1. Use ~/src/vc/adar/beads/bd (v0.9.10) with a v0.9.9 database\n2. Observe warning says binary is OUTDATED when it's actually newer\n\nExpected: Correct version comparison\nActual: Inverted comparison logic","design":"Fix version comparison in warning message generation. Should compare semantic versions correctly.","acceptance_criteria":"Warning correctly identifies which component (binary vs database) is newer/older","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-17T21:19:19.540274-07:00","updated_at":"2025-10-18T09:57:27.985547-07:00","closed_at":"2025-10-17T22:14:27.015397-07:00"}
@@ -40,7 +40,7 @@
{"id":"bd-134","title":"Global daemon should warn/reject --auto-commit and --auto-push","description":"When user runs 'bd daemon --global --auto-commit', it's unclear which repo the daemon will commit to (especially after fixing bd-121 where global daemon won't open a DB).\n\nOptions:\n1. Warn and ignore the flags in global mode\n2. Error out with clear message\n\nLine 87-91 already checks autoPush, but should skip check entirely for global mode. Add user-friendly messaging about flag incompatibility.","status":"closed","priority":3,"issue_type":"feature","created_at":"2025-10-17T22:58:02.137987-07:00","updated_at":"2025-10-18T09:57:28.13296-07:00","closed_at":"2025-10-17T23:04:30.223432-07:00"}
{"id":"bd-135","title":"Socket permissions should be 0600 for security","description":"Unix sockets should use 0600 permissions to prevent other users from connecting.\n\nCurrently:\n- Global .beads dir uses 0700 (good) \n- Local .beads dir uses 0700 (good)\n- But socket itself may inherit default perms\n\nVerify rpc.NewServer creates socket with 0600, or set umask/explicit perms.","status":"closed","priority":2,"issue_type":"chore","created_at":"2025-10-17T22:58:02.137989-07:00","updated_at":"2025-10-18T09:57:28.085858-07:00","closed_at":"2025-10-17T23:03:31.545735-07:00"}
{"id":"bd-136","title":"Global daemon still requires database and runs sync loop","description":"The --global flag skips git repo check (line 80) but runDaemonLoop still calls FindDatabasePath (line 500-507) and opens a store (line 512). It also runs the single-repo sync loop (lines 563-620).\n\nOracle correctly identified this violates the spec: 'Don't require being in a git repo when --global is used'.\n\nFix: Global mode should skip DB open and sync loop entirely. It should be a pure RPC router that uses per-request context (bd-114) to route to the correct repo's DB.\n\nImpact: Users can't run 'bd daemon --global' outside a repo, defeating the purpose.","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-17T22:58:02.138008-07:00","updated_at":"2025-10-18T09:57:28.140992-07:00","closed_at":"2025-10-17T23:00:08.734632-07:00"}
-{"id":"bd-137","title":"Test A","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-17T23:06:59.59343-07:00","updated_at":"2025-10-18T09:57:28.091779-07:00","closed_at":"2025-10-17T23:06:59.740704-07:00","dependencies":[{"issue_id":"bd-137","depends_on_id":"bd-138","type":"blocks","created_at":"2025-10-17T23:06:59.668292-07:00","created_by":"daemon"}]}
+{"id":"bd-137","title":"Test A","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-17T23:06:59.59343-07:00","updated_at":"2025-10-18T09:57:28.091779-07:00","closed_at":"2025-10-17T23:06:59.740704-07:00"}
{"id":"bd-138","title":"Test B","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-17T23:06:59.626612-07:00","updated_at":"2025-10-18T09:57:28.095042-07:00","closed_at":"2025-10-17T23:06:59.744519-07:00"}
{"id":"bd-139","title":"bd ready doesn't show epics/tasks ready to close when all children complete","description":"The 'bd ready' command doesn't show epics that have all children complete as ready work. Example: vc-30 (epic) blocks 4 children - 3 are closed, 1 is in_progress. The epic itself should be reviewable/closable but doesn't show in ready work. Similarly, vc-61 (epic, in_progress) depends on vc-48 (closed) but doesn't show as ready. Expected: epics with all dependencies satisfied should show as ready to review/close. Actual: 'bd ready' returns 'no ready work' even though multiple epics are completable.","acceptance_criteria":"bd ready shows epics/tasks that have all dependencies satisfied (even if status is in_progress), allowing user to review and close them","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-18T00:04:41.811991-07:00","updated_at":"2025-10-18T09:57:28.095697-07:00","closed_at":"2025-10-18T00:20:36.188211-07:00"}
{"id":"bd-14","title":"Investigate vector/semantic search for issue discovery","description":"From GH issue #2 RFC discussion: Evaluate if vector/semantic search over issues would provide value for beads.\n\n**Use case:** Find semantically related issues (e.g., 'login broken' finds 'authentication failure', 'session expired').\n\n**Questions to answer:**\n1. What workflows would this enable that we can't do now?\n2. Is dataset size (typically 50-200 issues) large enough to benefit?\n3. Do structured features (deps, tags, types) already provide better relationships?\n4. What's the maintenance cost (embeddings, storage, recomputation)?\n\n**Alternatives to consider:**\n- Improve 'bd list' filtering with regex/boolean queries\n- Add 'bd related \u003cid\u003e' showing deps + mentions + same tags\n- Export to JSON and pipe to external AI tools\n\n**Decision:** Only implement if clear use case emerges. Don't add complexity for theoretical benefits.\n\n**Context:** Part of evaluating Turso RFC ideas (GH #2). Vector search was proposed but unclear if needed for typical beads usage.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T10:09:23.532858-07:00","closed_at":"2025-10-18T10:09:23.532858-07:00"}
@@ -49,23 +49,23 @@
{"id":"bd-142","title":"Add 'bd stale' command to show orphaned claims and dead executors","description":"Need visibility into orphaned claims - issues stuck in_progress with execution_state but executor is dead/stopped. Add command to show: 1) All issues with execution_state where executor status=stopped or last_heartbeat \u003e threshold, 2) Executor instance details (when died, how long claimed), 3) Option to auto-release them. Makes manual recovery easier until auto-cleanup (bd-140) is implemented.","design":"Query: SELECT i.*, ei.status, ei.last_heartbeat FROM issues i JOIN issue_execution_state ies ON i.id = ies.issue_id JOIN executor_instances ei ON ies.executor_instance_id = ei.instance_id WHERE ei.status='stopped' OR ei.last_heartbeat \u003c NOW() - threshold. Add --release flag to auto-release all found issues.","acceptance_criteria":"bd stale shows orphaned claims, bd stale --release cleans them up","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-18T00:25:16.530937-07:00","updated_at":"2025-10-18T09:57:28.141701-07:00","closed_at":"2025-10-18T02:09:12.529064-07:00"}
{"id":"bd-143","title":"Bias ready work towards recent issues before oldest-first","description":"Currently 'bd ready' shows oldest issues first (by created_at). This can bury recently discovered work that might be more relevant. Propose a hybrid approach: show issues from the past 1-2 days first (sorted by priority), then fall back to oldest-first for older issues. This keeps fresh discoveries visible while still surfacing old forgotten work.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-18T09:31:15.036495-07:00","updated_at":"2025-10-18T09:57:28.105887-07:00","closed_at":"2025-10-18T09:35:55.084891-07:00"}
{"id":"bd-144","title":"Fix nil pointer dereference in renumber command","description":"The 'bd renumber' command crashes with a nil pointer dereference at renumber.go:52 because store is nil. The command doesn't properly handle daemon/direct mode initialization like other commands do. Error occurs on both --dry-run and --force modes.","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-18T09:54:31.59912-07:00","updated_at":"2025-10-18T09:57:28.106373-07:00","closed_at":"2025-10-18T09:56:49.88701-07:00"}
-{"id":"bd-145","title":"Add storage cache eviction policy to daemon","description":"Daemon caches DB connections forever in storageCache map (server.go:29). For users with 50+ repos, this causes memory leaks and file descriptor exhaustion.\n\nNeed LRU cache with:\n- Max size limit (default: 50 repos)\n- TTL-based eviction (default: 30min idle)\n- Periodic cleanup goroutine\n\nLocation: internal/rpc/server.go:29-40","design":"Add StorageCacheEntry struct with lastAccess timestamp.\n\nImplement evictStaleStorage() method that runs every 5 minutes to close connections idle \u003e30min.\n\nAdd max cache size enforcement (LRU eviction when full).\n\nMake limits configurable via env vars:\n- BEADS_DAEMON_MAX_CACHE_SIZE (default: 50)\n- BEADS_DAEMON_CACHE_TTL (default: 30m)","acceptance_criteria":"- Cache evicts entries after 30min idle\n- Cache respects max size limit\n- Cleanup goroutine runs periodically\n- Evicted storage connections are properly closed\n- No resource leaks under sustained load\n- Unit tests for eviction logic","status":"closed","priority":0,"issue_type":"feature","created_at":"2025-10-18T13:05:46.174245-07:00","updated_at":"2025-10-18T13:16:56.921023-07:00","closed_at":"2025-10-18T13:16:56.921023-07:00","dependencies":[{"issue_id":"bd-145","depends_on_id":"bd-155","type":"parent-child","created_at":"2025-10-18T13:07:49.077954-07:00","created_by":"daemon"}]}
-{"id":"bd-146","title":"Add daemon health check endpoint and probes","description":"Auto-start only checks socket existence, not daemon responsiveness. Daemon can be running but unresponsive (deadlock, hung DB). Users work in degraded direct mode without knowing why.\n\nNeed health check RPC operation that:\n- Tests DB connectivity (1s timeout)\n- Returns uptime, status, metrics\n- Used by auto-start before connecting\n- Enables monitoring/alerting\n\nLocation: internal/rpc/server.go, cmd/bd/main.go:100-108","design":"Add OpHealth RPC operation to protocol.\n\nhandleHealth() implementation:\n- Quick DB ping with 1s timeout\n- Return status, uptime, version\n- Include basic metrics (connections, cache size)\n\nUpdate TryConnect() to call Health() after socket connection:\n- If health check fails, close connection and return nil\n- Enables transparent failover to direct mode\n\nAdd 'bd daemon --health' CLI command for monitoring.","acceptance_criteria":"- Health check RPC endpoint works\n- Returns structured health status\n- Client uses health check before operations\n- bd daemon --health command exists\n- Unhealthy daemon triggers auto-restart or fallback\n- Health check completes in \u003c2 seconds","status":"closed","priority":0,"issue_type":"feature","created_at":"2025-10-18T13:05:58.647592-07:00","updated_at":"2025-10-18T13:32:15.106003-07:00","closed_at":"2025-10-18T13:32:15.106003-07:00","dependencies":[{"issue_id":"bd-146","depends_on_id":"bd-155","type":"parent-child","created_at":"2025-10-18T13:07:49.093618-07:00","created_by":"daemon"}]}
-{"id":"bd-147","title":"Add stale socket and crash recovery for daemon","description":"When daemon crashes (panic, OOM, signal), socket file remains and blocks new daemon start. Users must manually remove .beads/bd.sock.\n\nProblems:\n- Socket file remains after crash\n- PID file remains (isDaemonRunning false positive)\n- No automatic recovery\n- Users get 'daemon already running' error\n\nLocation: cmd/bd/daemon.go, cmd/bd/main.go:221-311","design":"Improve stale detection in tryAutoStartDaemon():\n\n1. If socket exists, try to connect\n2. If connection fails → stale socket, remove it\n3. Also remove PID file and lock files\n4. Retry daemon start\n\nAdd self-healing to daemon startup:\n- On startup, check for stale PID files\n- If PID in file doesn't exist, remove and continue\n- Use exclusive file lock to prevent races\n\nOptional: Add crash recovery watchdog that restarts daemon on exit.","acceptance_criteria":"- Stale sockets are automatically detected and removed\n- Auto-start recovers from daemon crashes\n- No manual intervention needed for crash recovery\n- PID file management is robust\n- Lock files prevent multiple daemon instances\n- Tests for crash recovery scenarios","notes":"Oracle code review identified race conditions. Improvements made:\n- Moved cleanup AFTER lock acquisition (prevents unlinking live sockets)\n- Added PID liveness check before removing socket\n- Added stale lock detection with retry\n- Tightened directory permissions to 0700\n- Improved socket readiness probing with short timeouts\n- Made removeOldSocket() ignore ENOENT errors\n\nChanges eliminate race where socket could be removed during daemon startup window.","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-18T13:06:10.116917-07:00","updated_at":"2025-10-18T13:56:51.318675-07:00","closed_at":"2025-10-18T13:56:51.318675-07:00","dependencies":[{"issue_id":"bd-147","depends_on_id":"bd-155","type":"parent-child","created_at":"2025-10-18T13:07:49.108099-07:00","created_by":"daemon"}]}
-{"id":"bd-148","title":"Add lifecycle management for beads-mcp processes","description":"MCP server processes accumulate without cleanup. Each tool invocation spawns a new Python process that lingers after Claude disconnects.\n\nObserved: 6+ beads-mcp processes running simultaneously.\n\nProblems:\n- No parent-child relationship tracking\n- No cleanup on MCP client disconnect\n- Processes leak over days of use\n- Could accumulate hundreds of processes\n\nLocation: integrations/beads-mcp/src/beads_mcp/server.py","design":"Add proper cleanup handlers to MCP server:\n\n1. Register atexit handler to close daemon connections\n2. Handle SIGTERM/SIGINT for graceful shutdown\n3. Close daemon client in cleanup()\n4. Remove any temp files\n\nOptional improvements:\n- Track active connections to daemon\n- Implement connection pooling\n- Add process timeout/TTL\n- Log lifecycle events for debugging\n\nExample:\nimport atexit\nimport signal\n\ndef cleanup():\n # Close daemon connections\n # Remove temp files\n pass\n\natexit.register(cleanup)\nsignal.signal(signal.SIGTERM, lambda s, f: cleanup())","acceptance_criteria":"- MCP processes clean up on exit\n- Daemon connections are properly closed\n- No process leaks after repeated use\n- Signal handlers work correctly\n- Cleanup runs on normal and abnormal exit\n- Test with multiple concurrent MCP invocations","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-18T13:06:22.030027-07:00","updated_at":"2025-10-18T14:27:41.87646-07:00","closed_at":"2025-10-18T14:27:41.87646-07:00","dependencies":[{"issue_id":"bd-148","depends_on_id":"bd-155","type":"parent-child","created_at":"2025-10-18T13:07:49.121494-07:00","created_by":"daemon"}]}
-{"id":"bd-149","title":"Add global daemon auto-start support","description":"Auto-start only works for local daemon. Users with multiple repos must manually run 'bd daemon --global'.\n\nProblems:\n- No detection of whether global daemon is preferable\n- No migration path from local → global\n- Multi-repo users don't discover global daemon\n- Manual setup required\n\nLocation: cmd/bd/main.go:221-311","design":"Add heuristics to shouldUseGlobalDaemon():\n\n1. Count .beads repos under home directory\n2. If \u003e3 repos found, prefer global daemon\n3. Check BEADS_PREFER_GLOBAL_DAEMON env var\n4. Check config file preference\n\nUpdate tryAutoStartDaemon() to:\n- Use shouldUseGlobalDaemon() to pick mode\n- Pass --global flag when appropriate\n- Log decision for debugging\n\nAdd migration helper:\n- Detect running local daemon\n- Suggest switching to global if multi-repo detected\n- bd daemon --migrate-to-global command","acceptance_criteria":"- Auto-start uses global daemon when appropriate\n- Multi-repo detection works correctly\n- Users can configure preference\n- Migration path is smooth\n- Both local and global auto-start work\n- Documentation updated","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-18T13:06:33.633238-07:00","updated_at":"2025-10-18T14:41:28.594337-07:00","closed_at":"2025-10-18T14:41:28.594337-07:00","dependencies":[{"issue_id":"bd-149","depends_on_id":"bd-155","type":"parent-child","created_at":"2025-10-18T13:07:49.135552-07:00","created_by":"daemon"}]}
-{"id":"bd-15","title":"Add performance benchmarks document","description":"Document actual performance metrics with hyperfine tests","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T10:09:23.532938-07:00","closed_at":"2025-10-18T10:09:23.532938-07:00","dependencies":[{"issue_id":"bd-15","depends_on_id":"bd-1","type":"parent-child","created_at":"2025-10-16T21:51:08.918095-07:00","created_by":"renumber"}]}
-{"id":"bd-150","title":"Improve daemon fallback visibility and user feedback","description":"When daemon is unavailable, bd silently falls back to direct mode. Users don't know:\n- That daemon exists\n- Why auto-start failed\n- That they're in degraded mode\n- How to fix it\n\nThis creates confusion for multi-repo users who get slower performance without explanation.\n\nLocation: cmd/bd/main.go:98-130","design":"Add visibility at multiple levels:\n\n1. Debug logging (existing BD_DEBUG):\n - Already shows daemon connection attempts\n - Add auto-start success/failure\n\n2. Verbose mode (BD_VERBOSE):\n - Show warning when falling back\n - Suggest 'bd daemon --status' to check\n\n3. Status indicator:\n - Add daemon status to all commands when --json\n - Example: {\"daemon_status\": \"healthy\", \"daemon_type\": \"local\", ...}\n\n4. Explicit status command:\n - bd daemon --status shows detailed info\n - Shows whether daemon is running/healthy/unavailable\n\n5. Helpful error messages:\n - When auto-start fails repeatedly\n - When falling back after health check failure\n - With actionable next steps","acceptance_criteria":"- Users can see daemon status easily\n- Fallback warnings are helpful not noisy\n- JSON output includes daemon status\n- Error messages are actionable\n- Documentation explains status indicators\n- bd daemon --status command works","status":"open","priority":1,"issue_type":"feature","created_at":"2025-10-18T13:06:46.212558-07:00","updated_at":"2025-10-18T13:06:46.212558-07:00","dependencies":[{"issue_id":"bd-150","depends_on_id":"bd-155","type":"parent-child","created_at":"2025-10-18T13:07:49.147701-07:00","created_by":"daemon"}]}
-{"id":"bd-151","title":"Add version compatibility checks for daemon RPC protocol","description":"Client (bd CLI) and daemon may be different versions after upgrade. This causes:\n- Missing features (newer CLI, older daemon)\n- Protocol mismatches (older CLI, newer daemon)\n- Silent failures or confusing errors\n- No guidance to restart daemon\n\nLocation: internal/rpc/protocol.go, internal/rpc/client.go","design":"Add version field to RPC protocol:\n\n1. Add ClientVersion to Request struct\n2. Populate from Version constant in client\n3. Server checks compatibility in handleRequest()\n\nCompatibility rules:\n- Major version must match\n- Minor version backward compatible\n- Patch version always compatible\n\nOn mismatch:\n- Return clear error message\n- Suggest 'bd daemon --stop \u0026\u0026 bd daemon'\n- Log version info for debugging\n\nAdd to ping/health response:\n- Server version\n- Protocol version\n- Compatibility info\n\nAdd bd version --daemon command to check running daemon version.","acceptance_criteria":"- Version field in RPC protocol\n- Server validates client version\n- Clear error messages on mismatch\n- Health check returns version info\n- bd version --daemon command works\n- Documentation on version policy\n- Tests for version compatibility","status":"open","priority":1,"issue_type":"feature","created_at":"2025-10-18T13:06:57.417411-07:00","updated_at":"2025-10-18T13:06:57.417411-07:00","dependencies":[{"issue_id":"bd-151","depends_on_id":"bd-155","type":"parent-child","created_at":"2025-10-18T13:07:49.158023-07:00","created_by":"daemon"}]}
-{"id":"bd-152","title":"Add resource limits to daemon (connections, cache, memory)","description":"Daemon has no resource limits. Under heavy load or attack, it could:\n- Accept unlimited connections\n- Cache unlimited databases\n- Use unbounded memory\n- Exhaust file descriptors\n\nNeed limits for:\n- Max concurrent RPC connections (default: 100)\n- Max storage cache size (default: 50)\n- Request timeout enforcement (default: 30s)\n- Memory pressure detection\n\nLocation: internal/rpc/server.go","design":"Add resource tracking to Server:\n\ntype Server struct {\n // ... existing\n maxConns int32\n activeConns int32 // atomic\n connSemaphore chan struct{}\n}\n\nUse semaphore pattern for connection limiting:\n- Acquire token before handling connection\n- Release on completion\n- Reject connections when full\n\nAdd configurable limits via env vars:\n- BEADS_DAEMON_MAX_CONNS (default: 100)\n- BEADS_DAEMON_MAX_CACHE_SIZE (default: 50)\n- BEADS_DAEMON_REQUEST_TIMEOUT (default: 30s)\n\nAdd memory pressure detection:\n- Monitor runtime.MemStats\n- Trigger cache eviction at threshold\n- Log warnings at high memory use","acceptance_criteria":"- Connection limit enforced\n- Excess connections rejected gracefully\n- Request timeouts work\n- Memory limits configurable\n- Metrics expose current usage\n- Tests for limit enforcement\n- Documentation on tuning limits","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-18T13:07:09.810963-07:00","updated_at":"2025-10-18T13:07:09.810963-07:00","dependencies":[{"issue_id":"bd-152","depends_on_id":"bd-155","type":"parent-child","created_at":"2025-10-18T13:07:49.168284-07:00","created_by":"daemon"}]}
-{"id":"bd-153","title":"Add telemetry and observability to daemon","description":"Daemon has no metrics or observability. Cannot monitor:\n- Request latency (p50, p95, p99)\n- Cache hit/miss rates\n- Active connections\n- Error rates\n- Resource usage over time\n\nNeeded for:\n- Performance debugging\n- Capacity planning\n- Production monitoring\n- SLA tracking\n\nLocation: internal/rpc/server.go","design":"Add metrics collection to daemon:\n\n1. Request metrics:\n - Total requests by operation\n - Latency histogram\n - Error count by type\n\n2. Cache metrics:\n - Hit/miss ratio\n - Eviction count\n - Current size\n\n3. Connection metrics:\n - Active connections\n - Total connections\n - Rejected connections\n\n4. Resource metrics:\n - Memory usage\n - Goroutine count\n - File descriptor count\n\nAdd metrics endpoint:\n- bd daemon --metrics (JSON output)\n- OpMetrics RPC operation\n- Prometheus-compatible format option\n\nAdd to health check response for free monitoring.","acceptance_criteria":"- Metrics collected for key operations\n- bd daemon --metrics command works\n- Metrics include timestamps\n- Latency percentiles calculated\n- Zero performance overhead\n- Documentation on metrics","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-18T13:07:19.835495-07:00","updated_at":"2025-10-18T13:07:19.835495-07:00","dependencies":[{"issue_id":"bd-153","depends_on_id":"bd-155","type":"parent-child","created_at":"2025-10-18T13:07:49.178547-07:00","created_by":"daemon"}]}
-{"id":"bd-154","title":"Add log rotation for daemon.log","description":"daemon.log grows forever without rotation. With sync every 5 minutes:\n- ~105k log entries per year\n- No size limit\n- No cleanup\n- Eventually fills disk\n\nNeed automatic log rotation with:\n- Size-based rotation (default: 10MB)\n- Age-based cleanup (default: 7 days)\n- Compression of old logs\n- Configurable retention\n\nLocation: cmd/bd/daemon.go:455","design":"Use lumberjack library for rotation:\n\nimport \"gopkg.in/natefinch/lumberjack.v2\"\n\nlogF := \u0026lumberjack.Logger{\n Filename: logPath,\n MaxSize: 10, // MB\n MaxBackups: 3,\n MaxAge: 7, // days\n Compress: true,\n}\n\nMake configurable via env vars:\n- BEADS_DAEMON_LOG_MAX_SIZE (default: 10MB)\n- BEADS_DAEMON_LOG_MAX_BACKUPS (default: 3)\n- BEADS_DAEMON_LOG_MAX_AGE (default: 7 days)\n\nAdd to daemon status output:\n- Current log size\n- Number of archived logs\n- Oldest log timestamp","acceptance_criteria":"- Log rotation works automatically\n- Old logs are compressed\n- Retention policy enforced\n- Configuration via env vars works\n- Log size stays bounded\n- No log data loss during rotation\n- Documentation updated","status":"in_progress","priority":1,"issue_type":"feature","created_at":"2025-10-18T13:07:30.94896-07:00","updated_at":"2025-10-18T16:24:25.124171-07:00","dependencies":[{"issue_id":"bd-154","depends_on_id":"bd-155","type":"parent-child","created_at":"2025-10-18T13:07:49.190007-07:00","created_by":"daemon"}]}
+{"id":"bd-145","title":"Add storage cache eviction policy to daemon","description":"Daemon caches DB connections forever in storageCache map (server.go:29). For users with 50+ repos, this causes memory leaks and file descriptor exhaustion.\n\nNeed LRU cache with:\n- Max size limit (default: 50 repos)\n- TTL-based eviction (default: 30min idle)\n- Periodic cleanup goroutine\n\nLocation: internal/rpc/server.go:29-40","design":"Add StorageCacheEntry struct with lastAccess timestamp.\n\nImplement evictStaleStorage() method that runs every 5 minutes to close connections idle \u003e30min.\n\nAdd max cache size enforcement (LRU eviction when full).\n\nMake limits configurable via env vars:\n- BEADS_DAEMON_MAX_CACHE_SIZE (default: 50)\n- BEADS_DAEMON_CACHE_TTL (default: 30m)","acceptance_criteria":"- Cache evicts entries after 30min idle\n- Cache respects max size limit\n- Cleanup goroutine runs periodically\n- Evicted storage connections are properly closed\n- No resource leaks under sustained load\n- Unit tests for eviction logic","status":"closed","priority":0,"issue_type":"feature","created_at":"2025-10-18T13:05:46.174245-07:00","updated_at":"2025-10-18T13:16:56.921023-07:00","closed_at":"2025-10-18T13:16:56.921023-07:00"}
+{"id":"bd-146","title":"Add daemon health check endpoint and probes","description":"Auto-start only checks socket existence, not daemon responsiveness. Daemon can be running but unresponsive (deadlock, hung DB). Users work in degraded direct mode without knowing why.\n\nNeed health check RPC operation that:\n- Tests DB connectivity (1s timeout)\n- Returns uptime, status, metrics\n- Used by auto-start before connecting\n- Enables monitoring/alerting\n\nLocation: internal/rpc/server.go, cmd/bd/main.go:100-108","design":"Add OpHealth RPC operation to protocol.\n\nhandleHealth() implementation:\n- Quick DB ping with 1s timeout\n- Return status, uptime, version\n- Include basic metrics (connections, cache size)\n\nUpdate TryConnect() to call Health() after socket connection:\n- If health check fails, close connection and return nil\n- Enables transparent failover to direct mode\n\nAdd 'bd daemon --health' CLI command for monitoring.","acceptance_criteria":"- Health check RPC endpoint works\n- Returns structured health status\n- Client uses health check before operations\n- bd daemon --health command exists\n- Unhealthy daemon triggers auto-restart or fallback\n- Health check completes in \u003c2 seconds","status":"closed","priority":0,"issue_type":"feature","created_at":"2025-10-18T13:05:58.647592-07:00","updated_at":"2025-10-18T13:32:15.106003-07:00","closed_at":"2025-10-18T13:32:15.106003-07:00"}
+{"id":"bd-147","title":"Add stale socket and crash recovery for daemon","description":"When daemon crashes (panic, OOM, signal), socket file remains and blocks new daemon start. Users must manually remove .beads/bd.sock.\n\nProblems:\n- Socket file remains after crash\n- PID file remains (isDaemonRunning false positive)\n- No automatic recovery\n- Users get 'daemon already running' error\n\nLocation: cmd/bd/daemon.go, cmd/bd/main.go:221-311","design":"Improve stale detection in tryAutoStartDaemon():\n\n1. If socket exists, try to connect\n2. If connection fails → stale socket, remove it\n3. Also remove PID file and lock files\n4. Retry daemon start\n\nAdd self-healing to daemon startup:\n- On startup, check for stale PID files\n- If PID in file doesn't exist, remove and continue\n- Use exclusive file lock to prevent races\n\nOptional: Add crash recovery watchdog that restarts daemon on exit.","acceptance_criteria":"- Stale sockets are automatically detected and removed\n- Auto-start recovers from daemon crashes\n- No manual intervention needed for crash recovery\n- PID file management is robust\n- Lock files prevent multiple daemon instances\n- Tests for crash recovery scenarios","notes":"Oracle code review identified race conditions. Improvements made:\n- Moved cleanup AFTER lock acquisition (prevents unlinking live sockets)\n- Added PID liveness check before removing socket\n- Added stale lock detection with retry\n- Tightened directory permissions to 0700\n- Improved socket readiness probing with short timeouts\n- Made removeOldSocket() ignore ENOENT errors\n\nChanges eliminate race where socket could be removed during daemon startup window.","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-18T13:06:10.116917-07:00","updated_at":"2025-10-18T13:56:51.318675-07:00","closed_at":"2025-10-18T13:56:51.318675-07:00"}
+{"id":"bd-148","title":"Add lifecycle management for beads-mcp processes","description":"MCP server processes accumulate without cleanup. Each tool invocation spawns a new Python process that lingers after Claude disconnects.\n\nObserved: 6+ beads-mcp processes running simultaneously.\n\nProblems:\n- No parent-child relationship tracking\n- No cleanup on MCP client disconnect\n- Processes leak over days of use\n- Could accumulate hundreds of processes\n\nLocation: integrations/beads-mcp/src/beads_mcp/server.py","design":"Add proper cleanup handlers to MCP server:\n\n1. Register atexit handler to close daemon connections\n2. Handle SIGTERM/SIGINT for graceful shutdown\n3. Close daemon client in cleanup()\n4. Remove any temp files\n\nOptional improvements:\n- Track active connections to daemon\n- Implement connection pooling\n- Add process timeout/TTL\n- Log lifecycle events for debugging\n\nExample:\nimport atexit\nimport signal\n\ndef cleanup():\n # Close daemon connections\n # Remove temp files\n pass\n\natexit.register(cleanup)\nsignal.signal(signal.SIGTERM, lambda s, f: cleanup())","acceptance_criteria":"- MCP processes clean up on exit\n- Daemon connections are properly closed\n- No process leaks after repeated use\n- Signal handlers work correctly\n- Cleanup runs on normal and abnormal exit\n- Test with multiple concurrent MCP invocations","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-18T13:06:22.030027-07:00","updated_at":"2025-10-18T14:27:41.87646-07:00","closed_at":"2025-10-18T14:27:41.87646-07:00"}
+{"id":"bd-149","title":"Add global daemon auto-start support","description":"Auto-start only works for local daemon. Users with multiple repos must manually run 'bd daemon --global'.\n\nProblems:\n- No detection of whether global daemon is preferable\n- No migration path from local → global\n- Multi-repo users don't discover global daemon\n- Manual setup required\n\nLocation: cmd/bd/main.go:221-311","design":"Add heuristics to shouldUseGlobalDaemon():\n\n1. Count .beads repos under home directory\n2. If \u003e3 repos found, prefer global daemon\n3. Check BEADS_PREFER_GLOBAL_DAEMON env var\n4. Check config file preference\n\nUpdate tryAutoStartDaemon() to:\n- Use shouldUseGlobalDaemon() to pick mode\n- Pass --global flag when appropriate\n- Log decision for debugging\n\nAdd migration helper:\n- Detect running local daemon\n- Suggest switching to global if multi-repo detected\n- bd daemon --migrate-to-global command","acceptance_criteria":"- Auto-start uses global daemon when appropriate\n- Multi-repo detection works correctly\n- Users can configure preference\n- Migration path is smooth\n- Both local and global auto-start work\n- Documentation updated","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-18T13:06:33.633238-07:00","updated_at":"2025-10-18T14:41:28.594337-07:00","closed_at":"2025-10-18T14:41:28.594337-07:00"}
+{"id":"bd-15","title":"Add performance benchmarks document","description":"Document actual performance metrics with hyperfine tests","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T10:09:23.532938-07:00","closed_at":"2025-10-18T10:09:23.532938-07:00"}
+{"id":"bd-150","title":"Improve daemon fallback visibility and user feedback","description":"When daemon is unavailable, bd silently falls back to direct mode. Users don't know:\n- That daemon exists\n- Why auto-start failed\n- That they're in degraded mode\n- How to fix it\n\nThis creates confusion for multi-repo users who get slower performance without explanation.\n\nLocation: cmd/bd/main.go:98-130","design":"Add visibility at multiple levels:\n\n1. Debug logging (existing BD_DEBUG):\n - Already shows daemon connection attempts\n - Add auto-start success/failure\n\n2. Verbose mode (BD_VERBOSE):\n - Show warning when falling back\n - Suggest 'bd daemon --status' to check\n\n3. Status indicator:\n - Add daemon status to all commands when --json\n - Example: {\"daemon_status\": \"healthy\", \"daemon_type\": \"local\", ...}\n\n4. Explicit status command:\n - bd daemon --status shows detailed info\n - Shows whether daemon is running/healthy/unavailable\n\n5. Helpful error messages:\n - When auto-start fails repeatedly\n - When falling back after health check failure\n - With actionable next steps","acceptance_criteria":"- Users can see daemon status easily\n- Fallback warnings are helpful not noisy\n- JSON output includes daemon status\n- Error messages are actionable\n- Documentation explains status indicators\n- bd daemon --status command works","status":"open","priority":1,"issue_type":"feature","created_at":"2025-10-18T13:06:46.212558-07:00","updated_at":"2025-10-18T13:06:46.212558-07:00"}
+{"id":"bd-151","title":"Add version compatibility checks for daemon RPC protocol","description":"Client (bd CLI) and daemon may be different versions after upgrade. This causes:\n- Missing features (newer CLI, older daemon)\n- Protocol mismatches (older CLI, newer daemon)\n- Silent failures or confusing errors\n- No guidance to restart daemon\n\nLocation: internal/rpc/protocol.go, internal/rpc/client.go","design":"Add version field to RPC protocol:\n\n1. Add ClientVersion to Request struct\n2. Populate from Version constant in client\n3. Server checks compatibility in handleRequest()\n\nCompatibility rules:\n- Major version must match\n- Minor version backward compatible\n- Patch version always compatible\n\nOn mismatch:\n- Return clear error message\n- Suggest 'bd daemon --stop \u0026\u0026 bd daemon'\n- Log version info for debugging\n\nAdd to ping/health response:\n- Server version\n- Protocol version\n- Compatibility info\n\nAdd bd version --daemon command to check running daemon version.","acceptance_criteria":"- Version field in RPC protocol\n- Server validates client version\n- Clear error messages on mismatch\n- Health check returns version info\n- bd version --daemon command works\n- Documentation on version policy\n- Tests for version compatibility","status":"open","priority":1,"issue_type":"feature","created_at":"2025-10-18T13:06:57.417411-07:00","updated_at":"2025-10-18T13:06:57.417411-07:00"}
+{"id":"bd-152","title":"Add resource limits to daemon (connections, cache, memory)","description":"Daemon has no resource limits. Under heavy load or attack, it could:\n- Accept unlimited connections\n- Cache unlimited databases\n- Use unbounded memory\n- Exhaust file descriptors\n\nNeed limits for:\n- Max concurrent RPC connections (default: 100)\n- Max storage cache size (default: 50)\n- Request timeout enforcement (default: 30s)\n- Memory pressure detection\n\nLocation: internal/rpc/server.go","design":"Add resource tracking to Server:\n\ntype Server struct {\n // ... existing\n maxConns int32\n activeConns int32 // atomic\n connSemaphore chan struct{}\n}\n\nUse semaphore pattern for connection limiting:\n- Acquire token before handling connection\n- Release on completion\n- Reject connections when full\n\nAdd configurable limits via env vars:\n- BEADS_DAEMON_MAX_CONNS (default: 100)\n- BEADS_DAEMON_MAX_CACHE_SIZE (default: 50)\n- BEADS_DAEMON_REQUEST_TIMEOUT (default: 30s)\n\nAdd memory pressure detection:\n- Monitor runtime.MemStats\n- Trigger cache eviction at threshold\n- Log warnings at high memory use","acceptance_criteria":"- Connection limit enforced\n- Excess connections rejected gracefully\n- Request timeouts work\n- Memory limits configurable\n- Metrics expose current usage\n- Tests for limit enforcement\n- Documentation on tuning limits","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-18T13:07:09.810963-07:00","updated_at":"2025-10-18T13:07:09.810963-07:00"}
+{"id":"bd-153","title":"Add telemetry and observability to daemon","description":"Daemon has no metrics or observability. Cannot monitor:\n- Request latency (p50, p95, p99)\n- Cache hit/miss rates\n- Active connections\n- Error rates\n- Resource usage over time\n\nNeeded for:\n- Performance debugging\n- Capacity planning\n- Production monitoring\n- SLA tracking\n\nLocation: internal/rpc/server.go","design":"Add metrics collection to daemon:\n\n1. Request metrics:\n - Total requests by operation\n - Latency histogram\n - Error count by type\n\n2. Cache metrics:\n - Hit/miss ratio\n - Eviction count\n - Current size\n\n3. Connection metrics:\n - Active connections\n - Total connections\n - Rejected connections\n\n4. Resource metrics:\n - Memory usage\n - Goroutine count\n - File descriptor count\n\nAdd metrics endpoint:\n- bd daemon --metrics (JSON output)\n- OpMetrics RPC operation\n- Prometheus-compatible format option\n\nAdd to health check response for free monitoring.","acceptance_criteria":"- Metrics collected for key operations\n- bd daemon --metrics command works\n- Metrics include timestamps\n- Latency percentiles calculated\n- Zero performance overhead\n- Documentation on metrics","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-18T13:07:19.835495-07:00","updated_at":"2025-10-18T13:07:19.835495-07:00"}
+{"id":"bd-154","title":"Add log rotation for daemon.log","description":"daemon.log grows forever without rotation. With sync every 5 minutes:\n- ~105k log entries per year\n- No size limit\n- No cleanup\n- Eventually fills disk\n\nNeed automatic log rotation with:\n- Size-based rotation (default: 10MB)\n- Age-based cleanup (default: 7 days)\n- Compression of old logs\n- Configurable retention\n\nLocation: cmd/bd/daemon.go:455","design":"Use lumberjack library for rotation:\n\nimport \"gopkg.in/natefinch/lumberjack.v2\"\n\nlogF := \u0026lumberjack.Logger{\n Filename: logPath,\n MaxSize: 10, // MB\n MaxBackups: 3,\n MaxAge: 7, // days\n Compress: true,\n}\n\nMake configurable via env vars:\n- BEADS_DAEMON_LOG_MAX_SIZE (default: 10MB)\n- BEADS_DAEMON_LOG_MAX_BACKUPS (default: 3)\n- BEADS_DAEMON_LOG_MAX_AGE (default: 7 days)\n\nAdd to daemon status output:\n- Current log size\n- Number of archived logs\n- Oldest log timestamp","acceptance_criteria":"- Log rotation works automatically\n- Old logs are compressed\n- Retention policy enforced\n- Configuration via env vars works\n- Log size stays bounded\n- No log data loss during rotation\n- Documentation updated","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-18T13:07:30.94896-07:00","updated_at":"2025-10-18T16:27:51.349037-07:00","closed_at":"2025-10-18T16:27:51.349037-07:00"}
{"id":"bd-155","title":"Daemon production readiness","description":"Make beads daemon production-ready for long-running use, multi-repo deployments, and resilient operation.\n\nCurrent state: Good foundation, works well for development\nTarget state: Production-ready for individual developers and small teams\n\nGap areas:\n1. Resource management (cache eviction, limits)\n2. Health monitoring and crash recovery\n3. Process lifecycle management\n4. User experience (visibility, feedback)\n5. Operational concerns (logging, metrics)\n\nSuccess criteria:\n- Can run for weeks without restart\n- Handles 50+ repositories efficiently\n- Recovers from crashes automatically\n- Users understand daemon status\n- Observable and debuggable","acceptance_criteria":"All child issues completed:\n- P0 issues: Storage cache, health checks, crash recovery, MCP cleanup\n- P1 issues: Global auto-start, visibility, version checks\n- P2 issues: Resource limits, telemetry, log rotation\n\nValidation:\n- Run daemon for 7+ days without issues\n- Test with 50+ repositories\n- Verify crash recovery\n- Confirm resource usage is bounded\n- Check metrics and logs are useful","status":"in_progress","priority":0,"issue_type":"epic","created_at":"2025-10-18T13:07:43.543715-07:00","updated_at":"2025-10-18T16:19:57.885896-07:00"}
{"id":"bd-16","title":"Add EXPLAIN QUERY PLAN tests for ready work query","description":"Verify that the hierarchical blocking query uses proper indexes and doesn't do full table scans.\n\n**Queries to analyze:**\n1. The recursive CTE (both base case and recursive case)\n2. The final SELECT with NOT EXISTS\n3. Impact of various filters (status, priority, assignee)\n\n**Implementation:**\nAdd test function that:\n- Runs EXPLAIN QUERY PLAN on GetReadyWork query\n- Parses output to verify no SCAN TABLE operations\n- Documents expected query plan in comments\n- Fails if query plan degrades\n\n**Benefits:**\n- Catch performance regressions in tests\n- Document expected query behavior\n- Ensure indexes are being used\n\nRelated to: bd-77 (composite index on depends_on_id, type)","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T12:47:44.284846-07:00","closed_at":"2025-10-18T12:47:44.284846-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-18T09:57:27.593569-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-18T09:57:27.595342-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-18T09:57:27.597151-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-18T09:57:27.539279-07:00","closed_at":"2025-10-14T13:12:16.610152-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-18T16:47:05.347564-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-18T09:57:27.598126-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-18T09:57:27.60018-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-18T09:57:27.603229-07:00","closed_at":"2025-10-18T09:43:18.250156-07:00"}
@@ -74,7 +74,7 @@
{"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-18T09:57:27.620326-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-18T09:57:27.623259-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-18T09:57:28.107934-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-18T09:57:27.6321-07:00","closed_at":"2025-10-16T10:07:33.961565-07:00","dependencies":[{"issue_id":"bd-28","depends_on_id":"bd-72","type":"blocks","created_at":"2025-10-16T21:51:08.916632-07:00","created_by":"renumber"}]}
+{"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-18T09:57:27.6321-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-18T09:57:27.667958-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":"open","priority":4,"issue_type":"feature","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T09:57:27.539944-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-18T09:57:27.670216-07:00","closed_at":"2025-10-16T10:07:22.46194-07:00"}
@@ -84,13 +84,13 @@
{"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-18T09:57:27.678979-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-18T09:57:28.108641-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-18T09:57:28.109135-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-18T09:57:27.6841-07:00","closed_at":"2025-10-16T10:07:22.461107-07:00","dependencies":[{"issue_id":"bd-37","depends_on_id":"bd-72","type":"parent-child","created_at":"2025-10-16T21:51:08.920845-07:00","created_by":"renumber"}]}
-{"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-18T09:57:27.686793-07:00","closed_at":"2025-10-14T02:51:52.198288-07:00","dependencies":[{"issue_id":"bd-38","depends_on_id":"bd-72","type":"parent-child","created_at":"2025-10-16T21:51:08.913972-07:00","created_by":"renumber"}]}
-{"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-18T09:57:27.689478-07:00","closed_at":"2025-10-14T02:51:52.198356-07:00","dependencies":[{"issue_id":"bd-39","depends_on_id":"bd-72","type":"parent-child","created_at":"2025-10-16T21:51:08.92251-07:00","created_by":"renumber"}]}
+{"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-18T09:57:27.6841-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-18T09:57:27.686793-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-18T09:57:27.689478-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-18T09:57:27.551726-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-18T09:57:27.691086-07:00","closed_at":"2025-10-16T10:07:34.003238-07:00","dependencies":[{"issue_id":"bd-40","depends_on_id":"bd-72","type":"parent-child","created_at":"2025-10-16T21:51:08.923374-07:00","created_by":"renumber"}]}
-{"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-18T09:57:27.692127-07:00","closed_at":"2025-10-16T10:07:34.007864-07:00","dependencies":[{"issue_id":"bd-41","depends_on_id":"bd-72","type":"parent-child","created_at":"2025-10-16T21:51:08.917092-07:00","created_by":"renumber"}]}
-{"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-18T09:57:27.695547-07:00","closed_at":"2025-10-16T10:07:34.028648-07:00","dependencies":[{"issue_id":"bd-42","depends_on_id":"bd-72","type":"parent-child","created_at":"2025-10-16T21:51:08.924312-07:00","created_by":"renumber"}]}
+{"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-18T09:57:27.691086-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-18T09:57:27.692127-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-18T09:57:27.695547-07:00","closed_at":"2025-10-16T10:07:34.028648-07:00"}
{"id":"bd-43","title":"bd should auto-detect .beads/*.db in current directory","description":"When bd is run without --db flag, it defaults to beads' own database instead of looking for a .beads/*.db file in the current working directory. This causes confusion when working on other projects that use beads for issue tracking (like vc).\n\nExpected behavior: bd should search for .beads/*.db in cwd and use that if found, before falling back to default beads database.\n\nExample: Running 'bd ready' in /Users/stevey/src/vc/vc/ should automatically find and use .beads/vc.db without requiring --db flag every time.","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T09:57:27.697431-07:00","closed_at":"2025-10-16T10:07:34.046944-07:00"}
{"id":"bd-44","title":"Document or automate JSONL sync workflow for git collaboration","description":"When using beads across multiple machines/environments via git, there's a workflow gap:\n\n1. Machine A: Create issues → stored in .beads/project.db\n2. Machine A: bd export -o .beads/issues.jsonl\n3. Machine A: git add .beads/issues.jsonl \u0026\u0026 git commit \u0026\u0026 git push\n4. Machine B: git pull\n5. Machine B: ??? issues.jsonl exists but project.db is empty/stale\n\nThe missing step is: bd import --db .beads/project.db -i .beads/issues.jsonl\n\nThis needs to be either:\na) Documented clearly in workflow docs\nb) Automated (e.g., git hook, or bd auto-imports if jsonl is newer than db)\nc) Both\n\nReal-world impact: User had Claude Code on GCP VM create vc issues from BOOTSTRAP.md. They were exported to issues.jsonl and committed. But on local machine, vc.db was empty until manual import was run.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T09:57:27.698095-07:00","closed_at":"2025-10-14T02:51:52.199766-07:00"}
{"id":"bd-45","title":"Root issue for dep tree test","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T09:57:27.69874-07:00","closed_at":"2025-10-16T10:07:34.1266-07:00"}
@@ -98,7 +98,7 @@
{"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-18T09:57:27.700455-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-18T09:57:27.701197-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-18T09:57:27.702016-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-18T09:57:27.552506-07:00","dependencies":[{"issue_id":"bd-5","depends_on_id":"bd-1","type":"parent-child","created_at":"2025-10-16T21:51:08.917589-07:00","created_by":"renumber"}]}
+{"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-18T09:57:27.552506-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-18T09:57:27.70312-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-18T09:57:27.703875-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-18T09:57:27.704593-07:00","closed_at":"2025-10-16T10:07:34.129768-07:00"}
@@ -111,11 +111,11 @@
{"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-18T09:57:27.713274-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-18T09:57:27.553387-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-18T09:57:27.715203-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-18T09:57:27.716231-07:00","closed_at":"2025-10-14T12:55:59.029894-07:00","dependencies":[{"issue_id":"bd-61","depends_on_id":"bd-60","type":"parent-child","created_at":"2025-10-16T21:51:08.919236-07:00","created_by":"renumber"}]}
-{"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-18T09:57:27.717536-07:00","closed_at":"2025-10-14T12:57:06.733755-07:00","dependencies":[{"issue_id":"bd-62","depends_on_id":"bd-60","type":"parent-child","created_at":"2025-10-16T21:51:08.911433-07:00","created_by":"renumber"}]}
-{"id":"bd-63","title":"Write plugin documentation","description":"Create comprehensive documentation for the plugin.\n\nContents:\n- Installation instructions\n- Available commands\n- MCP tools reference\n- Configuration options\n- Examples and workflows\n- Troubleshooting guide","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T09:57:27.721099-07:00","closed_at":"2025-10-14T12:58:39.701738-07:00","dependencies":[{"issue_id":"bd-63","depends_on_id":"bd-60","type":"parent-child","created_at":"2025-10-16T21:51:08.920198-07:00","created_by":"renumber"}]}
-{"id":"bd-64","title":"Test plugin installation and functionality","description":"Verify the plugin works end-to-end.\n\nTest cases:\n- Fresh installation via /plugin command\n- All slash commands work correctly\n- MCP server tools are accessible\n- Configuration options work\n- Documentation is accurate\n- Works in both terminal and VS Code","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T09:57:27.721923-07:00","closed_at":"2025-10-14T12:59:38.637269-07:00","dependencies":[{"issue_id":"bd-64","depends_on_id":"bd-60","type":"parent-child","created_at":"2025-10-16T21:51:08.913239-07:00","created_by":"renumber"}]}
-{"id":"bd-65","title":"Parent's blocker should block children in ready work calculation","description":"GitHub issue #19: If epic1 blocks epic2, children of epic2 should also be considered blocked when calculating ready work. Currently epic2's children show as ready even though their parent is blocked. This breaks the natural hierarchy of dependencies and can cause agents to work on tasks out of order.\n\nExpected: ready work calculation should traverse up parent-child hierarchy and check if any ancestor has blocking dependencies.\n\nSee: https://github.com/anthropics/claude-code/issues/19","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T09:57:27.724293-07:00","closed_at":"2025-10-14T12:53:41.146271-07:00","dependencies":[{"issue_id":"bd-65","depends_on_id":"bd-60","type":"parent-child","created_at":"2025-10-16T21:51:08.91611-07:00","created_by":"renumber"}]}
+{"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-18T09:57:27.716231-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-18T09:57:27.717536-07:00","closed_at":"2025-10-14T12:57:06.733755-07:00"}
+{"id":"bd-63","title":"Write plugin documentation","description":"Create comprehensive documentation for the plugin.\n\nContents:\n- Installation instructions\n- Available commands\n- MCP tools reference\n- Configuration options\n- Examples and workflows\n- Troubleshooting guide","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T09:57:27.721099-07:00","closed_at":"2025-10-14T12:58:39.701738-07:00"}
+{"id":"bd-64","title":"Test plugin installation and functionality","description":"Verify the plugin works end-to-end.\n\nTest cases:\n- Fresh installation via /plugin command\n- All slash commands work correctly\n- MCP server tools are accessible\n- Configuration options work\n- Documentation is accurate\n- Works in both terminal and VS Code","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T09:57:27.721923-07:00","closed_at":"2025-10-14T12:59:38.637269-07:00"}
+{"id":"bd-65","title":"Parent's blocker should block children in ready work calculation","description":"GitHub issue #19: If epic1 blocks epic2, children of epic2 should also be considered blocked when calculating ready work. Currently epic2's children show as ready even though their parent is blocked. This breaks the natural hierarchy of dependencies and can cause agents to work on tasks out of order.\n\nExpected: ready work calculation should traverse up parent-child hierarchy and check if any ancestor has blocking dependencies.\n\nSee: https://github.com/anthropics/claude-code/issues/19","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T09:57:27.724293-07:00","closed_at":"2025-10-14T12:53:41.146271-07:00"}
{"id":"bd-66","title":"Add composite index on dependencies(depends_on_id, type)","description":"The hierarchical blocking query does:\nJOIN dependencies d ON d.depends_on_id = bt.issue_id\nWHERE d.type = 'parent-child'\n\nCurrently we only have idx_dependencies_depends_on (line 41 in schema.go), which covers depends_on_id but not the type filter.\n\n**Impact:**\n- Query has to scan ALL dependencies for a given depends_on_id, then filter by type\n- With 10k+ issues and many dependencies, this could cause slowdowns\n- The blocker propagation happens recursively, amplifying the cost\n\n**Solution:**\nAdd composite index: CREATE INDEX idx_dependencies_depends_on_type ON dependencies(depends_on_id, type)\n\n**Testing:**\nRun EXPLAIN QUERY PLAN on GetReadyWork query before/after to verify index usage.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T09:57:27.725142-07:00","closed_at":"2025-10-14T13:00:04.441418-07:00"}
{"id":"bd-67","title":"Update ready_issues VIEW to use hierarchical blocking","description":"The ready_issues VIEW (schema.go:97-108) uses the OLD blocking logic that doesn't propagate through parent-child hierarchies.\n\n**Problem:**\n- GetReadyWork() function now uses recursive CTE with propagation\n- But the ready_issues VIEW still uses simple NOT EXISTS check\n- Any code using the VIEW will get DIFFERENT results than GetReadyWork()\n- This creates inconsistency and confusion\n\n**Impact:**\n- Unknown if the VIEW is actually used anywhere in the codebase\n- If it is used, it's returning incorrect results (showing children as ready when parent is blocked)\n\n**Solution:**\nEither:\n1. Update VIEW to match GetReadyWork logic (complex CTE in a view)\n2. Drop the VIEW entirely if unused\n3. Make VIEW call GetReadyWork as a function (if SQLite supports it)\n\n**Investigation needed:**\nGrep for 'ready_issues' to see if the view is actually used.","notes":"**Investigation results:**\nGrepped the codebase - the ready_issues VIEW appears in:\n- schema.go (definition)\n- WORKFLOW.md, DESIGN.md (documentation)\n- No actual Go code queries it directly\n\n**Conclusion:** The VIEW is defined but appears UNUSED by actual code. GetReadyWork() function is used instead.\n\n**Recommended solution:** Drop the VIEW entirely to avoid confusion. It serves no purpose if unused and creates a maintenance burden (needs to stay in sync with GetReadyWork logic).\n\n**Alternative:** If we want to keep it for direct SQL access, update the VIEW definition to match the new recursive CTE logic.","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T09:57:27.725833-07:00","closed_at":"2025-10-14T13:06:47.739336-07:00"}
{"id":"bd-68","title":"Verify and test Claude Code plugin","description":"Address remaining items from code review:\n\nCritical:\n1. Test plugin installation locally with /plugin marketplace add\n2. Verify ${CLAUDE_PLUGIN_ROOT} variable works correctly\n3. Test each slash command works\n4. Test @task-agent execution\n5. Verify MCP server connects properly\n\nDocumentation:\n1. Clarify 'one-command installation' vs prerequisites\n2. Add note about plugin development status\n3. Verify all paths and examples work\n\nNice-to-have:\n1. Add icon for marketplace (optional)\n2. Add categories field to plugin.json\n3. Add engines field for version compatibility","notes":"PLUGIN IMPLEMENTATION COMPLETE - READY FOR TESTING\n\nWhat was built:\n✅ .claude-plugin/plugin.json - Plugin metadata with MCP server config\n✅ .claude-plugin/marketplace.json - Marketplace configuration\n✅ 9 slash commands in .claude-plugin/commands/:\n - bd-ready, bd-create, bd-show, bd-update, bd-close\n - bd-workflow, bd-init, bd-stats, bd-version\n✅ Task agent in .claude-plugin/agents/task-agent.md\n✅ PLUGIN.md - Comprehensive documentation\n✅ README.md - Updated with plugin section\n✅ Version sync - All components at 0.9.2\n\nTesting Instructions for Next Agent:\n=====================================\n\n1. INSTALL PLUGIN FROM GITHUB:\n /plugin marketplace add steveyegge/beads\n /plugin install beads\n \n2. RESTART CLAUDE CODE (required for MCP server)\n\n3. TEST SLASH COMMANDS:\n /bd-version # Check versions (should show 0.9.2)\n /bd-workflow # Show workflow guide\n /bd-stats # Show project stats\n /bd-ready # Find ready work\n /bd-create \"Test plugin\" task 2\n /bd-show bd-\u003cid\u003e\n \n4. TEST MCP SERVER:\n /mcp # Verify 'beads' server appears\n \n5. TEST TASK AGENT:\n @task-agent # If supported in Claude Code\n \n6. VERIFY:\n - All commands work without errors\n - MCP tools are accessible\n - Version checking works\n - Documentation is accurate\n\nExpected Issues:\n- May need to adjust MCP server path variable (${CLAUDE_PLUGIN_ROOT})\n- Task agent syntax might differ\n- Some commands may need refinement based on actual usage\n\nIf testing fails, check:\n- bd CLI is in PATH: which bd\n- uv is installed: which uv\n- MCP server logs in Claude Code\n- PLUGIN.md troubleshooting section\n\nCommit references:\n- 9f38375: feat: Add Claude Code plugin for beads\n- d25fc53: feat: Add version compatibility checking\n- c0f1044: fix: Sync all component versions to 0.9.2\n- a5c71f0: feat: Add version bump script\n- a612b92: docs: Add version management to CLAUDE.md","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T09:57:27.726725-07:00","closed_at":"2025-10-16T21:03:25.525342-07:00"}
@@ -126,9 +126,9 @@
{"id":"bd-72","title":"Build collision resolution tooling for distributed branch workflows","description":"When branches diverge and both create issues, auto-incrementing IDs collide on merge. Build excellent tooling to detect collisions during import, auto-renumber issues with fewer dependencies, update all references in descriptions and dependency links, and provide clear user feedback. Goal: keep beautiful brevity of numeric IDs (bd-210) while handling distributed creation gracefully.","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-16T20:46:08.971822-07:00","updated_at":"2025-10-18T09:57:27.734434-07:00","closed_at":"2025-10-14T14:16:10.559862-07:00"}
{"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-18T09:57:28.110366-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-18T09:57:27.7382-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-18T09:57:27.738824-07:00","closed_at":"2025-10-17T23:51:47.390748-07:00","dependencies":[{"issue_id":"bd-75","depends_on_id":"bd-1","type":"parent-child","created_at":"2025-10-16T21:51:08.915539-07:00","created_by":"renumber"}]}
+{"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-18T09:57:27.738824-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-18T09:57:27.739799-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-18T09:57:27.740767-07:00","closed_at":"2025-10-14T13:39:55.828804-07:00","dependencies":[{"issue_id":"bd-77","depends_on_id":"bd-1","type":"parent-child","created_at":"2025-10-16T21:51:08.914487-07:00","created_by":"renumber"}]}
+{"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-18T09:57:27.740767-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-18T09:57:27.741758-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-18T09:57:28.110777-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-18T09:57:27.55699-07:00","closed_at":"2025-10-14T14:37:17.463352-07:00"}
@@ -149,7 +149,7 @@
{"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-18T09:57:27.833502-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-18T09:57:27.842205-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-18T09:57:28.111842-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-18T09:57:27.84789-07:00","closed_at":"2025-10-16T23:45:02.505335-07:00","dependencies":[{"issue_id":"bd-96","depends_on_id":"bd-97","type":"parent-child","created_at":"2025-10-16T21:54:56.032869-07:00","created_by":"stevey"}]}
+{"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-18T09:57:27.84789-07:00","closed_at":"2025-10-16T23:45:02.505335-07:00"}
{"id":"bd-97","title":"Phase 1: Implement RPC protocol infrastructure","description":"Create the foundation for daemon-client communication using Unix sockets and JSON.\n\nNew files to create:\n- internal/rpc/protocol.go - Request/response types, operations enum\n- internal/rpc/server.go - Unix socket server that daemon runs\n- internal/rpc/client.go - Client library for bd commands to use\n\nSocket location: .beads/bd.sock (per-repo)\n\nOperations to support initially: create, update, list, show, close, ready, stats","design":"protocol.go defines:\n- Request struct with Operation string and Args json.RawMessage\n- Response struct with Success bool, Data json.RawMessage, Error string\n- Operation constants for all bd commands\n\nserver.go implements:\n- Unix socket listener on .beads/bd.sock\n- Request handler that dispatches to storage layer\n- Graceful shutdown on signals\n\nclient.go implements:\n- TryConnect() to detect running daemon\n- Execute(operation, args) to send RPC request\n- Connection pooling/reuse for performance","acceptance_criteria":"- internal/rpc package compiles without errors\n- Server can accept and respond to simple ping request\n- Client can connect to socket and receive response\n- Unit tests for protocol serialization/deserialization\n- Socket cleanup on server shutdown","status":"closed","priority":0,"issue_type":"task","created_at":"2025-10-16T21:54:48.83081-07:00","updated_at":"2025-10-18T09:57:27.914342-07:00","closed_at":"2025-10-16T22:02:40.675096-07:00"}
-{"id":"bd-98","title":"Phase 2: Add client auto-detection in bd commands","description":"Modify all bd commands to detect if daemon is running and route through RPC client if available, otherwise fall back to direct storage access.\n\nChanges needed:\n- Update cmd/bd/main.go to check for daemon socket on startup\n- Wrap storage calls with TryConnect logic\n- Ensure all commands work identically in both modes\n- Add --no-daemon flag to force direct mode\n\nThis maintains backward compatibility while enabling daemon mode.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-10-16T22:47:36.185502-07:00","updated_at":"2025-10-18T09:57:27.926039-07:00","closed_at":"2025-10-16T23:05:11.299018-07:00","dependencies":[{"issue_id":"bd-98","depends_on_id":"bd-96","type":"parent-child","created_at":"2025-10-16T22:47:36.190931-07:00","created_by":"stevey"}]}
-{"id":"bd-99","title":"Phase 3: Implement daemon command with SQLite ownership","description":"Create 'bd daemon' command that starts the RPC server and owns the SQLite database.\n\nImplementation:\n- Add cmd/bd/daemon.go with start/stop/status subcommands\n- Daemon holds exclusive SQLite connection\n- Integrates git sync loop (batch exports every 5 seconds)\n- PID file management for daemon lifecycle\n- Logging for daemon operations\n\nSocket location: .beads/bd.sock per repository","status":"closed","priority":0,"issue_type":"task","created_at":"2025-10-16T22:47:42.86546-07:00","updated_at":"2025-10-18T09:57:27.931652-07:00","closed_at":"2025-10-16T23:18:57.600602-07:00","dependencies":[{"issue_id":"bd-99","depends_on_id":"bd-96","type":"parent-child","created_at":"2025-10-16T22:47:42.874284-07:00","created_by":"stevey"}]}
+{"id":"bd-98","title":"Phase 2: Add client auto-detection in bd commands","description":"Modify all bd commands to detect if daemon is running and route through RPC client if available, otherwise fall back to direct storage access.\n\nChanges needed:\n- Update cmd/bd/main.go to check for daemon socket on startup\n- Wrap storage calls with TryConnect logic\n- Ensure all commands work identically in both modes\n- Add --no-daemon flag to force direct mode\n\nThis maintains backward compatibility while enabling daemon mode.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-10-16T22:47:36.185502-07:00","updated_at":"2025-10-18T09:57:27.926039-07:00","closed_at":"2025-10-16T23:05:11.299018-07:00"}
+{"id":"bd-99","title":"Phase 3: Implement daemon command with SQLite ownership","description":"Create 'bd daemon' command that starts the RPC server and owns the SQLite database.\n\nImplementation:\n- Add cmd/bd/daemon.go with start/stop/status subcommands\n- Daemon holds exclusive SQLite connection\n- Integrates git sync loop (batch exports every 5 seconds)\n- PID file management for daemon lifecycle\n- Logging for daemon operations\n\nSocket location: .beads/bd.sock per repository","status":"closed","priority":0,"issue_type":"task","created_at":"2025-10-16T22:47:42.86546-07:00","updated_at":"2025-10-18T09:57:27.931652-07:00","closed_at":"2025-10-16T23:18:57.600602-07:00"}
diff --git a/cmd/bd/import.go b/cmd/bd/import.go
index 835ca9d..2e4f784 100644
--- a/cmd/bd/import.go
+++ b/cmd/bd/import.go
@@ -81,387 +81,87 @@ Behavior:
os.Exit(1)
}
- // Phase 2: Detect collisions
- sqliteStore, ok := store.(*sqlite.SQLiteStorage)
- if !ok {
- fmt.Fprintf(os.Stderr, "Error: collision detection requires SQLite storage backend\n")
- os.Exit(1)
+ // Phase 2: Use shared import logic
+ opts := ImportOptions{
+ ResolveCollisions: resolveCollisions,
+ DryRun: dryRun,
+ SkipUpdate: skipUpdate,
+ Strict: strict,
}
- collisionResult, err := sqlite.DetectCollisions(ctx, sqliteStore, allIssues)
+ result, err := importIssuesCore(ctx, dbPath, store, allIssues, opts)
+
+ // Handle errors and special cases
if err != nil {
- fmt.Fprintf(os.Stderr, "Error detecting collisions: %v\n", err)
- os.Exit(1)
- }
-
- var idMapping map[string]string
- var created, updated, skipped int
-
- // Phase 3: Handle collisions
- if len(collisionResult.Collisions) > 0 {
- // Print collision report
- printCollisionReport(collisionResult)
-
- if dryRun {
- // In dry-run mode, just print report and exit
- fmt.Fprintf(os.Stderr, "\nDry-run mode: no changes made\n")
- os.Exit(0)
- }
-
- if !resolveCollisions {
- // Default behavior: fail on collision (safe mode)
+ // Check if it's a collision error when not resolving
+ if !resolveCollisions && result != nil && len(result.CollisionIDs) > 0 {
+ // Print collision report before exiting
+ fmt.Fprintf(os.Stderr, "\n=== Collision Detection Report ===\n")
+ fmt.Fprintf(os.Stderr, "COLLISIONS DETECTED: %d\n\n", result.Collisions)
+ fmt.Fprintf(os.Stderr, "Colliding issue IDs: %v\n", result.CollisionIDs)
fmt.Fprintf(os.Stderr, "\nCollision detected! Use --resolve-collisions to automatically remap colliding issues.\n")
fmt.Fprintf(os.Stderr, "Or use --dry-run to preview without making changes.\n")
os.Exit(1)
}
-
- // Resolve collisions by scoring and remapping
- fmt.Fprintf(os.Stderr, "\nResolving collisions...\n")
-
- // Get all existing issues for scoring
- allExistingIssues, err := store.SearchIssues(ctx, "", types.IssueFilter{})
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error getting existing issues: %v\n", err)
- os.Exit(1)
- }
-
- // Score collisions
- if err := sqlite.ScoreCollisions(ctx, sqliteStore, collisionResult.Collisions, allExistingIssues); err != nil {
- fmt.Fprintf(os.Stderr, "Error scoring collisions: %v\n", err)
- os.Exit(1)
- }
-
- // Remap collisions
- idMapping, err = sqlite.RemapCollisions(ctx, sqliteStore, collisionResult.Collisions, allExistingIssues)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error remapping collisions: %v\n", err)
- os.Exit(1)
- }
-
- // Print remapping report
- printRemappingReport(idMapping, collisionResult.Collisions)
-
- // Colliding issues were already created with new IDs
- created = len(collisionResult.Collisions)
-
- // Remove colliding issues from allIssues (they're already processed)
- filteredIssues := make([]*types.Issue, 0)
- collidingIDs := make(map[string]bool)
- for _, collision := range collisionResult.Collisions {
- collidingIDs[collision.ID] = true
- }
- for _, issue := range allIssues {
- if !collidingIDs[issue.ID] {
- filteredIssues = append(filteredIssues, issue)
- }
- }
- allIssues = filteredIssues
- } else if dryRun {
- // No collisions in dry-run mode
- fmt.Fprintf(os.Stderr, "No collisions detected.\n")
- fmt.Fprintf(os.Stderr, "Would create %d new issues, update %d existing issues\n",
- len(collisionResult.NewIssues), len(collisionResult.ExactMatches))
- os.Exit(0)
- }
-
- // Phase 4: Process remaining issues (exact matches and new issues)
- // Separate existing issues (to update) from new issues (to batch create)
- var newIssues []*types.Issue
- seenNew := make(map[string]int) // Track duplicates within import batch
- for _, issue := range allIssues {
- // Check if issue exists
- existing, err := store.GetIssue(ctx, issue.ID)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error checking issue %s: %v\n", issue.ID, err)
- os.Exit(1)
- }
-
- if existing != nil {
- if skipUpdate {
- skipped++
- continue
- }
-
- // Update existing issue
- // Parse raw JSON to detect which fields are present
- var rawData map[string]interface{}
- jsonBytes, _ := json.Marshal(issue)
- if err := json.Unmarshal(jsonBytes, &rawData); err != nil {
- // If unmarshaling fails, treat all fields as present
- rawData = make(map[string]interface{})
- }
-
- updates := make(map[string]interface{})
- if _, ok := rawData["title"]; ok {
- updates["title"] = issue.Title
- }
- if _, ok := rawData["description"]; ok {
- updates["description"] = issue.Description
- }
- if _, ok := rawData["design"]; ok {
- updates["design"] = issue.Design
- }
- if _, ok := rawData["acceptance_criteria"]; ok {
- updates["acceptance_criteria"] = issue.AcceptanceCriteria
- }
- if _, ok := rawData["notes"]; ok {
- updates["notes"] = issue.Notes
- }
- if _, ok := rawData["status"]; ok {
- updates["status"] = issue.Status
- }
- if _, ok := rawData["priority"]; ok {
- updates["priority"] = issue.Priority
- }
- if _, ok := rawData["issue_type"]; ok {
- updates["issue_type"] = issue.IssueType
- }
- if _, ok := rawData["assignee"]; ok {
- updates["assignee"] = issue.Assignee
- }
- if _, ok := rawData["estimated_minutes"]; ok {
- if issue.EstimatedMinutes != nil {
- updates["estimated_minutes"] = *issue.EstimatedMinutes
- } else {
- updates["estimated_minutes"] = nil
- }
- }
- if _, ok := rawData["external_ref"]; ok {
- if issue.ExternalRef != nil {
- updates["external_ref"] = *issue.ExternalRef
- } else {
- updates["external_ref"] = nil
- }
- }
-
- if err := store.UpdateIssue(ctx, issue.ID, updates, "import"); err != nil {
- fmt.Fprintf(os.Stderr, "Error updating issue %s: %v\n", issue.ID, err)
- os.Exit(1)
- }
- updated++
- } else {
- // Normalize closed_at based on status before creating (enforce invariant)
- if issue.Status == types.StatusClosed {
- // Status is closed: ensure closed_at is set
- if issue.ClosedAt == nil {
- now := time.Now()
- issue.ClosedAt = &now
- }
- } else {
- // Status is not closed: ensure closed_at is NULL
- issue.ClosedAt = nil
- }
-
- // Handle duplicates within the same import batch (last one wins)
- if idx, ok := seenNew[issue.ID]; ok {
- // Last one wins regardless of skipUpdate (skipUpdate only applies to existing DB issues)
- newIssues[idx] = issue
- } else {
- seenNew[issue.ID] = len(newIssues)
- newIssues = append(newIssues, issue)
- }
- }
- }
-
- // Batch create all new issues in one atomic transaction (5-15x faster!)
- if len(newIssues) > 0 {
- if err := store.CreateIssues(ctx, newIssues, "import"); err != nil {
- fmt.Fprintf(os.Stderr, "Error creating issues: %v\n", err)
+ fmt.Fprintf(os.Stderr, "Import failed: %v\n", err)
os.Exit(1)
}
- created += len(newIssues)
- }
- // Phase 5: Sync ID counters after importing issues with explicit IDs
- // This prevents ID collisions with subsequently auto-generated issues
- // CRITICAL: If this fails, subsequent auto-generated IDs WILL collide with imported issues
- if err := sqliteStore.SyncAllCounters(ctx); err != nil {
- fmt.Fprintf(os.Stderr, "Error: failed to sync ID counters: %v\n", err)
- fmt.Fprintf(os.Stderr, "Cannot proceed - auto-generated IDs would collide with imported issues.\n")
- os.Exit(1)
- }
-
- // Phase 6: Process dependencies
- // Do this after all issues are created to handle forward references
- var depsCreated, depsSkipped int
- for _, issue := range allIssues {
- if len(issue.Dependencies) == 0 {
- continue
- }
-
- for _, dep := range issue.Dependencies {
- // Check if dependency already exists
- existingDeps, err := store.GetDependencyRecords(ctx, dep.IssueID)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error checking dependencies for %s: %v\n", dep.IssueID, err)
- os.Exit(1)
- }
-
- // Skip if this exact dependency already exists
- exists := false
- for _, existing := range existingDeps {
- if existing.DependsOnID == dep.DependsOnID && existing.Type == dep.Type {
- exists = true
- break
- }
- }
-
- if exists {
- depsSkipped++
- continue
- }
-
- // Add dependency
- if err := store.AddDependency(ctx, dep, "import"); err != nil {
- if strict {
- // In strict mode, fail on any dependency error
- fmt.Fprintf(os.Stderr, "Error: could not add dependency %s → %s: %v\n",
- dep.IssueID, dep.DependsOnID, err)
- fmt.Fprintf(os.Stderr, "Use --strict=false to treat dependency errors as warnings\n")
- os.Exit(1)
- }
- // In non-strict mode, ignore errors for missing target issues or cycles
- // This can happen if dependencies reference issues not in the import
- fmt.Fprintf(os.Stderr, "Warning: could not add dependency %s → %s: %v\n",
- dep.IssueID, dep.DependsOnID, err)
- continue
- }
- depsCreated++
+ // Handle dry-run mode
+ if dryRun {
+ if result.Collisions > 0 {
+ fmt.Fprintf(os.Stderr, "\n=== Collision Detection Report ===\n")
+ fmt.Fprintf(os.Stderr, "COLLISIONS DETECTED: %d\n", result.Collisions)
+ fmt.Fprintf(os.Stderr, "Colliding issue IDs: %v\n", result.CollisionIDs)
+ } else {
+ fmt.Fprintf(os.Stderr, "No collisions detected.\n")
}
+ fmt.Fprintf(os.Stderr, "Would create %d new issues, update %d existing issues\n",
+ result.Created, result.Updated)
+ fmt.Fprintf(os.Stderr, "\nDry-run mode: no changes made\n")
+ os.Exit(0)
}
- // Phase 7: Process labels
- // Sync labels for all imported issues
- var labelsAdded, labelsRemoved int
- for _, issue := range allIssues {
- if issue.Labels == nil {
- continue
- }
-
- // Get current labels for the issue
- currentLabels, err := store.GetLabels(ctx, issue.ID)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error getting labels for %s: %v\n", issue.ID, err)
- os.Exit(1)
+ // Print remapping report if collisions were resolved
+ if len(result.IDMapping) > 0 {
+ fmt.Fprintf(os.Stderr, "\n=== Remapping Report ===\n")
+ fmt.Fprintf(os.Stderr, "Issues remapped: %d\n\n", len(result.IDMapping))
+
+ // Sort by old ID for consistent output
+ type mapping struct {
+ oldID string
+ newID string
}
-
- // Convert slices to maps for easier comparison
- currentLabelMap := make(map[string]bool)
- for _, label := range currentLabels {
- currentLabelMap[label] = true
+ mappings := make([]mapping, 0, len(result.IDMapping))
+ for oldID, newID := range result.IDMapping {
+ mappings = append(mappings, mapping{oldID, newID})
}
- importedLabelMap := make(map[string]bool)
- for _, label := range issue.Labels {
- importedLabelMap[label] = true
- }
-
- // Add missing labels
- for _, label := range issue.Labels {
- if !currentLabelMap[label] {
- if err := store.AddLabel(ctx, issue.ID, label, "import"); err != nil {
- fmt.Fprintf(os.Stderr, "Error adding label %s to %s: %v\n", label, issue.ID, err)
- os.Exit(1)
- }
- labelsAdded++
- }
- }
-
- // Remove labels not in imported data
- for _, label := range currentLabels {
- if !importedLabelMap[label] {
- if err := store.RemoveLabel(ctx, issue.ID, label, "import"); err != nil {
- fmt.Fprintf(os.Stderr, "Error removing label %s from %s: %v\n", label, issue.ID, err)
- os.Exit(1)
- }
- labelsRemoved++
- }
+ sort.Slice(mappings, func(i, j int) bool {
+ return mappings[i].oldID < mappings[j].oldID
+ })
+
+ fmt.Fprintf(os.Stderr, "Remappings:\n")
+ for _, m := range mappings {
+ fmt.Fprintf(os.Stderr, " %s → %s\n", m.oldID, m.newID)
}
+ fmt.Fprintf(os.Stderr, "\nAll text and dependency references have been updated.\n")
}
// Schedule auto-flush after import completes
markDirtyAndScheduleFlush()
// Print summary
- fmt.Fprintf(os.Stderr, "Import complete: %d created, %d updated", created, updated)
- if skipped > 0 {
- fmt.Fprintf(os.Stderr, ", %d skipped", skipped)
- }
- if depsCreated > 0 || depsSkipped > 0 {
- fmt.Fprintf(os.Stderr, ", %d dependencies added", depsCreated)
- if depsSkipped > 0 {
- fmt.Fprintf(os.Stderr, " (%d already existed)", depsSkipped)
- }
+ fmt.Fprintf(os.Stderr, "Import complete: %d created, %d updated", result.Created, result.Updated)
+ if result.Skipped > 0 {
+ fmt.Fprintf(os.Stderr, ", %d skipped", result.Skipped)
}
- if len(idMapping) > 0 {
- fmt.Fprintf(os.Stderr, ", %d issues remapped", len(idMapping))
- }
- if labelsAdded > 0 || labelsRemoved > 0 {
- fmt.Fprintf(os.Stderr, ", %d labels synced", labelsAdded+labelsRemoved)
- if labelsAdded > 0 && labelsRemoved > 0 {
- fmt.Fprintf(os.Stderr, " (%d added, %d removed)", labelsAdded, labelsRemoved)
- } else if labelsAdded > 0 {
- fmt.Fprintf(os.Stderr, " (%d added)", labelsAdded)
- } else {
- fmt.Fprintf(os.Stderr, " (%d removed)", labelsRemoved)
- }
+ if len(result.IDMapping) > 0 {
+ fmt.Fprintf(os.Stderr, ", %d issues remapped", len(result.IDMapping))
}
fmt.Fprintf(os.Stderr, "\n")
},
}
-// printCollisionReport prints a detailed report of detected collisions
-func printCollisionReport(result *sqlite.CollisionResult) {
- fmt.Fprintf(os.Stderr, "\n=== Collision Detection Report ===\n")
- fmt.Fprintf(os.Stderr, "Exact matches (idempotent): %d\n", len(result.ExactMatches))
- fmt.Fprintf(os.Stderr, "New issues: %d\n", len(result.NewIssues))
- fmt.Fprintf(os.Stderr, "COLLISIONS DETECTED: %d\n\n", len(result.Collisions))
-
- if len(result.Collisions) > 0 {
- fmt.Fprintf(os.Stderr, "Colliding issues:\n")
- for _, collision := range result.Collisions {
- fmt.Fprintf(os.Stderr, " %s: %s\n", collision.ID, collision.IncomingIssue.Title)
- fmt.Fprintf(os.Stderr, " Conflicting fields: %v\n", collision.ConflictingFields)
- }
- }
-}
-
-// printRemappingReport prints a report of ID remappings with reference scores
-func printRemappingReport(idMapping map[string]string, collisions []*sqlite.CollisionDetail) {
- fmt.Fprintf(os.Stderr, "\n=== Remapping Report ===\n")
- fmt.Fprintf(os.Stderr, "Issues remapped: %d\n\n", len(idMapping))
-
- // Sort by old ID for consistent output
- type mapping struct {
- oldID string
- newID string
- score int
- }
- mappings := make([]mapping, 0, len(idMapping))
-
- scoreMap := make(map[string]int)
- for _, collision := range collisions {
- scoreMap[collision.ID] = collision.ReferenceScore
- }
-
- for oldID, newID := range idMapping {
- mappings = append(mappings, mapping{
- oldID: oldID,
- newID: newID,
- score: scoreMap[oldID],
- })
- }
-
- sort.Slice(mappings, func(i, j int) bool {
- return mappings[i].score < mappings[j].score
- })
-
- fmt.Fprintf(os.Stderr, "Remappings (sorted by reference count):\n")
- for _, m := range mappings {
- fmt.Fprintf(os.Stderr, " %s → %s (refs: %d)\n", m.oldID, m.newID, m.score)
- }
- fmt.Fprintf(os.Stderr, "\nAll text and dependency references have been updated.\n")
-}
-
func init() {
importCmd.Flags().StringP("input", "i", "", "Input file (default: stdin)")
importCmd.Flags().BoolP("skip-existing", "s", false, "Skip existing issues instead of updating them")
diff --git a/cmd/bd/main.go b/cmd/bd/main.go
index f0b3793..ee73a5c 100644
--- a/cmd/bd/main.go
+++ b/cmd/bd/main.go
@@ -712,12 +712,33 @@ func autoImportIfNewer() {
}
// Detect collisions before importing (bd-228 fix)
- sqliteStore, ok := store.(*sqlite.SQLiteStorage)
- if !ok {
- // Not SQLite - skip auto-import to avoid silent data loss without collision detection
- fmt.Fprintf(os.Stderr, "Auto-import disabled for non-SQLite backend (no collision detection).\n")
- fmt.Fprintf(os.Stderr, "To import manually, run: bd import -i %s\n", jsonlPath)
- return
+ // Auto-import needs direct SQLite access for collision detection
+ var sqliteStore *sqlite.SQLiteStorage
+
+ if store != nil {
+ // Direct mode - try to use existing store
+ var ok bool
+ sqliteStore, ok = store.(*sqlite.SQLiteStorage)
+ if !ok {
+ fmt.Fprintf(os.Stderr, "Auto-import disabled for non-SQLite backend (no collision detection).\n")
+ fmt.Fprintf(os.Stderr, "To import manually, run: bd import -i %s\n", jsonlPath)
+ return
+ }
+ } else {
+ // Daemon mode - open direct connection for auto-import
+ if dbPath == "" {
+ if os.Getenv("BD_DEBUG") != "" {
+ fmt.Fprintf(os.Stderr, "Debug: auto-import skipped, no database path\n")
+ }
+ return
+ }
+ var err error
+ sqliteStore, err = sqlite.New(dbPath)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Auto-import failed: could not open database: %v\n", err)
+ return
+ }
+ defer sqliteStore.Close()
}
collisionResult, err := sqlite.DetectCollisions(ctx, sqliteStore, allIssues)