diff --git a/.beads/beads.jsonl b/.beads/beads.jsonl index 88b45cc8..7eeffa58 100644 --- a/.beads/beads.jsonl +++ b/.beads/beads.jsonl @@ -1,16 +1,124 @@ {"id":"bd-1","title":"Investigate jujutsu integration for beads","description":"Research and document how beads could integrate with jujutsu (jj), the next-generation VCS. Key areas to explore:\n- How jj's operation model differs from git (immutable operations, working-copy-as-commit)\n- JSONL sync strategy with jj's conflict resolution model\n- Daemon compatibility with jj's more frequent rewrites\n- Whether auto-import/export needs changes for jj workflows\n- Example configurations and documentation updates needed","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-23T09:23:23.582009-07:00","updated_at":"2025-10-27T22:22:23.813236-07:00"} {"id":"bd-10","title":"Add \"bd daemons\" command for multi-daemon management","description":"Add a new \"bd daemons\" command with subcommands to manage daemon processes across all beads repositories/worktrees. Should show all running daemons with metadata (version, workspace, uptime, last sync), allow stopping/restarting individual daemons, auto-clean stale processes, view logs, and show exclusive lock status.","design":"Subcommands:\n- list: Show all running daemons with metadata (workspace, PID, version, socket path, uptime, last activity, exclusive lock status)\n- stop \u003cpath|pid\u003e: Gracefully stop a specific daemon\n- restart \u003cpath|pid\u003e: Stop and restart daemon\n- killall: Emergency stop all daemons\n- health: Verify each daemon responds to ping\n- logs \u003cpath\u003e: View daemon logs\n\nFeatures:\n- Auto-clean stale sockets/dead processes\n- Discovery: Scan for .beads/bd.sock files + running processes\n- Communication: Use existing socket protocol, add GET /status endpoint for metadata","status":"in_progress","priority":1,"issue_type":"epic","created_at":"2025-10-26T16:53:40.970042-07:00","updated_at":"2025-10-27T22:22:23.815728-07:00"} +{"id":"bd-100","title":"GH#146: No color showing in terminal for some users","description":"User reports color not working in macOS (Taho 26.0.1) with iTerm 3.6.4 and Terminal.app, despite color working elsewhere in terminal. Python rich and printf escape codes work.\n\nNeed to investigate:\n- Is NO_COLOR env var set?\n- Terminal type detection?\n- fatih/color library configuration\n- Does bd list show colors? bd ready? bd init?\n- What's the output of: echo $TERM, echo $NO_COLOR","status":"open","priority":2,"issue_type":"bug","created_at":"2025-10-24T22:26:36.22163-07:00","updated_at":"2025-10-25T23:15:33.508654-07:00","external_ref":"github:146"} +{"id":"bd-101","title":"Fix nil pointer crash in bd reopen command","description":"bd reopen crashes with SIGSEGV at reopen.go:30. Nil pointer dereference when trying to reopen an issue.","notes":"Fixed by adding daemon RPC support to reopen command. Pattern: check daemonClient != nil first, use RPC UpdateArgs with Status=open, fall back to direct store if daemon unavailable.","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-25T10:30:31.602438-07:00","updated_at":"2025-10-25T23:15:33.50884-07:00","closed_at":"2025-10-25T10:33:39.016623-07:00"} +{"id":"bd-102","title":"Address gosec security warnings (102 issues)","description":"Security linter warnings: file permissions (0755 should be 0750), G304 file inclusion via variable, G204 subprocess launches. Many are false positives but should be reviewed.","design":"Review each gosec warning. Add exclusions for legitimate cases to .golangci.yml. Fix real security issues (overly permissive file modes).","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-25T13:47:10.719134-07:00","updated_at":"2025-10-25T23:15:33.50904-07:00"} +{"id":"bd-103","title":"Multi-project MCP context switching (GH#145)","description":"Enable MCP server to manage multiple beads projects in a single session with per-request workspace_root parameter.\n\nCurrent bug: set_context(workspace_root) doesn't actually switch sockets - all operations hit first initialized socket.\n\nUse case: Managing tasks across multiple organizations with different permission models (internal, partners, open source).\n\nArchitecture: Connection pool keyed by workspace_root, each maintaining its own daemon socket connection. Request-scoped routing using ContextVar to avoid global state races.\n\nSee GH#145 for full requirements and user context.","design":"✅ APPROVED WITH MODIFICATIONS by architectural review (2025-10-25)\n\nLSP-style model is correct: Single MCP server → per-project daemons → isolated databases.\n\nCRITICAL CHANGES from review:\n1. **Simplify connection pool**: No LRU eviction initially (typical user: 2-5 projects)\n2. **Add asyncio.Lock**: Prevent race conditions in pool access\n3. **Defer health checks**: Only retry on failure, not preemptive pings\n4. **Handle submodules**: Check local .beads BEFORE git toplevel\n5. **Path canonicalization**: realpath + git toplevel with caching\n\nRISKS MITIGATED:\n- Global _client bug: Replace with connection pool keyed by canonical path\n- Race conditions: Add asyncio.Lock for pool mutations\n- Submodule edge case: Check .beads directory first\n- Stale sockets: Retry once on connection failure\n\nEstimated effort: 2.5-3.5 days (simplified from 2.5-4.5 days)\nConfidence: 8/10","acceptance_criteria":"- Multiple projects can be accessed in single MCP session\n- Per-request workspace_root parameter works on all tools\n- No cross-project data leakage\n- Concurrent calls to different projects work correctly\n- Stale sockets auto-reconnect with retry/backoff\n- Integration tests verify isolation across 2+ temp repos\n- set_context() still works as default fallback","notes":"Review doc: docs/bd-103-architectural-review.md\n\nImplementation order:\n1. bd-108 (connection manager) - Foundation with pool + lock\n2. bd-104 (ContextVar routing) - Per-request workspace\n3. bd-106 (require_context) - Validation\n4. bd-105 (tests) - Concurrency + edge cases\n5. bd-109 (docs) - Usage guide\n6. [deleted:bd-142] (health checks) - DEFERRED to Phase 2","status":"closed","priority":1,"issue_type":"epic","assignee":"amp","created_at":"2025-10-25T13:59:57.231937-07:00","updated_at":"2025-10-25T23:15:33.522558-07:00","closed_at":"2025-10-25T14:36:02.046142-07:00"} +{"id":"bd-104","title":"Implement request-scoped routing with ContextVar","description":"Add ContextVar-based routing to avoid global state races during concurrent multi-project calls.\n\nApproach:\n- Define current_workspace: ContextVar[str|None] in server.py\n- Add @with_workspace decorator that resolves workspace_root (via _resolve_workspace_root + realpath)\n- Set ContextVar for duration of tool call, reset after\n- Falls back to set_context default (BEADS_WORKING_DIR) if workspace_root not provided\n- beads_mcp.tools.get_client() reads current_workspace from ContextVar\n\nBlocks: bd-103 (connection manager must exist first)","design":"Decorator pattern with ContextVar for request-scoped workspace routing.\n\n@with_workspace decorator:\n- Extract workspace_root parameter from tool call\n- Resolve via _resolve_workspace_root + realpath\n- Set current_workspace ContextVar for request duration\n- Falls back to BEADS_WORKING_DIR if workspace_root not provided\n- Reset ContextVar after tool completes\n\nApplied to all tools in server.py. _get_client() reads current_workspace.\n\n⚠️ CONCURRENCY GOTCHA (from architectural review):\n- ContextVar doesn't propagate to asyncio.create_task() spawned tasks\n- SOLUTION: Keep tool calls synchronous, no background task spawning\n- If background tasks needed: use contextvars.copy_context()\n\nDocument this limitation in bd-109.","notes":"Blocks on bd-108 (connection pool must exist first).\n\nCRITICAL: Do NOT spawn background tasks within tool implementations.\nContextVar propagation to spawned tasks is unreliable.","status":"closed","priority":1,"issue_type":"task","assignee":"amp","created_at":"2025-10-25T14:00:27.895512-07:00","updated_at":"2025-10-25T23:15:33.522814-07:00","closed_at":"2025-10-25T14:32:36.531658-07:00","dependencies":[{"issue_id":"bd-104","depends_on_id":"bd-103","type":"parent-child","created_at":"2025-10-25T14:00:27.896366-07:00","created_by":"daemon"}]} +{"id":"bd-105","title":"Add integration tests for multi-project MCP switching","description":"Comprehensive tests to verify multi-project isolation, concurrency, and edge cases.\n\nEXPANDED TEST COVERAGE (per architectural review):\n\n**Concurrency tests (CRITICAL):**\n- asyncio.gather() with calls to different workspace_root values\n- Verify no cross-project data leakage\n- Verify pool lock prevents race conditions\n\n**Edge case tests:**\n- Submodule handling: Parent repo vs submodule with own .beads\n- Symlink deduplication: Same physical path via different symlinks\n- Stale socket recovery: Kill daemon, verify retry on failure\n- Missing .beads directory handling\n\n**Isolation tests:**\n- Create 2+ temp repos with bd init\n- Verify operations in project A don't affect project B\n- Stress test: many parallel calls across 3-5 repos\n\nEstimated effort: M (1-2 days) including fixtures for temp repos and daemon process management","design":"Test structure:\n\n1. test_concurrent_multi_project.py:\n - asyncio.gather with 2+ projects\n - Verify pool lock prevents corruption\n \n2. test_path_canonicalization.py:\n - Submodule edge case (check .beads first)\n - Symlink deduplication (realpath normalization)\n \n3. test_stale_socket_recovery.py:\n - Kill daemon mid-session\n - Verify retry-on-failure works\n \n4. test_cross_project_isolation.py:\n - Create issues in project A\n - List from project B, verify empty\n - No data leakage\n\nUse pytest fixtures for temp repos and daemon lifecycle.","acceptance_criteria":"- All concurrency tests pass with asyncio.gather\n- Submodule edge case handled correctly\n- Symlinks deduplicated to same connection\n- Stale socket retry works\n- No cross-project data leakage in stress tests","status":"closed","priority":1,"issue_type":"task","assignee":"amp","created_at":"2025-10-25T14:00:27.896623-07:00","updated_at":"2025-10-25T23:15:33.509737-07:00","closed_at":"2025-10-25T14:35:13.09686-07:00","dependencies":[{"issue_id":"bd-105","depends_on_id":"bd-103","type":"parent-child","created_at":"2025-10-25T14:00:27.90028-07:00","created_by":"daemon"}]} +{"id":"bd-106","title":"Fix require_context to support per-request workspace_root","description":"Update require_context decorator to pass if either:\n- workspace_root was provided on the tool call (via ContextVar), OR\n- BEADS_WORKING_DIR is set (from set_context)\n\nStop using BEADS_DB as router - treat it only as CLI fallback.\n\nEnsures backward compatibility with set_context() while supporting new per-request routing.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-25T14:00:27.896646-07:00","updated_at":"2025-10-25T23:15:33.509989-07:00","closed_at":"2025-10-25T14:32:36.533618-07:00","dependencies":[{"issue_id":"bd-106","depends_on_id":"bd-103","type":"parent-child","created_at":"2025-10-25T14:00:27.89804-07:00","created_by":"daemon"}]} +{"id":"bd-107","title":"Add health checks and reconnection logic for stale sockets","description":"Handle stale/broken socket connections after daemon restarts or upgrades.\n\nFeatures:\n- ping/health_check method on client\n- Check before use or periodic health check\n- On failure: drop from pool, attempt reconnect with exponential backoff\n- Clear error propagation if reconnect fails after retries\n- Handle version mismatch after daemon upgrade\n- Handle long-idle connections closed by daemon","design":"Add async ping() to DaemonClient. ConnectionManager.get_client() pings before returning cached client. On failure, del from pool and retry connect. Bounded retry (3-5 attempts) with backoff.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-25T14:00:27.8967-07:00","updated_at":"2025-10-25T23:15:33.510234-07:00","closed_at":"2025-10-25T17:35:42.762836-07:00"} +{"id":"bd-108","title":"Add connection manager for per-project daemon sockets","description":"Create connection pool for managing multiple daemon socket connections in beads_mcp.tools.\n\nSIMPLIFIED APPROACH (per architectural review):\n- Connection pool dict[str, BdClientBase] keyed by canonical path\n- Add asyncio.Lock for thread-safe pool access (CRITICAL)\n- Path canonicalization with @lru_cache for performance\n- NO LRU eviction (start simple, add if monitoring shows memory issues)\n- NO preemptive health checks (only retry on failure)\n\nFeatures:\n- get_client(workspace_root) → returns client for that project\n- Canonicalization: realpath + git toplevel (handles symlinks)\n- Submodule-aware: Check local .beads BEFORE git toplevel\n- Auto-start daemon if socket missing (existing behavior)\n- Validate version on connect (existing behavior)\n\nCRITICAL: Replace global _client singleton with pool to fix set_context() bug.","design":"Implementation in tools.py:\n\n```python\nfrom contextvars import ContextVar\nimport asyncio\nfrom functools import lru_cache\n\ncurrent_workspace: ContextVar[str | None] = ContextVar('workspace', default=None)\n_connection_pool: Dict[str, BdClientBase] = {}\n_pool_lock = asyncio.Lock() # Prevent race conditions\n\n@lru_cache(maxsize=128)\ndef _canonicalize_path(path: str) -\u003e str:\n # 1. realpath to resolve symlinks\n real = os.path.realpath(path)\n \n # 2. Check local .beads (submodule edge case)\n if os.path.exists(os.path.join(real, \".beads\")):\n return real\n \n # 3. Try git toplevel\n return _resolve_workspace_root(real)\n\nasync def _get_client() -\u003e BdClientBase:\n workspace = current_workspace.get() or os.environ.get(\"BEADS_WORKING_DIR\")\n if not workspace:\n raise BdError(\"No workspace set\")\n \n canonical = _canonicalize_path(workspace)\n \n async with _pool_lock: # CRITICAL: prevent concurrent mutations\n if canonical not in _connection_pool:\n _connection_pool[canonical] = create_bd_client(\n prefer_daemon=True,\n working_dir=canonical\n )\n return _connection_pool[canonical]\n```\n\n~200 LOC total (simplified from ~400-500)","status":"closed","priority":1,"issue_type":"task","assignee":"amp","created_at":"2025-10-25T14:00:27.896896-07:00","updated_at":"2025-10-25T23:15:33.511078-07:00","closed_at":"2025-10-25T14:31:08.910695-07:00","dependencies":[{"issue_id":"bd-108","depends_on_id":"bd-103","type":"parent-child","created_at":"2025-10-25T14:00:27.89917-07:00","created_by":"daemon"}]} +{"id":"bd-109","title":"Update MCP multi-project documentation","description":"Update documentation for multi-project workflow in README.md, AGENTS.md, and MCP integration docs.\n\nEXPANDED SECTIONS (per architectural review):\n\n**Usage examples:**\n- Per-request workspace_root parameter usage\n- Concurrent multi-project queries with asyncio.gather\n- Migration from set_context() to workspace_root parameter\n\n**Architecture notes:**\n- Connection pooling behavior (no limits initially)\n- set_context() as default fallback (still supported)\n- Library users NOT affected (all changes in MCP layer)\n\n**Concurrency gotchas (CRITICAL):**\n- ContextVar doesn't propagate to asyncio.create_task()\n- Do NOT spawn background tasks in tool implementations\n- All tool calls should be synchronous/sequential\n\n**Troubleshooting:**\n- Stale sockets (retry once on failure)\n- Version mismatches (auto-detected since v0.16.0)\n- Path aliasing via symlinks (deduplicated by realpath)\n- Submodules with own .beads (handled correctly)\n\n**Use cases:**\n- Multi-organization collaboration (GH#145)\n- Parallel project management scripts\n- Cross-project queries","design":"Documentation structure:\n\n1. integrations/beads-mcp/README.md:\n - Add \"Multi-Project Support\" section\n - workspace_root parameter examples\n - Connection pool behavior\n \n2. AGENTS.md:\n - Update MCP section with workspace_root usage\n - Add concurrency warning (no spawned tasks)\n - Document library non-impact\n \n3. New: docs/MCP_MULTI_PROJECT.md:\n - Detailed architecture explanation\n - Migration guide from set_context()\n - Troubleshooting guide\n - Edge cases (submodules, symlinks)","status":"closed","priority":2,"issue_type":"task","assignee":"amp","created_at":"2025-10-25T14:00:27.897025-07:00","updated_at":"2025-10-25T23:15:33.511411-07:00","closed_at":"2025-10-25T14:35:55.392654-07:00","dependencies":[{"issue_id":"bd-109","depends_on_id":"bd-103","type":"parent-child","created_at":"2025-10-25T14:00:27.901495-07:00","created_by":"daemon"}]} {"id":"bd-11","title":"Update AGENTS.md and README.md with \"bd daemons\" documentation","description":"Document the new \"bd daemons\" command and all subcommands in AGENTS.md and README.md. Include examples and troubleshooting guidance.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-26T19:41:11.099254-07:00","updated_at":"2025-10-27T22:22:23.815967-07:00"} -{"id":"bd-12","title":"Implement \"bd daemons logs\" subcommand","description":"Add command to view daemon logs for a specific workspace. Requires daemon logging to file (may need separate issue for log infrastructure).","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-26T19:41:11.099659-07:00","updated_at":"2025-10-27T22:22:23.816207-07:00"} -{"id":"bd-13","title":"Test database naming","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T18:27:28.309676-07:00","updated_at":"2025-10-27T22:22:23.816439-07:00"} -{"id":"bd-14","title":"Final validation test","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T18:27:28.310533-07:00","updated_at":"2025-10-27T22:22:23.816672-07:00"} -{"id":"bd-15","title":"Update LINTING.md with current baseline","description":"After cleanup, document the remaining acceptable baseline in LINTING.md so we can track regression.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T18:53:10.38679-07:00","updated_at":"2025-10-27T22:22:23.816904-07:00"} +{"id":"bd-110","title":"bd daemon auto-sync can wipe out issues.jsonl when database is empty","description":"During dogfooding session, bd daemon auto-sync exported empty database to JSONL, losing all 177 issues. Had to git restore to recover.\n\nRoot cause: bd export doesn't check if database is empty before exporting. When daemon has empty/wrong database, it wipes out valid JSONL file.\n\nImpact: DATA LOSS","design":"Add safeguard in bd export:\n1. Count total issues in database before export\n2. If count is 0, refuse to export and show error\n3. Provide --force flag to override if truly want empty export\n\nAlternative: Check if target JSONL exists and has issues, warn if about to replace with empty export","acceptance_criteria":"- bd export refuses to export when database has 0 issues\n- Clear error message: \"Refusing to export empty database (0 issues). Use --force to override.\"\n- --force flag allows override for intentional empty exports\n- Test: export with empty db fails, export with --force succeeds","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-25T16:29:16.045548-07:00","updated_at":"2025-10-25T23:15:33.511656-07:00","closed_at":"2025-10-25T16:35:38.233384-07:00"} +{"id":"bd-111","title":"bd import doesn't update database modification time (WAL mode)","description":"When running bd import in WAL mode, the -wal file is updated but main .db file timestamp stays old. This breaks staleness detection which only checks main .db file.\n\nDiscovered during dogfooding when import didn't trigger staleness refresh.\n\nImpact: Staleness checks fail to detect that database is newer than expected","design":"Two options:\n1. Checkpoint WAL after import to flush changes to main .db file\n2. Update staleness detection to check both .db and -wal file timestamps\n\nOption 1 is simpler and safer - just add PRAGMA wal_checkpoint(FULL) after import completes","acceptance_criteria":"- After bd import, main .db file modification time is updated\n- Staleness detection correctly sees database as fresh\n- Test: import, check .db mtime, verify it's recent","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-25T16:29:16.048176-07:00","updated_at":"2025-10-25T23:15:33.511871-07:00","closed_at":"2025-10-25T16:37:49.940187-07:00"} +{"id":"bd-112","title":"bd should show which database file it's using","description":"During dogfooding, bd showed \"0 issues\" when correct database had 177 issues. Confusion arose from which database path was being used (daemon default vs explicit --db flag).\n\nUsers need clear feedback about which database file bd is actually using, especially when daemon is involved.\n\nImpact: User confusion, working with wrong database unknowingly","design":"Add database path to verbose output or as a bd info command:\n1. bd info shows current database path, daemon status\n2. OR: bd ready/list/etc --verbose shows \"Using database: /path/to/.beads/beads.db\"\n3. Consider adding to bd status output\n\nWhen database path differs from expected, show warning","acceptance_criteria":"- User can easily determine which database file bd is using\n- bd info or similar command shows full database path\n- When using unexpected database (e.g., daemon vs explicit --db), show clear indication\n- Documentation updated with how to check database path","status":"closed","priority":1,"issue_type":"feature","assignee":"amp","created_at":"2025-10-25T16:29:16.059118-07:00","updated_at":"2025-10-25T23:15:33.512099-07:00","closed_at":"2025-10-25T16:42:45.768187-07:00"} +{"id":"bd-113","title":"Implement configurable sort policy for GetReadyWork","description":"Add SortPolicy field to WorkFilter to support different sorting strategies:\n- hybrid (default): Recent issues by priority, old by age\n- priority: Strict priority ordering for autonomous execution\n- oldest: Backlog clearing mode\n\nSolves issue where VC executor selects low-priority work instead of critical P0 work.","design":"See SORT_POLICY_DESIGN.md for complete design spec including:\n- Type definitions and constants\n- SQL ORDER BY clause generation\n- Testing strategy with test cases\n- CLI integration with --sort flag\n- Migration plan and backwards compatibility","acceptance_criteria":"- SortPolicy type added to types.go\n- buildOrderByClause() implemented in ready.go\n- Unit tests for all 3 policies pass\n- Integration tests verify priority selection order\n- bd ready --sort priority|oldest|hybrid works\n- Empty SortPolicy defaults to hybrid (backwards compatible)\n- Documentation updated in README.md and WORKFLOW.md","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-25T18:46:44.35198-07:00","updated_at":"2025-10-25T23:15:33.51234-07:00","closed_at":"2025-10-25T18:53:02.258745-07:00"} +{"id":"bd-114","title":"Add configurable SortPolicy to GetReadyWork","description":"Add SortPolicy field to WorkFilter to support different ordering strategies: hybrid (default), priority-first, oldest-first. See SORT_POLICY_DESIGN.md for full specification.","design":"See SORT_POLICY_DESIGN.md for complete design.\n\nImplementation summary:\n1. Add SortPolicy type and constants (hybrid, priority, oldest)\n2. Add SortPolicy field to WorkFilter \n3. Implement buildOrderByClause() to generate SQL based on policy\n4. Default to hybrid for backwards compatibility\n5. Add --sort flag to bd ready command\n\nThis enables autonomous execution systems (like VC) to use strict priority ordering while preserving the current hybrid behavior for interactive use.","acceptance_criteria":"Unit tests verify each policy generates correct ORDER BY. Integration tests verify priority, hybrid, and oldest policies select issues in expected order. CLI bd ready --sort priority works. Empty SortPolicy defaults to hybrid (backwards compatible).","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-25T18:51:11.560979-07:00","updated_at":"2025-10-26T12:25:44.40049-07:00","closed_at":"2025-10-26T12:25:44.40049-07:00"} +{"id":"bd-115","title":"Implement exclusive lock protocol for daemon/external tool coexistence","description":"VC (VibeCoder) cannot coexist with bd daemon managing the same database. VC needs deterministic execution and directly manages JSONL sync, but daemon's auto-flush creates timing conflicts and nondeterministic behavior.\n\nCurrent workaround (vc-195): VC kills ALL bd daemon processes with pkill, which is too aggressive and prevents developers from using daemon for their own workflow.\n\nSolution: Implement lock file protocol (.beads/.exclusive-lock) that allows applications to claim exclusive management of a database. bd daemon respects these locks and skips locked databases.\n\nSee VC_DAEMON_EXCLUSION_PROTOCOL.md for full specification.","design":"Lock File Protocol:\n- File: .beads/.exclusive-lock (JSON format)\n- Contains: holder name, PID, hostname, timestamp, version\n- Created when external tool (VC) starts\n- Removed on clean shutdown\n- Stale lock detection: if PID doesn't exist, lock is removed\n\nbd daemon behavior:\n1. Before touching any database, check for .exclusive-lock\n2. If lock exists and valid (PID alive): skip database in sync cycle\n3. If lock is stale (PID dead): remove lock and proceed\n4. If lock is malformed: log warning and skip (fail-safe)\n\nExternal tool behavior:\n1. On startup: create .exclusive-lock with process info\n2. If lock exists, check if stale; fail if another process is running\n3. On shutdown: remove .exclusive-lock\n\nBenefits:\n- Clean separation, no process killing\n- Developer-friendly (can run daemon for other projects)\n- Fail-safe with stale lock detection\n- Extensible for other tools beyond VC","acceptance_criteria":"1. bd daemon skips databases with valid exclusive locks\n2. bd daemon cleans up stale locks automatically\n3. Lock file format documented and implemented\n4. Integration tests show daemon + external tool coexistence\n5. Documentation updated with protocol specification","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-25T22:43:08.994891-07:00","updated_at":"2025-10-25T23:24:55.928527-07:00","closed_at":"2025-10-25T23:24:55.928527-07:00"} +{"id":"bd-116","title":"Add ExclusiveLock struct and JSON marshaling","description":"Create Go struct to represent exclusive lock file format with JSON marshaling support.\n\nFields needed:\n- Holder (string): name of lock holder (e.g., \"vc-executor\")\n- PID (int): process ID\n- Hostname (string): hostname where process is running\n- StartedAt (time.Time): when lock was acquired\n- Version (string): version of lock holder\n\nShould support both Marshal and Unmarshal for reading/writing lock files.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-25T22:43:18.536901-07:00","updated_at":"2025-10-25T23:19:48.792787-07:00","closed_at":"2025-10-25T23:19:48.792787-07:00","dependencies":[{"issue_id":"bd-116","depends_on_id":"bd-115","type":"parent-child","created_at":"2025-10-25T22:43:18.538184-07:00","created_by":"daemon"}]} +{"id":"bd-117","title":"Implement isProcessAlive() helper for PID validation","description":"Implement helper function to check if a process is alive given PID and hostname.\n\nLogic:\n- If hostname != current host: return true (can't verify remote, assume alive)\n- If hostname == current host: check if PID exists using os.FindProcess + Signal(0)\n- Return true if process exists, false otherwise\n\nNeeded for stale lock detection.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-25T22:43:26.074997-07:00","updated_at":"2025-10-25T23:20:24.641036-07:00","closed_at":"2025-10-25T23:20:24.641036-07:00","dependencies":[{"issue_id":"bd-117","depends_on_id":"bd-115","type":"parent-child","created_at":"2025-10-25T22:43:28.313879-07:00","created_by":"daemon"}]} +{"id":"bd-118","title":"Implement shouldSkipDatabase() to check for exclusive locks","description":"Add shouldSkipDatabase() function to daemon that checks for .beads/.exclusive-lock before processing a database.\n\nLogic:\n1. Check if .beads/.exclusive-lock exists\n2. If not: return false (proceed with database)\n3. If yes: read and parse JSON\n4. If malformed: log warning and skip (fail-safe)\n5. If valid: check if PID is alive\n6. If stale (PID dead): remove lock file and proceed\n7. If active (PID alive): log skip message and return true\n\nDepends on ExclusiveLock struct and isProcessAlive() helper.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-25T22:43:34.561247-07:00","updated_at":"2025-10-25T23:21:33.58887-07:00","closed_at":"2025-10-25T23:21:33.58887-07:00","dependencies":[{"issue_id":"bd-118","depends_on_id":"bd-116","type":"blocks","created_at":"2025-10-25T22:43:36.6504-07:00","created_by":"daemon"},{"issue_id":"bd-118","depends_on_id":"bd-117","type":"blocks","created_at":"2025-10-25T22:43:38.730862-07:00","created_by":"daemon"},{"issue_id":"bd-118","depends_on_id":"bd-115","type":"parent-child","created_at":"2025-10-25T22:43:40.602161-07:00","created_by":"daemon"}]} +{"id":"bd-119","title":"Integrate exclusive lock check into daemon sync cycle","description":"Integrate shouldSkipDatabase() into daemon's sync cycle to respect exclusive locks.\n\nBefore processing each database:\n1. Call shouldSkipDatabase(beadsDir)\n2. If true: skip all operations (export, import, commit, push)\n3. If false: proceed with normal sync\n\nAdd appropriate logging:\n- \"Skipping .beads/foo.db (locked by vc-executor, PID 12345)\" when skipping\n- \"Removed stale lock at .beads/foo.db (PID 12345 not found)\" when cleaning up\n\nDepends on shouldSkipDatabase() implementation.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-25T22:43:46.221736-07:00","updated_at":"2025-10-25T23:21:58.454603-07:00","closed_at":"2025-10-25T23:21:58.454603-07:00","dependencies":[{"issue_id":"bd-119","depends_on_id":"bd-118","type":"blocks","created_at":"2025-10-25T22:43:48.204682-07:00","created_by":"daemon"},{"issue_id":"bd-119","depends_on_id":"bd-115","type":"parent-child","created_at":"2025-10-25T22:43:50.283951-07:00","created_by":"daemon"}]} +{"id":"bd-12","title":"Implement \"bd daemons logs\" subcommand","description":"Add command to view daemon logs for a specific workspace. Requires daemon logging to file (may need separate issue for log infrastructure).","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-26T19:41:11.099659-07:00","updated_at":"2025-10-27T22:22:23.816207-07:00","dependencies":[{"issue_id":"bd-12","depends_on_id":"bd-11","type":"parent-child","created_at":"2025-10-24T13:17:40.322877-07:00","created_by":"renumber"}]} +{"id":"bd-120","title":"Add unit tests for exclusive lock detection","description":"Add unit tests for exclusive lock functionality:\n\nTest cases:\n1. No lock file exists -\u003e shouldSkipDatabase returns false\n2. Valid lock with alive PID -\u003e shouldSkipDatabase returns true\n3. Stale lock with dead PID -\u003e removes lock, returns false\n4. Malformed lock JSON -\u003e logs warning, returns true (fail-safe)\n5. Lock with different hostname -\u003e assumes alive, returns true\n6. isProcessAlive() correctly detects running/dead processes\n\nUse test helpers to create lock files with specific PIDs.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-25T22:43:57.616-07:00","updated_at":"2025-10-25T23:22:12.680681-07:00","closed_at":"2025-10-25T23:22:12.680681-07:00","dependencies":[{"issue_id":"bd-120","depends_on_id":"bd-118","type":"blocks","created_at":"2025-10-25T22:44:00.494553-07:00","created_by":"daemon"},{"issue_id":"bd-120","depends_on_id":"bd-115","type":"parent-child","created_at":"2025-10-25T22:44:02.7215-07:00","created_by":"daemon"}]} +{"id":"bd-121","title":"Add integration tests for daemon + external tool coexistence","description":"Add integration tests simulating real-world daemon + external tool usage:\n\nTest scenarios:\n1. Start daemon, create lock file, verify daemon skips database\n2. Create stale lock (with dead PID), start daemon, verify lock cleanup\n3. Multiple lock/unlock cycles\n4. Daemon resumes managing database after lock is removed\n5. Lock file created/removed during daemon operation\n\nShould verify:\n- Daemon log messages correct\n- No JSONL auto-flush when database is locked\n- Daemon resumes normal operation after lock removed","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-25T22:44:08.686473-07:00","updated_at":"2025-10-25T23:23:31.488427-07:00","closed_at":"2025-10-25T23:23:31.488427-07:00","dependencies":[{"issue_id":"bd-121","depends_on_id":"bd-119","type":"blocks","created_at":"2025-10-25T22:44:10.75056-07:00","created_by":"daemon"},{"issue_id":"bd-121","depends_on_id":"bd-115","type":"parent-child","created_at":"2025-10-25T22:44:12.984228-07:00","created_by":"daemon"}]} +{"id":"bd-122","title":"Document exclusive lock protocol in README and new doc file","description":"Update documentation to explain exclusive lock protocol:\n\n1. Create EXCLUSIVE_LOCK.md with:\n - Protocol specification\n - Lock file format (JSON schema)\n - Usage examples for external tools\n - Stale lock behavior\n - Edge cases and limitations\n\n2. Update README.md:\n - Mention exclusive lock support in daemon section\n - Link to EXCLUSIVE_LOCK.md for details\n\n3. Update AGENTS.md:\n - Note that external tools can use exclusive locks\n - Explain daemon skips locked databases\n\nTarget audience: developers integrating bd with external tools (like VC).","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-25T22:44:18.676992-07:00","updated_at":"2025-10-25T23:23:31.489472-07:00","closed_at":"2025-10-25T23:23:31.489472-07:00","dependencies":[{"issue_id":"bd-122","depends_on_id":"bd-119","type":"blocks","created_at":"2025-10-25T22:44:22.31844-07:00","created_by":"daemon"},{"issue_id":"bd-122","depends_on_id":"bd-115","type":"parent-child","created_at":"2025-10-25T22:44:24.324785-07:00","created_by":"daemon"}]} +{"id":"bd-123","title":"Add staleness check to non-daemon mode","description":"Extend staleness detection to non-daemon mode (--no-daemon).\n\nImplementation:\n- On database open, check if .beads/issues.jsonl exists\n- If JSONL exists and is newer than .db file: auto-import\n- Compare JSONL mtime vs .db mtime (both os.Stat)\n- Log: \"Auto-importing from .beads/issues.jsonl (newer than database)\"\n\nThis ensures both daemon and non-daemon modes handle git pull correctly.","notes":"INVESTIGATION COMPLETE:\n\nThe requested feature is already implemented in ensureStoreActive() (cmd/bd/direct_mode.go:79-81) which calls autoImportIfNewer() on every database open in non-daemon mode.\n\nThe implementation uses hash-based staleness detection via autoimport.AutoImportIfNewer() instead of mtime-based, which is BETTER because:\n1. Avoids unnecessary imports when file is merely touched\n2. Detects actual content changes reliably \n3. Works correctly after git pull\n\nVerified working with BD_DEBUG=1:\n```\nBD_DEBUG=1 ./bd --no-daemon stats\nDebug: auto-import skipped, JSONL unchanged (hash match)\n```\n\nThe issue description requested mtime-based approach like daemon mode, but hash-based is superior for non-daemon usage. Both modes now have auto-import after git pull.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-10-25T22:46:44.664917-07:00","updated_at":"2025-10-26T12:23:13.349472-07:00","closed_at":"2025-10-26T12:23:13.349472-07:00"} +{"id":"bd-124","title":"Add 'bd sync' command for explicit synchronization","description":"Add explicit `bd sync` command as fallback for manual synchronization after git pull.\n\nBehavior:\n- Import from .beads/issues.jsonl\n- If daemon mode: send RPC command to daemon to re-import\n- If non-daemon: directly import to local db\n- Show summary: \"Imported N issues, updated M issues\"\n\nUsage:\n```bash\ngit pull\nbd sync # Force immediate sync\n```\n\nThis complements auto-detection but gives users manual control.","notes":"IMPLEMENTED:\n\nAdded `bd sync --import-only` flag that:\n- Imports from .beads/issues.jsonl automatically (no need to specify path)\n- Works in both daemon and non-daemon modes\n- Shows summary: \"Import complete: X created, Y updated, Z unchanged, N remapped\"\n- Handles collisions automatically with --resolve-collisions\n\nUsage:\n```bash\ngit pull\nbd sync --import-only # Force immediate sync\n```\n\nThe existing `bd sync` command does full git workflow (export, commit, pull, import, push). The new --import-only flag complements --flush-only for granular control.\n\nImplementation in cmd/bd/sync.go","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-25T22:46:52.139434-07:00","updated_at":"2025-10-26T12:27:40.539108-07:00","closed_at":"2025-10-26T12:27:40.539108-07:00"} +{"id":"bd-125","title":"Add integration test for git pull sync scenario","description":"Add integration test simulating the git pull sync issue.\n\nTest scenario:\n1. Create temp git repo with beads initialized\n2. Clone 1: Create and close issue, export, commit, push\n3. Clone 2: Start daemon, git pull\n4. Clone 2: Verify bd show \u003cissue\u003e reflects closed status immediately\n5. Verify no manual import or daemon restart needed\n\nAlso test:\n- Non-daemon mode (--no-daemon) handles git pull correctly\n- bd sync command works in both modes\n- Performance: staleness check adds \u003c10ms overhead\n\nDepends on staleness detection implementation.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-10-25T22:47:01.101808-07:00","updated_at":"2025-10-26T12:32:34.054034-07:00","closed_at":"2025-10-26T12:32:34.054034-07:00","dependencies":[{"issue_id":"bd-125","depends_on_id":"bd-123","type":"blocks","created_at":"2025-10-25T22:47:05.615638-07:00","created_by":"daemon"}]} +{"id":"bd-126","title":"Add optional post-merge git hook example for bd sync","description":"Create example git hook that auto-runs bd sync after git pull/merge.\n\nAdd to examples/git-hooks/:\n- post-merge hook that checks if .beads/issues.jsonl changed\n- If changed: run `bd sync` automatically\n- Make it optional/documented (not auto-installed)\n\nBenefits:\n- Zero-friction sync after git pull\n- Complements auto-detection as belt-and-suspenders\n\nNote: post-merge hook already exists for pre-commit/post-merge. Extend it to support sync.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-25T22:47:14.668842-07:00","updated_at":"2025-10-25T23:15:33.515404-07:00","dependencies":[{"issue_id":"bd-126","depends_on_id":"bd-124","type":"blocks","created_at":"2025-10-25T22:47:16.949519-07:00","created_by":"daemon"}]} +{"id":"bd-127","title":"Update documentation for auto-sync behavior","description":"Update documentation to explain auto-sync after git pull.\n\nFiles to update:\n1. README.md - Add section on git workflow and auto-sync\n2. AGENTS.md - Note that bd auto-detects JSONL changes after git pull\n3. WORKFLOW.md - Update git pull workflow to remove manual import step\n4. FAQ.md - Add Q\u0026A about sync behavior and staleness\n\nKey points:\n- bd automatically detects when JSONL is newer than database\n- No manual import needed after git pull\n- bd sync command available for manual control\n- Optional git hook for guaranteed sync","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-25T22:47:24.618649-07:00","updated_at":"2025-10-26T12:44:33.996187-07:00","closed_at":"2025-10-26T12:44:33.996187-07:00"} +{"id":"bd-128","title":"Refactor autoImportIfNewer to be callable from daemon","description":"The staleness check in [deleted:bd-160] detects when JSONL is newer than last import, but can't trigger the actual import because autoImportIfNewer() is in cmd/bd and uses global variables.\n\nNeed to:\n1. Extract core import logic from autoImportIfNewer() into importable function\n2. Move to internal/autoimport or similar package\n3. Make it callable from daemon (no global state dependency)\n4. Update staleness check in server.go to call actual import instead of just logging\n\nThis completes the auto-sync feature - daemon will truly auto-import after git pull.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-10-25T23:10:41.392416-07:00","updated_at":"2025-10-25T23:51:09.811006-07:00","closed_at":"2025-10-25T23:51:09.811006-07:00"} +{"id":"bd-129","title":"Enforce daemon singleton per workspace with file locking","description":"Agent in ~/src/wyvern discovered 4 simultaneous daemon processes running, causing infinite directory recursion (.beads/.beads/.beads/...). Each daemon used relative paths and created nested .beads/ directories.\n\nRoot cause: No singleton enforcement. Multiple `bd daemon` processes can start in same workspace.\n\nExpected: One daemon per workspace (each workspace = separate .beads/ dir with bd.sock)\nActual: Multiple daemons can run simultaneously in same workspace\n\nNote: Separate git clones = separate workspaces = separate daemons (correct). Git worktrees share .beads/ and have known limitations (documented, use --no-daemon).","design":"Use flock (file locking) on daemon socket or database file to enforce singleton:\n\n1. On daemon start, attempt exclusive lock on .beads/bd.sock or .beads/daemon.lock\n2. If lock held by another process, refuse to start (exit with clear error)\n3. Hold lock for lifetime of daemon process\n4. Release lock on daemon shutdown\n\nAlternative: Use PID file with stale detection (check if PID is still running)\n\nImplementation location: Daemon startup code in cmd/bd/ or internal/daemon/","acceptance_criteria":"1. Starting second daemon process in same workspace fails with clear error\n2. Test: Start daemon, attempt second start, verify failure\n3. Killing daemon releases lock, allowing new daemon to start\n4. No infinite .beads/ directory recursion possible\n5. Works correctly with auto-start mechanism","status":"in_progress","priority":0,"issue_type":"bug","created_at":"2025-10-25T23:13:12.269549-07:00","updated_at":"2025-10-25T23:15:33.516072-07:00"} +{"id":"bd-13","title":"Test database naming","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T18:27:28.309676-07:00","updated_at":"2025-10-27T22:22:23.816439-07:00","dependencies":[{"issue_id":"bd-13","depends_on_id":"bd-11","type":"parent-child","created_at":"2025-10-24T13:17:40.321936-07:00","created_by":"renumber"},{"issue_id":"bd-13","depends_on_id":"bd-12","type":"blocks","created_at":"2025-10-24T13:17:40.322171-07:00","created_by":"renumber"}]} +{"id":"bd-130","title":"Track last JSONL import timestamp in daemon state","description":"Add state tracking to daemon to record when .beads/issues.jsonl was last imported.\n\nImplementation:\n- Add lastImportTime field to daemon state (time.Time)\n- Update timestamp after successful import\n- Persist across RPC requests (in-memory state)\n- Initialize on daemon startup\n\nNeeded for staleness detection to compare against JSONL mtime.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-10-25T23:13:12.270048-07:00","updated_at":"2025-10-25T23:15:33.516267-07:00","closed_at":"2025-10-25T23:04:33.056154-07:00"} +{"id":"bd-131","title":"Implement staleness check before serving daemon requests","description":"Add staleness detection to daemon RPC handler that checks if JSONL is newer than last import.\n\nLogic:\n1. Before processing any RPC request (show, list, ready, etc.)\n2. Get .beads/issues.jsonl mtime (os.Stat)\n3. Compare with lastImportTime\n4. If JSONL mtime \u003e lastImportTime: auto-import before processing request\n5. If import fails: log error but continue with existing data\n\nPerformance: mtime check is fast (\u003c1ms). Only imports if needed.\n\nDepends on lastImportTime tracking.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-10-25T23:13:12.270392-07:00","updated_at":"2025-10-25T23:15:33.516457-07:00","closed_at":"2025-10-25T23:04:33.056796-07:00"} +{"id":"bd-132","title":"Daemon fails to auto-import after git pull updates JSONL","description":"After git pull updates .beads/issues.jsonl, daemon doesn't automatically re-import changes, causing stale data to be shown until next sync cycle (up to 5 minutes).\n\nReproduction:\n1. Repo A: Close issues, export, commit, push\n2. Repo B: git pull (successfully updates .beads/issues.jsonl)\n3. bd show \u003cissue\u003e shows OLD status from daemon's SQLite db\n4. JSONL on disk has correct new status\n\nRoot cause: Daemon sync cycle runs on timer (5min). When user manually runs git pull, daemon doesn't detect JSONL was updated externally and continues serving stale data from SQLite.\n\nImpact:\n- High for AI agents using beads in git workflows\n- Breaks fundamental git-as-source-of-truth model\n- Confusing UX: git log shows commit, bd shows old state\n- Data consistency issues between JSONL and daemon\n\nSee WYVERN_SYNC_ISSUE.md for full analysis.","design":"Three possible solutions:\n\nOption 1: Auto-detect and re-import (recommended)\n- Before serving any bd command, check if .beads/issues.jsonl mtime \u003e last import time\n- If newer, auto-import before processing request\n- Fast check, minimal overhead\n\nOption 2: File watcher in daemon\n- Daemon watches .beads/issues.jsonl for mtime changes\n- Auto-imports when file changes\n- More complex, requires file watching infrastructure\n\nOption 3: Explicit sync command\n- User runs `bd sync` after git pull\n- Manual, error-prone, defeats automation\n\nRecommended: Option 1 (auto-detect) + Option 3 (explicit sync) as fallback.","acceptance_criteria":"1. After git pull updates .beads/issues.jsonl, next bd command sees fresh data\n2. No manual import or daemon restart required\n3. Performance impact \u003c 10ms per command (mtime check is fast)\n4. Works in both daemon and non-daemon modes\n5. Test: Two repo clones, update in one, pull in other, verify immediate sync","notes":"**Current Status (2025-10-26):**\n\n✅ **Completed (bd-128):**\n- Created internal/autoimport package with staleness detection\n- Daemon can detect when JSONL is newer than last import\n- Infrastructure exists to call import logic\n\n❌ **Remaining Work:**\nThe daemon's importFunc in server.go (line 2096-2102) is a stub that just logs a notice. It needs to actually import the issues.\n\n**Problem:** \n- importIssuesCore is in cmd/bd package, not accessible from internal/rpc\n- daemon's handleImport() returns 'not yet implemented' error\n\n**Two approaches:**\n1. Move importIssuesCore to internal/import package (shares with daemon)\n2. Use storage layer directly in daemon (create/update issues via Storage interface)\n\n**Blocker:** \nThis is the critical bug causing data corruption:\n- Agent A pushes changes\n- Agent B does git pull\n- Agent B's daemon serves stale SQLite data\n- Agent B exports stale data back to JSONL, overwriting Agent A's changes\n- Agent B pushes, losing Agent A's work\n\n**Next Steps:**\n1. Choose approach (probably #1 - move importIssuesCore to internal/import)\n2. Implement real importFunc in daemon's checkAndAutoImportIfStale()\n3. Test with two-repo scenario (push from A, pull in B, verify B sees changes)\n4. Ensure no data corruption in multi-agent workflows","status":"in_progress","priority":0,"issue_type":"epic","created_at":"2025-10-25T23:13:12.270766-07:00","updated_at":"2025-10-26T12:11:20.217716-07:00"} +{"id":"bd-133","title":"Enforce daemon singleton per workspace with file locking","description":"Agent in ~/src/wyvern discovered 4 simultaneous daemon processes running, causing infinite directory recursion (.beads/.beads/.beads/...). Each daemon used relative paths and created nested .beads/ directories.\n\nRoot cause: No singleton enforcement. Multiple `bd daemon` processes can start in same workspace.\n\nExpected: One daemon per workspace (each workspace = separate .beads/ dir with bd.sock)\nActual: Multiple daemons can run simultaneously in same workspace\n\nNote: Separate git clones = separate workspaces = separate daemons (correct). Git worktrees share .beads/ and have known limitations (documented, use --no-daemon).","design":"Use flock (file locking) on daemon socket or database file to enforce singleton:\n\n1. On daemon start, attempt exclusive lock on .beads/bd.sock or .beads/daemon.lock\n2. If lock held by another process, refuse to start (exit with clear error)\n3. Hold lock for lifetime of daemon process\n4. Release lock on daemon shutdown\n\nAlternative: Use PID file with stale detection (check if PID is still running)\n\nImplementation location: Daemon startup code in cmd/bd/ or internal/daemon/","acceptance_criteria":"1. Starting second daemon process in same workspace fails with clear error\n2. Test: Start daemon, attempt second start, verify failure\n3. Killing daemon releases lock, allowing new daemon to start\n4. No infinite .beads/ directory recursion possible\n5. Works correctly with auto-start mechanism","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-25T23:15:14.418051-07:00","updated_at":"2025-10-26T12:28:21.145649-07:00","closed_at":"2025-10-26T12:28:21.145649-07:00"} +{"id":"bd-134","title":"Track last JSONL import timestamp in daemon state","description":"Add state tracking to daemon to record when .beads/issues.jsonl was last imported.\n\nImplementation:\n- Add lastImportTime field to daemon state (time.Time)\n- Update timestamp after successful import\n- Persist across RPC requests (in-memory state)\n- Initialize on daemon startup\n\nNeeded for staleness detection to compare against JSONL mtime.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-10-25T23:15:14.4184-07:00","updated_at":"2025-10-25T23:15:33.517097-07:00","closed_at":"2025-10-25T23:04:33.056154-07:00"} +{"id":"bd-135","title":"Daemon fails to auto-import after git pull updates JSONL","description":"After git pull updates .beads/issues.jsonl, daemon doesn't automatically re-import changes, causing stale data to be shown until next sync cycle (up to 5 minutes).\n\nReproduction:\n1. Repo A: Close issues, export, commit, push\n2. Repo B: git pull (successfully updates .beads/issues.jsonl)\n3. bd show \u003cissue\u003e shows OLD status from daemon's SQLite db\n4. JSONL on disk has correct new status\n\nRoot cause: Daemon sync cycle runs on timer (5min). When user manually runs git pull, daemon doesn't detect JSONL was updated externally and continues serving stale data from SQLite.\n\nImpact:\n- High for AI agents using beads in git workflows\n- Breaks fundamental git-as-source-of-truth model\n- Confusing UX: git log shows commit, bd shows old state\n- Data consistency issues between JSONL and daemon\n\nSee WYVERN_SYNC_ISSUE.md for full analysis.","design":"Three possible solutions:\n\nOption 1: Auto-detect and re-import (recommended)\n- Before serving any bd command, check if .beads/issues.jsonl mtime \u003e last import time\n- If newer, auto-import before processing request\n- Fast check, minimal overhead\n\nOption 2: File watcher in daemon\n- Daemon watches .beads/issues.jsonl for mtime changes\n- Auto-imports when file changes\n- More complex, requires file watching infrastructure\n\nOption 3: Explicit sync command\n- User runs `bd sync` after git pull\n- Manual, error-prone, defeats automation\n\nRecommended: Option 1 (auto-detect) + Option 3 (explicit sync) as fallback.","acceptance_criteria":"1. After git pull updates .beads/issues.jsonl, next bd command sees fresh data\n2. No manual import or daemon restart required\n3. Performance impact \u003c 10ms per command (mtime check is fast)\n4. Works in both daemon and non-daemon modes\n5. Test: Two repo clones, update in one, pull in other, verify immediate sync","status":"closed","priority":0,"issue_type":"epic","created_at":"2025-10-25T23:15:14.418651-07:00","updated_at":"2025-10-26T11:59:31.178532-07:00","closed_at":"2025-10-26T11:59:31.178532-07:00"} +{"id":"bd-136","title":"Add configurable SortPolicy to GetReadyWork","description":"Add SortPolicy field to WorkFilter to support different ordering strategies: hybrid (default), priority-first, oldest-first. See SORT_POLICY_DESIGN.md for full specification.","design":"See SORT_POLICY_DESIGN.md for complete design.\n\nImplementation summary:\n1. Add SortPolicy type and constants (hybrid, priority, oldest)\n2. Add SortPolicy field to WorkFilter \n3. Implement buildOrderByClause() to generate SQL based on policy\n4. Default to hybrid for backwards compatibility\n5. Add --sort flag to bd ready command\n\nThis enables autonomous execution systems (like VC) to use strict priority ordering while preserving the current hybrid behavior for interactive use.","acceptance_criteria":"Unit tests verify each policy generates correct ORDER BY. Integration tests verify priority, hybrid, and oldest policies select issues in expected order. CLI bd ready --sort priority works. Empty SortPolicy defaults to hybrid (backwards compatible).","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-26T12:27:22.805413-07:00","updated_at":"2025-10-26T12:28:52.524291-07:00","closed_at":"2025-10-26T12:28:52.524291-07:00"} +{"id":"bd-137","title":"Add 'bd sync' command for explicit synchronization","description":"Add explicit `bd sync` command as fallback for manual synchronization after git pull.\n\nBehavior:\n- Import from .beads/issues.jsonl\n- If daemon mode: send RPC command to daemon to re-import\n- If non-daemon: directly import to local db\n- Show summary: \"Imported N issues, updated M issues\"\n\nUsage:\n```bash\ngit pull\nbd sync # Force immediate sync\n```\n\nThis complements auto-detection but gives users manual control.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-26T12:27:22.805868-07:00","updated_at":"2025-10-26T12:28:52.533454-07:00","closed_at":"2025-10-26T12:28:52.533454-07:00"} +{"id":"bd-138","title":"Add configurable SortPolicy to GetReadyWork","description":"Add SortPolicy field to WorkFilter to support different ordering strategies: hybrid (default), priority-first, oldest-first. See SORT_POLICY_DESIGN.md for full specification.","design":"See SORT_POLICY_DESIGN.md for complete design.\n\nImplementation summary:\n1. Add SortPolicy type and constants (hybrid, priority, oldest)\n2. Add SortPolicy field to WorkFilter \n3. Implement buildOrderByClause() to generate SQL based on policy\n4. Default to hybrid for backwards compatibility\n5. Add --sort flag to bd ready command\n\nThis enables autonomous execution systems (like VC) to use strict priority ordering while preserving the current hybrid behavior for interactive use.","acceptance_criteria":"Unit tests verify each policy generates correct ORDER BY. Integration tests verify priority, hybrid, and oldest policies select issues in expected order. CLI bd ready --sort priority works. Empty SortPolicy defaults to hybrid (backwards compatible).","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-26T12:27:22.889669-07:00","updated_at":"2025-10-26T12:28:21.152107-07:00","closed_at":"2025-10-26T12:28:21.152107-07:00"} +{"id":"bd-139","title":"Add 'bd sync' command for explicit synchronization","description":"Add explicit `bd sync` command as fallback for manual synchronization after git pull.\n\nBehavior:\n- Import from .beads/issues.jsonl\n- If daemon mode: send RPC command to daemon to re-import\n- If non-daemon: directly import to local db\n- Show summary: \"Imported N issues, updated M issues\"\n\nUsage:\n```bash\ngit pull\nbd sync # Force immediate sync\n```\n\nThis complements auto-detection but gives users manual control.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-26T12:27:22.890111-07:00","updated_at":"2025-10-26T12:28:21.133303-07:00","closed_at":"2025-10-26T12:28:21.133303-07:00"} +{"id":"bd-14","title":"Final validation test","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T18:27:28.310533-07:00","updated_at":"2025-10-27T22:22:23.816672-07:00","dependencies":[{"issue_id":"bd-14","depends_on_id":"bd-11","type":"parent-child","created_at":"2025-10-24T13:17:40.323317-07:00","created_by":"renumber"},{"issue_id":"bd-14","depends_on_id":"bd-13","type":"blocks","created_at":"2025-10-24T13:17:40.323527-07:00","created_by":"renumber"}]} +{"id":"bd-140","title":"Clarify that humans should run bd init, not agents","description":"Current docs are ambiguous about who runs `bd init`. This leads to agents running it incorrectly, causing daemon issues, sync problems, and confusion.\n\n**Problem:** Agents struggle with:\n- Interactive prompts (git hooks)\n- Directory detection\n- Understanding when to import existing JSONL\n- Daemon startup timing\n\n**Solution:** Make it crystal clear that `bd init` is a human setup task, like `npm install` or `git init`.","design":"Update docs to emphasize:\n1. README.md - Rewrite Quick Start to show human does `bd init` first\n2. AGENTS.md - Add clear \"Human does init, agent uses bd\" section\n3. QUICKSTART.md - Update tutorial flow\n4. FAQ.md - Add Q\u0026A about who runs init","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-26T12:50:14.555803-07:00","updated_at":"2025-10-26T12:53:10.836604-07:00","closed_at":"2025-10-26T12:53:10.836604-07:00","dependencies":[{"issue_id":"bd-140","depends_on_id":"bd-141","type":"blocks","created_at":"2025-10-26T12:52:23.433758-07:00","created_by":"daemon"}]} +{"id":"bd-141","title":"Make bd init --quiet skip interactive prompts","description":"Currently `bd init --quiet` flag exists but doesn't actually skip the git hooks prompt. This makes it impossible for agents to run init non-interactively.\n\n**Problem:** Agents setting up repos can't use `bd init` because it prompts for user input.\n\n**Solution:** Make `--quiet` flag actually work:\n- Skip git hooks prompt\n- Auto-install hooks by default in quiet mode (safest)\n- No output except errors","design":"In cmd/bd/init.go, check the quiet flag before prompting:\n\n```go\nif isGitRepo() \u0026\u0026 !hooksInstalled() {\n if quiet {\n // Auto-install hooks silently in quiet mode\n _ = installGitHooks() // Ignore errors\n } else {\n // Show prompt for interactive mode\n fmt.Printf(\"Install git hooks now? [Y/n] \")\n // ... existing prompt logic\n }\n}\n```","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-26T12:52:19.482162-07:00","updated_at":"2025-10-26T12:52:39.295979-07:00","closed_at":"2025-10-26T12:52:39.295979-07:00"} +{"id":"bd-142","title":"Local testing of bd init --quiet and auto-sync improvements","description":"Before doing official version bump, test the new changes locally across multiple agent projects:\n\n**Changes to test:**\n- bd init --quiet (non-interactive for agents)\n- Auto-sync documentation updates\n- Git hooks auto-install in quiet mode\n\n**Test scenarios:**\n1. Fresh repo clone with existing .beads/issues.jsonl (bd init --quiet)\n2. Agent setting up new project (bd init --quiet)\n3. Verify git hooks install automatically in quiet mode\n4. Test auto-import after git pull\n5. Verify no daemon conflicts across projects\n\n**Projects/agents to test:**\n- ~/src/vc (waiting on exclusive lock protocol)\n- Other agent projects with fresh clones\n- Multiple agents on same machine","design":"From RELEASING.md, for local testing:\n\n1. Build local binary: `go build -o bd ./cmd/bd`\n2. Use `./bd` directly (don't install via brew yet)\n3. Optional: `alias bd=\"$PWD/bd\"` to test across projects\n4. Kill all daemons first: `pkill -f \"bd.*daemon\"`\n\n**Testing workflow:**\n- Build latest bd binary in ~/src/beads\n- Create alias: `alias bd=\"$HOME/src/beads/bd\"`\n- Test with multiple agents in different repos\n- Verify version: `bd version` shows latest\n- Check daemon compatibility after restart","notes":"Found and fixed bug: bd init --quiet was returning before hooks installation.\n\nFixed by:\n1. Moving hooks check/install before quiet mode return\n2. Embedding hooks inline instead of using external install.sh\n3. This makes bd init --quiet fully self-contained\n\nTested successfully in /tmp/bd-test-quiet - hooks installed correctly.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-26T12:56:04.960569-07:00","updated_at":"2025-10-26T13:19:22.400117-07:00","closed_at":"2025-10-26T13:19:22.400117-07:00"} +{"id":"bd-143","title":"Review and respond to new GitHub PRs","description":"Check for new pull requests on GitHub and review/respond to them.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-26T13:19:22.407693-07:00","updated_at":"2025-10-26T13:22:33.395599-07:00","closed_at":"2025-10-26T13:22:33.395599-07:00"} +{"id":"bd-144","title":"Document bd edit command and verify MCP exclusion","description":"Follow-up from PR #152:\n1. Add \"bd edit\" to AGENTS.md with \"Humans only\" note\n2. Verify MCP server doesn't expose bd edit command\n3. Consider adding test for command registration","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-26T13:23:47.982295-07:00","updated_at":"2025-10-26T13:23:47.982295-07:00","dependencies":[{"issue_id":"bd-144","depends_on_id":"bd-143","type":"discovered-from","created_at":"2025-10-26T13:23:47.983557-07:00","created_by":"daemon"}]} +{"id":"bd-145","title":"Add \"bd daemons\" command for multi-daemon management","description":"Add a new \"bd daemons\" command with subcommands to manage daemon processes across all beads repositories/worktrees. Should show all running daemons with metadata (version, workspace, uptime, last sync), allow stopping/restarting individual daemons, auto-clean stale processes, view logs, and show exclusive lock status.","design":"Subcommands:\n- list: Show all running daemons with metadata (workspace, PID, version, socket path, uptime, last activity, exclusive lock status)\n- stop \u003cpath|pid\u003e: Gracefully stop a specific daemon\n- restart \u003cpath|pid\u003e: Stop and restart daemon\n- killall: Emergency stop all daemons\n- health: Verify each daemon responds to ping\n- logs \u003cpath\u003e: View daemon logs\n\nFeatures:\n- Auto-clean stale sockets/dead processes\n- Discovery: Scan for .beads/bd.sock files + running processes\n- Communication: Use existing socket protocol, add GET /status endpoint for metadata","status":"in_progress","priority":1,"issue_type":"epic","created_at":"2025-10-26T16:53:40.970042-07:00","updated_at":"2025-10-26T18:11:11.077613-07:00"} +{"id":"bd-146","title":"Implement daemon discovery mechanism","description":"Build the core discovery logic to find all running bd daemons. Scan filesystem for .beads/bd.sock files, check if processes are alive, and collect metadata.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-26T16:54:00.22163-07:00","updated_at":"2025-10-26T18:05:22.257361-07:00","closed_at":"2025-10-26T18:05:22.257361-07:00","dependencies":[{"issue_id":"bd-146","depends_on_id":"bd-145","type":"parent-child","created_at":"2025-10-26T16:54:00.222398-07:00","created_by":"daemon"}]} +{"id":"bd-147","title":"Implement \"bd daemons list\" subcommand","description":"Create the \"bd daemons list\" command that displays all running daemons in a table with: workspace path, PID, version, socket path, uptime, last activity, exclusive lock status. Include --json flag.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-26T16:54:00.232956-07:00","updated_at":"2025-10-26T18:10:24.905516-07:00","closed_at":"2025-10-26T18:10:24.905516-07:00","dependencies":[{"issue_id":"bd-147","depends_on_id":"bd-145","type":"parent-child","created_at":"2025-10-26T17:47:47.922208-07:00","created_by":"stevey"}]} +{"id":"bd-148","title":"Add GET /status endpoint to daemon HTTP server","description":"Add a new HTTP endpoint that returns daemon metadata: version, workspace path, PID, uptime, last activity timestamp, exclusive lock status.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-26T16:54:00.233084-07:00","updated_at":"2025-10-26T17:55:32.40399-07:00","closed_at":"2025-10-26T17:55:32.40399-07:00","dependencies":[{"issue_id":"bd-148","depends_on_id":"bd-145","type":"parent-child","created_at":"2025-10-26T16:54:00.238293-07:00","created_by":"daemon"}]} +{"id":"bd-149","title":"Add auto-cleanup of stale sockets and dead processes","description":"When discovering daemons, automatically detect and clean up stale socket files (where process is dead) and orphaned PID files. Should be safe and only remove confirmed-dead processes.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-26T16:54:00.246629-07:00","updated_at":"2025-10-26T18:17:18.560526-07:00","closed_at":"2025-10-26T18:17:18.560526-07:00","dependencies":[{"issue_id":"bd-149","depends_on_id":"bd-145","type":"parent-child","created_at":"2025-10-26T16:54:00.247788-07:00","created_by":"daemon"}]} +{"id":"bd-15","title":"Update LINTING.md with current baseline","description":"After cleanup, document the remaining acceptable baseline in LINTING.md so we can track regression.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T18:53:10.38679-07:00","updated_at":"2025-10-27T22:22:23.816904-07:00","dependencies":[{"issue_id":"bd-15","depends_on_id":"bd-11","type":"parent-child","created_at":"2025-10-24T13:17:40.324637-07:00","created_by":"renumber"},{"issue_id":"bd-15","depends_on_id":"bd-14","type":"blocks","created_at":"2025-10-24T13:17:40.324851-07:00","created_by":"renumber"}]} +{"id":"bd-150","title":"Update AGENTS.md and README.md with \"bd daemons\" documentation","description":"Document the new \"bd daemons\" command and all subcommands in AGENTS.md and README.md. Include examples and troubleshooting guidance.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-26T16:54:00.254006-07:00","updated_at":"2025-10-26T19:03:21.93015-07:00","closed_at":"2025-10-26T19:03:21.93015-07:00","dependencies":[{"issue_id":"bd-150","depends_on_id":"bd-145","type":"parent-child","created_at":"2025-10-26T16:54:00.254862-07:00","created_by":"daemon"}]} +{"id":"bd-151","title":"Implement \"bd daemons health\" subcommand","description":"Add health check command that pings each daemon and reports responsiveness. Should detect and report stale sockets, version mismatches, unresponsive daemons.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-26T16:54:00.255444-07:00","updated_at":"2025-10-26T18:21:59.75853-07:00","closed_at":"2025-10-26T18:21:59.75853-07:00","dependencies":[{"issue_id":"bd-151","depends_on_id":"bd-145","type":"parent-child","created_at":"2025-10-26T17:47:47.949848-07:00","created_by":"stevey"}]} +{"id":"bd-152","title":"Implement \"bd daemons logs\" subcommand","description":"Add command to view daemon logs for a specific workspace. Requires daemon logging to file (may need separate issue for log infrastructure).","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-26T16:54:00.256037-07:00","updated_at":"2025-10-26T19:03:21.929414-07:00","closed_at":"2025-10-26T19:03:21.929414-07:00","dependencies":[{"issue_id":"bd-152","depends_on_id":"bd-145","type":"parent-child","created_at":"2025-10-26T16:54:00.256797-07:00","created_by":"daemon"}]} +{"id":"bd-153","title":"Implement \"bd daemons killall\" subcommand","description":"Add emergency command to stop all running bd daemons. Should discover all daemons and stop them gracefully (with timeout fallback to SIGKILL).","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-26T16:54:00.258822-07:00","updated_at":"2025-10-26T19:03:21.928597-07:00","closed_at":"2025-10-26T19:03:21.928597-07:00","dependencies":[{"issue_id":"bd-153","depends_on_id":"bd-145","type":"parent-child","created_at":"2025-10-26T16:54:00.259421-07:00","created_by":"daemon"}]} +{"id":"bd-154","title":"Implement \"bd daemons stop\" and \"bd daemons restart\" subcommands","description":"Add commands to stop and restart individual daemons by path or PID. Should send graceful shutdown signal via socket, with fallback to SIGTERM.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-26T16:54:00.259875-07:00","updated_at":"2025-10-26T18:35:28.407904-07:00","closed_at":"2025-10-26T18:35:28.407904-07:00","dependencies":[{"issue_id":"bd-154","depends_on_id":"bd-145","type":"parent-child","created_at":"2025-10-26T16:54:00.260433-07:00","created_by":"daemon"}]} +{"id":"bd-155","title":"Daemon auto-import creates race condition with deletions","description":"When a user deletes an issue while the daemon is running, the daemon's periodic import from JSONL can immediately re-add the deleted issue before the deletion is flushed to the JSONL file.\n\n## Steps to reproduce:\n1. Start daemon: bd daemon --interval 30s --auto-commit --auto-push\n2. Delete an issue: bd delete wy-XX --force\n3. Wait for daemon sync cycle (observe daemon log showing \"Imported from JSONL\")\n4. Run bd show wy-XX - issue still exists despite successful deletion\n\n## Expected behavior:\nThe deletion should be immediately flushed to JSONL before the next import cycle, or imports should respect deletions in the database.\n\n## Actual behavior:\nThe daemon imports from JSONL and re-adds the deleted issue, overwriting the deletion. The user sees \"✓ Deleted wy-XX\" but the issue persists.\n\n## Workaround:\n1. Stop daemon: bd daemon --stop\n2. Delete issue: bd delete wy-XX --force\n3. Export to JSONL: bd export -o .beads/issues.jsonl\n4. Commit and push manually\n5. Restart daemon\n\n## Suggested fixes:\n1. Flush pending changes to JSONL before each import cycle\n2. Track deletions separately and don't re-import deleted issues\n3. Make delete operation immediately flush to JSONL when daemon is running\n4. Add a \"dirty\" flag that prevents import if there are pending exports","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-26T17:02:30.576489-07:00","updated_at":"2025-10-26T17:07:10.34777-07:00","closed_at":"2025-10-26T17:07:10.34777-07:00","labels":["daemon","data-integrity","race-condition"]} +{"id":"bd-156","title":"bd create files issues in wrong project when multiple beads databases exist","description":"When working in a directory with a beads database (e.g., /Users/stevey/src/wyvern/.beads/wy.db), bd create can file issues in a different project's database instead of the current directory's database.\n\n## Steps to reproduce:\n1. Have multiple beads projects (e.g., ~/src/wyvern with wy.db, ~/vibecoder with vc.db)\n2. cd ~/src/wyvern\n3. Run bd create --title \"Test\" --type bug\n4. Observe issue created with wrong prefix (e.g., vc-1 instead of wy-1)\n\n## Expected behavior:\nbd create should respect the current working directory and use the beads database in that directory (.beads/ folder).\n\n## Actual behavior:\nbd create appears to use a different project's database, possibly the last accessed or a global default.\n\n## Impact:\nThis can cause issues to be filed in completely wrong projects, polluting unrelated issue trackers.\n\n## Suggested fix:\n- Always check for .beads/ directory in current working directory first\n- Add --project flag to explicitly specify which database to use\n- Show which project/database is being used in command output\n- Add validation/confirmation when creating issues if current directory doesn't match database project","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-10-26T17:02:30.578817-07:00","updated_at":"2025-10-26T17:08:43.009159-07:00","closed_at":"2025-10-26T17:08:43.009159-07:00","labels":["cli","project-context"]} +{"id":"bd-157","title":"Implement \"bd daemons health\" subcommand","description":"Add health check command that pings each daemon and reports responsiveness. Should detect and report stale sockets, version mismatches, unresponsive daemons.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-26T17:09:51.138682-07:00","updated_at":"2025-10-26T17:47:47.958834-07:00","closed_at":"2025-10-26T17:47:47.958834-07:00","dependencies":[{"issue_id":"bd-157","depends_on_id":"bd-145","type":"parent-child","created_at":"2025-10-26T17:09:51.140111-07:00","created_by":"daemon"}]} +{"id":"bd-158","title":"Implement \"bd daemons list\" subcommand","description":"Create the \"bd daemons list\" command that displays all running daemons in a table with: workspace path, PID, version, socket path, uptime, last activity, exclusive lock status. Include --json flag.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-26T17:09:51.140442-07:00","updated_at":"2025-10-26T17:47:47.929666-07:00","closed_at":"2025-10-26T17:47:47.929666-07:00","dependencies":[{"issue_id":"bd-158","depends_on_id":"bd-145","type":"parent-child","created_at":"2025-10-26T17:09:51.150077-07:00","created_by":"daemon"}]} +{"id":"bd-159","title":"Timestamp-only changes still being exported despite dedup logic","description":"User observed timestamp-only changes in .beads/beads.jsonl causing dirty working tree. Example: bd-128's updated_at changed from 2025-10-25T23:51:09.811006-07:00 to 2025-10-26T14:12:45.207573-07:00 with no other field changes.\n\nThis should have been prevented by the export deduplication logic that's supposed to skip timestamp-only updates.\n\nNeed to investigate why timestamp-only changes are still being exported and fix the dedup logic.","status":"open","priority":1,"issue_type":"bug","created_at":"2025-10-26T17:58:15.41007-07:00","updated_at":"2025-10-26T17:58:15.41007-07:00"} {"id":"bd-16","title":"Delete skipped tests for \"old buggy behavior\"","description":"Three test functions are permanently skipped with comments indicating they test behavior that was fixed in GH#120. These tests will never run again and should be deleted.\n\nTest functions to remove:\n\n1. `cmd/bd/import_collision_test.go:228`\n ```go\n t.Skip(\"Test expects old buggy behavior - needs rewrite for GH#120 fix\")\n ```\n\n2. `cmd/bd/import_collision_test.go:505`\n ```go\n t.Skip(\"Test expects old buggy behavior - needs rewrite for GH#120 fix\")\n ```\n\n3. `internal/storage/sqlite/collision_test.go:919`\n ```go\n t.Skip(\"Test expects old buggy behavior - needs rewrite for GH#120 fix\")\n ```\n\nImpact: Removes ~150 LOC of permanently skipped tests","acceptance_criteria":"- Delete the 3 test functions entirely (~150 LOC total)\n- Update test file comments to reference GH#120 fix if needed\n- All remaining tests pass: `go test ./...`\n- No reduction in meaningful test coverage (these test fixed bugs)","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-27T20:30:19.961185-07:00","updated_at":"2025-10-27T22:22:23.817121-07:00","labels":["cleanup","dead-code","phase-1","test-cleanup"],"dependencies":[{"issue_id":"bd-16","depends_on_id":"bd-26","type":"parent-child","created_at":"2025-10-27T20:30:19.962815-07:00","created_by":"daemon"}]} -{"id":"bd-17","title":"Remove unreachable RPC methods","description":"Several RPC server and client methods are unreachable and should be removed:\n\nServer methods (internal/rpc/server.go):\n- `Server.GetLastImportTime` (line 2116)\n- `Server.SetLastImportTime` (line 2123)\n- `Server.findJSONLPath` (line 2255)\n\nClient methods (internal/rpc/client.go):\n- `Client.Import` (line 311) - RPC import not used (daemon uses autoimport)\n\nEvidence:\n```bash\ngo run golang.org/x/tools/cmd/deadcode@latest -test ./...\n```\n\nImpact: Removes ~80 LOC of unused RPC code","acceptance_criteria":"- Remove the 4 unreachable methods (~80 LOC total)\n- Verify no callers: `grep -r \"GetLastImportTime\\|SetLastImportTime\\|findJSONLPath\" .`\n- All tests pass: `go test ./internal/rpc/...`\n- Daemon functionality works: test daemon start/stop/operations","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T20:30:19.962209-07:00","updated_at":"2025-10-27T22:22:23.81754-07:00","labels":["cleanup","dead-code","phase-1","rpc"],"dependencies":[{"issue_id":"bd-17","depends_on_id":"bd-26","type":"parent-child","created_at":"2025-10-27T20:30:19.965239-07:00","created_by":"daemon"}]} -{"id":"bd-18","title":"Remove unreachable utility functions","description":"Several small utility functions are unreachable:\n\nFiles to clean:\n1. `internal/storage/sqlite/hash.go` - `computeIssueContentHash` (line 17)\n - Check if entire file can be deleted if only contains this function\n\n2. `internal/config/config.go` - `FileUsed` (line 151)\n - Delete unused config helper\n\n3. `cmd/bd/git_sync_test.go` - `verifyIssueOpen` (line 300)\n - Delete dead test helper\n\n4. `internal/compact/haiku.go` - `HaikuClient.SummarizeTier2` (line 81)\n - Tier 2 summarization not implemented\n - Options: implement feature OR delete method\n\nImpact: Removes 50-100 LOC depending on decisions","acceptance_criteria":"- Remove unreachable functions\n- If entire files can be deleted (like hash.go), delete them\n- For SummarizeTier2: decide to implement or delete, document decision\n- All tests pass: `go test ./...`\n- Verify no callers exist for each function","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T20:30:19.963392-07:00","updated_at":"2025-10-27T22:22:23.81795-07:00","labels":["cleanup","dead-code","phase-1"],"dependencies":[{"issue_id":"bd-18","depends_on_id":"bd-26","type":"parent-child","created_at":"2025-10-27T20:30:19.968126-07:00","created_by":"daemon"}]} +{"id":"bd-160","title":"Add database schema versioning","description":"Store beads version in SQLite database for version compatibility checking.\n\nImplementation:\n- Add metadata table with schema_version field (or use PRAGMA user_version)\n- Set on database creation (bd init)\n- Daemon validates on startup: schema version matches daemon version\n- Fail with clear error if mismatch: \"Database schema v0.17.5 but daemon is v0.18.0\"\n- Provide migration guidance in error message\n\nSchema version format:\n- Use semver (0.17.5)\n- Store in metadata table: CREATE TABLE metadata (key TEXT PRIMARY KEY, value TEXT)\n- Alternative: PRAGMA user_version (integer only)\n\nBenefits:\n- Detect version mismatches before corruption\n- Enable auto-migration in future\n- Clear error messages for users","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-26T19:41:11.098628-07:00","updated_at":"2025-10-26T19:41:11.115761-07:00","closed_at":"2025-10-26T19:04:07.843634-07:00","dependencies":[{"issue_id":"bd-160","depends_on_id":"bd-159","type":"parent-child","created_at":"2025-10-26T18:06:07.569191-07:00","created_by":"daemon"}]} +{"id":"bd-161","title":"Update AGENTS.md and README.md with \"bd daemons\" documentation","description":"Document the new \"bd daemons\" command and all subcommands in AGENTS.md and README.md. Include examples and troubleshooting guidance.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-26T19:41:11.099254-07:00","updated_at":"2025-10-26T19:41:11.099254-07:00","dependencies":[{"issue_id":"bd-161","depends_on_id":"bd-159","type":"parent-child","created_at":"2025-10-26T18:06:07.570687-07:00","created_by":"daemon"}]} +{"id":"bd-162","title":"Implement \"bd daemons logs\" subcommand","description":"Add command to view daemon logs for a specific workspace. Requires daemon logging to file (may need separate issue for log infrastructure).","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-26T19:41:11.099659-07:00","updated_at":"2025-10-26T19:41:11.099659-07:00"} +{"id":"bd-163","title":"Refactor high complexity functions (gocyclo)","description":"11 functions exceed cyclomatic complexity threshold (\u003e30): runDaemonLoop (42), importIssuesCore (71), TestLabelCommands (67), issueDataChanged (39), etc.","design":"Break down complex functions into smaller, testable units. Extract validation, error handling, and business logic into separate functions.","notes":"Refactored issueDataChanged from complexity 39 → 11 by extracting into fieldComparator struct with methods for each comparison type.\n\nRefactored runDaemonLoop from complexity 42 → 7 by extracting:\n- setupDaemonLogger: Logger initialization logic\n- setupDaemonLock: Lock and PID file management\n- startRPCServer: RPC server startup with error handling\n- runGlobalDaemon: Global daemon mode handling\n- createSyncFunc: Sync cycle logic (export, commit, pull, import, push)\n- runEventLoop: Signal handling and main event loop\n\nCode review fixes:\n- Fixed sync overlap: Changed initial sync from `go doSync()` to synchronous `doSync()` to prevent race with ticker\n- Fixed resource cleanup: Replaced `os.Exit(1)` with `return` after acquiring locks to ensure defers run and clean up PID files/locks\n- Added signal.Stop(sigChan) in runEventLoop and runGlobalDaemon to prevent lingering notifications\n- Added server.Stop() in serverErrChan case for consistent cleanup\n\nRefactored TestLabelCom\u0001\u0004\u0013\u0000\u0004\u0013\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000�\u000eA\u000b\u0000_\u001b\u0019�I�E\u00003temp-bad6eeef-f902-459�jA\u000b\u0000\u0017\u001b\u0019�I�E\u00003bd-13updateddaemon{\"id\":\"bd-51\",\"title\":\"Auto-flush writes test pollution and session work to git-tracked issues.jsonl\",\"description\":\"Auto-flush exports ALL issues from DB to issues.jsonl every 5 seconds, including:\\n- Test issues (bd-4053 through bd-4059 were version test junk)\\n- Issues created during debugging sessions\\n- Test pollution from stress tests\\n- Temporary diagnostic issues\\n\\nThis pollutes the git-tracked issues.jsonl with garbage that shouldn't be committed.\\n\\nExample from today:\\n- Git had 49 clean issues\\n- Our DB grew to 100+ with test junk and session work\\n- Auto-flush wrote all 100+ to issues.jsonl\\n- Git status showed modified issues.jsonl with 50+ unwanted issues\\n\\nImpact:\\n- Pollutes git history with test/debug garbage\\n- Makes code review difficult (noise in diffs)\\n- Can't distinguish real work from session artifacts\\n- Other team members pull polluted issues\\n\\nSolutions to consider:\\n1. Disable auto-flush by default (require explicit --enable-auto-flush)\\n2. Add .beadsignore to exclude issue ID patterns\\n3. Make auto-flush only export 'real' issues (exclude test-*)\\n4. Require manual 'bd sync' for git commit\\n5. Auto-flush to separate file (.beads/session.jsonl vs issues.jsonl)\\n\\nRelated: bd-49 (test pollution), isolation_test.go (test DB separation)\",\"status\":\"in_progress\",\"priority\":1,\"issue_type\":\"bug\",\"created_at\":\"2025-10-21T23:54:57.369511-07:00\",\"updated_at\":\"2025-10-22T00:04:09.389477-07:00\"}{\"design\":\"## Analysis\\n\\nConfirmed the issue exists - bd-52 through bd-58 are test pollution in the git-tracked issues.jsonl.\\n\\n### Solution Evaluation:\\n\\n**Option 1: Disable auto-flush by default** ❌\\n- Breaks the auto-sync workflow that users rely on\\n- Requires manual intervention which defeats the purpose\\n- Not recommended\\n\\n**Option 2: Add .beadsignore** ⚠️\\n- Complex to implement (pattern matching, configuration)\\n- Doesn't solve root cause: test issues in production DB\\n- Better to prevent pollution at source\\n\\n**Option 3: Filter on export** ❌\\n- Doesn't solve root cause\\n- Test issues still pollute production DB\\n- Complicates export logic\\n\\n**Option 4: Manual 'bd sync'** ❌\\n- Same issues as Option 1\\n- Breaks automated workflow\\n\\n**Option 5: Separate session file** ❌\\n- Splits issue tracking across files\\n- Confusing for users\\n- Import/export complexity\\n\\n### RECOMMENDED SOLUTION:\\n\\n**Fix the root cause: Tests should NEVER touch the production database**\\n\\nThe real problem is that Go tests ARE properly isolated (they use temp DBs), but someone must be manually creating test issues in the production DB during development/debugging.\\n\\n**Best fix:**\\n1. Document that production DB is for real work only\\n2. Add a convenience command: `bd test-create` that uses a separate test database\\n3. Clean up the existing test pollution: bd-52 through bd-58\\n4. Consider adding a git pre-commit hook to warn about suspicious issues\\n\\nTh","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-26T19:41:11.100062-07:00","updated_at":"2025-10-26T19:41:11.100062-07:00","closed_at":"2025-10-25T13:16:42.865768-07:00","dependencies":[{"issue_id":"bd-163","depends_on_id":"bd-159","type":"parent-child","created_at":"2025-10-26T18:06:07.572636-07:00","created_by":"daemon"}]} +{"id":"bd-164","title":"Add \"bd daemons\" command for multi-daemon management","description":"Add a new \"bd daemons\" command with subcommands to manage daemon processes across all beads repositories/worktrees. Should show all running daemons with metadata (version, workspace, uptime, last sync), allow stopping/restarting individual daemons, auto-clean stale processes, view logs, and show exclusive lock status.","design":"Subcommands:\n- list: Show all running daemons with metadata (workspace, PID, version, socket path, uptime, last activity, exclusive lock status)\n- stop \u003cpath|pid\u003e: Gracefully stop a specific daemon\n- restart \u003cpath|pid\u003e: Stop and restart daemon\n- killall: Emergency stop all daemons\n- health: Verify each daemon responds to ping\n- logs \u003cpath\u003e: View daemon logs\n\nFeatures:\n- Auto-clean stale sockets/dead processes\n- Discovery: Scan for .beads/bd.sock files + running processes\n- Communication: Use existing socket protocol, add GET /status endpoint for metadata","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-26T19:41:11.100511-07:00","updated_at":"2025-10-26T19:41:11.100511-07:00","closed_at":"2025-10-26T19:26:29.045738-07:00","dependencies":[{"issue_id":"bd-164","depends_on_id":"bd-162","type":"blocks","created_at":"2025-10-26T18:06:17.327717-07:00","created_by":"daemon"},{"issue_id":"bd-164","depends_on_id":"bd-160","type":"blocks","created_at":"2025-10-26T18:06:17.351768-07:00","created_by":"daemon"}]} +{"id":"bd-165","title":"Enforce canonical database name (beads.db)","description":"Always use beads.db as the canonical database name. Never auto-detect from multiple .db files.\n\nImplementation:\n- bd init always creates/uses beads.db\n- bd init detects and migrates old databases (vc.db → beads.db, bd.db → beads.db)\n- Daemon refuses to start if multiple .db files exist in .beads/ (exit with ambiguity error)\n- Update database discovery logic to prefer beads.db, error on ambiguity\n\nBenefits:\n- Prevents accidental use of stale databases\n- Clear single source of truth\n- Migration path for existing users","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T17:37:34.389764-07:00","updated_at":"2025-10-27T17:37:34.416718-07:00","closed_at":"2025-10-26T19:04:07.843634-07:00","dependencies":[{"issue_id":"bd-165","depends_on_id":"bd-159","type":"parent-child","created_at":"2025-10-26T18:06:18.339465-07:00","created_by":"daemon"}]} +{"id":"bd-166","title":"Stricter daemon lock file validation","description":"Enhance daemon.lock to include database path and version, validate on client connection.\n\nCurrent: daemon.lock has PID\nProposed: JSON format with database path and version\n\nLock file format:\n{\n \"pid\": 12345,\n \"database\": \"/full/path/to/.beads/beads.db\",\n \"version\": \"0.17.5\",\n \"started_at\": \"2025-10-26T18:00:00Z\"\n}\n\nImplementation:\n- Daemon writes enhanced lock on startup\n- Client reads lock and validates:\n - Database path matches expected\n - Version compatible\n - Fail hard (not just warn) on mismatch\n- Update existing lock validation code (already partially implemented)\n\nBenefits:\n- Catch daemon/database mismatches early\n- Better error messages\n- More robust multi-workspace scenarios","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T17:37:34.391114-07:00","updated_at":"2025-10-27T17:37:34.391114-07:00","closed_at":"2025-10-26T18:36:09.975648-07:00"} +{"id":"bd-167","title":"Enforce canonical database name (beads.db)","description":"Always use beads.db as the canonical database name. Never auto-detect from multiple .db files.\n\nImplementation:\n- bd init always creates/uses beads.db\n- bd init detects and migrates old databases (vc.db → beads.db, bd.db → beads.db)\n- Daemon refuses to start if multiple .db files exist in .beads/ (exit with ambiguity error)\n- Update database discovery logic to prefer beads.db, error on ambiguity\n\nBenefits:\n- Prevents accidental use of stale databases\n- Clear single source of truth\n- Migration path for existing users","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T17:37:34.391778-07:00","updated_at":"2025-10-27T17:37:34.391778-07:00","closed_at":"2025-10-26T18:16:56.23769-07:00"} +{"id":"bd-168","title":"Add .beads/config.json for database path configuration","description":"Create config file to eliminate ambiguity about which database is active.\n\nConfig file format (.beads/config.json):\n{\n \"database\": \"beads.db\",\n \"version\": \"0.17.5\",\n \"jsonl_export\": \"beads.jsonl\" // Allow user to rename\n}\n\nImplementation:\n- bd init creates config.json\n- Daemon and clients read config first (single source of truth)\n- Fall back to beads.db if config missing (backward compat)\n- bd init --jsonl-name allows customizing export filename\n- Gitignore: do NOT ignore config.json (part of repo state)\n\nBenefits:\n- Explicit configuration over convention\n- Allows JSONL renaming for git history hygiene\n- Single source of truth for file paths","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T17:37:34.392142-07:00","updated_at":"2025-10-27T17:37:34.392142-07:00","closed_at":"2025-10-26T18:44:16.133085-07:00"} +{"id":"bd-169","title":"Add migration tooling for database upgrades","description":"Create bd migrate command and auto-migration logic for version upgrades.\n\nImplementation:\n- bd migrate command (or bd init --migrate)\n- Auto-run on first command after daemon version upgrade\n- Detection logic:\n - Find all .db files in .beads/\n - Check schema version in each\n - Prompt to migrate/rename/delete\n- Migration operations:\n - Rename old database to beads.db\n - Update schema version metadata\n - Remove stale databases (with confirmation)\n- Could be part of daemon auto-start logic\n\nUser experience:\n$ bd ready\nDatabase schema mismatch detected.\n Found: vc.db (schema v0.16.0)\n Expected: beads.db (schema v0.17.5)\n \nRun 'bd migrate' to migrate automatically.\n\nBenefits:\n- Smooth upgrade path\n- Prevents confusion on version changes\n- Clean up stale databases\n\nDepends on:\n- Canonical naming (bd-160)\n- Schema versioning (bd-177)","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T17:37:34.392486-07:00","updated_at":"2025-10-27T17:38:38.074606-07:00","closed_at":"2025-10-26T19:04:02.023089-07:00"} +{"id":"bd-17","title":"Remove unreachable RPC methods","description":"Several RPC server and client methods are unreachable and should be removed:\n\nServer methods (internal/rpc/server.go):\n- `Server.GetLastImportTime` (line 2116)\n- `Server.SetLastImportTime` (line 2123)\n- `Server.findJSONLPath` (line 2255)\n\nClient methods (internal/rpc/client.go):\n- `Client.Import` (line 311) - RPC import not used (daemon uses autoimport)\n\nEvidence:\n```bash\ngo run golang.org/x/tools/cmd/deadcode@latest -test ./...\n```\n\nImpact: Removes ~80 LOC of unused RPC code","acceptance_criteria":"- Remove the 4 unreachable methods (~80 LOC total)\n- Verify no callers: `grep -r \"GetLastImportTime\\|SetLastImportTime\\|findJSONLPath\" .`\n- All tests pass: `go test ./internal/rpc/...`\n- Daemon functionality works: test daemon start/stop/operations","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T20:30:19.962209-07:00","updated_at":"2025-10-27T22:22:23.81754-07:00","labels":["cleanup","dead-code","phase-1","rpc"],"dependencies":[{"issue_id":"bd-17","depends_on_id":"bd-10","type":"discovered-from","created_at":"2025-10-24T13:17:40.32522-07:00","created_by":"renumber"},{"issue_id":"bd-17","depends_on_id":"bd-26","type":"parent-child","created_at":"2025-10-27T20:30:19.965239-07:00","created_by":"daemon"}]} +{"id":"bd-170","title":"Update AGENTS.md and README.md with \"bd daemons\" documentation","description":"Document the new \"bd daemons\" command and all subcommands in AGENTS.md and README.md. Include examples and troubleshooting guidance.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T17:37:34.392799-07:00","updated_at":"2025-10-27T17:37:34.392799-07:00"} +{"id":"bd-171","title":"Implement \"bd daemons logs\" subcommand","description":"Add command to view daemon logs for a specific workspace. Requires daemon logging to file (may need separate issue for log infrastructure).","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T17:37:34.393072-07:00","updated_at":"2025-10-27T17:37:34.393072-07:00"} +{"id":"bd-172","title":"Add \"bd daemons\" command for multi-daemon management","description":"Add a new \"bd daemons\" command with subcommands to manage daemon processes across all beads repositories/worktrees. Should show all running daemons with metadata (version, workspace, uptime, last sync), allow stopping/restarting individual daemons, auto-clean stale processes, view logs, and show exclusive lock status.","design":"Subcommands:\n- list: Show all running daemons with metadata (workspace, PID, version, socket path, uptime, last activity, exclusive lock status)\n- stop \u003cpath|pid\u003e: Gracefully stop a specific daemon\n- restart \u003cpath|pid\u003e: Stop and restart daemon\n- killall: Emergency stop all daemons\n- health: Verify each daemon responds to ping\n- logs \u003cpath\u003e: View daemon logs\n\nFeatures:\n- Auto-clean stale sockets/dead processes\n- Discovery: Scan for .beads/bd.sock files + running processes\n- Communication: Use existing socket protocol, add GET /status endpoint for metadata","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-27T17:37:34.393355-07:00","updated_at":"2025-10-27T17:37:34.393355-07:00","closed_at":"2025-10-26T19:26:29.045738-07:00"} +{"id":"bd-173","title":"Update AGENTS.md and README.md with \"bd daemons\" documentation","description":"Document the new \"bd daemons\" command and all subcommands in AGENTS.md and README.md. Include examples and troubleshooting guidance.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T17:38:38.054891-07:00","updated_at":"2025-10-27T17:38:38.054891-07:00"} +{"id":"bd-174","title":"Implement \"bd daemons logs\" subcommand","description":"Add command to view daemon logs for a specific workspace. Requires daemon logging to file (may need separate issue for log infrastructure).","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T17:38:38.05581-07:00","updated_at":"2025-10-27T17:38:38.05581-07:00"} +{"id":"bd-175","title":"Enforce canonical database name (beads.db)","description":"Always use beads.db as the canonical database name. Never auto-detect from multiple .db files.\n\nImplementation:\n- bd init always creates/uses beads.db\n- bd init detects and migrates old databases (vc.db → beads.db, bd.db → beads.db)\n- Daemon refuses to start if multiple .db files exist in .beads/ (exit with ambiguity error)\n- Update database discovery logic to prefer beads.db, error on ambiguity\n\nBenefits:\n- Prevents accidental use of stale databases\n- Clear single source of truth\n- Migration path for existing users","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T17:38:38.05621-07:00","updated_at":"2025-10-27T17:38:38.05621-07:00","closed_at":"2025-10-26T18:16:56.23769-07:00"} +{"id":"bd-176","title":"Add .beads/config.json for database path configuration","description":"Create config file to eliminate ambiguity about which database is active.\n\nConfig file format (.beads/config.json):\n{\n \"database\": \"beads.db\",\n \"version\": \"0.17.5\",\n \"jsonl_export\": \"beads.jsonl\" // Allow user to rename\n}\n\nImplementation:\n- bd init creates config.json\n- Daemon and clients read config first (single source of truth)\n- Fall back to beads.db if config missing (backward compat)\n- bd init --jsonl-name allows customizing export filename\n- Gitignore: do NOT ignore config.json (part of repo state)\n\nBenefits:\n- Explicit configuration over convention\n- Allows JSONL renaming for git history hygiene\n- Single source of truth for file paths","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T17:38:38.056524-07:00","updated_at":"2025-10-27T17:38:38.056524-07:00","closed_at":"2025-10-26T18:44:16.133085-07:00"} +{"id":"bd-177","title":"Stricter daemon lock file validation","description":"Enhance daemon.lock to include database path and version, validate on client connection.\n\nCurrent: daemon.lock has PID\nProposed: JSON format with database path and version\n\nLock file format:\n{\n \"pid\": 12345,\n \"database\": \"/full/path/to/.beads/beads.db\",\n \"version\": \"0.17.5\",\n \"started_at\": \"2025-10-26T18:00:00Z\"\n}\n\nImplementation:\n- Daemon writes enhanced lock on startup\n- Client reads lock and validates:\n - Database path matches expected\n - Version compatible\n - Fail hard (not just warn) on mismatch\n- Update existing lock validation code (already partially implemented)\n\nBenefits:\n- Catch daemon/database mismatches early\n- Better error messages\n- More robust multi-workspace scenarios","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T17:38:38.056822-07:00","updated_at":"2025-10-27T17:38:38.056822-07:00","closed_at":"2025-10-26T18:36:09.975648-07:00"} +{"id":"bd-178","title":"Add migration tooling for database upgrades","description":"Create bd migrate command and auto-migration logic for version upgrades.\n\nImplementation:\n- bd migrate command (or bd init --migrate)\n- Auto-run on first command after daemon version upgrade\n- Detection logic:\n - Find all .db files in .beads/\n - Check schema version in each\n - Prompt to migrate/rename/delete\n- Migration operations:\n - Rename old database to beads.db\n - Update schema version metadata\n - Remove stale databases (with confirmation)\n- Could be part of daemon auto-start logic\n\nUser experience:\n$ bd ready\nDatabase schema mismatch detected.\n Found: vc.db (schema v0.16.0)\n Expected: beads.db (schema v0.17.5)\n \nRun 'bd migrate' to migrate automatically.\n\nBenefits:\n- Smooth upgrade path\n- Prevents confusion on version changes\n- Clean up stale databases\n\nDepends on:\n- Canonical naming (bd-160)\n- Schema versioning (bd-187)","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T17:38:38.057188-07:00","updated_at":"2025-10-27T18:27:28.330167-07:00","closed_at":"2025-10-26T19:04:02.023089-07:00"} +{"id":"bd-179","title":"Improve database naming and version management robustness","description":"Make beads architecture more robust to prevent issues like accidental vc.db usage after version upgrades.\n\nKey improvements:\n\n1. **Canonical database name enforcement**\n - Always use beads.db, never auto-detect from multiple .db files\n - bd init migrates/renames any old databases (vc.db → beads.db, bd.db → beads.db)\n - Daemon refuses to start if multiple .db files exist (ambiguity error)\n\n2. **Database schema versioning**\n - Store beads version in SQLite (PRAGMA user_version or metadata table)\n - Daemon checks on startup: validate schema version matches\n - Auto-migrate or fail with clear instructions on version mismatch\n\n3. **Config file with database path**\n - .beads/config.json specifies {\"database\": \"beads.db\", \"version\": \"0.17.5\"}\n - Daemon and clients read config first (single source of truth)\n - No ambiguity about which file is active\n\n4. **Stricter daemon lock validation**\n - daemon.lock includes database path and beads version (JSON)\n - Client validates: lock says beads.db but I expect bd.db → hard error\n - Already partially implemented, make it stricter\n\n5. **Migration tooling**\n - bd init --migrate or auto-run on first command after upgrade\n - Detects old databases, prompts to migrate/clean up\n - Could be part of daemon auto-start logic\n\n**IMPORTANT**: Allow issues.jsonl to be renamed (users cycle through new names to avoid polluted git history). Only enforce database naming, not JSONL naming.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-27T17:38:38.057563-07:00","updated_at":"2025-10-27T17:38:38.057563-07:00","closed_at":"2025-10-26T19:04:07.843634-07:00"} +{"id":"bd-18","title":"Remove unreachable utility functions","description":"Several small utility functions are unreachable:\n\nFiles to clean:\n1. `internal/storage/sqlite/hash.go` - `computeIssueContentHash` (line 17)\n - Check if entire file can be deleted if only contains this function\n\n2. `internal/config/config.go` - `FileUsed` (line 151)\n - Delete unused config helper\n\n3. `cmd/bd/git_sync_test.go` - `verifyIssueOpen` (line 300)\n - Delete dead test helper\n\n4. `internal/compact/haiku.go` - `HaikuClient.SummarizeTier2` (line 81)\n - Tier 2 summarization not implemented\n - Options: implement feature OR delete method\n\nImpact: Removes 50-100 LOC depending on decisions","acceptance_criteria":"- Remove unreachable functions\n- If entire files can be deleted (like hash.go), delete them\n- For SummarizeTier2: decide to implement or delete, document decision\n- All tests pass: `go test ./...`\n- Verify no callers exist for each function","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T20:30:19.963392-07:00","updated_at":"2025-10-27T22:22:23.81795-07:00","labels":["cleanup","dead-code","phase-1"],"dependencies":[{"issue_id":"bd-18","depends_on_id":"bd-10","type":"related","created_at":"2025-10-24T13:17:40.325463-07:00","created_by":"renumber"},{"issue_id":"bd-18","depends_on_id":"bd-26","type":"parent-child","created_at":"2025-10-27T20:30:19.968126-07:00","created_by":"daemon"}]} +{"id":"bd-180","title":"Add \"bd daemons\" command for multi-daemon management","description":"Add a new \"bd daemons\" command with subcommands to manage daemon processes across all beads repositories/worktrees. Should show all running daemons with metadata (version, workspace, uptime, last sync), allow stopping/restarting individual daemons, auto-clean stale processes, view logs, and show exclusive lock status.","design":"Subcommands:\n- list: Show all running daemons with metadata (workspace, PID, version, socket path, uptime, last activity, exclusive lock status)\n- stop \u003cpath|pid\u003e: Gracefully stop a specific daemon\n- restart \u003cpath|pid\u003e: Stop and restart daemon\n- killall: Emergency stop all daemons\n- health: Verify each daemon responds to ping\n- logs \u003cpath\u003e: View daemon logs\n\nFeatures:\n- Auto-clean stale sockets/dead processes\n- Discovery: Scan for .beads/bd.sock files + running processes\n- Communication: Use existing socket protocol, add GET /status endpoint for metadata","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-27T17:38:38.057858-07:00","updated_at":"2025-10-27T17:38:38.057858-07:00","closed_at":"2025-10-26T19:26:29.045738-07:00"} +{"id":"bd-181","title":"Test database naming","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T18:27:28.309676-07:00","updated_at":"2025-10-27T18:27:28.309676-07:00"} +{"id":"bd-182","title":"Final validation test","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T18:27:28.310533-07:00","updated_at":"2025-10-27T18:27:28.310533-07:00"} +{"id":"bd-183","title":"Update AGENTS.md and README.md with \"bd daemons\" documentation","description":"Document the new \"bd daemons\" command and all subcommands in AGENTS.md and README.md. Include examples and troubleshooting guidance.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T18:27:28.310805-07:00","updated_at":"2025-10-27T18:27:28.310805-07:00"} +{"id":"bd-184","title":"Implement \"bd daemons logs\" subcommand","description":"Add command to view daemon logs for a specific workspace. Requires daemon logging to file (may need separate issue for log infrastructure).","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T18:27:28.311089-07:00","updated_at":"2025-10-27T18:27:28.311089-07:00"} +{"id":"bd-185","title":"Enforce canonical database name (beads.db)","description":"Always use beads.db as the canonical database name. Never auto-detect from multiple .db files.\n\nImplementation:\n- bd init always creates/uses beads.db\n- bd init detects and migrates old databases (vc.db → beads.db, bd.db → beads.db)\n- Daemon refuses to start if multiple .db files exist in .beads/ (exit with ambiguity error)\n- Update database discovery logic to prefer beads.db, error on ambiguity\n\nBenefits:\n- Prevents accidental use of stale databases\n- Clear single source of truth\n- Migration path for existing users","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T18:27:28.311354-07:00","updated_at":"2025-10-27T18:27:28.311354-07:00","closed_at":"2025-10-26T18:16:56.23769-07:00"} +{"id":"bd-186","title":"Add .beads/config.json for database path configuration","description":"Create config file to eliminate ambiguity about which database is active.\n\nConfig file format (.beads/config.json):\n{\n \"database\": \"beads.db\",\n \"version\": \"0.17.5\",\n \"jsonl_export\": \"beads.jsonl\" // Allow user to rename\n}\n\nImplementation:\n- bd init creates config.json\n- Daemon and clients read config first (single source of truth)\n- Fall back to beads.db if config missing (backward compat)\n- bd init --jsonl-name allows customizing export filename\n- Gitignore: do NOT ignore config.json (part of repo state)\n\nBenefits:\n- Explicit configuration over convention\n- Allows JSONL renaming for git history hygiene\n- Single source of truth for file paths","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T18:27:28.311644-07:00","updated_at":"2025-10-27T18:27:28.311644-07:00","closed_at":"2025-10-26T18:44:16.133085-07:00"} +{"id":"bd-187","title":"Stricter daemon lock file validation","description":"Enhance daemon.lock to include database path and version, validate on client connection.\n\nCurrent: daemon.lock has PID\nProposed: JSON format with database path and version\n\nLock file format:\n{\n \"pid\": 12345,\n \"database\": \"/full/path/to/.beads/beads.db\",\n \"version\": \"0.17.5\",\n \"started_at\": \"2025-10-26T18:00:00Z\"\n}\n\nImplementation:\n- Daemon writes enhanced lock on startup\n- Client reads lock and validates:\n - Database path matches expected\n - Version compatible\n - Fail hard (not just warn) on mismatch\n- Update existing lock validation code (already partially implemented)\n\nBenefits:\n- Catch daemon/database mismatches early\n- Better error messages\n- More robust multi-workspace scenarios","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T18:27:28.311897-07:00","updated_at":"2025-10-27T18:27:28.311897-07:00","closed_at":"2025-10-26T18:36:09.975648-07:00"} +{"id":"bd-188","title":"Add migration tooling for database upgrades","description":"Create bd migrate command and auto-migration logic for version upgrades.\n\nImplementation:\n- bd migrate command (or bd init --migrate)\n- Auto-run on first command after daemon version upgrade\n- Detection logic:\n - Find all .db files in .beads/\n - Check schema version in each\n - Prompt to migrate/rename/delete\n- Migration operations:\n - Rename old database to beads.db\n - Update schema version metadata\n - Remove stale databases (with confirmation)\n- Could be part of daemon auto-start logic\n\nUser experience:\n$ bd ready\nDatabase schema mismatch detected.\n Found: vc.db (schema v0.16.0)\n Expected: beads.db (schema v0.17.5)\n \nRun 'bd migrate' to migrate automatically.\n\nBenefits:\n- Smooth upgrade path\n- Prevents confusion on version changes\n- Clean up stale databases\n\nDepends on:\n- Canonical naming (bd-160)\n- Schema versioning (bd-198)","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T18:27:28.312163-07:00","updated_at":"2025-10-27T18:34:51.565471-07:00","closed_at":"2025-10-26T19:04:02.023089-07:00"} +{"id":"bd-189","title":"Improve database naming and version management robustness","description":"Make beads architecture more robust to prevent issues like accidental vc.db usage after version upgrades.\n\nKey improvements:\n\n1. **Canonical database name enforcement**\n - Always use beads.db, never auto-detect from multiple .db files\n - bd init migrates/renames any old databases (vc.db → beads.db, bd.db → beads.db)\n - Daemon refuses to start if multiple .db files exist (ambiguity error)\n\n2. **Database schema versioning**\n - Store beads version in SQLite (PRAGMA user_version or metadata table)\n - Daemon checks on startup: validate schema version matches\n - Auto-migrate or fail with clear instructions on version mismatch\n\n3. **Config file with database path**\n - .beads/config.json specifies {\"database\": \"beads.db\", \"version\": \"0.17.5\"}\n - Daemon and clients read config first (single source of truth)\n - No ambiguity about which file is active\n\n4. **Stricter daemon lock validation**\n - daemon.lock includes database path and beads version (JSON)\n - Client validates: lock says beads.db but I expect bd.db → hard error\n - Already partially implemented, make it stricter\n\n5. **Migration tooling**\n - bd init --migrate or auto-run on first command after upgrade\n - Detects old databases, prompts to migrate/clean up\n - Could be part of daemon auto-start logic\n\n**IMPORTANT**: Allow issues.jsonl to be renamed (users cycle through new names to avoid polluted git history). Only enforce database naming, not JSONL naming.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-27T18:27:28.312446-07:00","updated_at":"2025-10-27T18:27:28.312446-07:00","closed_at":"2025-10-26T19:04:07.843634-07:00"} {"id":"bd-19","title":"Extract SQLite migrations into separate files","description":"The file `internal/storage/sqlite/sqlite.go` is 2,136 lines and contains 11 sequential migrations alongside core storage logic. Extract migrations into a versioned system.\n\nCurrent issues:\n- 11 migration functions mixed with core logic\n- Hard to see migration history\n- Sequential migrations slow database open\n- No clear migration versioning\n\nMigration functions to extract:\n- `migrateDirtyIssuesTable()`\n- `migrateIssueCountersTable()`\n- `migrateExternalRefColumn()`\n- `migrateCompositeIndexes()`\n- `migrateClosedAtConstraint()`\n- `migrateCompactionColumns()`\n- `migrateSnapshotsTable()`\n- `migrateCompactionConfig()`\n- `migrateCompactedAtCommitColumn()`\n- `migrateExportHashesTable()`\n- Plus 1 more (11 total)\n\nTarget structure:\n```\ninternal/storage/sqlite/\n├── sqlite.go # Core storage (~800 lines)\n├── schema.go # Table definitions (~200 lines)\n├── migrations.go # Migration orchestration (~200 lines)\n└── migrations/ # Individual migrations\n ├── 001_initial_schema.go\n ├── 002_dirty_issues.go\n ├── 003_issue_counters.go\n [... through 011_export_hashes.go]\n```\n\nBenefits:\n- Clear migration history\n- Each migration self-contained\n- Easier to review migration changes in PRs\n- Future migrations easier to add","acceptance_criteria":"- All 11 migrations extracted to separate files\n- Migration version tracking in database\n- Migrations run in order on fresh database\n- Existing databases upgrade correctly\n- All tests pass: `go test ./internal/storage/sqlite/...`\n- Database initialization time unchanged or improved\n- Add migration rollback capability (optional, nice-to-have)","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T20:30:47.870671-07:00","updated_at":"2025-10-27T22:22:23.81842-07:00","labels":["database","phase-2","refactor"],"dependencies":[{"issue_id":"bd-19","depends_on_id":"bd-26","type":"parent-child","created_at":"2025-10-27T20:30:47.875564-07:00","created_by":"daemon"}]} +{"id":"bd-190","title":"Add \"bd daemons\" command for multi-daemon management","description":"Add a new \"bd daemons\" command with subcommands to manage daemon processes across all beads repositories/worktrees. Should show all running daemons with metadata (version, workspace, uptime, last sync), allow stopping/restarting individual daemons, auto-clean stale processes, view logs, and show exclusive lock status.","design":"Subcommands:\n- list: Show all running daemons with metadata (workspace, PID, version, socket path, uptime, last activity, exclusive lock status)\n- stop \u003cpath|pid\u003e: Gracefully stop a specific daemon\n- restart \u003cpath|pid\u003e: Stop and restart daemon\n- killall: Emergency stop all daemons\n- health: Verify each daemon responds to ping\n- logs \u003cpath\u003e: View daemon logs\n\nFeatures:\n- Auto-clean stale sockets/dead processes\n- Discovery: Scan for .beads/bd.sock files + running processes\n- Communication: Use existing socket protocol, add GET /status endpoint for metadata","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-27T18:27:28.31272-07:00","updated_at":"2025-10-27T18:27:28.31272-07:00","closed_at":"2025-10-26T19:26:29.045738-07:00"} +{"id":"bd-191","title":"bd sync --dry-run should not modify database during auto-import collision resolution","description":"When running 'bd sync --dry-run', the auto-import step detects colliding issues and remaps them in the database, then exports the modified DB to JSONL. This makes the JSONL file dirty and modifies the database state, which violates the dry-run contract.\n\nExpected: Dry-run should only preview what would happen without making any changes to the database or JSONL.\n\nActual: Auto-import collision resolution runs and modifies the DB, causing the JSONL to become dirty after a supposedly no-op dry-run.\n\nReproduction:\n1. Have colliding issues between DB and JSONL (e.g., after git pull)\n2. Run 'bd sync --dry-run'\n3. Observe that .beads/beads.jsonl becomes modified\n4. Run 'bd sync --dry-run' again - no collisions found (already resolved)\n\nThe dry-run flag needs to be propagated to the auto-import step so it previews collision resolution without applying it.","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-27T18:32:48.522521-07:00","updated_at":"2025-10-27T18:36:50.950009-07:00","closed_at":"2025-10-27T18:36:50.950009-07:00"} +{"id":"bd-192","title":"Test database naming","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T18:34:51.543439-07:00","updated_at":"2025-10-27T18:34:51.543439-07:00"} +{"id":"bd-193","title":"Final validation test","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T18:34:51.543831-07:00","updated_at":"2025-10-27T18:34:51.543831-07:00"} +{"id":"bd-194","title":"Update AGENTS.md and README.md with \"bd daemons\" documentation","description":"Document the new \"bd daemons\" command and all subcommands in AGENTS.md and README.md. Include examples and troubleshooting guidance.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T18:34:51.544152-07:00","updated_at":"2025-10-27T18:34:51.544152-07:00"} +{"id":"bd-195","title":"Implement \"bd daemons logs\" subcommand","description":"Add command to view daemon logs for a specific workspace. Requires daemon logging to file (may need separate issue for log infrastructure).","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T18:34:51.54455-07:00","updated_at":"2025-10-27T18:34:51.54455-07:00"} +{"id":"bd-196","title":"Enforce canonical database name (beads.db)","description":"Always use beads.db as the canonical database name. Never auto-detect from multiple .db files.\n\nImplementation:\n- bd init always creates/uses beads.db\n- bd init detects and migrates old databases (vc.db → beads.db, bd.db → beads.db)\n- Daemon refuses to start if multiple .db files exist in .beads/ (exit with ambiguity error)\n- Update database discovery logic to prefer beads.db, error on ambiguity\n\nBenefits:\n- Prevents accidental use of stale databases\n- Clear single source of truth\n- Migration path for existing users","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T18:34:51.544928-07:00","updated_at":"2025-10-27T18:34:51.544928-07:00","closed_at":"2025-10-26T18:16:56.23769-07:00"} +{"id":"bd-197","title":"Add .beads/config.json for database path configuration","description":"Create config file to eliminate ambiguity about which database is active.\n\nConfig file format (.beads/config.json):\n{\n \"database\": \"beads.db\",\n \"version\": \"0.17.5\",\n \"jsonl_export\": \"beads.jsonl\" // Allow user to rename\n}\n\nImplementation:\n- bd init creates config.json\n- Daemon and clients read config first (single source of truth)\n- Fall back to beads.db if config missing (backward compat)\n- bd init --jsonl-name allows customizing export filename\n- Gitignore: do NOT ignore config.json (part of repo state)\n\nBenefits:\n- Explicit configuration over convention\n- Allows JSONL renaming for git history hygiene\n- Single source of truth for file paths","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T18:34:51.545261-07:00","updated_at":"2025-10-27T18:34:51.545261-07:00","closed_at":"2025-10-26T18:44:16.133085-07:00"} +{"id":"bd-198","title":"Stricter daemon lock file validation","description":"Enhance daemon.lock to include database path and version, validate on client connection.\n\nCurrent: daemon.lock has PID\nProposed: JSON format with database path and version\n\nLock file format:\n{\n \"pid\": 12345,\n \"database\": \"/full/path/to/.beads/beads.db\",\n \"version\": \"0.17.5\",\n \"started_at\": \"2025-10-26T18:00:00Z\"\n}\n\nImplementation:\n- Daemon writes enhanced lock on startup\n- Client reads lock and validates:\n - Database path matches expected\n - Version compatible\n - Fail hard (not just warn) on mismatch\n- Update existing lock validation code (already partially implemented)\n\nBenefits:\n- Catch daemon/database mismatches early\n- Better error messages\n- More robust multi-workspace scenarios","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T18:34:51.545623-07:00","updated_at":"2025-10-27T18:34:51.545623-07:00","closed_at":"2025-10-26T18:36:09.975648-07:00"} +{"id":"bd-199","title":"Add migration tooling for database upgrades","description":"Create bd migrate command and auto-migration logic for version upgrades.\n\nImplementation:\n- bd migrate command (or bd init --migrate)\n- Auto-run on first command after daemon version upgrade\n- Detection logic:\n - Find all .db files in .beads/\n - Check schema version in each\n - Prompt to migrate/rename/delete\n- Migration operations:\n - Rename old database to beads.db\n - Update schema version metadata\n - Remove stale databases (with confirmation)\n- Could be part of daemon auto-start logic\n\nUser experience:\n$ bd ready\nDatabase schema mismatch detected.\n Found: vc.db (schema v0.16.0)\n Expected: beads.db (schema v0.17.5)\n \nRun 'bd migrate' to migrate automatically.\n\nBenefits:\n- Smooth upgrade path\n- Prevents confusion on version changes\n- Clean up stale databases\n\nDepends on:\n- Canonical naming (bd-160)\n- Schema versioning (bd-161)","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T18:34:51.546-07:00","updated_at":"2025-10-27T18:34:51.576772-07:00","closed_at":"2025-10-26T19:04:02.023089-07:00"} {"id":"bd-2","title":"Clean up linter errors (914 total issues)","description":"The codebase has 914 linter issues reported by golangci-lint. While many are documented as baseline in LINTING.md, we should clean these up systematically to improve code quality and maintainability.","design":"Break down by linter category, prioritizing high-impact issues:\n1. dupl (7) - Code duplication\n2. goconst (12) - Repeated strings\n3. gocyclo (11) - High complexity functions\n4. revive (78) - Style issues\n5. gosec (102) - Security warnings\n6. errcheck (683) - Unchecked errors (many in tests)","acceptance_criteria":"All linter categories reduced to acceptable levels, with remaining baseline documented in LINTING.md","notes":"Reduced from 56 to 41 issues locally, then to 0 issues.\n\n**Fixed in commits:**\n- c2c7eda: Fixed 15 actual errors (dupl, gosec, revive, staticcheck, unparam)\n- 963181d: Configured exclusions to get to 0 issues locally\n\n**Current status:**\n- ✅ Local: golangci-lint reports 0 issues\n- ❌ CI: Still failing (see [deleted:bd-50])\n\n**Problem:**\nConfig v2 format or golangci-lint-action@v8 compatibility issue causing CI to fail despite local success.\n\n**Next:** Debug [deleted:bd-50] to fix CI/local discrepancy","status":"in_progress","priority":2,"issue_type":"epic","created_at":"2025-10-24T01:01:12.997982-07:00","updated_at":"2025-10-27T22:22:23.813486-07:00"} {"id":"bd-20","title":"Extract normalizeLabels to shared utility package","description":"The `normalizeLabels` function appears in multiple locations with identical implementation. Extract to a shared utility package.\n\nCurrent locations:\n- `internal/rpc/server.go:37` (53 lines) - full implementation\n- `cmd/bd/list.go:50-52` - uses the server version (needs to use new shared version)\n\nFunction purpose:\n- Trims whitespace from labels\n- Removes empty strings\n- Deduplicates labels\n- Preserves order\n\nTarget structure:\n```\ninternal/util/\n├── strings.go # String utilities\n └── NormalizeLabels([]string) []string\n```\n\nImpact: DRY principle, single source of truth, easier to test","acceptance_criteria":"- Create `internal/util/strings.go` with `NormalizeLabels`\n- Add comprehensive unit tests in `internal/util/strings_test.go`\n- Update `internal/rpc/server.go` to import and use `util.NormalizeLabels`\n- Update `cmd/bd/list.go` to import and use `util.NormalizeLabels`\n- Remove duplicate implementations\n- All tests pass: `go test ./...`\n- Verify label normalization works: test `bd list --label` commands","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T20:31:19.078622-07:00","updated_at":"2025-10-27T22:22:23.818801-07:00","labels":["deduplication","phase-3","refactor"],"dependencies":[{"issue_id":"bd-20","depends_on_id":"bd-26","type":"parent-child","created_at":"2025-10-27T20:31:19.08015-07:00","created_by":"daemon"}]} +{"id":"bd-200","title":"Improve database naming and version management robustness","description":"Make beads architecture more robust to prevent issues like accidental vc.db usage after version upgrades.\n\nKey improvements:\n\n1. **Canonical database name enforcement**\n - Always use beads.db, never auto-detect from multiple .db files\n - bd init migrates/renames any old databases (vc.db → beads.db, bd.db → beads.db)\n - Daemon refuses to start if multiple .db files exist (ambiguity error)\n\n2. **Database schema versioning**\n - Store beads version in SQLite (PRAGMA user_version or metadata table)\n - Daemon checks on startup: validate schema version matches\n - Auto-migrate or fail with clear instructions on version mismatch\n\n3. **Config file with database path**\n - .beads/config.json specifies {\"database\": \"beads.db\", \"version\": \"0.17.5\"}\n - Daemon and clients read config first (single source of truth)\n - No ambiguity about which file is active\n\n4. **Stricter daemon lock validation**\n - daemon.lock includes database path and beads version (JSON)\n - Client validates: lock says beads.db but I expect bd.db → hard error\n - Already partially implemented, make it stricter\n\n5. **Migration tooling**\n - bd init --migrate or auto-run on first command after upgrade\n - Detects old databases, prompts to migrate/clean up\n - Could be part of daemon auto-start logic\n\n**IMPORTANT**: Allow issues.jsonl to be renamed (users cycle through new names to avoid polluted git history). Only enforce database naming, not JSONL naming.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-27T18:34:51.546639-07:00","updated_at":"2025-10-27T18:34:51.546639-07:00","closed_at":"2025-10-26T19:04:07.843634-07:00"} +{"id":"bd-201","title":"Add \"bd daemons\" command for multi-daemon management","description":"Add a new \"bd daemons\" command with subcommands to manage daemon processes across all beads repositories/worktrees. Should show all running daemons with metadata (version, workspace, uptime, last sync), allow stopping/restarting individual daemons, auto-clean stale processes, view logs, and show exclusive lock status.","design":"Subcommands:\n- list: Show all running daemons with metadata (workspace, PID, version, socket path, uptime, last activity, exclusive lock status)\n- stop \u003cpath|pid\u003e: Gracefully stop a specific daemon\n- restart \u003cpath|pid\u003e: Stop and restart daemon\n- killall: Emergency stop all daemons\n- health: Verify each daemon responds to ping\n- logs \u003cpath\u003e: View daemon logs\n\nFeatures:\n- Auto-clean stale sockets/dead processes\n- Discovery: Scan for .beads/bd.sock files + running processes\n- Communication: Use existing socket protocol, add GET /status endpoint for metadata","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-27T18:34:51.546979-07:00","updated_at":"2025-10-27T18:34:51.546979-07:00","closed_at":"2025-10-26T19:26:29.045738-07:00"} +{"id":"bd-202","title":"Add optional post-merge git hook example for bd sync","description":"Create example git hook that auto-runs bd sync after git pull/merge.\n\nAdd to examples/git-hooks/:\n- post-merge hook that checks if .beads/issues.jsonl changed\n- If changed: run `bd sync` automatically\n- Make it optional/documented (not auto-installed)\n\nBenefits:\n- Zero-friction sync after git pull\n- Complements auto-detection as belt-and-suspenders\n\nNote: post-merge hook already exists for pre-commit/post-merge. Extend it to support sync.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T18:43:48.058293-07:00","updated_at":"2025-10-27T18:43:48.058293-07:00","closed_at":"2025-10-27T18:25:19.888407-07:00"} +{"id":"bd-203","title":"Update LINTING.md with current baseline","description":"After cleanup, document the remaining acceptable baseline in LINTING.md so we can track regression.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T18:53:10.38679-07:00","updated_at":"2025-10-27T18:53:10.38679-07:00"} +{"id":"bd-204","title":"Update LINTING.md with current baseline","description":"After cleanup, document the remaining acceptable baseline in LINTING.md so we can track regression.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T18:53:14.531787-07:00","updated_at":"2025-10-27T18:53:14.531787-07:00","closed_at":"2025-10-27T18:37:08.880971-07:00"} +{"id":"bd-205","title":"Update LINTING.md with current baseline","description":"After cleanup, document the remaining acceptable baseline in LINTING.md so we can track regression.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T18:53:14.532297-07:00","updated_at":"2025-10-27T18:53:14.532297-07:00"} +{"id":"bd-206","title":"Import fails when updating open issue to closed without setting closed_at","description":"When importing JSONL, if an issue exists in the database as \"open\" but the JSONL has it as \"closed\", the import tries to UPDATE status to \"closed\" without setting the closed_at timestamp. This violates the CHECK constraint: (status = 'closed') = (closed_at IS NOT NULL).\n\n**Steps to reproduce:**\n1. Have issue bd-X in database with status=\"open\", closed_at=NULL\n2. JSONL has same issue with status=\"closed\", closed_at=\"2025-10-27T...\"\n3. Run bd import -i .beads/beads.jsonl --resolve-collisions\n4. Error: \"constraint failed: CHECK constraint failed: (status = 'closed') = (closed_at IS NOT NULL) (275)\"\n\n**Expected behavior:**\nImport should update both status AND closed_at when transitioning to closed.\n\n**Actual behavior:**\nImport only updates status field, leaving closed_at=NULL, violating constraint.\n\n**Observed during:**\nSyncing two workspaces where collision resolution remapped bd-45. One workspace had it open, the other had it closed. Import tried to update open→closed but didn't copy closed_at from JSONL.\n\n**Impact:**\n- Prevents successful import when JSONL has closed issues that DB has as open\n- Blocks multi-workspace sync scenarios\n- Forces manual database rebuilds\n\n**Suggested fix:**\nIn import code, when updating an issue, if status changes to \"closed\", ensure closed_at is set from JSONL. Similarly, if status changes from \"closed\" to \"open\", ensure closed_at is cleared.","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-27T18:58:42.228957-07:00","updated_at":"2025-10-27T19:06:37.684793-07:00","closed_at":"2025-10-27T19:06:37.684793-07:00"} +{"id":"bd-207","title":"Fix remaining test failures - database initialization errors","description":"36 tests in cmd/bd are failing with 'database not initialized: issue_prefix config is missing' errors.\n\nAlready fixed (24 tests):\n- ✅ autoimport_collision_test.go - updated createTestDBWithIssues helper\n- ✅ autostart_test.go - added config.Initialize() call\n- ✅ compact_test.go - added SetConfig calls \n- ✅ compactor_test.go - updated setupTestStorage and createClosedIssue\n- ✅ ready_test.go - using newTestStore helper\n\nStill failing (36 tests in cmd/bd):\n- merge_test.go (TestValidateMerge, TestValidateMergeMultipleSelfReferences, TestPerformMergeIdempotent, TestPerformMergePartialRetry)\n- main_test.go (various auto-import/export tests)\n- dep_test.go (TestDepAdd, TestDepRemove, TestDepTypes, TestDepCycleDetection)\n- export_import_test.go, import_*.go files (various import tests)\n- init_test.go (TestInitWithCustomDBPath)\n- integrity_test.go (TestCheckOrphanedDeps, TestCountDBIssues, TestValidatePreExport)\n\nSolution:\nUpdated test_helpers_test.go with newTestStore(t, dbPath) helper that:\n1. Creates directory structure\n2. Initializes SQLite store\n3. Sets issue_prefix config to 'test'\n4. Auto-cleanup via t.Cleanup()\n\nAll remaining tests need to replace manual sqlite.New() calls with newTestStore(t, dbPath).","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T19:36:16.764891-07:00","updated_at":"2025-10-27T19:54:31.429989-07:00","closed_at":"2025-10-27T19:54:31.429989-07:00"} {"id":"bd-21","title":"Centralize BD_DEBUG logging into debug package","description":"The codebase has 43 scattered instances of `if os.Getenv(\"BD_DEBUG\") != \"\"` debug checks across 6 files. Centralize into a debug logging package.\n\nCurrent locations:\n- `cmd/bd/main.go` - 15 checks\n- `cmd/bd/autoflush.go` - 6 checks\n- `cmd/bd/nodb.go` - 4 checks\n- `internal/rpc/server.go` - 2 checks\n- `internal/rpc/client.go` - 5 checks\n- `cmd/bd/daemon_autostart.go` - 11 checks\n\nTarget structure:\n```\ninternal/debug/\n└── debug.go\n```\n\nBenefits:\n- Centralized debug logging\n- Easier to add structured logging later\n- Testable (can mock debug output)\n- Consistent debug message format\n\nImpact: Removes 43 scattered checks, improves code clarity","acceptance_criteria":"- Create `internal/debug/debug.go` with `Enabled`, `Logf`, `Printf`\n- Add unit tests in `internal/debug/debug_test.go` (test with/without BD_DEBUG)\n- Replace all 43 instances of `os.Getenv(\"BD_DEBUG\")` checks with `debug.Logf()`\n- Verify debug output works: run with `BD_DEBUG=1 bd status`\n- All tests pass: `go test ./...`\n- No behavior change (output identical to before)","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T20:31:19.089078-07:00","updated_at":"2025-10-27T22:22:23.819123-07:00","labels":["deduplication","logging","phase-3","refactor"],"dependencies":[{"issue_id":"bd-21","depends_on_id":"bd-26","type":"parent-child","created_at":"2025-10-27T21:48:41.542395-07:00","created_by":"stevey"}]} {"id":"bd-22","title":"Consider central serialization package for JSON handling","description":"Multiple parts of the codebase handle JSON serialization of issues with slightly different approaches. Consider creating a centralized serialization package to ensure consistency.\n\nCurrent serialization locations:\n- `cmd/bd/export.go` - JSONL export (issues to file)\n- `cmd/bd/import.go` - JSONL import (file to issues)\n- `internal/rpc/protocol.go` - RPC JSON marshaling\n- `internal/storage/memory/memory.go` - In-memory marshaling\n\nPotential benefits:\n- Single source of truth for JSON format\n- Consistent field naming\n- Easier to add new fields\n- Centralized validation\n\nNote: This is marked **optional** because:\n- Current serialization mostly works\n- May not provide enough benefit to justify refactor\n- Risk of breaking compatibility\n\nDecision point: Evaluate if benefits outweigh refactoring cost\n\nImpact: TBD based on investigation - may defer to future work","acceptance_criteria":"- Create serialization package with documented JSON format\n- Migrate export/import to use centralized serialization\n- All existing JSONL files can be read with new code\n- All tests pass: `go test ./...`\n- Export/import round-trip works perfectly\n- RPC protocol unchanged (or backwards compatible)","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-27T20:31:19.090608-07:00","updated_at":"2025-10-27T22:22:23.81947-07:00","labels":["deduplication","optional","phase-3","refactor","serialization"],"dependencies":[{"issue_id":"bd-22","depends_on_id":"bd-26","type":"parent-child","created_at":"2025-10-27T20:31:19.092328-07:00","created_by":"daemon"}]} {"id":"bd-23","title":"Audit and consolidate collision test coverage","description":"The codebase has 2,019 LOC of collision detection tests across 3 files. Run coverage analysis to identify redundant test cases and consolidate.\n\nTest files:\n- `cmd/bd/import_collision_test.go` - 974 LOC\n- `cmd/bd/autoimport_collision_test.go` - 750 LOC\n- `cmd/bd/import_collision_regression_test.go` - 295 LOC\n\nTotal: 2,019 LOC of collision tests\n\nAnalysis steps:\n1. Run coverage analysis\n2. Identify redundant tests\n3. Document findings\n\nConsolidation strategy:\n- Keep regression tests for critical bugs\n- Merge overlapping table-driven tests\n- Remove redundant edge case tests covered elsewhere\n- Ensure all collision scenarios still tested\n\nExpected outcome: Reduce to ~1,200 LOC (save ~800 lines) while maintaining coverage\n\nImpact: Faster test runs, easier maintenance, clearer test intent","acceptance_criteria":"- Coverage analysis completed and documented\n- Redundant tests identified (~800 LOC estimated)\n- Consolidated test suite maintains or improves coverage\n- All remaining tests pass: `go test ./cmd/bd/...`\n- Test run time unchanged or faster\n- Document which tests were removed and why\n- Coverage percentage maintained: `go test -cover ./cmd/bd/` shows same %","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T20:32:00.130855-07:00","updated_at":"2025-10-27T22:22:23.819794-07:00","labels":["phase-4","test-cleanup"],"dependencies":[{"issue_id":"bd-23","depends_on_id":"bd-26","type":"parent-child","created_at":"2025-10-27T20:32:00.132251-07:00","created_by":"daemon"}]} @@ -21,10 +129,10 @@ {"id":"bd-28","title":"Fix auto-import creating duplicates instead of updating issues","description":"ROOT CAUSE: server_export_import_auto.go line 221 uses ResolveCollisions: true for ALL auto-imports. This is wrong.\n\nProblem:\n- ResolveCollisions is for branch merges (different issues with same ID)\n- Auto-import should UPDATE existing issues, not create duplicates\n- Every git pull creates NEW duplicate issues with different IDs\n- Two agents ping-pong creating endless duplicates\n\nEvidence:\n- 31 duplicate groups found (bd duplicates)\n- bd-236-246 are duplicates of bd-224-235\n- Both agents keep pulling and creating more duplicates\n- JSONL file grows endlessly with duplicates\n\nThe Fix:\nChange checkAndAutoImportIfStale in server_export_import_auto.go:\n- Remove ResolveCollisions: true (line 221)\n- Use normal import logic that updates existing issues by ID\n- Only use ResolveCollisions for explicit bd import --resolve-collisions\n\nImpact: Critical - makes beads unusable for multi-agent workflows","acceptance_criteria":"- Auto-import does NOT create duplicates when pulling git changes\n- Existing issues are updated in-place by ID match\n- No ping-pong commits between agents\n- Test: two agents updating same issue should NOT create duplicates\n- bd duplicates shows 0 groups after fix","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-27T21:48:57.733846-07:00","updated_at":"2025-10-27T22:26:40.627239-07:00","closed_at":"2025-10-27T22:26:40.627239-07:00"} {"id":"bd-29","title":"Remove Daemon Storage Cache","description":"The daemon's multi-repo storage cache is the root cause of stale data bugs. Since global daemon is deprecated, we only ever serve one repository, making the cache unnecessary complexity. This epic removes the cache entirely for simpler, more reliable direct storage access.","design":"For local daemon (single repository), eliminate the cache entirely:\n- Use s.storage field directly (opened at daemon startup)\n- Remove getStorageForRequest() routing logic\n- Remove server_cache_storage.go entirely (~300 lines)\n- Remove cache-related tests\n- Simplify Server struct\n\nBenefits:\n✅ No staleness bugs: Always using live SQLite connection\n✅ Simpler code: Remove ~300 lines of cache management\n✅ Easier debugging: Direct storage access, no cache indirection\n✅ Same performance: Cache was always 1 entry for local daemon anyway","acceptance_criteria":"- Daemon has no storage cache code\n- All tests pass\n- MCP integration works\n- No stale data bugs\n- Documentation updated\n- Performance validated","status":"open","priority":1,"issue_type":"epic","created_at":"2025-10-27T22:55:10.388648-07:00","updated_at":"2025-10-27T22:55:10.388648-07:00"} {"id":"bd-3","title":"Investigate and upgrade to modernc.org/sqlite 1.39.1+","description":"We had to pin modernc.org/sqlite to v1.38.2 due to a FOREIGN KEY constraint regression in v1.39.1 (SQLite 3.50.4).\n\n**Issue:** [deleted:bd-47], GH #144\n\n**Symptom:** CloseIssue fails with \"FOREIGN KEY constraint failed (787)\" when called via MCP/daemon, but works fine via CLI.\n\n**Root Cause:** Unknown - likely stricter FK enforcement in SQLite 3.50.4 or modernc.org wrapper changes.\n\n**Workaround:** Pinned to v1.38.2 (SQLite 3.49.x)\n\n**TODO:**\n1. Monitor modernc.org/sqlite releases for fixes\n2. Check SQLite 3.50.5+ changelogs for FK-related fixes\n3. Investigate why daemon mode fails but CLI succeeds (connection reuse? transaction isolation?)\n4. Consider filing upstream issue with reproducible test case\n5. Upgrade when safe","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-24T11:49:12.836292-07:00","updated_at":"2025-10-27T22:22:23.813745-07:00"} -{"id":"bd-30","title":"Audit Current Cache Usage","description":"Understand exactly what code depends on the storage cache","acceptance_criteria":"- Document showing all cache dependencies\n- Confirmation that removing cache won't break MCP\n- List of tests that need updating\n\nFiles to examine:\n- internal/rpc/server_cache_storage.go (cache implementation)\n- internal/rpc/client.go (how req.Cwd is set)\n- internal/rpc/server_*.go (all getStorageForRequest calls)\n- integrations/beads-mcp/ (MCP multi-repo logic)\n\nTasks:\n- Document all callers of getStorageForRequest()\n- Verify req.Cwd is only set by RPC client for database discovery\n- Confirm MCP server doesn't rely on multi-repo cache behavior\n- Check if any tests assume multi-repo routing\n- Review environment variables: BEADS_DAEMON_MAX_CACHE_SIZE, BEADS_DAEMON_CACHE_TTL, BEADS_DAEMON_MEMORY_THRESHOLD_MB","notes":"AUDIT COMPLETE\n\ngetStorageForRequest() callers: 17 production + 11 test\n- server_issues_epics.go: 8 calls\n- server_labels_deps_comments.go: 4 calls \n- server_export_import_auto.go: 2 calls\n- server_compact.go: 2 calls\n- server_routing_validation_diagnostics.go: 1 call\n- server_eviction_test.go: 11 calls (DELETE entire file)\n\nPattern everywhere: store, err := s.getStorageForRequest(req) → store := s.storage\n\nreq.Cwd usage: Only for multi-repo routing. Local daemon always serves 1 repo, so routing is unused.\n\nMCP server: Uses separate daemons per repo (no req.Cwd usage found). NOT affected by cache removal.\n\nCache env vars to deprecate:\n- BEADS_DAEMON_MAX_CACHE_SIZE (used in server_core.go:63)\n- BEADS_DAEMON_CACHE_TTL (used in server_core.go:72)\n- BEADS_DAEMON_MEMORY_THRESHOLD_MB (used in server_cache_storage.go:47)\n\nServer struct fields to remove:\n- storageCache, cacheMu, maxCacheSize, cacheTTL, cleanupTicker, cacheHits, cacheMisses\n\nTests to delete:\n- server_eviction_test.go (entire file - 9 tests)\n- limits_test.go cache assertions\n\nSpecial consideration: ValidateDatabase endpoint uses findDatabaseForCwd() outside cache. Verify if used, then remove or inline.\n\nSafe to proceed with removal - cache always had 1 entry in local daemon model.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T22:55:19.3723-07:00","updated_at":"2025-10-27T23:04:55.127012-07:00","closed_at":"2025-10-27T23:02:41.30653-07:00","dependencies":[{"issue_id":"bd-30","depends_on_id":"bd-29","type":"parent-child","created_at":"2025-10-27T22:55:19.373816-07:00","created_by":"stevey"}]} -{"id":"bd-31","title":"Remove Storage Cache from Server Struct","description":"Eliminate cache fields and use s.storage directly","acceptance_criteria":"- Server struct has no cache fields\n- NewServer() doesn't initialize cache\n- Start() doesn't run cache cleanup goroutines\n- Stop() only closes single s.storage\n\nChanges needed:\n- Remove cache-related fields from Server struct in server_core.go\n- Remove cache size/TTL parsing from env vars in NewServer()\n- Remove cleanup ticker goroutine from Start()\n- Remove cache cleanup logic from Stop()","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T22:55:25.474412-07:00","updated_at":"2025-10-27T23:06:57.205442-07:00","closed_at":"2025-10-27T23:06:57.205442-07:00","dependencies":[{"issue_id":"bd-31","depends_on_id":"bd-29","type":"parent-child","created_at":"2025-10-27T22:55:25.475344-07:00","created_by":"stevey"}]} -{"id":"bd-32","title":"Replace getStorageForRequest with Direct Access","description":"Replace all getStorageForRequest(req) calls with s.storage","acceptance_criteria":"- No references to getStorageForRequest() in codebase (except in deleted file)\n- All handlers use s.storage directly\n- Code compiles without errors\n\nFiles to update:\n- internal/rpc/server_issues_epics.go (~8 calls)\n- internal/rpc/server_labels_deps_comments.go (~4 calls)\n- internal/rpc/server_compact.go (~2 calls)\n- internal/rpc/server_export_import_auto.go (~2 calls)\n- internal/rpc/server_routing_validation_diagnostics.go (~1 call)\n\nPattern: store, err := s.getStorageForRequest(req) → store := s.storage","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T22:55:33.196818-07:00","updated_at":"2025-10-27T23:12:20.944306-07:00","closed_at":"2025-10-27T23:12:20.944306-07:00","dependencies":[{"issue_id":"bd-32","depends_on_id":"bd-29","type":"parent-child","created_at":"2025-10-27T22:55:33.19824-07:00","created_by":"stevey"},{"issue_id":"bd-32","depends_on_id":"bd-31","type":"blocks","created_at":"2025-10-27T22:55:33.198782-07:00","created_by":"stevey"}]} -{"id":"bd-33","title":"Delete server_cache_storage.go","description":"Remove the entire cache implementation file (~286 lines)","acceptance_criteria":"- File deleted from repository\n- No compilation errors\n- No references to deleted functions\n\nFunctions being removed:\n- StorageCacheEntry struct\n- evictStaleStorage() - LRU eviction\n- evictCacheBasedOnMemory() - memory pressure eviction\n- getStorageForRequest() - cache lookup and routing\n- findDatabaseForCwd() - database discovery\n- evictStorageForRequest() - manual eviction","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-27T22:55:38.729299-07:00","updated_at":"2025-10-27T22:55:38.729299-07:00","dependencies":[{"issue_id":"bd-33","depends_on_id":"bd-29","type":"parent-child","created_at":"2025-10-27T22:55:38.730254-07:00","created_by":"stevey"},{"issue_id":"bd-33","depends_on_id":"bd-32","type":"blocks","created_at":"2025-10-27T22:55:38.730747-07:00","created_by":"stevey"}]} +{"id":"bd-30","title":"Audit Current Cache Usage","description":"Understand exactly what code depends on the storage cache","acceptance_criteria":"- Document showing all cache dependencies\n- Confirmation that removing cache won't break MCP\n- List of tests that need updating\n\nFiles to examine:\n- internal/rpc/server_cache_storage.go (cache implementation)\n- internal/rpc/client.go (how req.Cwd is set)\n- internal/rpc/server_*.go (all getStorageForRequest calls)\n- integrations/beads-mcp/ (MCP multi-repo logic)\n\nTasks:\n- Document all callers of getStorageForRequest()\n- Verify req.Cwd is only set by RPC client for database discovery\n- Confirm MCP server doesn't rely on multi-repo cache behavior\n- Check if any tests assume multi-repo routing\n- Review environment variables: BEADS_DAEMON_MAX_CACHE_SIZE, BEADS_DAEMON_CACHE_TTL, BEADS_DAEMON_MEMORY_THRESHOLD_MB","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-27T22:55:19.3723-07:00","updated_at":"2025-10-27T22:55:19.3723-07:00","dependencies":[{"issue_id":"bd-30","depends_on_id":"bd-28","type":"parent-child","created_at":"2025-10-24T13:17:40.325689-07:00","created_by":"renumber"},{"issue_id":"bd-30","depends_on_id":"bd-29","type":"parent-child","created_at":"2025-10-27T22:55:19.373816-07:00","created_by":"stevey"}]} +{"id":"bd-31","title":"Remove Storage Cache from Server Struct","description":"Eliminate cache fields and use s.storage directly","acceptance_criteria":"- Server struct has no cache fields\n- NewServer() doesn't initialize cache\n- Start() doesn't run cache cleanup goroutines\n- Stop() only closes single s.storage\n\nChanges needed:\n- Remove cache-related fields from Server struct in server_core.go\n- Remove cache size/TTL parsing from env vars in NewServer()\n- Remove cleanup ticker goroutine from Start()\n- Remove cache cleanup logic from Stop()","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-27T22:55:25.474412-07:00","updated_at":"2025-10-27T22:55:25.474412-07:00","dependencies":[{"issue_id":"bd-31","depends_on_id":"bd-28","type":"parent-child","created_at":"2025-10-24T13:17:40.323778-07:00","created_by":"renumber"},{"issue_id":"bd-31","depends_on_id":"bd-29","type":"parent-child","created_at":"2025-10-27T22:55:25.475344-07:00","created_by":"stevey"}]} +{"id":"bd-32","title":"Replace getStorageForRequest with Direct Access","description":"Replace all getStorageForRequest(req) calls with s.storage","acceptance_criteria":"- No references to getStorageForRequest() in codebase (except in deleted file)\n- All handlers use s.storage directly\n- Code compiles without errors\n\nFiles to update:\n- internal/rpc/server_issues_epics.go (~8 calls)\n- internal/rpc/server_labels_deps_comments.go (~4 calls)\n- internal/rpc/server_compact.go (~2 calls)\n- internal/rpc/server_export_import_auto.go (~2 calls)\n- internal/rpc/server_routing_validation_diagnostics.go (~1 call)\n\nPattern: store, err := s.getStorageForRequest(req) → store := s.storage","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-27T22:55:33.196818-07:00","updated_at":"2025-10-27T22:55:33.196818-07:00","dependencies":[{"issue_id":"bd-32","depends_on_id":"bd-28","type":"parent-child","created_at":"2025-10-24T13:17:40.328628-07:00","created_by":"renumber"},{"issue_id":"bd-32","depends_on_id":"bd-29","type":"parent-child","created_at":"2025-10-27T22:55:33.19824-07:00","created_by":"stevey"},{"issue_id":"bd-32","depends_on_id":"bd-31","type":"blocks","created_at":"2025-10-27T22:55:33.198782-07:00","created_by":"stevey"}]} +{"id":"bd-33","title":"Delete server_cache_storage.go","description":"Remove the entire cache implementation file (~286 lines)","acceptance_criteria":"- File deleted from repository\n- No compilation errors\n- No references to deleted functions\n\nFunctions being removed:\n- StorageCacheEntry struct\n- evictStaleStorage() - LRU eviction\n- evictCacheBasedOnMemory() - memory pressure eviction\n- getStorageForRequest() - cache lookup and routing\n- findDatabaseForCwd() - database discovery\n- evictStorageForRequest() - manual eviction","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-27T22:55:38.729299-07:00","updated_at":"2025-10-27T22:55:38.729299-07:00","dependencies":[{"issue_id":"bd-33","depends_on_id":"bd-28","type":"parent-child","created_at":"2025-10-24T13:17:40.326967-07:00","created_by":"renumber"},{"issue_id":"bd-33","depends_on_id":"bd-29","type":"parent-child","created_at":"2025-10-27T22:55:38.730254-07:00","created_by":"stevey"},{"issue_id":"bd-33","depends_on_id":"bd-32","type":"blocks","created_at":"2025-10-27T22:55:38.730747-07:00","created_by":"stevey"}]} {"id":"bd-34","title":"Remove Cache-Related Tests","description":"Delete or update tests that assume multi-repo caching","acceptance_criteria":"- server_eviction_test.go deleted\n- limits_test.go updated (no cache assertions)\n- All tests pass: go test ./internal/rpc/...\n\nTests to delete:\n- TestCacheEviction\n- TestMemoryPressureEviction\n- TestMtimeInvalidation\n- TestConcurrentCacheAccess\n- TestSubdirectoryCanonicalization\n- TestManualEviction\n- TestLRUEviction\n\nFiles to update:\n- internal/rpc/server_eviction_test.go (DELETE entire file)\n- internal/rpc/limits_test.go (remove cache assertions)","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-27T22:55:44.511897-07:00","updated_at":"2025-10-27T22:55:44.511897-07:00","dependencies":[{"issue_id":"bd-34","depends_on_id":"bd-29","type":"parent-child","created_at":"2025-10-27T22:55:44.512885-07:00","created_by":"stevey"},{"issue_id":"bd-34","depends_on_id":"bd-32","type":"blocks","created_at":"2025-10-27T22:55:44.51336-07:00","created_by":"stevey"}]} {"id":"bd-35","title":"Update Metrics and Health Endpoints","description":"Remove cache-related metrics from health/metrics endpoints","acceptance_criteria":"- bd daemon --health output has no cache fields\n- bd daemon --metrics output has no cache fields\n- No compilation errors\n\nChanges needed:\n- Remove cache_size from health endpoint in server_routing_validation_diagnostics.go\n- Remove cache_size, cache_hits, cache_misses from metrics endpoint\n- Remove CacheHits and CacheMisses fields from internal/rpc/metrics.go","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-27T22:55:49.212047-07:00","updated_at":"2025-10-27T22:55:49.212047-07:00","dependencies":[{"issue_id":"bd-35","depends_on_id":"bd-29","type":"parent-child","created_at":"2025-10-27T22:55:49.213529-07:00","created_by":"stevey"},{"issue_id":"bd-35","depends_on_id":"bd-32","type":"blocks","created_at":"2025-10-27T22:55:49.214149-07:00","created_by":"stevey"}]} {"id":"bd-36","title":"Remove Cache Configuration Docs","description":"Remove documentation of deprecated cache env vars","acceptance_criteria":"- Documentation doesn't reference removed env vars\n- CHANGELOG documents breaking change\n- No mentions of storage cache except in CHANGELOG\n\nFiles to update:\n- ADVANCED.md (remove cache configuration section)\n- commands/daemons.md (remove cache env vars)\n- integrations/beads-mcp/SETUP_DAEMON.md (remove cache tuning)\n- CHANGELOG.md (add removal entry)\n\nDeprecated env vars:\n- BEADS_DAEMON_MAX_CACHE_SIZE\n- BEADS_DAEMON_CACHE_TTL\n- BEADS_DAEMON_MEMORY_THRESHOLD_MB","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-27T22:55:55.365748-07:00","updated_at":"2025-10-27T22:55:55.365748-07:00","dependencies":[{"issue_id":"bd-36","depends_on_id":"bd-29","type":"parent-child","created_at":"2025-10-27T22:55:55.36691-07:00","created_by":"stevey"}]} @@ -32,11 +140,68 @@ {"id":"bd-38","title":"Integration Testing","description":"Verify cache removal doesn't break any workflows","acceptance_criteria":"- All test cases pass\n- No stale data observed\n- Performance is same or better\n- MCP works as before\n\nTest cases:\n1. Basic daemon operations (bd daemon --stop, bd daemon, bd list, bd create, bd show)\n2. Auto-import/export cycle (edit beads.jsonl externally, bd list auto-imports)\n3. Git workflow (git pull updates beads.jsonl, bd list shows pulled issues)\n4. Concurrent operations (multiple bd commands simultaneously)\n5. Daemon health (bd daemon --health, bd daemon --metrics)\n6. MCP operations (test MCP server with multiple repos, verify project switching)","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-27T22:56:10.193552-07:00","updated_at":"2025-10-27T22:56:10.193552-07:00","dependencies":[{"issue_id":"bd-38","depends_on_id":"bd-29","type":"parent-child","created_at":"2025-10-27T22:56:10.195091-07:00","created_by":"stevey"},{"issue_id":"bd-38","depends_on_id":"bd-32","type":"blocks","created_at":"2025-10-27T22:56:10.195658-07:00","created_by":"stevey"},{"issue_id":"bd-38","depends_on_id":"bd-37","type":"blocks","created_at":"2025-10-27T22:56:10.196137-07:00","created_by":"stevey"}]} {"id":"bd-39","title":"Performance Validation","description":"Confirm no performance regression from cache removal","acceptance_criteria":"- Benchmarks show no significant regression\n- Document performance characteristics\n- Confirm single SQLite connection is reused\n\nBenchmarks: go test -bench=. -benchmem ./internal/rpc/...\n\nMetrics to track:\n- Request latency (p50, p99)\n- Throughput (requests/sec)\n- Memory usage\n- SQLite connection overhead\n\nExpected results:\n- Latency: Same or better (no cache overhead)\n- Throughput: Same (cache was always 1 entry)\n- Memory: Lower (no cache structs)\n- Connection overhead: Zero (single connection reused)","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-27T22:56:16.465188-07:00","updated_at":"2025-10-27T22:56:16.465188-07:00","dependencies":[{"issue_id":"bd-39","depends_on_id":"bd-29","type":"parent-child","created_at":"2025-10-27T22:56:16.466028-07:00","created_by":"stevey"},{"issue_id":"bd-39","depends_on_id":"bd-38","type":"blocks","created_at":"2025-10-27T22:56:16.466491-07:00","created_by":"stevey"}]} {"id":"bd-4","title":"GH#146: No color showing in terminal for some users","description":"User reports color not working in macOS (Taho 26.0.1) with iTerm 3.6.4 and Terminal.app, despite color working elsewhere in terminal. Python rich and printf escape codes work.\n\nNeed to investigate:\n- Is NO_COLOR env var set?\n- Terminal type detection?\n- fatih/color library configuration\n- Does bd list show colors? bd ready? bd init?\n- What's the output of: echo $TERM, echo $NO_COLOR","status":"open","priority":2,"issue_type":"bug","created_at":"2025-10-24T22:26:36.22163-07:00","updated_at":"2025-10-27T22:22:23.814019-07:00","external_ref":"github:146"} -{"id":"bd-40","title":"Audit Current Cache Usage","description":"Understand exactly what code depends on the storage cache","acceptance_criteria":"- Document showing all cache dependencies\n- Confirmation that removing cache won't break MCP\n- List of tests that need updating\n\nFiles to examine:\n- internal/rpc/server_cache_storage.go (cache implementation)\n- internal/rpc/client.go (how req.Cwd is set)\n- internal/rpc/server_*.go (all getStorageForRequest calls)\n- integrations/beads-mcp/ (MCP multi-repo logic)\n\nTasks:\n- Document all callers of getStorageForRequest()\n- Verify req.Cwd is only set by RPC client for database discovery\n- Confirm MCP server doesn't rely on multi-repo cache behavior\n- Check if any tests assume multi-repo routing\n- Review environment variables: BEADS_DAEMON_MAX_CACHE_SIZE, BEADS_DAEMON_CACHE_TTL, BEADS_DAEMON_MEMORY_THRESHOLD_MB","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-27T23:01:15.172045-07:00","updated_at":"2025-10-27T23:01:15.172045-07:00"} -{"id":"bd-41","title":"Audit Current Cache Usage","description":"Understand exactly what code depends on the storage cache","acceptance_criteria":"- Document showing all cache dependencies\n- Confirmation that removing cache won't break MCP\n- List of tests that need updating\n\nFiles to examine:\n- internal/rpc/server_cache_storage.go (cache implementation)\n- internal/rpc/client.go (how req.Cwd is set)\n- internal/rpc/server_*.go (all getStorageForRequest calls)\n- integrations/beads-mcp/ (MCP multi-repo logic)\n\nTasks:\n- Document all callers of getStorageForRequest()\n- Verify req.Cwd is only set by RPC client for database discovery\n- Confirm MCP server doesn't rely on multi-repo cache behavior\n- Check if any tests assume multi-repo routing\n- Review environment variables: BEADS_DAEMON_MAX_CACHE_SIZE, BEADS_DAEMON_CACHE_TTL, BEADS_DAEMON_MEMORY_THRESHOLD_MB","status":"in_progress","priority":1,"issue_type":"task","created_at":"2025-10-27T23:02:43.506373-07:00","updated_at":"2025-10-27T23:02:43.506373-07:00"} -{"id":"bd-42","title":"Audit Current Cache Usage","description":"Understand exactly what code depends on the storage cache","acceptance_criteria":"- Document showing all cache dependencies\n- Confirmation that removing cache won't break MCP\n- List of tests that need updating\n\nFiles to examine:\n- internal/rpc/server_cache_storage.go (cache implementation)\n- internal/rpc/client.go (how req.Cwd is set)\n- internal/rpc/server_*.go (all getStorageForRequest calls)\n- integrations/beads-mcp/ (MCP multi-repo logic)\n\nTasks:\n- Document all callers of getStorageForRequest()\n- Verify req.Cwd is only set by RPC client for database discovery\n- Confirm MCP server doesn't rely on multi-repo cache behavior\n- Check if any tests assume multi-repo routing\n- Review environment variables: BEADS_DAEMON_MAX_CACHE_SIZE, BEADS_DAEMON_CACHE_TTL, BEADS_DAEMON_MEMORY_THRESHOLD_MB","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T23:04:55.30365-07:00","updated_at":"2025-10-27T23:04:55.30365-07:00","closed_at":"2025-10-27T23:02:41.30653-07:00"} +{"id":"bd-40","title":"Audit Current Cache Usage","description":"Understand exactly what code depends on the storage cache","acceptance_criteria":"- Document showing all cache dependencies\n- Confirmation that removing cache won't break MCP\n- List of tests that need updating\n\nFiles to examine:\n- internal/rpc/server_cache_storage.go (cache implementation)\n- internal/rpc/client.go (how req.Cwd is set)\n- internal/rpc/server_*.go (all getStorageForRequest calls)\n- integrations/beads-mcp/ (MCP multi-repo logic)\n\nTasks:\n- Document all callers of getStorageForRequest()\n- Verify req.Cwd is only set by RPC client for database discovery\n- Confirm MCP server doesn't rely on multi-repo cache behavior\n- Check if any tests assume multi-repo routing\n- Review environment variables: BEADS_DAEMON_MAX_CACHE_SIZE, BEADS_DAEMON_CACHE_TTL, BEADS_DAEMON_MEMORY_THRESHOLD_MB","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T23:03:44.788141-07:00","updated_at":"2025-10-27T23:03:44.788141-07:00","closed_at":"2025-10-27T23:02:41.30653-07:00"} +{"id":"bd-41","title":"Fix code duplication in label.go (dupl)","description":"Lines 72-120 duplicate lines 122-170 in cmd/bd/label.go. The add and remove commands have nearly identical structure.","design":"Extract common batch operation logic into a shared helper function that takes the operation type as a parameter.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T23:05:31.891478-07:00","updated_at":"2025-10-27T23:05:31.945326-07:00","closed_at":"2025-10-27T23:05:31.945328-07:00","dependencies":[{"issue_id":"bd-41","depends_on_id":"bd-40","type":"parent-child","created_at":"2025-10-24T13:17:40.325899-07:00","created_by":"renumber"}]} +{"id":"bd-42","title":"Refactor high complexity functions (gocyclo)","description":"11 functions exceed cyclomatic complexity threshold (\u003e30): runDaemonLoop (42), importIssuesCore (71), TestLabelCommands (67), issueDataChanged (39), etc.","design":"Break down complex functions into smaller, testable units. Extract validation, error handling, and business logic into separate functions.","notes":"Refactored issueDataChanged from complexity 39 → 11 by extracting into fieldComparator struct with methods for each comparison type.\n\nRefactored runDaemonLoop from complexity 42 → 7 by extracting:\n- setupDaemonLogger: Logger initialization logic\n- setupDaemonLock: Lock and PID file management\n- startRPCServer: RPC server startup with error handling\n- runGlobalDaemon: Global daemon mode handling\n- createSyncFunc: Sync cycle logic (export, commit, pull, import, push)\n- runEventLoop: Signal handling and main event loop\n\nCode review fixes:\n- Fixed sync overlap: Changed initial sync from `go doSync()` to synchronous `doSync()` to prevent race with ticker\n- Fixed resource cleanup: Replaced `os.Exit(1)` with `return` after acquiring locks to ensure defers run and clean up PID files/locks\n- Added signal.Stop(sigChan) in runEventLoop and runGlobalDaemon to prevent lingering notifications\n- Added server.Stop() in serverErrChan case for consistent cleanup\n\nRefactored TestLabelCommands from complexity 67 → \u003c10 by extracting labelTestHelper with methods:\n- createIssue: Issue creation helper\n- addLabel/addLabels: Label addition helpers\n- removeLabel: Label removal helper\n- getLabels: Label retrieval helper\n- assertLabelCount/assertHasLabel/assertHasLabels/assertNotHasLabel: Assertion helpers\n- assertLabelEvent: Event verification helper\n\nRefactored TestReopenCommand from complexity 37 → \u003c10 by extracting reopenTestHelper with methods:\n- createIssue: Issue creation helper\n- closeIssue/reopenIssue: State transition helpers\n- getIssue: Issue retrieval helper\n- addComment: Comment addition helper\n- assertStatus/assertClosedAtSet/assertClosedAtNil: Status assertion helpers\n- assertCommentEvent: Event verification helper\n\nRefactored tryAutoStartDaemon from complexity 34 → \u003c10 by extracting:\n- debugLog: Centralized debug logging helper\n- isDaemonHealthy: Fast-path health check\n- acquireStartLock: Lock acquisition with wait/retry logic\n- handleStaleLock: Stale lock detection and retry\n- handleExistingSocket: Socket cleanup and validation\n- determineSocketMode: Global vs local daemon logic\n- startDaemonProcess: Process spawning and readiness wait\n- setupDaemonIO: I/O redirection setup\n\nRefactored DeleteIssues from complexity 37 → \u003c10 by extracting:\n- buildIDSet: ID deduplication\n- resolveDeleteSet: Cascade/force/validation mode routing\n- expandWithDependents: Recursive dependent collection\n- validateNoDependents: Dependency validation\n- checkSingleIssueValidation: Per-issue dependent check\n- trackOrphanedIssues: Force-mode orphan tracking\n- collectOrphansForID: Per-issue orphan collection\n- buildSQLInClause: SQL placeholder generation\n- populateDeleteStats: Dry-run statistics collection\n- executeDelete: Actual deletion execution\n\nCode review fix (via oracle):\n- Added rows.Err() check in checkSingleIssueValidation to catch iterator errors\n\nRefactored TestLibraryIntegration from complexity 32 → \u003c10 by extracting integrationTestHelper with methods:\n- createIssue/createFullIssue: Issue creation helpers\n- updateIssue/closeIssue: Issue modification helpers\n- addDependency/addLabel/addComment: Relationship helpers\n- getIssue/getDependencies/getLabels/getComments: Retrieval helpers\n- assertID/assertEqual/assertNotNil/assertCount: Assertion helpers\n\nRefactored TestExportImport from complexity 31 → \u003c10 by extracting exportImportHelper with methods:\n- createIssue/createFullIssue: Issue creation helpers\n- searchIssues/getIssue/updateIssue: Storage operations\n- encodeJSONL/validateJSONLines: JSONL encoding and validation\n- assertCount/assertEqual/assertSorted: Assertion helpers\n\nRefactored TestListCommand from complexity 31 → \u003c10 by extracting listTestHelper with methods:\n- createTestIssues: Batch test data creation\n- addLabel: Label addition\n- search: Issue search with filters\n- assertCount/assertEqual/assertAtMost: Assertion helpers\n\nRefactored TestGetEpicsEligibleForClosure from complexity 32 → \u003c10 by extracting epicTestHelper with methods:\n- createEpic/createTask: Issue creation\n- addParentChildDependency/closeIssue: Issue relationships\n- getEligibleEpics/findEpic: Epic status queries\n- assertEpicStats/assertEpicFound/assertEpicNotFound: Epic-specific assertions\n\nRefactored TestCreateIssues from complexity 35 → \u003c10 by extracting createIssuesTestHelper with methods:\n- newIssue: Issue construction helper\n- createIssues: Batch issue creation\n- assertNoError/assertError: Error assertions\n- assertCount/assertIDSet/assertTimestampSet: Field assertions\n- assertUniqueIDs/assertEqual/assertNotNil: Validation helpers\n- assertNoAutoGenID: Error-case validation\n\nAll tests pass after refactoring. ✅\n\n**importIssuesCore was already refactored** (complexity 71 → ~10) using phase-based extraction:\n- getOrCreateStore, handlePrefixMismatch, handleCollisions\n- upsertIssues, importDependencies, importLabels, importComments\n\n**Status:** All 11 high-complexity functions have been refactored to \u003c10 complexity.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T23:05:31.891763-07:00","updated_at":"2025-10-27T23:05:31.945612-07:00","closed_at":"2025-10-27T23:05:31.945614-07:00","dependencies":[{"issue_id":"bd-42","depends_on_id":"bd-40","type":"parent-child","created_at":"2025-10-24T13:17:40.323992-07:00","created_by":"renumber"}]} +{"id":"bd-43","title":"Fix revive style issues (78 issues)","description":"Style violations: unused parameters (many cmd/args in cobra commands), missing exported comments, stuttering names (SQLiteStorage), indent-error-flow issues.","design":"Rename unused params to _, add godoc comments to exported types, fix stuttering names, simplify control flow.","notes":"Fixed 19 revive issues:\n- 14 unused-parameter (renamed to _)\n- 2 redefines-builtin-id (max→maxCount, min→minInt)\n- 3 indent-error-flow (gofmt fixed 2, skipped 1 complex nested one)\n\nRemaining issues are acceptable: 11 unused-params in deeper code, 2 empty-blocks with comments, 1 complex indent case, 1 superfluous-else in test.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-27T23:05:31.891996-07:00","updated_at":"2025-10-27T23:05:31.945939-07:00","closed_at":"2025-10-27T23:05:31.945945-07:00","dependencies":[{"issue_id":"bd-43","depends_on_id":"bd-40","type":"parent-child","created_at":"2025-10-24T13:17:40.322412-07:00","created_by":"renumber"}]} +{"id":"bd-44","title":"Handle unchecked errors (errcheck - 683 issues)","description":"683 unchecked error returns, mostly in tests (Close, Rollback, RemoveAll). Many already excluded in config but still showing up.","design":"Review .golangci.yml exclude-rules. Most defer Close/Rollback errors in tests can be ignored. Add systematic exclusions or explicit _ = assignments where appropriate.","notes":"Fixed all errcheck warnings in production code:\n- Enabled errcheck linter (was disabled)\n- Set tests: false in .golangci.yml to focus on production code\n- Fixed 27 total errors in production code using Oracle guidance:\n * Database patterns: defer func() { _ = rows.Close() }() and defer func() { _ = tx.Rollback() }()\n * Best-effort closers: _ = store.Close(), _ = client.Close()\n * Proper error handling for file writes, fmt.Scanln(), os.Remove()\n- All tests pass\n- Only 2 \"unused\" linter warnings remain (not errcheck)","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-27T23:05:31.892241-07:00","updated_at":"2025-10-27T23:05:31.946189-07:00","closed_at":"2025-10-27T23:05:31.946191-07:00","dependencies":[{"issue_id":"bd-44","depends_on_id":"bd-40","type":"parent-child","created_at":"2025-10-24T13:17:40.324423-07:00","created_by":"renumber"}]} +{"id":"bd-45","title":"Update LINTING.md with current baseline","description":"After cleanup, document the remaining acceptable baseline in LINTING.md so we can track regression.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T23:05:31.892448-07:00","updated_at":"2025-10-27T23:05:31.946419-07:00","closed_at":"2025-10-27T23:05:31.946421-07:00","dependencies":[{"issue_id":"bd-45","depends_on_id":"bd-40","type":"parent-child","created_at":"2025-10-24T13:17:40.327184-07:00","created_by":"renumber"},{"issue_id":"bd-45","depends_on_id":"bd-41","type":"blocks","created_at":"2025-10-24T13:17:40.327422-07:00","created_by":"renumber"},{"issue_id":"bd-45","depends_on_id":"bd-42","type":"blocks","created_at":"2025-10-24T13:17:40.327827-07:00","created_by":"renumber"},{"issue_id":"bd-45","depends_on_id":"bd-43","type":"blocks","created_at":"2025-10-24T13:17:40.32803-07:00","created_by":"renumber"},{"issue_id":"bd-45","depends_on_id":"bd-44","type":"blocks","created_at":"2025-10-24T13:51:54.447799-07:00","created_by":"renumber"}]} +{"id":"bd-46","title":"Fix Windows CI test failures (5 failing tests)","description":"Windows CI has 5 flaky/failing tests: TestTryDaemonLockDetectsRunning, TestIsDaemonRunning_CurrentProcess (PID detection issues), TestScripts/import, TestMetricsSnapshot/uptime, TestSocketCleanup (socket in use).","design":"Investigate Windows-specific PID/process detection and socket cleanup. These may be race conditions or platform differences in how Windows handles process IDs and file locks.","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-27T23:05:31.892655-07:00","updated_at":"2025-10-27T23:05:31.946646-07:00","closed_at":"2025-10-27T23:05:31.946648-07:00"} +{"id":"bd-47","title":"Investigate GH#144: FOREIGN KEY regression in v0.16.0","description":"v0.16.0 introduced FOREIGN KEY constraint error when closing issues via MCP (daemon mode). CLI works fine.\n\n**Key Finding**: Only change between v0.15.0 and v0.16.0 that could affect FK behavior is:\n- modernc.org/sqlite bumped from 1.38.2 to 1.39.1 (commit fbe63bf)\n\n**Evidence**:\n- User reports v0.15.0 worked perfectly (Oct 24, 04:35 UTC)\n- v0.16.0 fails with 'constraint failed: FOREIGN KEY constraint failed (787)'\n- Error occurs in both close() tool and update(status=closed) smart routing\n- CLI 'bd close' works fine, only MCP/daemon fails\n- No changes to CloseIssue() implementation between versions\n- No changes to schema or RPC server handlers\n\n**Next Steps**:\n1. Test downgrading sqlite to 1.38.2\n2. Check modernc.org/sqlite changelog for FK-related changes\n3. Reproduce locally with MCP\n4. If sqlite is the culprit, either fix or pin version\n\n**Related**: GH #144","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-27T23:05:31.892867-07:00","updated_at":"2025-10-27T23:05:31.946888-07:00","closed_at":"2025-10-27T23:05:31.94689-07:00"} +{"id":"bd-48","title":"Remove unused issueMap in scoreCollisions","description":"scoreCollisions() creates issueMap and populates it (lines 135-138) but never uses it. Either remove it or add a TODO comment explaining future use. Located in collision.go:135-138. Cosmetic cleanup.","status":"closed","priority":4,"issue_type":"chore","created_at":"2025-10-27T23:05:31.893135-07:00","updated_at":"2025-10-27T23:05:31.956335-07:00","closed_at":"2025-10-27T23:05:31.956337-07:00"} +{"id":"bd-49","title":"Add --show-all-paths flag to bd dep tree","description":"Currently bd dep tree deduplicates nodes when multiple paths exist (diamond dependencies). Add optional --show-all-paths flag to display the full graph with all paths, showing duplicates. Useful for debugging complex dependency structures and understanding all relationships.","status":"closed","priority":3,"issue_type":"feature","created_at":"2025-10-27T23:05:31.893328-07:00","updated_at":"2025-10-27T23:05:31.955799-07:00","closed_at":"2025-10-27T23:05:31.955801-07:00","dependencies":[{"issue_id":"bd-49","depends_on_id":"bd-47","type":"discovered-from","created_at":"2025-10-24T13:17:40.321578-07:00","created_by":"renumber"}]} {"id":"bd-5","title":"Address gosec security warnings (102 issues)","description":"Security linter warnings: file permissions (0755 should be 0750), G304 file inclusion via variable, G204 subprocess launches. Many are false positives but should be reviewed.","design":"Review each gosec warning. Add exclusions for legitimate cases to .golangci.yml. Fix real security issues (overly permissive file modes).","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-25T13:47:10.719134-07:00","updated_at":"2025-10-27T22:22:23.814301-07:00"} +{"id":"bd-50","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-27T23:05:31.893509-07:00","updated_at":"2025-10-27T23:05:31.953436-07:00","closed_at":"2025-10-27T23:05:31.953438-07:00"} +{"id":"bd-51","title":"Add findByExternalRef query and database index","description":"Implement storage layer support for looking up issues by external_ref field.\n\n## Tasks\n- Add findByExternalRef(ctx, externalRef) method to SQLiteStorage\n- Add database index: CREATE INDEX IF NOT EXISTS idx_issues_external_ref ON issues(external_ref)\n- Handle nil/empty external_ref cases properly\n- Add unit tests for the new query method","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T23:05:31.893715-07:00","updated_at":"2025-10-27T23:05:31.947865-07:00","closed_at":"2025-10-27T23:05:31.947867-07:00"} +{"id":"bd-52","title":"Modify collision detection to check external_ref first","description":"Update DetectCollisions in collision.go to use external_ref as primary matching key.\n\n## Changes\n- In DetectCollisions: before checking issue ID, check if incoming has external_ref\n- If external_ref is set, call findByExternalRef to find existing issue\n- If found by external_ref, compare content:\n - If matches: add to ExactMatches\n - If differs: treat as UPDATE (not collision)\n- Only fall back to ID-based matching if no external_ref\n- Add comprehensive tests for all matching scenarios","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T23:05:31.893887-07:00","updated_at":"2025-10-27T23:05:31.948104-07:00","closed_at":"2025-10-27T23:05:31.94811-07:00"} +{"id":"bd-53","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-27T23:05:31.894073-07:00","updated_at":"2025-10-27T23:05:31.949998-07:00","closed_at":"2025-10-27T23:05:31.950001-07:00"} +{"id":"bd-54","title":"Write comprehensive tests for external_ref import scenarios","description":"Create test suite covering all external_ref import behaviors.\n\n## Test Cases\n1. Import with external_ref → creates new issue\n2. Re-import same external_ref with changes → updates existing\n3. Re-import same external_ref unchanged → idempotent (no update)\n4. Import external issue with ID collision → auto-remaps external issue\n5. Import without external_ref → uses current ID-based logic\n6. Mixed batch: some with external_ref, some without\n7. External_ref match + ID mismatch → updates by external_ref\n8. Local issue (no external_ref) never matched by external import\n9. Performance test with external_ref index\n\nAdd tests to:\n- cmd/bd/import_shared_test.go\n- internal/storage/sqlite/collision_test.go","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T23:05:31.894244-07:00","updated_at":"2025-10-27T23:05:31.94856-07:00","closed_at":"2025-10-27T23:05:31.948562-07:00"} +{"id":"bd-55","title":"Update documentation for external_ref import behavior","description":"Document the new external_ref-based import matching behavior.\n\n## Files to Update\n- README.md: Add external_ref import section\n- QUICKSTART.md: Add example of Jira/GitHub integration workflow\n- AGENTS.md: Document external_ref import behavior for AI agents\n- FAQ.md: Add Q\u0026A about external system integration\n- Add examples/ directory entry showing Jira/GitHub/Linear integration\n\n## Key Points to Document\n- How external_ref matching works\n- That local issues are protected from external imports\n- Example workflow: import → add local tasks → re-import updates\n- ID conflict resolution behavior","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T23:05:31.894446-07:00","updated_at":"2025-10-27T23:05:31.948791-07:00","closed_at":"2025-10-27T23:05:31.948792-07:00"} +{"id":"bd-56","title":"Code review: external_ref import feature","description":"Comprehensive code review of external_ref import implementation.\n\n## Review Checklist\n- [ ] Storage layer changes are correct and efficient\n- [ ] Index created properly on external_ref column\n- [ ] Collision detection logic handles all edge cases\n- [ ] Import flow correctly distinguishes external vs local issues\n- [ ] No breaking changes to existing workflows\n- [ ] Tests cover all scenarios (see bd-54)\n- [ ] Documentation is clear and complete (see bd-55)\n- [ ] Performance impact is acceptable\n- [ ] Error messages are helpful\n- [ ] Logging is appropriate for debugging\n\n## Oracle Review\nUse oracle tool to analyze implementation for correctness, edge cases, and potential issues.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T23:05:31.894714-07:00","updated_at":"2025-10-27T23:05:31.949021-07:00","closed_at":"2025-10-27T23:05:31.949023-07:00"} +{"id":"bd-57","title":"Warn when multiple beads databases detected in workspace hierarchy","description":"Add detection and warning when multiple .beads directories exist in the workspace hierarchy to prevent confusion and database pollution.\n\n## Problem\nUsers can accidentally work in the wrong beads database when multiple exist (e.g., ~/src/beads and ~/src/fred/beads), leading to:\n- Database pollution from cross-contamination\n- Lost work when changes go to wrong database\n- Confusion about which database is active\n\n## Solution\nOn startup, scan parent directories for additional .beads directories and:\n- Warn if multiple found\n- Show which database is currently active\n- Suggest consolidation or cleanup\n\n## Detection Strategy\n1. Walk up directory tree from CWD\n2. Check for .beads/bd.db in each level\n3. If multiple found, show warning with paths\n4. Optionally: check common sibling directories\n\n## Example Warning\n```\n⚠️ Multiple beads databases detected:\n - /Users/stevey/src/beads/.beads (ACTIVE - 111 issues)\n - /Users/stevey/src/fred/beads/.beads (202 issues)\n \nConsider consolidating or removing unused databases.\n```","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-27T23:05:31.894945-07:00","updated_at":"2025-10-27T23:05:31.94925-07:00","closed_at":"2025-10-27T23:05:31.949252-07:00"} +{"id":"bd-58","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-27T23:05:31.895149-07:00","updated_at":"2025-10-27T23:05:31.949475-07:00","closed_at":"2025-10-27T23:05:31.949483-07:00"} +{"id":"bd-59","title":"Fix flaky TestMetricsSnapshot/memory_stats on Linux","description":"Linux CI test TestMetricsSnapshot/memory_stats fails with \"Expected non-zero memory allocation\". Appears to be a flaky test - metrics_test.go:168.","design":"Add retry logic or wait for GC stats to populate, or adjust test expectations for timing.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-10-27T23:05:31.895358-07:00","updated_at":"2025-10-27T23:05:31.949736-07:00","closed_at":"2025-10-27T23:05:31.949738-07:00"} {"id":"bd-6","title":"Add optional post-merge git hook example for bd sync","description":"Create example git hook that auto-runs bd sync after git pull/merge.\n\nAdd to examples/git-hooks/:\n- post-merge hook that checks if .beads/issues.jsonl changed\n- If changed: run `bd sync` automatically\n- Make it optional/documented (not auto-installed)\n\nBenefits:\n- Zero-friction sync after git pull\n- Complements auto-detection as belt-and-suspenders\n\nNote: post-merge hook already exists for pre-commit/post-merge. Extend it to support sync.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-25T22:47:14.668842-07:00","updated_at":"2025-10-27T22:22:23.814647-07:00"} +{"id":"bd-60","title":"Add merged_into field to database schema","description":"Add merged_into field to Issue struct and update database schema to support merge tracking","notes":"Simplified: no schema field needed. Close merged issues with reason 'Merged into bd-X'. See bd-29 design.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T23:05:31.895596-07:00","updated_at":"2025-10-27T23:05:31.950867-07:00","closed_at":"2025-10-27T23:05:31.95087-07:00"} +{"id":"bd-61","title":"Update export/import for merge fields","description":"Include merged_into in JSONL export format. Handle merge relationships on import.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T23:05:31.895826-07:00","updated_at":"2025-10-27T23:05:31.951232-07:00","closed_at":"2025-10-27T23:05:31.951236-07:00"} +{"id":"bd-62","title":"Implement text reference scanning and replacement","description":"Scan all issues for text references to merged IDs (bd-X patterns) and update to target ID. Reuse logic from import collision resolution.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T23:05:31.89605-07:00","updated_at":"2025-10-27T23:05:31.951471-07:00","closed_at":"2025-10-27T23:05:31.951474-07:00"} +{"id":"bd-63","title":"Add CLI merge command and flags","description":"Implement bd merge command with: multiple sources, --into target, --dry-run, --json flags. Add interactive confirmation.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T23:05:31.896334-07:00","updated_at":"2025-10-27T23:05:31.951814-07:00","closed_at":"2025-10-27T23:05:31.951817-07:00"} +{"id":"bd-64","title":"Document label best practices and use cases","description":"Create documentation covering:\n- When to use labels vs structured fields\n- Common label sets (coding agents, open source, product dev, SRE)\n- Naming conventions (kebab-case, specificity, present tense)\n- Anti-patterns (too many labels, overlapping, personal labels)\n- Label lifecycle management\n\nContent from LABELS.md analysis document.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-27T23:05:31.896573-07:00","updated_at":"2025-10-27T23:05:31.952075-07:00","closed_at":"2025-10-27T23:05:31.952078-07:00"} +{"id":"bd-65","title":"Implement dependency migration for merge","description":"Migrate all dependencies from source issue(s) to target issue during merge, removing duplicates and preserving graph integrity","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T23:05:31.896776-07:00","updated_at":"2025-10-27T23:05:31.952296-07:00","closed_at":"2025-10-27T23:05:31.952298-07:00"} +{"id":"bd-66","title":"Fix flaky CI tests in compactor and daemon modules","description":"Multiple test failures observed in CI:\n- TestCompactTier1_DryRun \n- TestCompactTier1Batch_DryRun\n- TestCompactTier1Batch_WithIneligible\n- TestMockAPI_CompactTier1\n- TestBatchOperations_ErrorHandling\n- TestCommentOperationsViaRPC\n- TestMemoryPressureDetection\n- TestPing\n\nAll failures related to 'issue has open dependents or not closed long enough' eligibility checks.\n\nSee CI run: https://github.com/steveyegge/beads/actions/runs/18688772658","notes":"Fixed race condition in compactor_test.go. The createClosedIssue helper was setting ClosedAt to time.Now(), but the eligibility check uses '\u003c= datetime(now, -0 days)'. Changed to now.Add(-1*time.Second) to ensure issues are always eligible. All tests now passing.","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-27T23:05:31.896984-07:00","updated_at":"2025-10-27T23:05:31.952546-07:00","closed_at":"2025-10-27T23:05:31.952549-07:00"} +{"id":"bd-67","title":"Compact command fails with daemon - requires --no-daemon workaround","description":"The 'bd compact' command fails with 'Error: compact requires SQLite storage' when used with the daemon (default mode), but works correctly with the '--no-daemon' flag.\n\nThe daemon RPC interface doesn't properly expose the compact command, even though the daemon itself uses SQLite storage.\n\nReproduction:\n1. Ensure daemon is running (bd daemon status)\n2. Run: bd compact --stats\n Result: Error: compact requires SQLite storage\n3. Run: bd compact --stats --no-daemon\n Result: Works correctly, shows statistics\n\nExpected behavior:\nThe compact command should work through the daemon RPC interface just like other commands (list, create, update, delete, renumber, etc.)\n\nImpact:\nUsers cannot use compact operations in the normal workflow. They must use --no-daemon which bypasses the daemon entirely.\n\nSuggested fix:\nAdd compact operation support to the daemon RPC interface, similar to how renumber and other operations are exposed.","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-27T23:05:31.897217-07:00","updated_at":"2025-10-27T23:05:31.952761-07:00","closed_at":"2025-10-27T23:05:31.952764-07:00"} +{"id":"bd-68","title":"Investigate stress test database pollution (vc-248)","description":"Investigation of stress tests polluting production database with 1,600+ test issues on Oct 21 at 20:24-20:25. Root cause analysis completed. Tests now verified to work correctly with proper isolation.","notes":"Bug confirmed! Tests DO pollute production DB. 1,000 test issues created at 20:46:01-20:46:02 during TestStressNoUniqueConstraintViolations. Root cause: test goroutines connect to production daemon at .beads/bd.sock instead of test daemon.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T23:05:31.89743-07:00","updated_at":"2025-10-27T23:05:31.95299-07:00","closed_at":"2025-10-27T23:05:31.952991-07:00"} +{"id":"bd-69","title":"Consider implementing pre-commit hooks for Storage interface changes","description":"The documentation (INTERFACE_CHANGES.md) suggests adding pre-commit hooks that automatically check for Storage interface changes and verify all mocks are updated. This would prevent similar issues in the future where interface changes break mock implementations.\n\nDiscovered during execution of vc-228 (dogfooding run #14/15).","design":"Implement a pre-commit hook that:\n1. Detects changes to internal/storage/storage.go\n2. Runs scripts/find-storage-mocks.sh to find all mock implementations\n3. Attempts to compile all test files with mocks\n4. Blocks commit if compilation fails\n\nTools: husky, pre-commit framework, or simple .git/hooks/pre-commit script","acceptance_criteria":"- Pre-commit hook installed and documented\n- Hook detects Storage interface changes\n- Hook validates all mocks compile\n- Hook can be bypassed with --no-verify if needed\n- Documentation updated with installation instructions","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-27T23:05:31.89763-07:00","updated_at":"2025-10-27T23:05:31.95319-07:00","closed_at":"2025-10-27T23:05:31.953192-07:00"} {"id":"bd-7","title":"Enforce daemon singleton per workspace with file locking","description":"Agent in ~/src/wyvern discovered 4 simultaneous daemon processes running, causing infinite directory recursion (.beads/.beads/.beads/...). Each daemon used relative paths and created nested .beads/ directories.\n\nRoot cause: No singleton enforcement. Multiple `bd daemon` processes can start in same workspace.\n\nExpected: One daemon per workspace (each workspace = separate .beads/ dir with bd.sock)\nActual: Multiple daemons can run simultaneously in same workspace\n\nNote: Separate git clones = separate workspaces = separate daemons (correct). Git worktrees share .beads/ and have known limitations (documented, use --no-daemon).","design":"Use flock (file locking) on daemon socket or database file to enforce singleton:\n\n1. On daemon start, attempt exclusive lock on .beads/bd.sock or .beads/daemon.lock\n2. If lock held by another process, refuse to start (exit with clear error)\n3. Hold lock for lifetime of daemon process\n4. Release lock on daemon shutdown\n\nAlternative: Use PID file with stale detection (check if PID is still running)\n\nImplementation location: Daemon startup code in cmd/bd/ or internal/daemon/","acceptance_criteria":"1. Starting second daemon process in same workspace fails with clear error\n2. Test: Start daemon, attempt second start, verify failure\n3. Killing daemon releases lock, allowing new daemon to start\n4. No infinite .beads/ directory recursion possible\n5. Works correctly with auto-start mechanism","status":"in_progress","priority":0,"issue_type":"bug","created_at":"2025-10-25T23:13:12.269549-07:00","updated_at":"2025-10-27T22:22:23.814937-07:00"} +{"id":"bd-70","title":"Add customizable time threshold for compact command","description":"Currently compact uses fixed 30-day and 90-day tiers. Add support for custom time thresholds like '--older-than 60h' or '--older-than 2.5d' to allow more flexible compaction policies.\n\nExamples:\n bd compact --all --older-than 60h\n bd compact --all --older-than 2.5d\n bd compact --all --tier 1 --age 48h\n\nThis would allow users to set their own compaction schedules based on their workflow needs.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-27T23:05:31.897864-07:00","updated_at":"2025-10-27T23:05:31.953654-07:00","closed_at":"2025-10-27T23:05:31.953656-07:00"} +{"id":"bd-71","title":"Add --id flag to bd list for filtering by specific issue IDs","description":"","design":"Add --id flag accepting comma-separated IDs. Usage: bd list --id wy-11,wy-12. Combines with other filters. From filter-flag-design.md.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-27T23:05:31.898064-07:00","updated_at":"2025-10-27T23:05:31.953874-07:00","closed_at":"2025-10-27T23:05:31.953876-07:00"} +{"id":"bd-72","title":"bd sync crashes with nil pointer when daemon is running","description":"The 'bd sync' command crashes with a nil pointer dereference when the daemon is running.\n\n**Reproduction:**\n```bash\n# With daemon running\n./bd sync\n```\n\n**Error:**\n```\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x120 pc=0x1012314ac]\n\ngoroutine 1 [running]:\nmain.exportToJSONL({0x1014ec2e0, 0x101a49900}, {0x14000028db0, 0x30})\n /Users/stevey/src/fred/beads/cmd/bd/sync.go:245 +0x4c\n```\n\n**Root cause:**\nThe sync command's `exportToJSONL` function directly accesses `store.SearchIssues()` at line 245, but when daemon mode is active, the global `store` variable is nil. The sync command should either:\n1. Use daemon RPC when daemon is running, or\n2. Force direct mode for sync operations\n\n**Workaround:**\nUse `--no-daemon` flag: `bd sync --no-daemon`","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-27T23:05:31.898293-07:00","updated_at":"2025-10-27T23:05:31.954071-07:00","closed_at":"2025-10-27T23:05:31.954074-07:00"} +{"id":"bd-73","title":"Optimize export dependency queries (N+1 problem)","description":"Export triggers separate GetDependencyRecords() per issue. For large DBs (1000+ issues), this is N+1 queries. Add GetAllDependencyRecords() to fetch all dependencies in one query. Location: cmd/bd/export.go:52-59, import.go:138-142","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-27T23:05:31.89855-07:00","updated_at":"2025-10-27T23:05:31.954311-07:00","closed_at":"2025-10-27T23:05:31.954313-07:00"} +{"id":"bd-74","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":"closed","priority":3,"issue_type":"feature","created_at":"2025-10-27T23:05:31.898778-07:00","updated_at":"2025-10-27T23:05:31.95454-07:00","closed_at":"2025-10-27T23:05:31.954542-07:00"} +{"id":"bd-75","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-27T23:05:31.898986-07:00","updated_at":"2025-10-27T23:05:31.954757-07:00","closed_at":"2025-10-27T23:05:31.954759-07:00"} +{"id":"bd-76","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-27T23:05:31.899204-07:00","updated_at":"2025-10-27T23:05:31.954956-07:00","closed_at":"2025-10-27T23:05:31.954958-07:00"} +{"id":"bd-77","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-27T23:05:31.899406-07:00","updated_at":"2025-10-27T23:05:31.955189-07:00","closed_at":"2025-10-27T23:05:31.955191-07:00"} +{"id":"bd-78","title":"Add compact --dry-run that shows size savings estimates","description":"When running 'bd compact --dry-run', show estimated database size reduction in KB/MB and percentage, similar to what 'du -h' would show.\n\nExample output:\n Tier 1 candidates: 15 issues\n Current size: 2.4 MB\n After compaction: ~1.7 MB (70% reduction, 0.7 MB saved)\n \nThis helps users understand impact before compacting.","status":"closed","priority":3,"issue_type":"feature","created_at":"2025-10-27T23:05:31.899651-07:00","updated_at":"2025-10-27T23:05:31.955403-07:00","closed_at":"2025-10-27T23:05:31.955404-07:00"} +{"id":"bd-79","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-36 (composite index on depends_on_id, type)","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-27T23:05:31.899874-07:00","updated_at":"2025-10-27T23:05:31.955608-07:00","closed_at":"2025-10-27T23:05:31.955611-07:00"} {"id":"bd-8","title":"Daemon fails to auto-import after git pull updates JSONL","description":"After git pull updates .beads/issues.jsonl, daemon doesn't automatically re-import changes, causing stale data to be shown until next sync cycle (up to 5 minutes).\n\nReproduction:\n1. Repo A: Close issues, export, commit, push\n2. Repo B: git pull (successfully updates .beads/issues.jsonl)\n3. bd show \u003cissue\u003e shows OLD status from daemon's SQLite db\n4. JSONL on disk has correct new status\n\nRoot cause: Daemon sync cycle runs on timer (5min). When user manually runs git pull, daemon doesn't detect JSONL was updated externally and continues serving stale data from SQLite.\n\nImpact:\n- High for AI agents using beads in git workflows\n- Breaks fundamental git-as-source-of-truth model\n- Confusing UX: git log shows commit, bd shows old state\n- Data consistency issues between JSONL and daemon\n\nSee WYVERN_SYNC_ISSUE.md for full analysis.","design":"Three possible solutions:\n\nOption 1: Auto-detect and re-import (recommended)\n- Before serving any bd command, check if .beads/issues.jsonl mtime \u003e last import time\n- If newer, auto-import before processing request\n- Fast check, minimal overhead\n\nOption 2: File watcher in daemon\n- Daemon watches .beads/issues.jsonl for mtime changes\n- Auto-imports when file changes\n- More complex, requires file watching infrastructure\n\nOption 3: Explicit sync command\n- User runs `bd sync` after git pull\n- Manual, error-prone, defeats automation\n\nRecommended: Option 1 (auto-detect) + Option 3 (explicit sync) as fallback.","acceptance_criteria":"1. After git pull updates .beads/issues.jsonl, next bd command sees fresh data\n2. No manual import or daemon restart required\n3. Performance impact \u003c 10ms per command (mtime check is fast)\n4. Works in both daemon and non-daemon modes\n5. Test: Two repo clones, update in one, pull in other, verify immediate sync","notes":"**Current Status (2025-10-26):**\n\n✅ **Completed (bd-128):**\n- Created internal/autoimport package with staleness detection\n- Daemon can detect when JSONL is newer than last import\n- Infrastructure exists to call import logic\n\n❌ **Remaining Work:**\nThe daemon's importFunc in server.go (line 2096-2102) is a stub that just logs a notice. It needs to actually import the issues.\n\n**Problem:** \n- importIssuesCore is in cmd/bd package, not accessible from internal/rpc\n- daemon's handleImport() returns 'not yet implemented' error\n\n**Two approaches:**\n1. Move importIssuesCore to internal/import package (shares with daemon)\n2. Use storage layer directly in daemon (create/update issues via Storage interface)\n\n**Blocker:** \nThis is the critical bug causing data corruption:\n- Agent A pushes changes\n- Agent B does git pull\n- Agent B's daemon serves stale SQLite data\n- Agent B exports stale data back to JSONL, overwriting Agent A's changes\n- Agent B pushes, losing Agent A's work\n\n**Next Steps:**\n1. Choose approach (probably #1 - move importIssuesCore to internal/import)\n2. Implement real importFunc in daemon's checkAndAutoImportIfStale()\n3. Test with two-repo scenario (push from A, pull in B, verify B sees changes)\n4. Ensure no data corruption in multi-agent workflows","status":"in_progress","priority":0,"issue_type":"epic","created_at":"2025-10-25T23:13:12.270766-07:00","updated_at":"2025-10-27T22:22:23.815209-07:00"} +{"id":"bd-80","title":"Add performance benchmarks document","description":"Document actual performance metrics with hyperfine tests","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-27T23:05:31.900098-07:00","updated_at":"2025-10-27T23:05:31.956-07:00","closed_at":"2025-10-27T23:05:31.956004-07:00"} +{"id":"bd-81","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-24T13:31:30.82189-07:00","updated_at":"2025-10-25T23:15:33.503824-07:00","closed_at":"2025-10-18T10:09:23.532858-07:00"} +{"id":"bd-82","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":"closed","priority":3,"issue_type":"feature","created_at":"2025-10-24T13:31:30.822073-07:00","updated_at":"2025-10-25T23:15:33.50409-07:00","closed_at":"2025-10-20T14:34:52.483358-07:00"} +{"id":"bd-83","title":"Write tests for merge functionality","description":"Unit tests: validation, merge logic, data integrity. Integration tests: end-to-end workflow, export/import. Edge case tests: chains, circular refs, epics.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-24T13:31:30.82284-07:00","updated_at":"2025-10-25T23:15:33.504325-07:00","closed_at":"2025-10-22T01:07:04.72062-07:00"} +{"id":"bd-84","title":"Add godoc comments for auto-flush functions","description":"Add comprehensive godoc comments for findJSONLPath(), markDirtyAndScheduleFlush(), and flushToJSONL() explaining behavior, concurrency considerations, and error handling. Include notes about debouncing behavior (timer resets on each write, flush occurs 5s after LAST operation) and flush-on-exit guarantees. Located in cmd/bd/main.go:188-307.","status":"closed","priority":4,"issue_type":"chore","created_at":"2025-10-24T13:31:30.82441-07:00","updated_at":"2025-10-25T23:15:33.504524-07:00","closed_at":"2025-10-19T19:22:19.172983-07:00"} +{"id":"bd-85","title":"Document merge command and AI integration","description":"Update README, AGENTS.md with merge command examples. Document AI agent duplicate detection workflow.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-24T13:31:30.824587-07:00","updated_at":"2025-10-25T23:15:33.504759-07:00","closed_at":"2025-10-22T11:37:41.104918-07:00"} +{"id":"bd-86","title":"Stress tests pollute production database with test issues","description":"TestStressNoUniqueConstraintViolations and other stress tests in internal/rpc/stress_test.go create issues in production database instead of test database. Confirmed: 1,000 test issues (Agent X Issue Y) created at 20:46:01 during test run. Root cause: test goroutines connect to production daemon at .beads/bd.sock instead of isolated test daemon in temp directory.","status":"closed","priority":0,"issue_type":"bug","assignee":"amp","created_at":"2025-10-24T13:31:30.824773-07:00","updated_at":"2025-10-25T23:15:33.504967-07:00","closed_at":"2025-10-22T00:35:00.620546-07:00"} +{"id":"bd-87","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-28 (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-27 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-27 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":"closed","priority":4,"issue_type":"feature","created_at":"2025-10-24T13:31:30.824965-07:00","updated_at":"2025-10-25T23:15:33.521043-07:00","closed_at":"2025-10-20T22:00:31.966891-07:00"} +{"id":"bd-88","title":"Add rule-based compaction (e.g., compact children of closed epics)","description":"Support semantic compaction rules beyond just time-based, such as:\n- Compact all children of closed epics\n- Compact by priority level (e.g., all P3/P4 closed issues)\n- Compact by label (e.g., all issues labeled 'archive')\n- Compact by type (e.g., all closed chores)\n\nThis would allow smarter database size management based on semantic meaning rather than just age.","status":"closed","priority":3,"issue_type":"feature","created_at":"2025-10-24T13:31:30.825312-07:00","updated_at":"2025-10-25T23:15:33.505393-07:00","closed_at":"2025-10-22T21:59:19.989241-07:00"} +{"id":"bd-89","title":"Add automated duplicate detection tool for post-import cleanup","description":"After collision resolution with --resolve-collisions, we can end up with content duplicates (different IDs, identical content) when parallel work creates the same issues.\n\n## Problem\nCurrent situation:\n- `deduplicateIncomingIssues()` only deduplicates within the import batch\n- Doesn't detect duplicates between DB and incoming issues\n- Doesn't detect duplicates across the entire database post-import\n- Manual detection: `bd list --json | jq 'group_by(.title) | map(select(length \u003e 1))'`\n\n## Real Example\nAfter import with collision resolution, we had 7 duplicate pairs:\n--196/bd-67: Same external_ref epic\n--196-196: Same findByExternalRef task\n--196-196: Same collision detection task\n--196-196: Same import flow task\n--196-196: Same test writing task\n--196-196: Same documentation task\n--196-196: Same code review task\n\n## Proposed Solution\nAdd `bd duplicates` command that:\n1. Groups all issues by content hash (title + description + design + acceptance_criteria)\n2. Reports duplicate groups with suggested merge target (lowest ID or most references)\n3. Optionally auto-merge with `--auto-merge` flag\n4. Respects status (don't merge open with closed)\n\n## Example Output\n```\n🔍 Found 7 duplicate groups:\n\nGroup 1: \"Feature: Use external_ref as primary matching key\"\n --196 (open, P1, 0 references)\n - bd-67 (open, P1, 0 references)\n Suggested merge: bd merge-196 --into bd-67\n\nGroup 2: \"Add findByExternalRef query\"\n --196 (open, P1, 0 references) \n --196 (open, P1, 0 references)\n Suggested merge: bd merge-196 --into-196\n...\n\nRun with --auto-merge to execute all suggested merges\n```\n\n## Implementation Notes\n- Use same content hashing as deduplicateIncomingIssues\n- Consider reference counts when choosing merge target\n- Skip duplicates with different status (open vs closed)\n- Add --dry-run mode\n- Integration with import: `bd import --resolve-collisions --dedupe-after`","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-24T13:35:14.97041-07:00","updated_at":"2025-10-25T23:15:33.505601-07:00","closed_at":"2025-10-24T13:44:05.529998-07:00"} {"id":"bd-9","title":"Document bd edit command and verify MCP exclusion","description":"Follow-up from PR #152:\n1. Add \"bd edit\" to AGENTS.md with \"Humans only\" note\n2. Verify MCP server doesn't expose bd edit command\n3. Consider adding test for command registration","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-26T13:23:47.982295-07:00","updated_at":"2025-10-27T22:22:23.815469-07:00"} +{"id":"bd-90","title":"Make merge command idempotent for safe retry after partial failures","description":"The merge command currently performs 3 operations without an outer transaction:\n1. Migrate dependencies from source → target\n2. Update text references across all issues\n3. Close source issues\n\nIf merge fails mid-operation (network issue, daemon crash, etc.), a retry will fail or produce incorrect results because some operations already succeeded.\n\n**Goal:** Make merge idempotent so retrying after partial failure is safe and completes the remaining work.\n\n**Idempotency checks needed:**\n- Skip dependency migration if target already has the dependency\n- Skip text reference updates if already updated\n- Skip closing source issues if already closed\n- Report which operations were skipped vs performed\n\n**Example output:**\n```\n✓ Merged 2 issue(s) into bd-48\n - Dependencies: 3 migrated, 2 already existed\n - Text references: 5 updated, 0 already correct\n - Source issues: 1 closed, 1 already closed\n```\n\n**Related:** bd-1 originally requested transaction support, but idempotency is a better solution for this use case since individual operations are already atomic.","design":"Current merge code already has some idempotency:\n- Dependency migration checks `alreadyExists` before adding (line ~145-151 in merge.go)\n- Text reference updates are naturally idempotent (replacing bd-X with bd-Y twice has same result)\n\nMissing idempotency:\n- CloseIssue fails if source already closed\n- Error messages don't distinguish \"already done\" from \"real failure\"\n\nImplementation:\n1. Check source issue status before closing - skip if already closed\n2. Track which operations succeeded/skipped\n3. Return detailed results for user visibility\n4. Consider adding --dry-run output showing what would be done vs skipped","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-24T13:35:23.107034-07:00","updated_at":"2025-10-25T23:15:33.521286-07:00","closed_at":"2025-10-22T11:56:36.526276-07:00"} +{"id":"bd-91","title":"Daemon storage cache doesn't detect external database modifications","description":"When bd commands bypass the daemon and directly modify the database (e.g., `bd import` with direct file access, or deleting/recreating bd.db), the daemon's cached storage connection becomes stale and serves outdated data.\n\n**Reproduction**:\n1. Start daemon: `bd daemon`\n2. Run bd stats → shows N issues\n3. Delete database: `rm .beads/bd.db` \n4. Reinit and import: `bd init \u0026\u0026 bd import -i .beads/issues.jsonl`\n5. Run bd stats → shows 0 issues (wrong!)\n6. Direct query: `sqlite3 .beads/bd.db 'SELECT COUNT(*) FROM issues'` → shows correct count\n7. Restart daemon: `bd daemon --stop` then retry stats → now shows correct count\n\n**Root cause**: \n- server.go:1410-1414 retrieves cached storage without checking if DB file changed\n- Cache only evicts based on TTL (30min) or LRU, never on external modifications\n- Direct file operations bypass daemon, leaving cache stale\n\n**Impact**:\n- Users see incorrect/stale data after external DB operations\n- Confusing behavior with no clear indication cache is stale\n- Requires daemon restart to fix\n\n**Proposed fixes**:\n1. Check mtime on cache hit, invalidate if file changed\n2. Add cache eviction API (bd cache --clear)\n3. Use file locking to prevent external modifications while daemon running\n4. SQLite WAL mode change notifications","design":"**Better approach: Check DB file mtime on cache lookup**\n\nToo many commands bypass the daemon (import, init, renumber, compact, delete, dep tree, export, stale). Notifying from each would be error-prone and easy to forget when adding new commands.\n\n**Implementation:**\n\n1. Add `dbMtime time.Time` field to `StorageCacheEntry`\n2. In `getStorageForRequest()` on cache hit:\n - Stat the DB file to get current mtime\n - If mtime changed since cached, evict entry and reopen\n - Otherwise return cached connection\n3. Store mtime when initially caching\n\n**Code location:**\n- `internal/rpc/server.go:1410-1414` (cache hit path)\n- `internal/rpc/server.go:49-52` (StorageCacheEntry struct)\n\n**Benefits:**\n- Simple, centralized check\n- Works for all commands that bypass daemon\n- Works for external tools modifying DB\n- No need to update every command\n- Minimal performance overhead (one stat() call on cache hit)\n\n**Trade-offs:**\n- Small overhead on every cache hit (negligible - stat is fast)\n- mtime granularity may miss rapid changes (unlikely in practice)","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-24T13:35:23.108829-07:00","updated_at":"2025-10-25T23:15:33.506573-07:00","closed_at":"2025-10-21T21:51:22.331957-07:00"} +{"id":"bd-92","title":"Implement bd quickstart command","description":"Add bd quickstart command to show context-aware repo information: recent issues, database location, configured prefix, example queries. Helps AI agents understand current project state. Companion to bd onboard.","notes":"After review, we already have good context tools: bd stats, bd list, bd ready, and the AGENTS.md onboarding section. Adding bd quickstart would be redundant and doesn't add enough value to justify maintenance cost. Closing as won't implement.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-24T13:35:23.109187-07:00","updated_at":"2025-10-25T23:15:33.506924-07:00","closed_at":"2025-10-22T21:30:29.491988-07:00"} +{"id":"bd-93","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-27 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-24T13:35:23.10938-07:00","updated_at":"2025-10-25T23:15:33.521501-07:00","closed_at":"2025-10-17T23:04:30.223432-07:00"} +{"id":"bd-94","title":"Convert repeated strings to constants (goconst)","description":"12 instances of repeated strings that should be constants: \"alice\", \"windows\", \"bd-2\", \"daemon\", \"import\", \"healthy\", \"unhealthy\", \"1.0.0\", \"custom-1\", \"custom-2\"","design":"Create package-level or test-level constants for frequently used test strings and command names.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-24T13:35:23.109555-07:00","updated_at":"2025-10-25T23:15:33.521665-07:00","closed_at":"2025-10-25T18:02:26.966923-07:00"} +{"id":"bd-95","title":"Auto-flush writes test pollution and session work to git-tracked issues.jsonl","description":"Auto-flush exports ALL issues from DB to issues.jsonl every 5 seconds, including:\n- Test issues (bd-4053 through bd-4059 were version test junk)\n- Issues created during debugging sessions\n- Test pollution from stress tests\n- Temporary diagnostic issues\n\nThis pollutes the git-tracked issues.jsonl with garbage that shouldn't be committed.\n\nExample from today:\n- Git had 49 clean issues\n- Our DB grew to 100+ with test junk and session work\n- Auto-flush wrote all 100+ to issues.jsonl\n- Git status showed modified issues.jsonl with 50+ unwanted issues\n\nImpact:\n- Pollutes git history with test/debug garbage\n- Makes code review difficult (noise in diffs)\n- Can't distinguish real work from session artifacts\n- Other team members pull polluted issues\n\nSolutions to consider:\n1. Disable auto-flush by default (require explicit --enable-auto-flush)\n2. Add .beadsignore to exclude issue ID patterns\n3. Make auto-flush only export 'real' issues (exclude test-*)\n4. Require manual 'bd sync' for git commit\n5. Auto-flush to separate file (.beads/session.jsonl vs issues.jsonl)\n\nRelated: bd-8 (test pollution), isolation_test.go (test DB separation)","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-24T13:35:23.109731-07:00","updated_at":"2025-10-25T23:15:33.52183-07:00","closed_at":"2025-10-22T01:05:59.459797-07:00"} +{"id":"bd-96","title":"Issue counter gets out of sync with actual issues","description":"The issue counter in issue_counters table frequently desyncs from actual max issue ID, causing:\n- Import from JSONL leaves counter at old high value\n- Test pollution increments counter but cleanup doesn't decrement it\n- Delete issues doesn't update counter\n- Only fix is 'rm -rf .beads' which is destructive\n\nExamples from today's session:\n- Had 48 issues but counter at 7714 after test pollution\n- Import from git didn't reset counter\n- Next new issue would be bd-7715 instead of bd-8\n\nProposed fixes:\n1. Auto-recalculate counter from max(issue_id) on import\n2. Add 'bd fix-counter' command\n3. Make counter lazy (always compute from DB, don't store)\n4. Import should reset counter to match imported data\n\nRelated:-254 (test isolation), bd-12 (init timestamp bug)","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-24T13:35:23.109915-07:00","updated_at":"2025-10-25T23:15:33.522009-07:00","closed_at":"2025-10-21T23:13:04.249149-07:00"} +{"id":"bd-97","title":"Counter not synced after import on existing DB with populated issue_counters table","description":"The counter sync fix in counter_sync_test.go only syncs during initial migration when issue_counters table is empty (migrateIssueCountersTable checks count==0). For existing databases with stale counters:\n\n- Import doesn't resync the counter\n- Delete doesn't update counter \n- Renumber doesn't fix counter\n- Counter remains stuck at old high value\n\nExample from today:\n- Had 49 issues after clean import\n- Counter stuck at 4106 from previous test pollution\n- Next issue would be bd-4107 instead of bd-12\n- Even after renumber, counter stayed at 4106\n\nRoot cause: Migration only syncs if table is empty (line 182 in sqlite.go). Once populated, never resyncs.\n\nFix needed: \n1. Sync counter after import operations (not just empty table)\n2. Add counter resync after renumber\n3. Daemon caches counter value - needs to reload after external changes\n\nRelated: bd-8 (original counter sync fix), bd-9 (daemon cache staleness)","notes":"## Investigation Results\n\nAfter thorough code review, all the fixes mentioned in the issue description have ALREADY been implemented:\n\n### ✅ Fixes Already in Place:\n\n1. **Import DOES resync counters**\n - `cmd/bd/import_shared.go:253` calls `SyncAllCounters()` after batch import\n - Verified with new test `TestCounterSyncAfterImport`\n\n2. **Delete DOES update counters**\n - `internal/storage/sqlite/sqlite.go:1424` calls `SyncAllCounters()` after deletion\n - Both single delete and batch delete sync properly\n - Verified with existing tests: `TestCounterSyncAfterDelete`, `TestCounterSyncAfterBatchDelete`\n\n3. **Renumber DOES fix counters**\n - `cmd/bd/renumber.go:298-304` calls `ResetCounter()` then `SyncAllCounters()`\n - Forces counter to actual max ID (not just MAX with stale value)\n\n4. **Daemon cache DOES detect external changes**\n - `internal/rpc/server.go:1466-1487` checks file mtime and evicts stale cache\n - When DB file changes externally, cached storage is evicted and reopened\n\n### Tests Added:\n\n- `TestCounterSyncAfterImport`: Confirms import syncs counters from stale value (4106) to actual max (49)\n- `TestCounterNotSyncedWithoutExplicitSync`: Documents what would happen without the fix (bd-4107 instead of bd-12)\n\n### Conclusion:\n\nThe issue described in bd-12 has been **fully resolved**. All operations (import, delete, renumber) now properly sync counters. The daemon correctly detects external DB changes via file modification time.\n\nThe root cause (migration only syncing empty tables) was fixed by adding explicit `SyncAllCounters()` calls after import, delete, and renumber operations.","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-24T13:35:23.110118-07:00","updated_at":"2025-10-25T23:15:33.522231-07:00","closed_at":"2025-10-22T00:03:46.697918-07:00"} +{"id":"bd-98","title":"Re-land TestDatabaseReinitialization after fixing Windows/Nix issues","description":"TestDatabaseReinitialization test was reverted due to CI failures:\n- Windows: JSON parse errors, missing files \n- Nix: git not available in build environment\n\nNeed to fix and re-land:\n1. Make test work on Windows (path separators, file handling)\n2. Skip test in Nix environment or mock git\n3. Fix JSON parsing issues","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-24T15:06:27.385396-07:00","updated_at":"2025-10-25T23:15:33.508271-07:00","closed_at":"2025-10-25T17:48:52.214323-07:00"} +{"id":"bd-99","title":"Feature: Use external_ref as primary matching key for import updates","description":"Implement external_ref-based matching for imports to enable hybrid workflows with external systems (Jira, GitHub, Linear).\n\n## Problem\nCurrent import collision detection treats any content change as a collision, preventing users from syncing updates from external systems without creating duplicates.\n\n## Solution\nUse external_ref field as primary matching key during imports. When an incoming issue has external_ref set:\n- Search for existing issue with same external_ref\n- If found, UPDATE (not collision)\n- If not found, create new issue\n- Never match local issues (without external_ref)\n\n## Use Cases\n- Jira integration: Import backlog, add local tasks, re-sync updates\n- GitHub integration: Import issues, track with local subtasks, sync status\n- Linear integration: Team coordination with local breakdown\n\n## Reference\nGitHub issue #142: https://github.com/steveyegge/beads/issues/142","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-24T22:10:24.862547-07:00","updated_at":"2025-10-25T23:15:33.508456-07:00","closed_at":"2025-10-25T10:17:33.543504-07:00"}