From ccdacf087b46a3d0a8e925263db426682b8afc81 Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Tue, 14 Oct 2025 12:35:48 -0700 Subject: [PATCH] fix: Auto-export to JSONL now works correctly [fixes #23] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed bug where PersistentPostRun was clearing isDirty flag before calling flushToJSONL(), causing the flush to abort immediately. The fix ensures flushToJSONL() handles the isDirty flag itself, allowing the JSONL export to complete successfully. Also added Arch Linux AUR installation instructions to README. Changes: - cmd/bd/main.go: Fixed PersistentPostRun flush logic - README.md: Added Arch Linux (AUR) installation section - .beads/bd.jsonl: Auto-exported issue bd-169 (init -q flag bug) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .beads/bd.jsonl | 275 +++++++++++++++++++++++++++++++----------------- README.md | 11 ++ cmd/bd/main.go | 12 +-- 3 files changed, 197 insertions(+), 101 deletions(-) diff --git a/.beads/bd.jsonl b/.beads/bd.jsonl index 4549aa94..a9996bd7 100644 --- a/.beads/bd.jsonl +++ b/.beads/bd.jsonl @@ -1,95 +1,180 @@ -{"id":"bd-1","title":"Add export/import commands","description":"Support bd export --format=jsonl and bd import for text-based git workflow","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-12T00:43:03.453438-07:00","updated_at":"2025-10-14T02:42:01.095371-07:00","closed_at":"2025-10-12T20:20:06.977679-07:00"} -{"id":"bd-10","title":"Extend export to include dependencies in JSONL","description":"Modify export.go to include dependencies array in each issue's JSONL output. This makes JSONL self-contained and enables proper collision resolution. Format: {\"id\":\"bd-10\",\"dependencies\":[{\"depends_on_id\":\"bd-5\",\"type\":\"blocks\"}]}","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-12T14:32:19.163526-07:00","updated_at":"2025-10-14T02:42:01.095691-07:00","closed_at":"2025-10-12T15:07:47.937992-07:00","dependencies":[{"issue_id":"bd-10","depends_on_id":"bd-9","type":"parent-child","created_at":"2025-10-12T14:35:59.213222-07:00","created_by":"stevey"}]} -{"id":"bd-11","title":"Test issue to verify fix","description":"This should be bd-11 if the fix works","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-12T14:40:21.419082-07:00","updated_at":"2025-10-14T02:42:01.095834-07:00","closed_at":"2025-10-12T14:40:32.963312-07:00"} -{"id":"bd-12","title":"Implement collision detection in import","description":"Create collision.go with detectCollisions() function. Compare incoming JSONL issues against DB state. Distinguish between: (1) exact match (idempotent), (2) ID match but different content (collision), (3) new issue. Return list of colliding issues.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.056588-07:00","updated_at":"2025-10-14T02:42:01.095994-07:00","closed_at":"2025-10-12T16:06:25.575038-07:00","dependencies":[{"issue_id":"bd-12","depends_on_id":"bd-9","type":"parent-child","created_at":"2025-10-12T14:41:07.947358-07:00","created_by":"stevey"}]} -{"id":"bd-13","title":"Implement reference scoring algorithm","description":"Count references for each colliding issue: text mentions in descriptions/notes/design fields + dependency references. Sort collisions by score ascending (fewest refs first). This minimizes total updates during renumbering.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.204518-07:00","updated_at":"2025-10-14T02:42:01.096115-07:00","closed_at":"2025-10-12T16:26:46.572201-07:00","dependencies":[{"issue_id":"bd-13","depends_on_id":"bd-9","type":"parent-child","created_at":"2025-10-12T14:41:07.951605-07:00","created_by":"stevey"}]} -{"id":"bd-14","title":"Implement ID remapping with reference updates","description":"Allocate new IDs for colliding issues. Update all text field references using word-boundary regex (\\bbd-10\\b). Update dependency records. Build id_mapping for reporting. Handle chain dependencies properly.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.367596-07:00","updated_at":"2025-10-14T02:42:01.096244-07:00","closed_at":"2025-10-12T16:35:13.159992-07:00","dependencies":[{"issue_id":"bd-14","depends_on_id":"bd-9","type":"parent-child","created_at":"2025-10-12T14:41:07.956041-07:00","created_by":"stevey"}]} -{"id":"bd-15","title":"Add --resolve-collisions flag and user reporting","description":"Add import flags: --resolve-collisions (auto-fix) and --dry-run (preview). Display clear report: collisions detected, remappings applied (old→new with scores), reference counts updated. Default behavior: fail on collision (safe).","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.534721-07:00","updated_at":"2025-10-14T02:42:01.09634-07:00","closed_at":"2025-10-12T16:47:11.491645-07:00","dependencies":[{"issue_id":"bd-15","depends_on_id":"bd-9","type":"parent-child","created_at":"2025-10-12T14:41:07.961157-07:00","created_by":"stevey"}]} -{"id":"bd-16","title":"Write comprehensive collision resolution tests","description":"Test cases: simple collision, multiple collisions, dependency updates, text reference updates, chain dependencies, edge cases (partial ID matches, case sensitivity, triple merges). Add to import_test.go and collision_test.go.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.702127-07:00","updated_at":"2025-10-14T02:42:01.096442-07:00","closed_at":"2025-10-12T16:54:25.273886-07:00","dependencies":[{"issue_id":"bd-16","depends_on_id":"bd-9","type":"parent-child","created_at":"2025-10-12T14:41:07.965816-07:00","created_by":"stevey"}]} -{"id":"bd-17","title":"Update documentation for collision resolution","description":"Update README.md with collision resolution section. Update CLAUDE.md with new workflow. Document --resolve-collisions and --dry-run flags. Add example scenarios showing branch merge workflows.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.866649-07:00","updated_at":"2025-10-14T02:42:01.096535-07:00","closed_at":"2025-10-12T17:06:14.930928-07:00","dependencies":[{"issue_id":"bd-17","depends_on_id":"bd-9","type":"parent-child","created_at":"2025-10-12T14:41:07.970302-07:00","created_by":"stevey"}]} -{"id":"bd-18","title":"Add design/notes/acceptance_criteria fields to update command","description":"Currently bd update only supports status, priority, title, assignee. Add support for --design, --notes, --acceptance-criteria flags. This makes it easier to add detailed designs to issues after creation.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-12T14:40:57.032395-07:00","updated_at":"2025-10-14T02:42:01.096627-07:00","closed_at":"2025-10-12T17:10:53.958318-07:00"} -{"id":"bd-19","title":"Fix import zero-value field handling","description":"Import uses zero-value checks (Priority != 0) to determine field updates. This prevents setting priority to 0 or clearing string fields. Export/import round-trip not fully idempotent for zero values. Consider JSON presence detection or explicit preserve-existing semantics. Location: cmd/bd/import.go:95-106","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-10-12T15:13:17.895083-07:00","updated_at":"2025-10-14T02:42:01.096723-07:00"} -{"id":"bd-2","title":"Add PostgreSQL backend","description":"Implement PostgreSQL storage backend as alternative to SQLite for larger teams","status":"closed","priority":3,"issue_type":"feature","created_at":"2025-10-12T00:43:03.457453-07:00","updated_at":"2025-10-14T02:42:01.096822-07:00","closed_at":"2025-10-12T14:15:04.00695-07:00"} -{"id":"bd-20","title":"Add --strict flag for dependency import failures","description":"Currently dependency import errors are warnings (logged to stderr, execution continues). Missing targets or cycles may indicate JSONL corruption. Add --strict flag to fail on any dependency errors for data integrity validation. Location: cmd/bd/import.go:159-164","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-12T15:13:18.954834-07:00","updated_at":"2025-10-14T02:42:01.096911-07:00"} -{"id":"bd-21","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-12T15:13:20.114733-07:00","updated_at":"2025-10-14T02:42:01.097-07:00"} -{"id":"bd-22","title":"Add validation/warning for malformed issue IDs","description":"getNextID silently ignores non-numeric ID suffixes (e.g., bd-foo). CAST returns NULL for invalid strings. Consider detecting and warning about malformed IDs in database. Location: internal/storage/sqlite/sqlite.go:79-82","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-12T15:13:21.195975-07:00","updated_at":"2025-10-14T02:42:01.097096-07:00"} -{"id":"bd-23","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-12T15:13:22.325113-07:00","updated_at":"2025-10-14T02:42:01.097195-07:00"} -{"id":"bd-24","title":"Support ID space partitioning for parallel worker agents","description":"Enable external orchestrators (like AI worker swarms) to control issue ID assignment. Add --id flag to 'bd create' for explicit ID specification. Optionally support 'bd config set next_id N' to set the starting point for auto-increment. Storage layer already supports pre-assigned IDs (sqlite.go:52-71), just need CLI wiring. This keeps beads simple while letting orchestrators implement their own ID partitioning strategies to minimize merge conflicts. Complementary to bd-9's collision resolution.","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-12T16:10:37.808226-07:00","updated_at":"2025-10-14T02:42:01.097298-07:00","closed_at":"2025-10-13T23:18:01.637695-07:00"} -{"id":"bd-25","title":"Add transaction support to storage layer for atomic multi-operation workflows","description":"Currently each storage method (CreateIssue, UpdateIssue, etc.) starts its own transaction. This makes it impossible to perform atomic multi-step operations like collision resolution. Add support for passing *sql.Tx through the storage interface, or create transaction-aware versions of methods. This would make remapCollisions and other batch operations truly atomic.","status":"closed","priority":4,"issue_type":"feature","created_at":"2025-10-12T16:39:00.66572-07:00","updated_at":"2025-10-14T02:42:01.097392-07:00","closed_at":"2025-10-13T22:53:56.401108-07:00"} -{"id":"bd-26","title":"Optimize reference updates to avoid loading all issues into memory","description":"In updateReferences(), we call SearchIssues with no filter to get ALL issues for updating references. For large databases (10k+ issues), this loads everything into memory. Options: 1) Use batched processing with LIMIT/OFFSET, 2) Use SQL UPDATE with REPLACE() directly, 3) Stream results instead of loading all at once. Located in collision.go:266","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-12T16:39:10.327861-07:00","updated_at":"2025-10-14T02:42:01.097492-07:00"} -{"id":"bd-27","title":"Cache compiled regexes in replaceIDReferences for performance","description":"replaceIDReferences() compiles the same regex patterns on every call. With 100 issues and 10 ID mappings, that's 1000 regex compilations. Pre-compile regexes once and reuse. Can use a struct with compiled regex, placeholder, and newID. Located in collision.go:329. Estimated performance improvement: 10-100x for large batches.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-12T16:39:18.305517-07:00","updated_at":"2025-10-14T02:42:01.097592-07:00","closed_at":"2025-10-13T23:50:25.865317-07:00"} -{"id":"bd-28","title":"Improve error handling in dependency removal during remapping","description":"In updateDependencyReferences(), RemoveDependency errors are caught and ignored with continue (line 392). Comment says 'if dependency doesn't exist' but this catches ALL errors including real failures. Should check error type with errors.Is(err, ErrDependencyNotFound) and only ignore not-found errors, returning other errors properly.","status":"open","priority":3,"issue_type":"bug","created_at":"2025-10-12T16:39:26.78219-07:00","updated_at":"2025-10-14T02:42:01.097684-07:00"} -{"id":"bd-29","title":"Use safer placeholder pattern in replaceIDReferences","description":"Currently uses __PLACEHOLDER_0__ 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":"open","priority":3,"issue_type":"task","created_at":"2025-10-12T16:39:33.665449-07:00","updated_at":"2025-10-14T02:42:01.097793-07:00"} -{"id":"bd-3","title":"Document git workflow in README","description":"Add Git Workflow section to README explaining binary vs text approaches","status":"closed","priority":1,"issue_type":"chore","created_at":"2025-10-12T00:43:03.461615-07:00","updated_at":"2025-10-14T02:42:01.097888-07:00","closed_at":"2025-10-12T00:43:30.283178-07:00"} -{"id":"bd-30","title":"Remove unused issueMap in scoreCollisions","description":"scoreCollisions() creates issueMap and populates it (lines 135-138) but never uses it. Either remove it or add a TODO comment explaining future use. Located in collision.go:135-138. Cosmetic cleanup.","status":"open","priority":4,"issue_type":"chore","created_at":"2025-10-12T16:39:40.101611-07:00","updated_at":"2025-10-14T02:42:01.097979-07:00"} -{"id":"bd-31","title":"Test issue for design field","description":"Testing the new update flags","design":"## Design Plan\\n- Add flags to update command\\n- Test thoroughly\\n- Document changes","acceptance_criteria":"- All three fields (design, notes, acceptance-criteria) can be updated\\n- Changes persist in database\\n- bd show displays the fields correctly","notes":"Implementation complete. All tests passing.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-12T17:09:22.147446-07:00","updated_at":"2025-10-14T02:42:01.098075-07:00","closed_at":"2025-10-12T17:10:32.828906-07:00"} -{"id":"bd-32","title":"bd should auto-detect .beads/*.db in current directory","description":"When bd is run without --db flag, it defaults to beads' own database instead of looking for a .beads/*.db file in the current working directory. This causes confusion when working on other projects that use beads for issue tracking (like vc).\n\nExpected behavior: bd should search for .beads/*.db in cwd and use that if found, before falling back to default beads database.\n\nExample: Running 'bd ready' in /Users/stevey/src/vc/vc/ should automatically find and use .beads/vc.db without requiring --db flag every time.","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-13T21:15:16.866255-07:00","updated_at":"2025-10-14T02:42:01.09818-07:00","closed_at":"2025-10-13T21:30:47.456341-07:00"} -{"id":"bd-33","title":"Document or automate JSONL sync workflow for git collaboration","description":"When using beads across multiple machines/environments via git, there's a workflow gap:\n\n1. Machine A: Create issues → stored in .beads/project.db\n2. Machine A: bd export -o .beads/issues.jsonl\n3. Machine A: git add .beads/issues.jsonl \u0026\u0026 git commit \u0026\u0026 git push\n4. Machine B: git pull\n5. Machine B: ??? issues.jsonl exists but project.db is empty/stale\n\nThe missing step is: bd import --db .beads/project.db -i .beads/issues.jsonl\n\nThis needs to be either:\na) Documented clearly in workflow docs\nb) Automated (e.g., git hook, or bd auto-imports if jsonl is newer than db)\nc) Both\n\nReal-world impact: User had Claude Code on GCP VM create vc issues from BOOTSTRAP.md. They were exported to issues.jsonl and committed. But on local machine, vc.db was empty until manual import was run.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-13T21:15:30.271236-07:00","updated_at":"2025-10-14T02:42:01.098273-07:00","closed_at":"2025-10-13T22:47:51.587822-07:00"} -{"id":"bd-34","title":"Implement reserved database name _.db","description":"Auto-detection now skips .beads/_.db to prevent pollution when beads dogfoods itself. This allows beads to use its own issue tracker without interfering with other projects using beads in the same directory tree. Implementation includes filtering in findDatabase(), stopping directory walk when .beads/ is found, and documentation in README.md and CLAUDE.md.","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-13T21:46:15.189582-07:00","updated_at":"2025-10-14T02:42:01.098382-07:00","closed_at":"2025-10-13T21:54:26.388271-07:00"} -{"id":"bd-35","title":"Auto-flush JSONL on CRUD operations with 5-second debounce","description":"Implemented automatic write-through from SQLite to JSONL with 5-second debouncing. After any CRUD operation (create, update, close, dep add/remove), changes are scheduled to flush to JSONL after 5 seconds of inactivity. On process exit, any pending changes are flushed immediately. This prevents .db and .jsonl from getting out of sync, solving the workflow gap where agents forget to run 'bd export'. Can be disabled with --no-auto-flush flag. Addresses bd-33.","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-13T22:21:13.94705-07:00","updated_at":"2025-10-14T02:42:01.098478-07:00","closed_at":"2025-10-13T22:22:38.359968-07:00"} -{"id":"bd-36","title":"Handle missing JSONL directory in findJSONLPath","description":"findJSONLPath() assumes the database directory exists. If someone runs bd init to create a new database but the .beads directory doesn't exist yet, the glob operations might fail silently. Add os.MkdirAll(dbDir, 0755) to ensure directory exists before globbing. Located in cmd/bd/main.go:188-201.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-10-13T22:34:35.944346-07:00","updated_at":"2025-10-14T02:42:01.098582-07:00","closed_at":"2025-10-13T22:50:53.269614-07:00"} -{"id":"bd-37","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":"open","priority":3,"issue_type":"task","created_at":"2025-10-13T22:34:43.429201-07:00","updated_at":"2025-10-14T02:42:01.098676-07:00","closed_at":"2025-10-14T00:15:14.782393-07:00"} -{"id":"bd-38","title":"Add visibility for auto-flush failures","description":"flushToJSONL() writes warnings to stderr when flush fails, but calling code has no way to know if flush succeeded or failed. This means a command could return success even though JSONL is now out of sync. Consider maintaining a 'last flush status' variable or counter for failed flushes, and warn user after multiple consecutive failures (e.g., 3+). Located in cmd/bd/main.go:227-307.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-13T22:34:52.440117-07:00","updated_at":"2025-10-14T02:42:01.098763-07:00","closed_at":"2025-10-13T23:22:47.805211-07:00"} -{"id":"bd-39","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-13T22:34:59.26425-07:00","updated_at":"2025-10-14T02:42:01.098863-07:00","closed_at":"2025-10-14T00:08:51.834812-07:00"} -{"id":"bd-4","title":"Add demo GIF/video showing bd quickstart in action","description":"Record asciinema or create animated GIF showing the full workflow","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-12T10:50:49.500051-07:00","updated_at":"2025-10-14T02:42:01.098952-07:00","dependencies":[{"issue_id":"bd-4","depends_on_id":"bd-8","type":"parent-child","created_at":"2025-10-12T10:51:08.399915-07:00","created_by":"stevey"}]} -{"id":"bd-40","title":"Make auto-flush debounce duration configurable","description":"flushDebounce is hardcoded to 5 seconds. Make it configurable via environment variable BEADS_FLUSH_DEBOUNCE (e.g., '500ms', '10s'). Current 5-second value is reasonable for interactive use, but CI/automated scenarios might want faster flush. Add getDebounceDuration() helper function. Located in cmd/bd/main.go:31.","status":"open","priority":3,"issue_type":"feature","created_at":"2025-10-13T22:35:06.126282-07:00","updated_at":"2025-10-14T02:42:01.099043-07:00"} -{"id":"bd-41","title":"Add godoc comments for auto-flush functions","description":"Add comprehensive godoc comments for findJSONLPath(), markDirtyAndScheduleFlush(), and flushToJSONL() explaining behavior, concurrency considerations, and error handling. Include notes about debouncing behavior (timer resets on each write, flush occurs 5s after LAST operation) and flush-on-exit guarantees. Located in cmd/bd/main.go:188-307.","status":"open","priority":4,"issue_type":"chore","created_at":"2025-10-13T22:35:13.518442-07:00","updated_at":"2025-10-14T02:42:01.099149-07:00"} -{"id":"bd-42","title":"Add test coverage for auto-flush feature","description":"Add comprehensive tests for auto-flush functionality:\\n- Test that markDirtyAndScheduleFlush() is called after CRUD operations\\n- Test debounce timing (rapid operations result in single flush)\\n- Test --no-auto-flush flag disables feature\\n- Test flush on program exit\\n- Test concurrent operations don't cause races\\n- Test error scenarios (disk full, permission denied, etc.)\\n- Test import command triggers auto-flush\\n\\nCurrent implementation has no test coverage for the auto-flush feature. Located in cmd/bd/main_test.go (to be created).","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-13T22:35:22.079794-07:00","updated_at":"2025-10-14T02:42:01.099253-07:00","closed_at":"2025-10-13T23:36:28.90411-07:00"} -{"id":"bd-43","title":"Test auto-sync feature","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-13T22:47:41.738165-07:00","updated_at":"2025-10-14T02:42:01.099344-07:00","closed_at":"2025-10-13T22:48:02.844213-07:00"} -{"id":"bd-44","title":"Regular auto-ID issue","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-13T23:16:29.970089-07:00","updated_at":"2025-10-14T02:42:01.099441-07:00","closed_at":"2025-10-13T23:16:45.231439-07:00"} -{"id":"bd-45","title":"Test flush tracking","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-13T23:22:18.472476-07:00","updated_at":"2025-10-14T02:42:01.09953-07:00","closed_at":"2025-10-13T23:22:31.397095-07:00"} -{"id":"bd-46","title":"Test export cancels timer","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-13T23:26:20.523923-07:00","updated_at":"2025-10-14T02:42:01.099629-07:00","closed_at":"2025-10-13T23:26:35.813165-07:00"} -{"id":"bd-47","title":"Test incremental export","description":"Testing bd-39 implementation","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T00:06:24.42044-07:00","updated_at":"2025-10-14T02:42:01.099716-07:00","closed_at":"2025-10-14T00:14:45.968261-07:00"} -{"id":"bd-48","title":"Test incremental 2","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T00:07:14.157987-07:00","updated_at":"2025-10-14T02:42:01.099808-07:00","closed_at":"2025-10-14T00:14:45.968593-07:00"} -{"id":"bd-49","title":"Final test","description":"Testing with new binary","status":"in_progress","priority":1,"issue_type":"task","created_at":"2025-10-14T00:07:46.650341-07:00","updated_at":"2025-10-14T02:42:01.099895-07:00","closed_at":"2025-10-14T00:14:45.968699-07:00"} -{"id":"bd-5","title":"Implement MCP server for Claude Desktop","description":"Complete the claude-desktop-mcp example with working TypeScript implementation","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-12T10:50:50.942964-07:00","updated_at":"2025-10-14T02:42:01.099984-07:00","closed_at":"2025-10-13T23:20:41.816853-07:00","dependencies":[{"issue_id":"bd-5","depends_on_id":"bd-8","type":"parent-child","created_at":"2025-10-12T10:51:08.404381-07:00","created_by":"stevey"}]} -{"id":"bd-50","title":"Test label dirty tracking","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-14T00:14:25.484565-07:00","updated_at":"2025-10-14T02:42:01.100079-07:00","closed_at":"2025-10-14T00:14:45.968771-07:00"} -{"id":"bd-51","title":"Auto-migrate dirty_issues table on startup","description":"The dirty_issues table was added in bd-39 for incremental export optimization. Existing databases created before this feature won't have the table, causing errors when trying to use dirty tracking.\n\nAdd migration logic to check for the dirty_issues table on startup and create it if missing. This should happen in sqlite.New() after opening the database connection but before returning the storage instance.\n\nImplementation:\n- Check if dirty_issues table exists (SELECT name FROM sqlite_master WHERE type='table' AND name='dirty_issues')\n- If missing, execute the CREATE TABLE and CREATE INDEX statements from schema.go\n- This makes bd-39 work seamlessly with existing databases without requiring manual migration\n\nLocation: internal/storage/sqlite/sqlite.go:28-58 (New() function)","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-14T00:16:00.850055-07:00","updated_at":"2025-10-14T02:42:01.100165-07:00","closed_at":"2025-10-14T00:19:19.355078-07:00"} -{"id":"bd-52","title":"Critical: TOCTOU bug in dirty tracking - ClearDirtyIssues race condition","description":"The GetDirtyIssues/ClearDirtyIssues pattern has a race condition. If a CRUD operation marks an issue dirty between GetDirtyIssues() and ClearDirtyIssues(), that change will be lost. The export will miss that issue until the next time it's modified.\n\nImpact: Data loss - changes can be lost during concurrent operations\nLocation: internal/storage/sqlite/dirty.go:78-86\nSuggested fix: Use a transaction-based approach or track which specific IDs were exported","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-14T00:21:46.229671-07:00","updated_at":"2025-10-14T02:42:01.10026-07:00","closed_at":"2025-10-14T00:29:31.174835-07:00"} -{"id":"bd-53","title":"Bug: Export with status filter clears all dirty issues incorrectly","description":"When exporting with a status filter (e.g., bd export --status open -o file.jsonl), the code clears ALL dirty issues even though only issues matching the filter were exported. This means dirty issues that don't match the filter are marked as clean despite not being exported.\n\nImpact: Inconsistent export state, missing data in JSONL\nLocation: cmd/bd/export.go:86-92\nSuggested fix: Only clear dirty flags for issues that were actually exported","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-14T00:21:47.327014-07:00","updated_at":"2025-10-14T02:42:01.100372-07:00","closed_at":"2025-10-14T00:29:31.179483-07:00"} -{"id":"bd-54","title":"Bug: Malformed ID detection query never finds malformed IDs","description":"The query checking for malformed IDs uses 'CAST(SUBSTR(...) AS INTEGER) IS NULL' but SQLite's CAST never returns NULL for invalid integers - it returns 0. This means malformed IDs with non-numeric suffixes are never detected or warned about.\n\nImpact: Silent data quality issues, incorrect ID generation\nLocation: internal/storage/sqlite/sqlite.go:125-145\nSuggested fix: Use a regex or check if the SUBSTR result matches '^[0-9]+$' pattern","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-10-14T00:21:48.404838-07:00","updated_at":"2025-10-14T02:42:01.100463-07:00","closed_at":"2025-10-14T00:32:51.521595-07:00"} -{"id":"bd-55","title":"Enhancement: Migration should validate dirty_issues table schema","description":"The migrateDirtyIssuesTable function only checks if the table exists, not if it has the correct schema. If someone created a dirty_issues table with a different schema, the migration would silently succeed and cause runtime errors later.\n\nImpact: Silent schema inconsistencies, difficult debugging\nLocation: internal/storage/sqlite/sqlite.go:65-98\nSuggested fix: Check table schema (column names/types) and either migrate or fail with clear error","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T00:22:04.773185-07:00","updated_at":"2025-10-14T02:42:01.100561-07:00"} -{"id":"bd-56","title":"Enhancement: Inconsistent dependency dirty marking can cause partial updates","description":"In AddDependency and RemoveDependency, both issues are marked dirty in sequence. If the transaction fails after marking the first issue but before marking the second, dirty state becomes inconsistent. While the transaction will rollback, this pattern is fragile.\n\nImpact: Potential inconsistent dirty state on transaction failures\nLocation: internal/storage/sqlite/dependencies.go:113-131, 160-177\nSuggested fix: Use MarkIssuesDirty() batch function instead of separate statements","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-10-14T00:22:05.619682-07:00","updated_at":"2025-10-14T02:42:01.10065-07:00","closed_at":"2025-10-14T00:35:43.188168-07:00"} -{"id":"bd-57","title":"Code quality: Remove dead code in GetDirtyIssueCount","description":"GetDirtyIssueCount checks for sql.ErrNoRows but SELECT COUNT(*) never returns ErrNoRows - it always returns 0 for empty tables. This is unnecessary dead code.\n\nImpact: Code clarity, minor performance\nLocation: internal/storage/sqlite/dirty.go:88-96\nSuggested fix: Remove the ErrNoRows check","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T00:22:06.46476-07:00","updated_at":"2025-10-14T02:42:01.100761-07:00"} -{"id":"bd-58","title":"Enhancement: Add observability for dirty tracking system","description":"No metrics or observability for the dirty tracking system. Difficult to debug production issues like: how many issues are typically dirty? How long do they stay dirty? How often do exports fail?\n\nImpact: Poor debuggability, hard to tune performance\nSuggested additions:\n- Metrics for dirty count over time\n- Duration tracking for dirty state\n- Export success/failure rates\n- Auto-flush statistics","status":"open","priority":3,"issue_type":"feature","created_at":"2025-10-14T00:22:07.567867-07:00","updated_at":"2025-10-14T02:42:01.100849-07:00"} -{"id":"bd-59","title":"Enhancement: Use consistent timestamps within transactions","description":"Multiple CRUD operations call time.Now() multiple times within a transaction. For consistency, should call once and reuse the same timestamp throughout the transaction so all operations have identical timestamps.\n\nImpact: Minor timestamp inconsistencies, harder to debug event ordering\nLocations: Multiple files in internal/storage/sqlite/\nSuggested fix: Call time.Now() once at transaction start, pass to all operations","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T00:22:08.949261-07:00","updated_at":"2025-10-14T02:42:01.10096-07:00"} -{"id":"bd-6","title":"Add migration scripts for GitHub Issues","description":"Create scripts to import from GitHub Issues API or exported JSON","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-12T10:50:52.140018-07:00","updated_at":"2025-10-14T02:42:01.101063-07:00","dependencies":[{"issue_id":"bd-6","depends_on_id":"bd-8","type":"parent-child","created_at":"2025-10-12T10:51:08.40857-07:00","created_by":"stevey"}]} -{"id":"bd-60","title":"Enhancement: Make auto-flush debounce configurable","description":"The 5-second debounce for auto-flush is hardcoded. For high-frequency operations or slow filesystems, this might not be optimal. Should be configurable via environment variable or config.\n\nImpact: Flexibility for different use cases\nLocation: cmd/bd/main.go (flushDebounce variable)\nSuggested fix: Add BEADS_FLUSH_DEBOUNCE env var or config option","status":"open","priority":4,"issue_type":"feature","created_at":"2025-10-14T00:22:19.075914-07:00","updated_at":"2025-10-14T02:42:01.101153-07:00"} -{"id":"bd-61","title":"Documentation: Transaction isolation levels should be documented","description":"All BeginTx(ctx, nil) calls use default isolation level. For SQLite with WAL mode, this is fine and gives us snapshot isolation. However, this should be documented in the code or in developer docs to make the concurrency guarantees explicit.\n\nImpact: Developer understanding, maintainability\nLocations: All BeginTx calls throughout codebase\nSuggested fix: Add comment explaining isolation guarantees","status":"open","priority":4,"issue_type":"task","created_at":"2025-10-14T00:22:20.33128-07:00","updated_at":"2025-10-14T02:42:01.101241-07:00"} -{"id":"bd-62","title":"Merge PR #8: Fix parallel issue creation race condition","description":"PR #8 fixes a critical race condition in parallel issue creation by replacing the in-memory ID counter with an atomic database-backed counter. However, it has conflicts with recent changes to main.\n\n**PR Summary:**\n- Adds issue_counters table for atomic ID generation\n- Replaces in-memory nextID counter with getNextIDForPrefix()\n- Adds SyncAllCounters() to prevent collisions after import\n- Includes comprehensive tests for multi-process scenarios\n\n**Conflicts with main:**\n1. SQLiteStorage struct - PR removes nextID/idMu fields added to main\n2. New() function - PR doesn't include migrateDirtyIssuesTable() added in f3a61a6\n3. CreateIssue() - Both versions have dirty tracking but different ID generation\n4. Schema - PR adds issue_counters, main added dirty_issues table\n5. getNextID() - PR removes function that was recently fixed in 3aeeeb7 for bd-54\n\n**Work needed:**\n- Rebase PR #8 on current main\n- Preserve dirty_issues table and migration\n- Add issue_counters table with similar migration pattern\n- Integrate atomic counter system with existing dirty tracking\n- Ensure all tests pass\n- Verify both features work together\n\n**Context:**\n- PR: https://github.com/steveyegge/beads/pull/8\n- Closes: bd-6 (if issue exists)\n- Related commits: f3a61a6, 3aeeeb7, bafb280","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-14T01:14:45.357198-07:00","updated_at":"2025-10-14T02:42:01.10135-07:00","closed_at":"2025-10-14T01:20:31.049608-07:00"} -{"id":"bd-63","title":"Test merged features","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-14T01:19:37.745731-07:00","updated_at":"2025-10-14T02:42:01.101453-07:00","closed_at":"2025-10-14T01:19:50.064461-07:00"} -{"id":"bd-64","title":"CRITICAL: Fix SyncAllCounters performance bottleneck in CreateIssue","description":"SyncAllCounters() is called on EVERY issue creation with auto-generated IDs (sqlite.go:143). This scans the entire issues table on every create, causing O(n) overhead.\n\n**Impact:**\n- With 1,000 issues: full table scan per create\n- With 10,000 issues: massive performance hit\n- Unacceptable for production use\n\n**Root cause:** Lines 140-145 in internal/storage/sqlite/sqlite.go sync all counters to handle edge cases (DB created before fix, or issues imported without syncing).\n\n**Solutions:**\n1. **Lazy init (preferred)**: Only sync if counter doesn't exist for the prefix\n2. **One-time at startup**: Call SyncAllCounters() once in New()\n3. **Remove entirely**: import.go now syncs, edge cases are rare\n\n**Recommended fix:** Add ensureCounterSynced() that checks if counter exists before syncing only that prefix.","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-14T01:23:23.041743-07:00","updated_at":"2025-10-14T02:42:01.10154-07:00","closed_at":"2025-10-14T01:29:32.233892-07:00","dependencies":[{"issue_id":"bd-64","depends_on_id":"bd-71","type":"parent-child","created_at":"2025-10-14T01:24:35.859964-07:00","created_by":"stevey"}]} -{"id":"bd-65","title":"Add migration for issue_counters table","description":"There's a migrateDirtyIssuesTable() function but no corresponding migration for issue_counters table.\n\n**Problem:**\n- Existing databases won't have the issue_counters table\n- They rely on schema 'CREATE TABLE IF NOT EXISTS' \n- Counter won't be initialized with existing issue IDs\n- Could lead to ID collisions if issues already exist in DB\n\n**Location:** internal/storage/sqlite/sqlite.go:48-51\n\n**Solution:** Add migrateIssueCountersTable() similar to migrateDirtyIssuesTable():\n1. Check if table exists\n2. If not, create it\n3. Sync counters from existing issues","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-14T01:23:32.02232-07:00","updated_at":"2025-10-14T02:42:01.101641-07:00","closed_at":"2025-10-14T01:32:38.263621-07:00","dependencies":[{"issue_id":"bd-65","depends_on_id":"bd-71","type":"parent-child","created_at":"2025-10-14T01:24:35.864429-07:00","created_by":"stevey"}]} -{"id":"bd-66","title":"Make import counter sync failure fatal instead of warning","description":"In cmd/bd/import.go:243, SyncAllCounters() failure is treated as a non-fatal warning:\n\n```go\nif err := sqliteStore.SyncAllCounters(ctx); err != nil {\n fmt.Fprintf(os.Stderr, \"Warning: failed to sync ID counters: %v\\n\", err)\n // Don't exit - this is not fatal, just a warning\n}\n```\n\n**Problem:** If counter sync fails, subsequent auto-generated IDs WILL collide with imported issues. This can corrupt data.\n\n**Decision needed:**\n1. Make it fatal (fail hard) - safer but less forgiving\n2. Keep as warning but document the risk clearly\n3. Add a --strict flag to control behavior\n\n**Recommendation:** Make it fatal by default. Data integrity \u003e convenience.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-14T01:23:40.61527-07:00","updated_at":"2025-10-14T02:42:01.101732-07:00","closed_at":"2025-10-14T01:33:10.337387-07:00","dependencies":[{"issue_id":"bd-66","depends_on_id":"bd-71","type":"parent-child","created_at":"2025-10-14T01:24:35.869311-07:00","created_by":"stevey"}]} -{"id":"bd-67","title":"Update test comments to reflect post-fix state","description":"Test comments in internal/storage/sqlite/sqlite_test.go:264-266 refer to 'with the bug' but the bug is now fixed:\n\n```go\n// With the bug, we expect UNIQUE constraint errors\nif len(errors) \u003e 0 {\n t.Logf(\"Got %d errors (expected with current implementation):\", len(errors))\n```\n\n**Issue:** This is confusing and suggests the bug still exists.\n\n**Fix:** Update comments to say 'after the fix, no errors expected' and make the test fail hard if errors occur (lines 279-281).","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-14T01:23:48.488537-07:00","updated_at":"2025-10-14T02:42:01.101836-07:00","closed_at":"2025-10-14T01:33:52.447248-07:00","dependencies":[{"issue_id":"bd-67","depends_on_id":"bd-71","type":"parent-child","created_at":"2025-10-14T01:24:35.873665-07:00","created_by":"stevey"}]} -{"id":"bd-68","title":"Add performance benchmarks for CreateIssue with varying DB sizes","description":"Add benchmark tests to measure CreateIssue performance as database grows.\n\n**Goal:** Catch performance regressions early, especially around ID generation.\n\n**Test cases:**\n- Benchmark with 10, 100, 1k, 10k existing issues\n- Measure auto-generated ID creation time\n- Measure explicit ID creation time\n- Compare single vs concurrent operations\n\n**Location:** internal/storage/sqlite/sqlite_test.go\n\n**Related:** This would have caught the SyncAllCounters issue (bd-64) immediately.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T01:23:57.134825-07:00","updated_at":"2025-10-14T02:42:01.101924-07:00","dependencies":[{"issue_id":"bd-68","depends_on_id":"bd-71","type":"parent-child","created_at":"2025-10-14T01:24:35.87799-07:00","created_by":"stevey"}]} -{"id":"bd-69","title":"Add metrics/logging for counter sync operations","description":"Add observability for ID counter operations to help diagnose issues and monitor performance.\n\n**What to log:**\n- When SyncAllCounters() is called\n- How long it takes\n- How many counters are synced\n- Any collisions detected/prevented\n\n**Use cases:**\n- Debug ID generation issues\n- Monitor performance impact of counter syncs\n- Detect when databases need optimization\n\n**Implementation:**\n- Add structured logging (consider using slog)\n- Make it optional (via flag or env var)\n- Include in both CreateIssue and import flows","status":"open","priority":3,"issue_type":"feature","created_at":"2025-10-14T01:24:06.079067-07:00","updated_at":"2025-10-14T02:42:01.102025-07:00","dependencies":[{"issue_id":"bd-69","depends_on_id":"bd-71","type":"parent-child","created_at":"2025-10-14T01:24:35.882631-07:00","created_by":"stevey"}]} -{"id":"bd-7","title":"Add performance benchmarks document","description":"Document actual performance metrics with hyperfine tests","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-12T10:50:53.294516-07:00","updated_at":"2025-10-14T02:42:01.102113-07:00","dependencies":[{"issue_id":"bd-7","depends_on_id":"bd-8","type":"parent-child","created_at":"2025-10-12T10:51:08.412835-07:00","created_by":"stevey"}]} -{"id":"bd-70","title":"Add EXPLAIN QUERY PLAN tests for counter queries","description":"Add tests to verify that counter-related SQL queries use proper indexes and don't cause full table scans.\n\n**Queries to test:**\n1. getNextIDForPrefix() - INSERT with ON CONFLICT\n2. SyncAllCounters() - GROUP BY with MAX and CAST\n3. Any new lazy init query added for bd-64\n\n**Implementation:**\n- Use SQLite's EXPLAIN QUERY PLAN\n- Parse output to verify no SCAN TABLE operations\n- Add to sqlite_test.go\n\n**Benefits:**\n- Catch performance regressions in tests\n- Document expected query plans\n- Ensure indexes are being used","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:24:15.473927-07:00","updated_at":"2025-10-14T02:42:01.102201-07:00","dependencies":[{"issue_id":"bd-70","depends_on_id":"bd-71","type":"parent-child","created_at":"2025-10-14T01:24:35.887151-07:00","created_by":"stevey"}]} -{"id":"bd-71","title":"Code review follow-up: Post-PR #8 merge improvements","description":"Follow-up tasks from the ultrathink code review of PR #8 merge (bd-62).\n\n**Context:** PR #8 successfully merged atomic counter + dirty tracking. Core functionality is solid but several improvements identified.\n\n**Critical (P0-P1):**\n- bd-64: Fix SyncAllCounters performance bottleneck (P0)\n- bd-65: Add migration for issue_counters table (P1)\n- bd-66: Make import counter sync failure fatal (P1)\n\n**Nice to have (P2-P3):**\n- bd-67: Update test comments (P2)\n- bd-68: Add performance benchmarks (P2)\n- bd-69: Add metrics/logging (P3)\n- bd-70: Add EXPLAIN QUERY PLAN tests (P3)\n\n**Overall assessment:** 4/5 stars - Excellent implementation with one critical performance issue. After bd-64 is fixed, this becomes 5/5.\n\n**Review document:** Available if needed","notes":"Status update: All P0-P1 critical tasks completed! bd-64 (performance), bd-65 (migration), bd-66 (fatal error), bd-67 (comments) are all done. Atomic counter implementation is now production-ready. Remaining tasks are P2-P3 enhancements.","status":"open","priority":1,"issue_type":"epic","created_at":"2025-10-14T01:24:27.716237-07:00","updated_at":"2025-10-14T02:42:01.102303-07:00"} -{"id":"bd-72","title":"Test performance - issue 1","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T01:27:53.520056-07:00","updated_at":"2025-10-14T02:42:01.102395-07:00"} -{"id":"bd-73","title":"Performance test 1","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.931707-07:00","updated_at":"2025-10-14T02:42:01.10249-07:00"} -{"id":"bd-74","title":"Performance test 2","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.936642-07:00","updated_at":"2025-10-14T02:42:01.102578-07:00"} -{"id":"bd-75","title":"Performance test 3","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.941591-07:00","updated_at":"2025-10-14T02:42:01.102667-07:00"} -{"id":"bd-76","title":"Performance test 4","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.946053-07:00","updated_at":"2025-10-14T02:42:01.102754-07:00"} -{"id":"bd-77","title":"Performance test 5","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.950618-07:00","updated_at":"2025-10-14T02:42:01.102839-07:00"} -{"id":"bd-78","title":"Performance test 6","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.955773-07:00","updated_at":"2025-10-14T02:42:01.102925-07:00"} -{"id":"bd-79","title":"Performance test 7","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.96021-07:00","updated_at":"2025-10-14T02:42:01.103015-07:00"} -{"id":"bd-8","title":"Reach 1.0 release milestone","description":"Stabilize API, finalize documentation, comprehensive testing","status":"open","priority":1,"issue_type":"epic","created_at":"2025-10-12T10:50:54.457348-07:00","updated_at":"2025-10-14T02:42:01.103107-07:00"} -{"id":"bd-80","title":"Performance test 8","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.964861-07:00","updated_at":"2025-10-14T02:42:01.103194-07:00"} -{"id":"bd-81","title":"Performance test 9","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.969882-07:00","updated_at":"2025-10-14T02:42:01.103292-07:00"} -{"id":"bd-82","title":"Performance test 10","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.974738-07:00","updated_at":"2025-10-14T02:42:01.103447-07:00"} -{"id":"bd-83","title":"Add external_ref field for tracking GitHub issues","description":"Add optional external_ref field to issues table to track external references like 'gh-9', 'jira-ABC', etc. Includes schema migration, CLI flags (--external-ref for create/update), and tests. This enables linking bd issues to GitHub issues for better workflow integration.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-14T02:27:01.187087-07:00","updated_at":"2025-10-14T02:42:01.103535-07:00","closed_at":"2025-10-14T02:34:54.508385-07:00"} -{"id":"bd-84","title":"Auto-import fails in git workflows due to mtime issues","description":"The auto-import mechanism (autoImportIfNewer) relies on file modification time comparison between JSONL and DB. This breaks in git workflows because git does not preserve original file modification times - pulled files get fresh mtimes based on checkout time.\n\nRoot causes:\n1. Git checkout sets mtime to 'now', not original commit time\n2. Auto-import compares JSONL mtime vs DB mtime (line 181 in main.go)\n3. If DB was recently modified (agents working), mtime check fails\n4. Auto-import silently returns without feedback\n5. Agents continue with stale database state\n\nThis caused issues in VC project where 3 parallel agents:\n- Pulled updated .beads/issues.jsonl from git\n- Auto-import didn't trigger (JSONL appeared older than DB)\n- Agents couldn't find their assigned issues\n- Agents exported from wrong database, corrupting JSONL","design":"Recommended approach: Checksum-based sync (option 3 from original design)\n\n## Solution: Hash-based content comparison\n\nReplace mtime comparison with JSONL content hash comparison:\n\n1. **Compute JSONL hash on startup**:\n - SHA256 hash of .beads/issues.jsonl contents\n - Fast enough for typical repos (\u003c1MB = ~20ms)\n - Only computed once per command invocation\n\n2. **Store last import hash in DB**:\n - Add metadata table if not exists: CREATE TABLE IF NOT EXISTS metadata (key TEXT PRIMARY KEY, value TEXT)\n - Store hash after successful import: INSERT OR REPLACE INTO metadata (key, value) VALUES ('last_import_hash', '\u003chash\u003e')\n - Query on startup: SELECT value FROM metadata WHERE key = 'last_import_hash'\n\n3. **Compare hashes instead of mtimes**:\n - If JSONL hash != stored hash: auto-import (content changed)\n - If JSONL hash == stored hash: skip import (no changes)\n - If no stored hash: fall back to mtime comparison (backward compat)\n\n4. **Update autoImportIfNewer() in cmd/bd/main.go**:\n - Lines 155-279 currently use mtime comparison (line 181)\n - Replace with hash comparison\n - Keep mtime as fallback for old DBs without metadata table\n\n## Implementation Details\n\n### New storage interface method:\n```go\n// In internal/storage/storage.go\ntype Storage interface {\n // ... existing methods ...\n GetMetadata(ctx context.Context, key string) (string, error)\n SetMetadata(ctx context.Context, key, value string) error\n}\n```\n\n### Migration:\n```go\n// In internal/storage/sqlite/sqlite.go init\nCREATE TABLE IF NOT EXISTS metadata (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n);\n```\n\n### Updated autoImportIfNewer():\n```go\nfunc autoImportIfNewer() {\n jsonlPath := findJSONLPath()\n \n // Check if JSONL exists\n jsonlData, err := os.ReadFile(jsonlPath)\n if err != nil {\n return // No JSONL, skip\n }\n \n // Compute current hash\n hasher := sha256.New()\n hasher.Write(jsonlData)\n currentHash := hex.EncodeToString(hasher.Sum(nil))\n \n // Get last import hash from DB\n ctx := context.Background()\n lastHash, err := store.GetMetadata(ctx, \"last_import_hash\")\n if err != nil {\n // No metadata support (old DB) - fall back to mtime comparison\n autoImportIfNewerByMtime()\n return\n }\n \n // Compare hashes\n if currentHash == lastHash {\n return // No changes, skip import\n }\n \n // Content changed - import\n if err := importJSONLSilent(jsonlPath, jsonlData); err != nil {\n return // Import failed, skip\n }\n \n // Store new hash\n _ = store.SetMetadata(ctx, \"last_import_hash\", currentHash)\n}\n```\n\n## Benefits\n\n- **Git-proof**: Works regardless of file timestamps\n- **Universal**: Works with git, Dropbox, rsync, manual edits\n- **Backward compatible**: Falls back to mtime for old DBs\n- **Efficient**: SHA256 is fast (~20ms for 1MB)\n- **Accurate**: Only imports when content actually changed\n- **No user action**: Fully automatic, invisible\n\n## Performance Optimization\n\nFor very large repos (\u003e10MB JSONL):\n- Only hash if mtime changed (combine both checks)\n- Use incremental hashing if metadata table tracks line count\n- Consider sampling hash (first 1MB + last 1MB)\n\nBut start simple - full hash is fast enough for 99% of use cases.\n\n## Rollout Plan\n\n1. Add metadata table + Get/SetMetadata methods (backward compatible)\n2. Update autoImportIfNewer() with hash logic + mtime fallback\n3. Test with old and new DBs\n4. Ship in next minor version (v0.10.0)\n5. Document in CHANGELOG as \"more reliable auto-import\"\n6. Git hooks remain optional but unnecessary for most users","acceptance_criteria":"- Auto-import works correctly after git pull\n- Agents in parallel workflows see consistent database state\n- Clear feedback when import is needed\n- Performance acceptable for large databases\n- Works in both git and non-git workflows\n- Documentation updated with multi-agent best practices","status":"in_progress","priority":1,"issue_type":"bug","created_at":"2025-10-14T02:37:34.073953-07:00","updated_at":"2025-10-14T02:44:36.271191-07:00"} -{"id":"bd-85","title":"GH-1: Fix bd dep tree graph display issues","description":"Tree display has several issues: 1) Epic items may not expand all sub-items, 2) Subitems repeat multiple times at same level, 3) Items with multiple blockers appear multiple times. The tree visualization doesn't properly handle graph structures with multiple dependencies.","status":"open","priority":1,"issue_type":"bug","created_at":"2025-10-14T02:44:28.702222-07:00","updated_at":"2025-10-14T02:44:28.702222-07:00","external_ref":"gh-1"} -{"id":"bd-86","title":"GH-2: Evaluate optional Turso backend for collaboration","description":"RFC proposal for optional Turso/libSQL backend to enable: database branching, near-real-time sync between agents/humans, native vector search, browser-ready persistence (WASM/OPFS), and concurrent writes. Would be opt-in, keeping current JSONL+SQLite as default. Requires storage driver interface.","status":"open","priority":3,"issue_type":"feature","created_at":"2025-10-14T02:44:51.932233-07:00","updated_at":"2025-10-14T02:44:51.932233-07:00","external_ref":"gh-2"} -{"id":"bd-87","title":"GH-3: Debug zsh killed error on bd init","description":"User reports 'zsh: killed bd init' when running bd init or just bd command. Likely a crash or signal. Need to reproduce and investigate cause.","status":"open","priority":1,"issue_type":"bug","created_at":"2025-10-14T02:44:53.054411-07:00","updated_at":"2025-10-14T02:44:53.054411-07:00","external_ref":"gh-3"} -{"id":"bd-88","title":"GH-4: Consider system-wide/multi-repo beads usage","description":"User wants to use beads across multiple repositories and for sysadmin tasks. Currently beads is project-scoped (.beads/ directory). Explore options for system-wide issue tracking that spans multiple repos. Related question: how does beads compare to membank MCP?","status":"open","priority":3,"issue_type":"feature","created_at":"2025-10-14T02:44:54.343447-07:00","updated_at":"2025-10-14T02:44:54.343447-07:00","external_ref":"gh-4"} -{"id":"bd-89","title":"GH-6: Fix race condition in parallel issue creation","description":"Creating multiple issues rapidly in parallel causes 'UNIQUE constraint failed: issues.id' error. The ID generation has a race condition. Reproducible with: for i in {26..35}; do ./bd create parallel_ 2\u003e\u00261 \u0026 done","status":"open","priority":0,"issue_type":"bug","created_at":"2025-10-14T02:44:55.510776-07:00","updated_at":"2025-10-14T02:44:55.510776-07:00","external_ref":"gh-6"} -{"id":"bd-9","title":"Build collision resolution tooling for distributed branch workflows","description":"When branches diverge and both create issues, auto-incrementing IDs collide on merge. Build excellent tooling to detect collisions during import, auto-renumber issues with fewer dependencies, update all references in descriptions and dependency links, and provide clear user feedback. Goal: keep beautiful brevity of numeric IDs (bd-302) while handling distributed creation gracefully.","status":"in_progress","priority":1,"issue_type":"feature","created_at":"2025-10-12T13:39:34.608218-07:00","updated_at":"2025-10-14T02:42:01.103776-07:00"} -{"id":"bd-90","title":"GH-7: Package available in AUR (beads-git)","description":"Community member created AUR package for Arch Linux: https://aur.archlinux.org/packages/beads-git. This is informational - no action needed, but good to track for release process and documentation.","status":"open","priority":4,"issue_type":"chore","created_at":"2025-10-14T02:44:56.4535-07:00","updated_at":"2025-10-14T02:44:56.4535-07:00","external_ref":"gh-7"} -{"id":"bd-91","title":"GH-9: Support markdown files in bd create","description":"Request to support markdown files as input to bd create, which would parse the markdown and split it into multiple issues. Use case: developers keep feature drafts in markdown files in version control, then want to convert them into issues. Example: bd create -f feature-draft.md","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-14T02:44:57.405586-07:00","updated_at":"2025-10-14T02:44:57.405586-07:00","external_ref":"gh-9"} -{"id":"bd-92","title":"GH-11: Add Docker support for hosted/shared instance","description":"Request for Docker container hosting to use beads across multiple dev machines. Would need to consider: centralized database (PostgreSQL?), authentication, concurrent access, API server, etc. This is a significant architectural change from the current local-first model.","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-14T02:44:58.469094-07:00","updated_at":"2025-10-14T02:44:58.469094-07:00","external_ref":"gh-11"} -{"id":"bd-93","title":"GH-18: Add --deps flag to bd create for one-command issue creation","description":"Request to add dependency specification to bd create command instead of requiring separate 'bd dep add' command. Proposed syntax: bd create 'Fix bug' --deps discovered-from=bd-20. This would be especially useful for aider integration and reducing command verbosity.","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-14T02:44:59.610192-07:00","updated_at":"2025-10-14T02:44:59.610192-07:00","external_ref":"gh-18"} -{"id":"test-100","title":"Test issue with explicit ID","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-13T23:16:20.601292-07:00","updated_at":"2025-10-14T02:42:01.103869-07:00","closed_at":"2025-10-13T23:16:45.231096-07:00"} -{"id":"worker2-500","title":"Another explicit ID","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-13T23:16:29.978183-07:00","updated_at":"2025-10-14T02:42:01.103955-07:00","closed_at":"2025-10-13T23:16:45.231376-07:00"} +{"id":"bd-1","title":"Add export/import commands","description":"Support bd export --format=jsonl and bd import for text-based git workflow","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-12T00:43:03.453438-07:00","updated_at":"2025-10-14T03:04:05.957997-07:00","closed_at":"2025-10-12T20:20:06.977679-07:00"} +{"id":"bd-10","title":"Extend export to include dependencies in JSONL","description":"Modify export.go to include dependencies array in each issue's JSONL output. This makes JSONL self-contained and enables proper collision resolution. Format: {\"id\":\"bd-10\",\"dependencies\":[{\"depends_on_id\":\"bd-5\",\"type\":\"blocks\"}]}","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-12T14:32:19.163526-07:00","updated_at":"2025-10-14T03:04:05.95838-07:00","closed_at":"2025-10-12T15:07:47.937992-07:00","dependencies":[{"issue_id":"bd-10","depends_on_id":"bd-9","type":"parent-child","created_at":"2025-10-12T14:35:59.213222-07:00","created_by":"stevey"}]} +{"id":"bd-100","title":"parallel_test_10","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:46.946477-07:00","updated_at":"2025-10-14T02:55:46.946477-07:00"} +{"id":"bd-101","title":"parallel_test_3","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:46.971429-07:00","updated_at":"2025-10-14T02:55:46.971429-07:00"} +{"id":"bd-102","title":"parallel_test_8","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:46.997449-07:00","updated_at":"2025-10-14T02:55:46.997449-07:00"} +{"id":"bd-103","title":"parallel_test_9","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:46.998608-07:00","updated_at":"2025-10-14T02:55:46.998608-07:00"} +{"id":"bd-104","title":"parallel_26","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:51.254662-07:00","updated_at":"2025-10-14T02:55:51.254662-07:00"} +{"id":"bd-105","title":"parallel_31","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:51.255055-07:00","updated_at":"2025-10-14T02:55:51.255055-07:00"} +{"id":"bd-106","title":"parallel_32","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:51.255348-07:00","updated_at":"2025-10-14T02:55:51.255348-07:00"} +{"id":"bd-107","title":"parallel_33","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:51.255454-07:00","updated_at":"2025-10-14T02:55:51.255454-07:00"} +{"id":"bd-108","title":"parallel_28","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:51.255731-07:00","updated_at":"2025-10-14T02:55:51.255731-07:00"} +{"id":"bd-109","title":"parallel_29","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:51.255867-07:00","updated_at":"2025-10-14T02:55:51.255867-07:00"} +{"id":"bd-11","title":"Test issue to verify fix","description":"This should be bd-11 if the fix works","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-12T14:40:21.419082-07:00","updated_at":"2025-10-14T03:04:05.958591-07:00","closed_at":"2025-10-12T14:40:32.963312-07:00"} +{"id":"bd-110","title":"parallel_27","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:51.255932-07:00","updated_at":"2025-10-14T02:55:51.255932-07:00"} +{"id":"bd-111","title":"parallel_30","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:51.258491-07:00","updated_at":"2025-10-14T02:55:51.258491-07:00"} +{"id":"bd-112","title":"parallel_35","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:51.258879-07:00","updated_at":"2025-10-14T02:55:51.258879-07:00"} +{"id":"bd-113","title":"parallel_34","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:51.265162-07:00","updated_at":"2025-10-14T02:55:51.265162-07:00"} +{"id":"bd-114","title":"stress_3","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.092233-07:00","updated_at":"2025-10-14T02:55:55.092233-07:00"} +{"id":"bd-115","title":"stress_5","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.092311-07:00","updated_at":"2025-10-14T02:55:55.092311-07:00"} +{"id":"bd-116","title":"stress_10","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.093319-07:00","updated_at":"2025-10-14T02:55:55.093319-07:00"} +{"id":"bd-117","title":"stress_2","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.093453-07:00","updated_at":"2025-10-14T02:55:55.093453-07:00"} +{"id":"bd-118","title":"stress_8","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.093516-07:00","updated_at":"2025-10-14T02:55:55.093516-07:00"} +{"id":"bd-119","title":"stress_13","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.094405-07:00","updated_at":"2025-10-14T02:55:55.094405-07:00"} +{"id":"bd-12","title":"Implement collision detection in import","description":"Create collision.go with detectCollisions() function. Compare incoming JSONL issues against DB state. Distinguish between: (1) exact match (idempotent), (2) ID match but different content (collision), (3) new issue. Return list of colliding issues.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.056588-07:00","updated_at":"2025-10-14T03:04:05.958784-07:00","closed_at":"2025-10-12T16:06:25.575038-07:00","dependencies":[{"issue_id":"bd-12","depends_on_id":"bd-9","type":"parent-child","created_at":"2025-10-12T14:41:07.947358-07:00","created_by":"stevey"}]} +{"id":"bd-120","title":"stress_14","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.094519-07:00","updated_at":"2025-10-14T02:55:55.094519-07:00"} +{"id":"bd-121","title":"stress_1","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.095805-07:00","updated_at":"2025-10-14T02:55:55.095805-07:00"} +{"id":"bd-122","title":"stress_7","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.096461-07:00","updated_at":"2025-10-14T02:55:55.096461-07:00"} +{"id":"bd-123","title":"stress_17","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.096904-07:00","updated_at":"2025-10-14T02:55:55.096904-07:00"} +{"id":"bd-124","title":"stress_6","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.097331-07:00","updated_at":"2025-10-14T02:55:55.097331-07:00"} +{"id":"bd-125","title":"stress_19","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.098391-07:00","updated_at":"2025-10-14T02:55:55.098391-07:00"} +{"id":"bd-126","title":"stress_20","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.098827-07:00","updated_at":"2025-10-14T02:55:55.098827-07:00"} +{"id":"bd-127","title":"stress_15","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.099861-07:00","updated_at":"2025-10-14T02:55:55.099861-07:00"} +{"id":"bd-128","title":"stress_24","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.100328-07:00","updated_at":"2025-10-14T02:55:55.100328-07:00"} +{"id":"bd-129","title":"stress_18","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.100957-07:00","updated_at":"2025-10-14T02:55:55.100957-07:00"} +{"id":"bd-13","title":"Implement reference scoring algorithm","description":"Count references for each colliding issue: text mentions in descriptions/notes/design fields + dependency references. Sort collisions by score ascending (fewest refs first). This minimizes total updates during renumbering.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.204518-07:00","updated_at":"2025-10-14T03:04:05.958979-07:00","closed_at":"2025-10-12T16:26:46.572201-07:00","dependencies":[{"issue_id":"bd-13","depends_on_id":"bd-9","type":"parent-child","created_at":"2025-10-12T14:41:07.951605-07:00","created_by":"stevey"}]} +{"id":"bd-130","title":"stress_22","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.101073-07:00","updated_at":"2025-10-14T02:55:55.101073-07:00"} +{"id":"bd-131","title":"stress_28","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.101635-07:00","updated_at":"2025-10-14T02:55:55.101635-07:00"} +{"id":"bd-132","title":"stress_25","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.101763-07:00","updated_at":"2025-10-14T02:55:55.101763-07:00"} +{"id":"bd-133","title":"stress_29","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.102151-07:00","updated_at":"2025-10-14T02:55:55.102151-07:00"} +{"id":"bd-134","title":"stress_26","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.102208-07:00","updated_at":"2025-10-14T02:55:55.102208-07:00"} +{"id":"bd-135","title":"stress_9","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.103216-07:00","updated_at":"2025-10-14T02:55:55.103216-07:00"} +{"id":"bd-136","title":"stress_30","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.103737-07:00","updated_at":"2025-10-14T02:55:55.103737-07:00"} +{"id":"bd-137","title":"stress_32","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.104085-07:00","updated_at":"2025-10-14T02:55:55.104085-07:00"} +{"id":"bd-138","title":"stress_16","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.104635-07:00","updated_at":"2025-10-14T02:55:55.104635-07:00"} +{"id":"bd-139","title":"stress_27","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.105136-07:00","updated_at":"2025-10-14T02:55:55.105136-07:00"} +{"id":"bd-14","title":"Implement ID remapping with reference updates","description":"Allocate new IDs for colliding issues. Update all text field references using word-boundary regex (\\bbd-10\\b). Update dependency records. Build id_mapping for reporting. Handle chain dependencies properly.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.367596-07:00","updated_at":"2025-10-14T03:04:05.95917-07:00","closed_at":"2025-10-12T16:35:13.159992-07:00","dependencies":[{"issue_id":"bd-14","depends_on_id":"bd-9","type":"parent-child","created_at":"2025-10-12T14:41:07.956041-07:00","created_by":"stevey"}]} +{"id":"bd-140","title":"stress_31","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.105666-07:00","updated_at":"2025-10-14T02:55:55.105666-07:00"} +{"id":"bd-141","title":"stress_35","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.106196-07:00","updated_at":"2025-10-14T02:55:55.106196-07:00"} +{"id":"bd-142","title":"stress_37","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.106722-07:00","updated_at":"2025-10-14T02:55:55.106722-07:00"} +{"id":"bd-143","title":"stress_34","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.107203-07:00","updated_at":"2025-10-14T02:55:55.107203-07:00"} +{"id":"bd-144","title":"stress_36","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.108466-07:00","updated_at":"2025-10-14T02:55:55.108466-07:00"} +{"id":"bd-145","title":"stress_21","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.108868-07:00","updated_at":"2025-10-14T02:55:55.108868-07:00"} +{"id":"bd-146","title":"stress_38","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.109501-07:00","updated_at":"2025-10-14T02:55:55.109501-07:00"} +{"id":"bd-147","title":"stress_42","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.109907-07:00","updated_at":"2025-10-14T02:55:55.109907-07:00"} +{"id":"bd-148","title":"stress_43","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.109971-07:00","updated_at":"2025-10-14T02:55:55.109971-07:00"} +{"id":"bd-149","title":"stress_39","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.110079-07:00","updated_at":"2025-10-14T02:55:55.110079-07:00"} +{"id":"bd-15","title":"Add --resolve-collisions flag and user reporting","description":"Add import flags: --resolve-collisions (auto-fix) and --dry-run (preview). Display clear report: collisions detected, remappings applied (old→new with scores), reference counts updated. Default behavior: fail on collision (safe).","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.534721-07:00","updated_at":"2025-10-14T03:04:05.959333-07:00","closed_at":"2025-10-12T16:47:11.491645-07:00","dependencies":[{"issue_id":"bd-15","depends_on_id":"bd-9","type":"parent-child","created_at":"2025-10-12T14:41:07.961157-07:00","created_by":"stevey"}]} +{"id":"bd-150","title":"stress_45","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.110194-07:00","updated_at":"2025-10-14T02:55:55.110194-07:00"} +{"id":"bd-151","title":"stress_46","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.110798-07:00","updated_at":"2025-10-14T02:55:55.110798-07:00"} +{"id":"bd-152","title":"stress_48","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.111726-07:00","updated_at":"2025-10-14T02:55:55.111726-07:00"} +{"id":"bd-153","title":"stress_44","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.111834-07:00","updated_at":"2025-10-14T02:55:55.111834-07:00"} +{"id":"bd-154","title":"stress_40","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.112308-07:00","updated_at":"2025-10-14T02:55:55.112308-07:00"} +{"id":"bd-155","title":"stress_41","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.113413-07:00","updated_at":"2025-10-14T02:55:55.113413-07:00"} +{"id":"bd-156","title":"stress_12","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.114106-07:00","updated_at":"2025-10-14T02:55:55.114106-07:00"} +{"id":"bd-157","title":"stress_47","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.114674-07:00","updated_at":"2025-10-14T02:55:55.114674-07:00"} +{"id":"bd-158","title":"stress_49","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.115792-07:00","updated_at":"2025-10-14T02:55:55.115792-07:00"} +{"id":"bd-159","title":"stress_50","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.115854-07:00","updated_at":"2025-10-14T02:55:55.115854-07:00"} +{"id":"bd-16","title":"Write comprehensive collision resolution tests","description":"Test cases: simple collision, multiple collisions, dependency updates, text reference updates, chain dependencies, edge cases (partial ID matches, case sensitivity, triple merges). Add to import_test.go and collision_test.go.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.702127-07:00","updated_at":"2025-10-14T03:04:05.959492-07:00","closed_at":"2025-10-12T16:54:25.273886-07:00","dependencies":[{"issue_id":"bd-16","depends_on_id":"bd-9","type":"parent-child","created_at":"2025-10-12T14:41:07.965816-07:00","created_by":"stevey"}]} +{"id":"bd-160","title":"stress_33","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.117101-07:00","updated_at":"2025-10-14T02:55:55.117101-07:00"} +{"id":"bd-161","title":"stress_23","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.122506-07:00","updated_at":"2025-10-14T02:55:55.122506-07:00"} +{"id":"bd-162","title":"stress_11","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.13063-07:00","updated_at":"2025-10-14T02:55:55.13063-07:00"} +{"id":"bd-163","title":"stress_4","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:55.131872-07:00","updated_at":"2025-10-14T02:55:55.131872-07:00"} +{"id":"bd-164","title":"Add visual indicators for nodes with multiple parents in dep tree","description":"When a node appears in the dependency tree via multiple paths (diamond dependencies), add a visual indicator like (*) or (multiple parents) to help users understand the graph structure. This would make it clear when deduplication has occurred. Example: 'bd-503: Shared dependency (*) [P1] (open)'","status":"open","priority":3,"issue_type":"feature","created_at":"2025-10-14T03:10:49.222828-07:00","updated_at":"2025-10-14T03:10:49.222828-07:00","dependencies":[{"issue_id":"bd-164","depends_on_id":"bd-85","type":"discovered-from","created_at":"2025-10-14T03:11:00.326599-07:00","created_by":"stevey"}]} +{"id":"bd-165","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":"open","priority":3,"issue_type":"feature","created_at":"2025-10-14T03:10:50.337481-07:00","updated_at":"2025-10-14T03:10:50.337481-07:00","dependencies":[{"issue_id":"bd-165","depends_on_id":"bd-85","type":"discovered-from","created_at":"2025-10-14T03:11:00.3313-07:00","created_by":"stevey"}]} +{"id":"bd-166","title":"Make maxDepth configurable in bd dep tree command","description":"Currently maxDepth is hardcoded to 50 in GetDependencyTree. Add --max-depth flag to bd dep tree command to allow users to control recursion depth. Default should remain 50 for safety, but users with very deep trees or wanting shallow views should be able to configure it.","status":"open","priority":4,"issue_type":"feature","created_at":"2025-10-14T03:10:51.883256-07:00","updated_at":"2025-10-14T03:10:51.883256-07:00","dependencies":[{"issue_id":"bd-166","depends_on_id":"bd-85","type":"discovered-from","created_at":"2025-10-14T03:11:00.336267-07:00","created_by":"stevey"}]} +{"id":"bd-167","title":"Test issue with --deps flag","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-14T03:24:21.100585-07:00","updated_at":"2025-10-14T03:24:46.260976-07:00","closed_at":"2025-10-14T03:24:46.260976-07:00","dependencies":[{"issue_id":"bd-167","depends_on_id":"bd-89","type":"discovered-from","created_at":"2025-10-14T03:24:21.100912-07:00","created_by":"stevey"}]} +{"id":"bd-168","title":"Another test with multiple deps","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-14T03:24:32.746757-07:00","updated_at":"2025-10-14T03:24:46.261275-07:00","closed_at":"2025-10-14T03:24:46.261275-07:00","dependencies":[{"issue_id":"bd-168","depends_on_id":"bd-89","type":"blocks","created_at":"2025-10-14T03:24:32.747029-07:00","created_by":"stevey"},{"issue_id":"bd-168","depends_on_id":"bd-90","type":"blocks","created_at":"2025-10-14T03:24:32.747181-07:00","created_by":"stevey"}]} +{"id":"bd-169","title":"Fix: bd init --prefix test -q flag not recognized","description":"The init command doesn't recognize the -q flag. When running 'bd init --prefix test -q', it fails silently or behaves unexpectedly. The flag should either be implemented for quiet mode or removed from documentation if not supported.","status":"open","priority":2,"issue_type":"bug","created_at":"2025-10-14T12:33:51.614293-07:00","updated_at":"2025-10-14T12:33:51.614293-07:00"} +{"id":"bd-17","title":"Update documentation for collision resolution","description":"Update README.md with collision resolution section. Update CLAUDE.md with new workflow. Document --resolve-collisions and --dry-run flags. Add example scenarios showing branch merge workflows.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.866649-07:00","updated_at":"2025-10-14T03:04:05.959647-07:00","closed_at":"2025-10-12T17:06:14.930928-07:00","dependencies":[{"issue_id":"bd-17","depends_on_id":"bd-9","type":"parent-child","created_at":"2025-10-12T14:41:07.970302-07:00","created_by":"stevey"}]} +{"id":"bd-18","title":"Add design/notes/acceptance_criteria fields to update command","description":"Currently bd update only supports status, priority, title, assignee. Add support for --design, --notes, --acceptance-criteria flags. This makes it easier to add detailed designs to issues after creation.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-12T14:40:57.032395-07:00","updated_at":"2025-10-14T03:04:05.959826-07:00","closed_at":"2025-10-12T17:10:53.958318-07:00"} +{"id":"bd-19","title":"Fix import zero-value field handling","description":"Import uses zero-value checks (Priority != 0) to determine field updates. This prevents setting priority to 0 or clearing string fields. Export/import round-trip not fully idempotent for zero values. Consider JSON presence detection or explicit preserve-existing semantics. Location: cmd/bd/import.go:95-106","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-10-12T15:13:17.895083-07:00","updated_at":"2025-10-14T03:04:05.959987-07:00"} +{"id":"bd-2","title":"Add PostgreSQL backend","description":"Implement PostgreSQL storage backend as alternative to SQLite for larger teams","status":"closed","priority":3,"issue_type":"feature","created_at":"2025-10-12T00:43:03.457453-07:00","updated_at":"2025-10-14T03:04:05.960143-07:00","closed_at":"2025-10-12T14:15:04.00695-07:00"} +{"id":"bd-20","title":"Add --strict flag for dependency import failures","description":"Currently dependency import errors are warnings (logged to stderr, execution continues). Missing targets or cycles may indicate JSONL corruption. Add --strict flag to fail on any dependency errors for data integrity validation. Location: cmd/bd/import.go:159-164","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-12T15:13:18.954834-07:00","updated_at":"2025-10-14T03:04:05.960298-07:00"} +{"id":"bd-21","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-12T15:13:20.114733-07:00","updated_at":"2025-10-14T03:04:05.96047-07:00"} +{"id":"bd-22","title":"Add validation/warning for malformed issue IDs","description":"getNextID silently ignores non-numeric ID suffixes (e.g., bd-foo). CAST returns NULL for invalid strings. Consider detecting and warning about malformed IDs in database. Location: internal/storage/sqlite/sqlite.go:79-82","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-12T15:13:21.195975-07:00","updated_at":"2025-10-14T03:04:05.960627-07:00"} +{"id":"bd-23","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-12T15:13:22.325113-07:00","updated_at":"2025-10-14T03:04:05.960784-07:00"} +{"id":"bd-24","title":"Support ID space partitioning for parallel worker agents","description":"Enable external orchestrators (like AI worker swarms) to control issue ID assignment. Add --id flag to 'bd create' for explicit ID specification. Optionally support 'bd config set next_id N' to set the starting point for auto-increment. Storage layer already supports pre-assigned IDs (sqlite.go:52-71), just need CLI wiring. This keeps beads simple while letting orchestrators implement their own ID partitioning strategies to minimize merge conflicts. Complementary to bd-9's collision resolution.","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-12T16:10:37.808226-07:00","updated_at":"2025-10-14T03:04:05.960947-07:00","closed_at":"2025-10-13T23:18:01.637695-07:00"} +{"id":"bd-25","title":"Add transaction support to storage layer for atomic multi-operation workflows","description":"Currently each storage method (CreateIssue, UpdateIssue, etc.) starts its own transaction. This makes it impossible to perform atomic multi-step operations like collision resolution. Add support for passing *sql.Tx through the storage interface, or create transaction-aware versions of methods. This would make remapCollisions and other batch operations truly atomic.","status":"closed","priority":4,"issue_type":"feature","created_at":"2025-10-12T16:39:00.66572-07:00","updated_at":"2025-10-14T03:04:05.961132-07:00","closed_at":"2025-10-13T22:53:56.401108-07:00"} +{"id":"bd-26","title":"Optimize reference updates to avoid loading all issues into memory","description":"In updateReferences(), we call SearchIssues with no filter to get ALL issues for updating references. For large databases (10k+ issues), this loads everything into memory. Options: 1) Use batched processing with LIMIT/OFFSET, 2) Use SQL UPDATE with REPLACE() directly, 3) Stream results instead of loading all at once. Located in collision.go:266","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-12T16:39:10.327861-07:00","updated_at":"2025-10-14T03:04:05.9613-07:00"} +{"id":"bd-27","title":"Cache compiled regexes in replaceIDReferences for performance","description":"replaceIDReferences() compiles the same regex patterns on every call. With 100 issues and 10 ID mappings, that's 1000 regex compilations. Pre-compile regexes once and reuse. Can use a struct with compiled regex, placeholder, and newID. Located in collision.go:329. Estimated performance improvement: 10-100x for large batches.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-12T16:39:18.305517-07:00","updated_at":"2025-10-14T03:04:05.961471-07:00","closed_at":"2025-10-13T23:50:25.865317-07:00"} +{"id":"bd-28","title":"Improve error handling in dependency removal during remapping","description":"In updateDependencyReferences(), RemoveDependency errors are caught and ignored with continue (line 392). Comment says 'if dependency doesn't exist' but this catches ALL errors including real failures. Should check error type with errors.Is(err, ErrDependencyNotFound) and only ignore not-found errors, returning other errors properly.","status":"open","priority":3,"issue_type":"bug","created_at":"2025-10-12T16:39:26.78219-07:00","updated_at":"2025-10-14T03:04:05.961624-07:00"} +{"id":"bd-29","title":"Use safer placeholder pattern in replaceIDReferences","description":"Currently uses __PLACEHOLDER_0__ 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":"open","priority":3,"issue_type":"task","created_at":"2025-10-12T16:39:33.665449-07:00","updated_at":"2025-10-14T03:04:05.961787-07:00"} +{"id":"bd-3","title":"Document git workflow in README","description":"Add Git Workflow section to README explaining binary vs text approaches","status":"closed","priority":1,"issue_type":"chore","created_at":"2025-10-12T00:43:03.461615-07:00","updated_at":"2025-10-14T03:04:05.961963-07:00","closed_at":"2025-10-12T00:43:30.283178-07:00"} +{"id":"bd-30","title":"Remove unused issueMap in scoreCollisions","description":"scoreCollisions() creates issueMap and populates it (lines 135-138) but never uses it. Either remove it or add a TODO comment explaining future use. Located in collision.go:135-138. Cosmetic cleanup.","status":"open","priority":4,"issue_type":"chore","created_at":"2025-10-12T16:39:40.101611-07:00","updated_at":"2025-10-14T03:04:05.962118-07:00"} +{"id":"bd-31","title":"Test issue for design field","description":"Testing the new update flags","design":"## Design Plan\\n- Add flags to update command\\n- Test thoroughly\\n- Document changes","acceptance_criteria":"- All three fields (design, notes, acceptance-criteria) can be updated\\n- Changes persist in database\\n- bd show displays the fields correctly","notes":"Implementation complete. All tests passing.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-12T17:09:22.147446-07:00","updated_at":"2025-10-14T03:04:05.962277-07:00","closed_at":"2025-10-12T17:10:32.828906-07:00"} +{"id":"bd-32","title":"bd should auto-detect .beads/*.db in current directory","description":"When bd is run without --db flag, it defaults to beads' own database instead of looking for a .beads/*.db file in the current working directory. This causes confusion when working on other projects that use beads for issue tracking (like vc).\n\nExpected behavior: bd should search for .beads/*.db in cwd and use that if found, before falling back to default beads database.\n\nExample: Running 'bd ready' in /Users/stevey/src/vc/vc/ should automatically find and use .beads/vc.db without requiring --db flag every time.","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-13T21:15:16.866255-07:00","updated_at":"2025-10-14T03:04:05.962442-07:00","closed_at":"2025-10-13T21:30:47.456341-07:00"} +{"id":"bd-33","title":"Document or automate JSONL sync workflow for git collaboration","description":"When using beads across multiple machines/environments via git, there's a workflow gap:\n\n1. Machine A: Create issues → stored in .beads/project.db\n2. Machine A: bd export -o .beads/issues.jsonl\n3. Machine A: git add .beads/issues.jsonl \u0026\u0026 git commit \u0026\u0026 git push\n4. Machine B: git pull\n5. Machine B: ??? issues.jsonl exists but project.db is empty/stale\n\nThe missing step is: bd import --db .beads/project.db -i .beads/issues.jsonl\n\nThis needs to be either:\na) Documented clearly in workflow docs\nb) Automated (e.g., git hook, or bd auto-imports if jsonl is newer than db)\nc) Both\n\nReal-world impact: User had Claude Code on GCP VM create vc issues from BOOTSTRAP.md. They were exported to issues.jsonl and committed. But on local machine, vc.db was empty until manual import was run.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-13T21:15:30.271236-07:00","updated_at":"2025-10-14T03:04:05.962624-07:00","closed_at":"2025-10-13T22:47:51.587822-07:00"} +{"id":"bd-34","title":"Implement reserved database name _.db","description":"Auto-detection now skips .beads/_.db to prevent pollution when beads dogfoods itself. This allows beads to use its own issue tracker without interfering with other projects using beads in the same directory tree. Implementation includes filtering in findDatabase(), stopping directory walk when .beads/ is found, and documentation in README.md and CLAUDE.md.","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-13T21:46:15.189582-07:00","updated_at":"2025-10-14T03:04:05.962784-07:00","closed_at":"2025-10-13T21:54:26.388271-07:00"} +{"id":"bd-35","title":"Auto-flush JSONL on CRUD operations with 5-second debounce","description":"Implemented automatic write-through from SQLite to JSONL with 5-second debouncing. After any CRUD operation (create, update, close, dep add/remove), changes are scheduled to flush to JSONL after 5 seconds of inactivity. On process exit, any pending changes are flushed immediately. This prevents .db and .jsonl from getting out of sync, solving the workflow gap where agents forget to run 'bd export'. Can be disabled with --no-auto-flush flag. Addresses bd-33.","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-13T22:21:13.94705-07:00","updated_at":"2025-10-14T03:04:05.962955-07:00","closed_at":"2025-10-13T22:22:38.359968-07:00"} +{"id":"bd-36","title":"Handle missing JSONL directory in findJSONLPath","description":"findJSONLPath() assumes the database directory exists. If someone runs bd init to create a new database but the .beads directory doesn't exist yet, the glob operations might fail silently. Add os.MkdirAll(dbDir, 0755) to ensure directory exists before globbing. Located in cmd/bd/main.go:188-201.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-10-13T22:34:35.944346-07:00","updated_at":"2025-10-14T03:04:05.963113-07:00","closed_at":"2025-10-13T22:50:53.269614-07:00"} +{"id":"bd-37","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":"open","priority":3,"issue_type":"task","created_at":"2025-10-13T22:34:43.429201-07:00","updated_at":"2025-10-14T03:04:05.963269-07:00","closed_at":"2025-10-14T00:15:14.782393-07:00"} +{"id":"bd-38","title":"Add visibility for auto-flush failures","description":"flushToJSONL() writes warnings to stderr when flush fails, but calling code has no way to know if flush succeeded or failed. This means a command could return success even though JSONL is now out of sync. Consider maintaining a 'last flush status' variable or counter for failed flushes, and warn user after multiple consecutive failures (e.g., 3+). Located in cmd/bd/main.go:227-307.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-13T22:34:52.440117-07:00","updated_at":"2025-10-14T03:04:05.963435-07:00","closed_at":"2025-10-13T23:22:47.805211-07:00"} +{"id":"bd-39","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-13T22:34:59.26425-07:00","updated_at":"2025-10-14T03:04:05.963592-07:00","closed_at":"2025-10-14T00:08:51.834812-07:00"} +{"id":"bd-4","title":"Add demo GIF/video showing bd quickstart in action","description":"Record asciinema or create animated GIF showing the full workflow","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-12T10:50:49.500051-07:00","updated_at":"2025-10-14T03:04:05.963755-07:00","dependencies":[{"issue_id":"bd-4","depends_on_id":"bd-8","type":"parent-child","created_at":"2025-10-12T10:51:08.399915-07:00","created_by":"stevey"}]} +{"id":"bd-40","title":"Make auto-flush debounce duration configurable","description":"flushDebounce is hardcoded to 5 seconds. Make it configurable via environment variable BEADS_FLUSH_DEBOUNCE (e.g., '500ms', '10s'). Current 5-second value is reasonable for interactive use, but CI/automated scenarios might want faster flush. Add getDebounceDuration() helper function. Located in cmd/bd/main.go:31.","status":"open","priority":3,"issue_type":"feature","created_at":"2025-10-13T22:35:06.126282-07:00","updated_at":"2025-10-14T03:04:05.963926-07:00"} +{"id":"bd-41","title":"Add godoc comments for auto-flush functions","description":"Add comprehensive godoc comments for findJSONLPath(), markDirtyAndScheduleFlush(), and flushToJSONL() explaining behavior, concurrency considerations, and error handling. Include notes about debouncing behavior (timer resets on each write, flush occurs 5s after LAST operation) and flush-on-exit guarantees. Located in cmd/bd/main.go:188-307.","status":"open","priority":4,"issue_type":"chore","created_at":"2025-10-13T22:35:13.518442-07:00","updated_at":"2025-10-14T03:04:05.964078-07:00"} +{"id":"bd-42","title":"Add test coverage for auto-flush feature","description":"Add comprehensive tests for auto-flush functionality:\\n- Test that markDirtyAndScheduleFlush() is called after CRUD operations\\n- Test debounce timing (rapid operations result in single flush)\\n- Test --no-auto-flush flag disables feature\\n- Test flush on program exit\\n- Test concurrent operations don't cause races\\n- Test error scenarios (disk full, permission denied, etc.)\\n- Test import command triggers auto-flush\\n\\nCurrent implementation has no test coverage for the auto-flush feature. Located in cmd/bd/main_test.go (to be created).","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-13T22:35:22.079794-07:00","updated_at":"2025-10-14T03:04:05.964233-07:00","closed_at":"2025-10-13T23:36:28.90411-07:00"} +{"id":"bd-43","title":"Test auto-sync feature","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-13T22:47:41.738165-07:00","updated_at":"2025-10-14T03:04:05.964408-07:00","closed_at":"2025-10-13T22:48:02.844213-07:00"} +{"id":"bd-44","title":"Regular auto-ID issue","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-13T23:16:29.970089-07:00","updated_at":"2025-10-14T03:04:05.964564-07:00","closed_at":"2025-10-13T23:16:45.231439-07:00"} +{"id":"bd-45","title":"Test flush tracking","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-13T23:22:18.472476-07:00","updated_at":"2025-10-14T03:04:05.964727-07:00","closed_at":"2025-10-13T23:22:31.397095-07:00"} +{"id":"bd-46","title":"Test export cancels timer","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-13T23:26:20.523923-07:00","updated_at":"2025-10-14T03:04:05.964883-07:00","closed_at":"2025-10-13T23:26:35.813165-07:00"} +{"id":"bd-47","title":"Test incremental export","description":"Testing bd-39 implementation","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T00:06:24.42044-07:00","updated_at":"2025-10-14T03:04:05.965036-07:00","closed_at":"2025-10-14T00:14:45.968261-07:00"} +{"id":"bd-48","title":"Test incremental 2","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T00:07:14.157987-07:00","updated_at":"2025-10-14T03:04:05.965206-07:00","closed_at":"2025-10-14T00:14:45.968593-07:00"} +{"id":"bd-49","title":"Final test","description":"Testing with new binary","status":"in_progress","priority":1,"issue_type":"task","created_at":"2025-10-14T00:07:46.650341-07:00","updated_at":"2025-10-14T03:04:05.965361-07:00","closed_at":"2025-10-14T00:14:45.968699-07:00"} +{"id":"bd-5","title":"Implement MCP server for Claude Desktop","description":"Complete the claude-desktop-mcp example with working TypeScript implementation","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-12T10:50:50.942964-07:00","updated_at":"2025-10-14T03:04:05.965517-07:00","closed_at":"2025-10-13T23:20:41.816853-07:00","dependencies":[{"issue_id":"bd-5","depends_on_id":"bd-8","type":"parent-child","created_at":"2025-10-12T10:51:08.404381-07:00","created_by":"stevey"}]} +{"id":"bd-50","title":"Test label dirty tracking","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-14T00:14:25.484565-07:00","updated_at":"2025-10-14T03:04:05.965672-07:00","closed_at":"2025-10-14T00:14:45.968771-07:00"} +{"id":"bd-51","title":"Auto-migrate dirty_issues table on startup","description":"The dirty_issues table was added in bd-39 for incremental export optimization. Existing databases created before this feature won't have the table, causing errors when trying to use dirty tracking.\n\nAdd migration logic to check for the dirty_issues table on startup and create it if missing. This should happen in sqlite.New() after opening the database connection but before returning the storage instance.\n\nImplementation:\n- Check if dirty_issues table exists (SELECT name FROM sqlite_master WHERE type='table' AND name='dirty_issues')\n- If missing, execute the CREATE TABLE and CREATE INDEX statements from schema.go\n- This makes bd-39 work seamlessly with existing databases without requiring manual migration\n\nLocation: internal/storage/sqlite/sqlite.go:28-58 (New() function)","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-14T00:16:00.850055-07:00","updated_at":"2025-10-14T03:04:05.965826-07:00","closed_at":"2025-10-14T00:19:19.355078-07:00"} +{"id":"bd-52","title":"Critical: TOCTOU bug in dirty tracking - ClearDirtyIssues race condition","description":"The GetDirtyIssues/ClearDirtyIssues pattern has a race condition. If a CRUD operation marks an issue dirty between GetDirtyIssues() and ClearDirtyIssues(), that change will be lost. The export will miss that issue until the next time it's modified.\n\nImpact: Data loss - changes can be lost during concurrent operations\nLocation: internal/storage/sqlite/dirty.go:78-86\nSuggested fix: Use a transaction-based approach or track which specific IDs were exported","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-14T00:21:46.229671-07:00","updated_at":"2025-10-14T03:04:05.966004-07:00","closed_at":"2025-10-14T00:29:31.174835-07:00"} +{"id":"bd-53","title":"Bug: Export with status filter clears all dirty issues incorrectly","description":"When exporting with a status filter (e.g., bd export --status open -o file.jsonl), the code clears ALL dirty issues even though only issues matching the filter were exported. This means dirty issues that don't match the filter are marked as clean despite not being exported.\n\nImpact: Inconsistent export state, missing data in JSONL\nLocation: cmd/bd/export.go:86-92\nSuggested fix: Only clear dirty flags for issues that were actually exported","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-14T00:21:47.327014-07:00","updated_at":"2025-10-14T03:04:05.966165-07:00","closed_at":"2025-10-14T00:29:31.179483-07:00"} +{"id":"bd-54","title":"Bug: Malformed ID detection query never finds malformed IDs","description":"The query checking for malformed IDs uses 'CAST(SUBSTR(...) AS INTEGER) IS NULL' but SQLite's CAST never returns NULL for invalid integers - it returns 0. This means malformed IDs with non-numeric suffixes are never detected or warned about.\n\nImpact: Silent data quality issues, incorrect ID generation\nLocation: internal/storage/sqlite/sqlite.go:125-145\nSuggested fix: Use a regex or check if the SUBSTR result matches '^[0-9]+$' pattern","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-10-14T00:21:48.404838-07:00","updated_at":"2025-10-14T03:04:05.96634-07:00","closed_at":"2025-10-14T00:32:51.521595-07:00"} +{"id":"bd-55","title":"Enhancement: Migration should validate dirty_issues table schema","description":"The migrateDirtyIssuesTable function only checks if the table exists, not if it has the correct schema. If someone created a dirty_issues table with a different schema, the migration would silently succeed and cause runtime errors later.\n\nImpact: Silent schema inconsistencies, difficult debugging\nLocation: internal/storage/sqlite/sqlite.go:65-98\nSuggested fix: Check table schema (column names/types) and either migrate or fail with clear error","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T00:22:04.773185-07:00","updated_at":"2025-10-14T03:04:05.966496-07:00"} +{"id":"bd-56","title":"Enhancement: Inconsistent dependency dirty marking can cause partial updates","description":"In AddDependency and RemoveDependency, both issues are marked dirty in sequence. If the transaction fails after marking the first issue but before marking the second, dirty state becomes inconsistent. While the transaction will rollback, this pattern is fragile.\n\nImpact: Potential inconsistent dirty state on transaction failures\nLocation: internal/storage/sqlite/dependencies.go:113-131, 160-177\nSuggested fix: Use MarkIssuesDirty() batch function instead of separate statements","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-10-14T00:22:05.619682-07:00","updated_at":"2025-10-14T03:04:05.966665-07:00","closed_at":"2025-10-14T00:35:43.188168-07:00"} +{"id":"bd-57","title":"Code quality: Remove dead code in GetDirtyIssueCount","description":"GetDirtyIssueCount checks for sql.ErrNoRows but SELECT COUNT(*) never returns ErrNoRows - it always returns 0 for empty tables. This is unnecessary dead code.\n\nImpact: Code clarity, minor performance\nLocation: internal/storage/sqlite/dirty.go:88-96\nSuggested fix: Remove the ErrNoRows check","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T00:22:06.46476-07:00","updated_at":"2025-10-14T03:04:05.966823-07:00"} +{"id":"bd-58","title":"Enhancement: Add observability for dirty tracking system","description":"No metrics or observability for the dirty tracking system. Difficult to debug production issues like: how many issues are typically dirty? How long do they stay dirty? How often do exports fail?\n\nImpact: Poor debuggability, hard to tune performance\nSuggested additions:\n- Metrics for dirty count over time\n- Duration tracking for dirty state\n- Export success/failure rates\n- Auto-flush statistics","status":"open","priority":3,"issue_type":"feature","created_at":"2025-10-14T00:22:07.567867-07:00","updated_at":"2025-10-14T03:04:05.966973-07:00"} +{"id":"bd-59","title":"Enhancement: Use consistent timestamps within transactions","description":"Multiple CRUD operations call time.Now() multiple times within a transaction. For consistency, should call once and reuse the same timestamp throughout the transaction so all operations have identical timestamps.\n\nImpact: Minor timestamp inconsistencies, harder to debug event ordering\nLocations: Multiple files in internal/storage/sqlite/\nSuggested fix: Call time.Now() once at transaction start, pass to all operations","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T00:22:08.949261-07:00","updated_at":"2025-10-14T03:04:05.967135-07:00"} +{"id":"bd-6","title":"Add migration scripts for GitHub Issues","description":"Create scripts to import from GitHub Issues API or exported JSON","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-12T10:50:52.140018-07:00","updated_at":"2025-10-14T03:04:05.96729-07:00","dependencies":[{"issue_id":"bd-6","depends_on_id":"bd-8","type":"parent-child","created_at":"2025-10-12T10:51:08.40857-07:00","created_by":"stevey"}]} +{"id":"bd-60","title":"Enhancement: Make auto-flush debounce configurable","description":"The 5-second debounce for auto-flush is hardcoded. For high-frequency operations or slow filesystems, this might not be optimal. Should be configurable via environment variable or config.\n\nImpact: Flexibility for different use cases\nLocation: cmd/bd/main.go (flushDebounce variable)\nSuggested fix: Add BEADS_FLUSH_DEBOUNCE env var or config option","status":"open","priority":4,"issue_type":"feature","created_at":"2025-10-14T00:22:19.075914-07:00","updated_at":"2025-10-14T03:04:05.967437-07:00"} +{"id":"bd-61","title":"Documentation: Transaction isolation levels should be documented","description":"All BeginTx(ctx, nil) calls use default isolation level. For SQLite with WAL mode, this is fine and gives us snapshot isolation. However, this should be documented in the code or in developer docs to make the concurrency guarantees explicit.\n\nImpact: Developer understanding, maintainability\nLocations: All BeginTx calls throughout codebase\nSuggested fix: Add comment explaining isolation guarantees","status":"open","priority":4,"issue_type":"task","created_at":"2025-10-14T00:22:20.33128-07:00","updated_at":"2025-10-14T03:04:05.967596-07:00"} +{"id":"bd-62","title":"Merge PR #8: Fix parallel issue creation race condition","description":"PR #8 fixes a critical race condition in parallel issue creation by replacing the in-memory ID counter with an atomic database-backed counter. However, it has conflicts with recent changes to main.\n\n**PR Summary:**\n- Adds issue_counters table for atomic ID generation\n- Replaces in-memory nextID counter with getNextIDForPrefix()\n- Adds SyncAllCounters() to prevent collisions after import\n- Includes comprehensive tests for multi-process scenarios\n\n**Conflicts with main:**\n1. SQLiteStorage struct - PR removes nextID/idMu fields added to main\n2. New() function - PR doesn't include migrateDirtyIssuesTable() added in f3a61a6\n3. CreateIssue() - Both versions have dirty tracking but different ID generation\n4. Schema - PR adds issue_counters, main added dirty_issues table\n5. getNextID() - PR removes function that was recently fixed in 3aeeeb7 for bd-54\n\n**Work needed:**\n- Rebase PR #8 on current main\n- Preserve dirty_issues table and migration\n- Add issue_counters table with similar migration pattern\n- Integrate atomic counter system with existing dirty tracking\n- Ensure all tests pass\n- Verify both features work together\n\n**Context:**\n- PR: https://github.com/steveyegge/beads/pull/8\n- Closes: bd-6 (if issue exists)\n- Related commits: f3a61a6, 3aeeeb7, bafb280","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-14T01:14:45.357198-07:00","updated_at":"2025-10-14T03:04:05.96775-07:00","closed_at":"2025-10-14T01:20:31.049608-07:00"} +{"id":"bd-63","title":"Test merged features","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-14T01:19:37.745731-07:00","updated_at":"2025-10-14T03:04:05.967917-07:00","closed_at":"2025-10-14T01:19:50.064461-07:00"} +{"id":"bd-64","title":"CRITICAL: Fix SyncAllCounters performance bottleneck in CreateIssue","description":"SyncAllCounters() is called on EVERY issue creation with auto-generated IDs (sqlite.go:143). This scans the entire issues table on every create, causing O(n) overhead.\n\n**Impact:**\n- With 1,000 issues: full table scan per create\n- With 10,000 issues: massive performance hit\n- Unacceptable for production use\n\n**Root cause:** Lines 140-145 in internal/storage/sqlite/sqlite.go sync all counters to handle edge cases (DB created before fix, or issues imported without syncing).\n\n**Solutions:**\n1. **Lazy init (preferred)**: Only sync if counter doesn't exist for the prefix\n2. **One-time at startup**: Call SyncAllCounters() once in New()\n3. **Remove entirely**: import.go now syncs, edge cases are rare\n\n**Recommended fix:** Add ensureCounterSynced() that checks if counter exists before syncing only that prefix.","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-14T01:23:23.041743-07:00","updated_at":"2025-10-14T03:04:05.968071-07:00","closed_at":"2025-10-14T01:29:32.233892-07:00","dependencies":[{"issue_id":"bd-64","depends_on_id":"bd-71","type":"parent-child","created_at":"2025-10-14T01:24:35.859964-07:00","created_by":"stevey"}]} +{"id":"bd-65","title":"Add migration for issue_counters table","description":"There's a migrateDirtyIssuesTable() function but no corresponding migration for issue_counters table.\n\n**Problem:**\n- Existing databases won't have the issue_counters table\n- They rely on schema 'CREATE TABLE IF NOT EXISTS' \n- Counter won't be initialized with existing issue IDs\n- Could lead to ID collisions if issues already exist in DB\n\n**Location:** internal/storage/sqlite/sqlite.go:48-51\n\n**Solution:** Add migrateIssueCountersTable() similar to migrateDirtyIssuesTable():\n1. Check if table exists\n2. If not, create it\n3. Sync counters from existing issues","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-14T01:23:32.02232-07:00","updated_at":"2025-10-14T03:04:05.96824-07:00","closed_at":"2025-10-14T01:32:38.263621-07:00","dependencies":[{"issue_id":"bd-65","depends_on_id":"bd-71","type":"parent-child","created_at":"2025-10-14T01:24:35.864429-07:00","created_by":"stevey"}]} +{"id":"bd-66","title":"Make import counter sync failure fatal instead of warning","description":"In cmd/bd/import.go:243, SyncAllCounters() failure is treated as a non-fatal warning:\n\n```go\nif err := sqliteStore.SyncAllCounters(ctx); err != nil {\n fmt.Fprintf(os.Stderr, \"Warning: failed to sync ID counters: %v\\n\", err)\n // Don't exit - this is not fatal, just a warning\n}\n```\n\n**Problem:** If counter sync fails, subsequent auto-generated IDs WILL collide with imported issues. This can corrupt data.\n\n**Decision needed:**\n1. Make it fatal (fail hard) - safer but less forgiving\n2. Keep as warning but document the risk clearly\n3. Add a --strict flag to control behavior\n\n**Recommendation:** Make it fatal by default. Data integrity \u003e convenience.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-14T01:23:40.61527-07:00","updated_at":"2025-10-14T03:04:05.968391-07:00","closed_at":"2025-10-14T01:33:10.337387-07:00","dependencies":[{"issue_id":"bd-66","depends_on_id":"bd-71","type":"parent-child","created_at":"2025-10-14T01:24:35.869311-07:00","created_by":"stevey"}]} +{"id":"bd-67","title":"Update test comments to reflect post-fix state","description":"Test comments in internal/storage/sqlite/sqlite_test.go:264-266 refer to 'with the bug' but the bug is now fixed:\n\n```go\n// With the bug, we expect UNIQUE constraint errors\nif len(errors) \u003e 0 {\n t.Logf(\"Got %d errors (expected with current implementation):\", len(errors))\n```\n\n**Issue:** This is confusing and suggests the bug still exists.\n\n**Fix:** Update comments to say 'after the fix, no errors expected' and make the test fail hard if errors occur (lines 279-281).","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-14T01:23:48.488537-07:00","updated_at":"2025-10-14T03:04:05.968558-07:00","closed_at":"2025-10-14T01:33:52.447248-07:00","dependencies":[{"issue_id":"bd-67","depends_on_id":"bd-71","type":"parent-child","created_at":"2025-10-14T01:24:35.873665-07:00","created_by":"stevey"}]} +{"id":"bd-68","title":"Add performance benchmarks for CreateIssue with varying DB sizes","description":"Add benchmark tests to measure CreateIssue performance as database grows.\n\n**Goal:** Catch performance regressions early, especially around ID generation.\n\n**Test cases:**\n- Benchmark with 10, 100, 1k, 10k existing issues\n- Measure auto-generated ID creation time\n- Measure explicit ID creation time\n- Compare single vs concurrent operations\n\n**Location:** internal/storage/sqlite/sqlite_test.go\n\n**Related:** This would have caught the SyncAllCounters issue (bd-64) immediately.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T01:23:57.134825-07:00","updated_at":"2025-10-14T03:04:05.968709-07:00","dependencies":[{"issue_id":"bd-68","depends_on_id":"bd-71","type":"parent-child","created_at":"2025-10-14T01:24:35.87799-07:00","created_by":"stevey"}]} +{"id":"bd-69","title":"Add metrics/logging for counter sync operations","description":"Add observability for ID counter operations to help diagnose issues and monitor performance.\n\n**What to log:**\n- When SyncAllCounters() is called\n- How long it takes\n- How many counters are synced\n- Any collisions detected/prevented\n\n**Use cases:**\n- Debug ID generation issues\n- Monitor performance impact of counter syncs\n- Detect when databases need optimization\n\n**Implementation:**\n- Add structured logging (consider using slog)\n- Make it optional (via flag or env var)\n- Include in both CreateIssue and import flows","status":"open","priority":3,"issue_type":"feature","created_at":"2025-10-14T01:24:06.079067-07:00","updated_at":"2025-10-14T03:04:05.968871-07:00","dependencies":[{"issue_id":"bd-69","depends_on_id":"bd-71","type":"parent-child","created_at":"2025-10-14T01:24:35.882631-07:00","created_by":"stevey"}]} +{"id":"bd-7","title":"Add performance benchmarks document","description":"Document actual performance metrics with hyperfine tests","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-12T10:50:53.294516-07:00","updated_at":"2025-10-14T03:04:05.969028-07:00","dependencies":[{"issue_id":"bd-7","depends_on_id":"bd-8","type":"parent-child","created_at":"2025-10-12T10:51:08.412835-07:00","created_by":"stevey"}]} +{"id":"bd-70","title":"Add EXPLAIN QUERY PLAN tests for counter queries","description":"Add tests to verify that counter-related SQL queries use proper indexes and don't cause full table scans.\n\n**Queries to test:**\n1. getNextIDForPrefix() - INSERT with ON CONFLICT\n2. SyncAllCounters() - GROUP BY with MAX and CAST\n3. Any new lazy init query added for bd-64\n\n**Implementation:**\n- Use SQLite's EXPLAIN QUERY PLAN\n- Parse output to verify no SCAN TABLE operations\n- Add to sqlite_test.go\n\n**Benefits:**\n- Catch performance regressions in tests\n- Document expected query plans\n- Ensure indexes are being used","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:24:15.473927-07:00","updated_at":"2025-10-14T03:04:05.969172-07:00","dependencies":[{"issue_id":"bd-70","depends_on_id":"bd-71","type":"parent-child","created_at":"2025-10-14T01:24:35.887151-07:00","created_by":"stevey"}]} +{"id":"bd-71","title":"Code review follow-up: Post-PR #8 merge improvements","description":"Follow-up tasks from the ultrathink code review of PR #8 merge (bd-62).\n\n**Context:** PR #8 successfully merged atomic counter + dirty tracking. Core functionality is solid but several improvements identified.\n\n**Critical (P0-P1):**\n- bd-64: Fix SyncAllCounters performance bottleneck (P0)\n- bd-65: Add migration for issue_counters table (P1)\n- bd-66: Make import counter sync failure fatal (P1)\n\n**Nice to have (P2-P3):**\n- bd-67: Update test comments (P2)\n- bd-68: Add performance benchmarks (P2)\n- bd-69: Add metrics/logging (P3)\n- bd-70: Add EXPLAIN QUERY PLAN tests (P3)\n\n**Overall assessment:** 4/5 stars - Excellent implementation with one critical performance issue. After bd-64 is fixed, this becomes 5/5.\n\n**Review document:** Available if needed","notes":"Status update: All P0-P1 critical tasks completed! bd-64 (performance), bd-65 (migration), bd-66 (fatal error), bd-67 (comments) are all done. Atomic counter implementation is now production-ready. Remaining tasks are P2-P3 enhancements.","status":"open","priority":1,"issue_type":"epic","created_at":"2025-10-14T01:24:27.716237-07:00","updated_at":"2025-10-14T03:04:05.969337-07:00"} +{"id":"bd-72","title":"Test performance - issue 1","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T01:27:53.520056-07:00","updated_at":"2025-10-14T03:04:05.969484-07:00"} +{"id":"bd-73","title":"Performance test 1","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.931707-07:00","updated_at":"2025-10-14T03:04:05.969643-07:00"} +{"id":"bd-74","title":"Performance test 2","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.936642-07:00","updated_at":"2025-10-14T03:04:05.969793-07:00"} +{"id":"bd-75","title":"Performance test 3","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.941591-07:00","updated_at":"2025-10-14T03:04:05.969939-07:00"} +{"id":"bd-76","title":"Performance test 4","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.946053-07:00","updated_at":"2025-10-14T03:04:05.970081-07:00"} +{"id":"bd-77","title":"Performance test 5","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.950618-07:00","updated_at":"2025-10-14T03:04:05.970222-07:00"} +{"id":"bd-78","title":"Performance test 6","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.955773-07:00","updated_at":"2025-10-14T03:04:05.970365-07:00"} +{"id":"bd-79","title":"Performance test 7","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.96021-07:00","updated_at":"2025-10-14T03:04:05.970507-07:00"} +{"id":"bd-8","title":"Reach 1.0 release milestone","description":"Stabilize API, finalize documentation, comprehensive testing","status":"open","priority":1,"issue_type":"epic","created_at":"2025-10-12T10:50:54.457348-07:00","updated_at":"2025-10-14T03:04:05.970653-07:00"} +{"id":"bd-80","title":"Performance test 8","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.964861-07:00","updated_at":"2025-10-14T03:04:05.970821-07:00"} +{"id":"bd-81","title":"Performance test 9","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.969882-07:00","updated_at":"2025-10-14T03:04:05.97098-07:00"} +{"id":"bd-82","title":"Performance test 10","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-14T01:27:59.974738-07:00","updated_at":"2025-10-14T03:04:05.97112-07:00"} +{"id":"bd-83","title":"Add external_ref field for tracking GitHub issues","description":"Add optional external_ref field to issues table to track external references like 'gh-9', 'jira-ABC', etc. Includes schema migration, CLI flags (--external-ref for create/update), and tests. This enables linking bd issues to GitHub issues for better workflow integration.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-14T02:27:01.187087-07:00","updated_at":"2025-10-14T03:04:05.971268-07:00","closed_at":"2025-10-14T02:34:54.508385-07:00"} +{"id":"bd-84","title":"Auto-import fails in git workflows due to mtime issues","description":"The auto-import mechanism (autoImportIfNewer) relies on file modification time comparison between JSONL and DB. This breaks in git workflows because git does not preserve original file modification times - pulled files get fresh mtimes based on checkout time.\n\nRoot causes:\n1. Git checkout sets mtime to 'now', not original commit time\n2. Auto-import compares JSONL mtime vs DB mtime (line 181 in main.go)\n3. If DB was recently modified (agents working), mtime check fails\n4. Auto-import silently returns without feedback\n5. Agents continue with stale database state\n\nThis caused issues in VC project where 3 parallel agents:\n- Pulled updated .beads/issues.jsonl from git\n- Auto-import didn't trigger (JSONL appeared older than DB)\n- Agents couldn't find their assigned issues\n- Agents exported from wrong database, corrupting JSONL","design":"Recommended approach: Checksum-based sync (option 3 from original design)\n\n## Solution: Hash-based content comparison\n\nReplace mtime comparison with JSONL content hash comparison:\n\n1. **Compute JSONL hash on startup**:\n - SHA256 hash of .beads/issues.jsonl contents\n - Fast enough for typical repos (\u003c1MB = ~20ms)\n - Only computed once per command invocation\n\n2. **Store last import hash in DB**:\n - Add metadata table if not exists: CREATE TABLE IF NOT EXISTS metadata (key TEXT PRIMARY KEY, value TEXT)\n - Store hash after successful import: INSERT OR REPLACE INTO metadata (key, value) VALUES ('last_import_hash', '\u003chash\u003e')\n - Query on startup: SELECT value FROM metadata WHERE key = 'last_import_hash'\n\n3. **Compare hashes instead of mtimes**:\n - If JSONL hash != stored hash: auto-import (content changed)\n - If JSONL hash == stored hash: skip import (no changes)\n - If no stored hash: fall back to mtime comparison (backward compat)\n\n4. **Update autoImportIfNewer() in cmd/bd/main.go**:\n - Lines 155-279 currently use mtime comparison (line 181)\n - Replace with hash comparison\n - Keep mtime as fallback for old DBs without metadata table\n\n## Implementation Details\n\n### New storage interface method:\n```go\n// In internal/storage/storage.go\ntype Storage interface {\n // ... existing methods ...\n GetMetadata(ctx context.Context, key string) (string, error)\n SetMetadata(ctx context.Context, key, value string) error\n}\n```\n\n### Migration:\n```go\n// In internal/storage/sqlite/sqlite.go init\nCREATE TABLE IF NOT EXISTS metadata (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n);\n```\n\n### Updated autoImportIfNewer():\n```go\nfunc autoImportIfNewer() {\n jsonlPath := findJSONLPath()\n \n // Check if JSONL exists\n jsonlData, err := os.ReadFile(jsonlPath)\n if err != nil {\n return // No JSONL, skip\n }\n \n // Compute current hash\n hasher := sha256.New()\n hasher.Write(jsonlData)\n currentHash := hex.EncodeToString(hasher.Sum(nil))\n \n // Get last import hash from DB\n ctx := context.Background()\n lastHash, err := store.GetMetadata(ctx, \"last_import_hash\")\n if err != nil {\n // No metadata support (old DB) - fall back to mtime comparison\n autoImportIfNewerByMtime()\n return\n }\n \n // Compare hashes\n if currentHash == lastHash {\n return // No changes, skip import\n }\n \n // Content changed - import\n if err := importJSONLSilent(jsonlPath, jsonlData); err != nil {\n return // Import failed, skip\n }\n \n // Store new hash\n _ = store.SetMetadata(ctx, \"last_import_hash\", currentHash)\n}\n```\n\n## Benefits\n\n- **Git-proof**: Works regardless of file timestamps\n- **Universal**: Works with git, Dropbox, rsync, manual edits\n- **Backward compatible**: Falls back to mtime for old DBs\n- **Efficient**: SHA256 is fast (~20ms for 1MB)\n- **Accurate**: Only imports when content actually changed\n- **No user action**: Fully automatic, invisible\n\n## Performance Optimization\n\nFor very large repos (\u003e10MB JSONL):\n- Only hash if mtime changed (combine both checks)\n- Use incremental hashing if metadata table tracks line count\n- Consider sampling hash (first 1MB + last 1MB)\n\nBut start simple - full hash is fast enough for 99% of use cases.\n\n## Rollout Plan\n\n1. Add metadata table + Get/SetMetadata methods (backward compatible)\n2. Update autoImportIfNewer() with hash logic + mtime fallback\n3. Test with old and new DBs\n4. Ship in next minor version (v0.10.0)\n5. Document in CHANGELOG as \"more reliable auto-import\"\n6. Git hooks remain optional but unnecessary for most users","acceptance_criteria":"- Auto-import works correctly after git pull\n- Agents in parallel workflows see consistent database state\n- Clear feedback when import is needed\n- Performance acceptable for large databases\n- Works in both git and non-git workflows\n- Documentation updated with multi-agent best practices","status":"in_progress","priority":1,"issue_type":"bug","created_at":"2025-10-14T02:37:34.073953-07:00","updated_at":"2025-10-14T03:04:05.97143-07:00"} +{"id":"bd-85","title":"GH-1: Fix bd dep tree graph display issues","description":"Tree display has several issues: 1) Epic items may not expand all sub-items, 2) Subitems repeat multiple times at same level, 3) Items with multiple blockers appear multiple times. The tree visualization doesn't properly handle graph structures with multiple dependencies.","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-14T02:44:28.702222-07:00","updated_at":"2025-10-14T03:06:51.74719-07:00","closed_at":"2025-10-14T03:06:51.74719-07:00","external_ref":"gh-1"} +{"id":"bd-86","title":"GH-2: Evaluate optional Turso backend for collaboration","description":"RFC proposal for optional Turso/libSQL backend to enable: database branching, near-real-time sync between agents/humans, native vector search, browser-ready persistence (WASM/OPFS), and concurrent writes. Would be opt-in, keeping current JSONL+SQLite as default. Requires storage driver interface.","status":"open","priority":3,"issue_type":"feature","created_at":"2025-10-14T02:44:51.932233-07:00","updated_at":"2025-10-14T03:04:05.971828-07:00","external_ref":"gh-2"} +{"id":"bd-87","title":"GH-3: Debug zsh killed error on bd init","description":"User reports 'zsh: killed bd init' when running bd init or just bd command. Likely a crash or signal. Need to reproduce and investigate cause.","status":"open","priority":1,"issue_type":"bug","created_at":"2025-10-14T02:44:53.054411-07:00","updated_at":"2025-10-14T03:04:05.972856-07:00","external_ref":"gh-3"} +{"id":"bd-88","title":"GH-4: Consider system-wide/multi-repo beads usage","description":"User wants to use beads across multiple repositories and for sysadmin tasks. Currently beads is project-scoped (.beads/ directory). Explore options for system-wide issue tracking that spans multiple repos. Related question: how does beads compare to membank MCP?","status":"open","priority":3,"issue_type":"feature","created_at":"2025-10-14T02:44:54.343447-07:00","updated_at":"2025-10-14T03:04:05.973014-07:00","external_ref":"gh-4"} +{"id":"bd-89","title":"GH-6: Fix race condition in parallel issue creation","description":"Creating multiple issues rapidly in parallel causes 'UNIQUE constraint failed: issues.id' error. The ID generation has a race condition. Reproducible with: for i in {26..35}; do ./bd create parallel_ 2\u003e\u00261 \u0026 done","status":"open","priority":0,"issue_type":"bug","created_at":"2025-10-14T02:44:55.510776-07:00","updated_at":"2025-10-14T03:04:05.97313-07:00","closed_at":"2025-10-14T02:58:22.645874-07:00","external_ref":"gh-6"} +{"id":"bd-9","title":"Build collision resolution tooling for distributed branch workflows","description":"When branches diverge and both create issues, auto-incrementing IDs collide on merge. Build excellent tooling to detect collisions during import, auto-renumber issues with fewer dependencies, update all references in descriptions and dependency links, and provide clear user feedback. Goal: keep beautiful brevity of numeric IDs (bd-302) while handling distributed creation gracefully.","status":"in_progress","priority":1,"issue_type":"feature","created_at":"2025-10-12T13:39:34.608218-07:00","updated_at":"2025-10-14T03:04:05.973251-07:00"} +{"id":"bd-90","title":"GH-7: Package available in AUR (beads-git)","description":"Community member created AUR package for Arch Linux: https://aur.archlinux.org/packages/beads-git. This is informational - no action needed, but good to track for release process and documentation.","status":"open","priority":4,"issue_type":"chore","created_at":"2025-10-14T02:44:56.4535-07:00","updated_at":"2025-10-14T03:04:05.973364-07:00","external_ref":"gh-7"} +{"id":"bd-91","title":"GH-9: Support markdown files in bd create","description":"Request to support markdown files as input to bd create, which would parse the markdown and split it into multiple issues. Use case: developers keep feature drafts in markdown files in version control, then want to convert them into issues. Example: bd create -f feature-draft.md","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-14T02:44:57.405586-07:00","updated_at":"2025-10-14T03:04:05.973505-07:00","external_ref":"gh-9"} +{"id":"bd-92","title":"GH-11: Add Docker support for hosted/shared instance","description":"Request for Docker container hosting to use beads across multiple dev machines. Would need to consider: centralized database (PostgreSQL?), authentication, concurrent access, API server, etc. This is a significant architectural change from the current local-first model.","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-14T02:44:58.469094-07:00","updated_at":"2025-10-14T03:04:05.973622-07:00","external_ref":"gh-11"} +{"id":"bd-93","title":"GH-18: Add --deps flag to bd create for one-command issue creation","description":"Request to add dependency specification to bd create command instead of requiring separate 'bd dep add' command. Proposed syntax: bd create 'Fix bug' --deps discovered-from=bd-20. This would be especially useful for aider integration and reducing command verbosity.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-14T02:44:59.610192-07:00","updated_at":"2025-10-14T03:26:59.536349-07:00","closed_at":"2025-10-14T03:26:59.536349-07:00","external_ref":"gh-18"} +{"id":"bd-94","title":"parallel_test_1","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:46.913771-07:00","updated_at":"2025-10-14T02:55:46.913771-07:00"} +{"id":"bd-95","title":"parallel_test_4","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:46.920107-07:00","updated_at":"2025-10-14T02:55:46.920107-07:00"} +{"id":"bd-96","title":"parallel_test_7","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:46.920612-07:00","updated_at":"2025-10-14T02:55:46.920612-07:00"} +{"id":"bd-97","title":"parallel_test_6","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:46.931334-07:00","updated_at":"2025-10-14T02:55:46.931334-07:00"} +{"id":"bd-98","title":"parallel_test_5","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:46.932369-07:00","updated_at":"2025-10-14T02:55:46.932369-07:00"} +{"id":"bd-99","title":"parallel_test_2","description":"","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-14T02:55:46.946379-07:00","updated_at":"2025-10-14T02:55:46.946379-07:00"} +{"id":"test-100","title":"Test issue with explicit ID","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-13T23:16:20.601292-07:00","updated_at":"2025-10-14T03:04:05.973845-07:00","closed_at":"2025-10-13T23:16:45.231096-07:00"} +{"id":"test-500","title":"Root issue for dep tree test","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-14T03:03:20.195117-07:00","updated_at":"2025-10-14T03:06:42.688954-07:00","closed_at":"2025-10-14T03:06:42.688954-07:00","dependencies":[{"issue_id":"test-500","depends_on_id":"test-501","type":"blocks","created_at":"2025-10-14T03:03:28.960169-07:00","created_by":"stevey"},{"issue_id":"test-500","depends_on_id":"test-502","type":"blocks","created_at":"2025-10-14T03:03:28.964808-07:00","created_by":"stevey"}]} +{"id":"test-501","title":"Dependency A","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-14T03:03:21.377968-07:00","updated_at":"2025-10-14T03:06:42.693557-07:00","closed_at":"2025-10-14T03:06:42.693557-07:00","dependencies":[{"issue_id":"test-501","depends_on_id":"test-503","type":"blocks","created_at":"2025-10-14T03:03:28.969145-07:00","created_by":"stevey"}]} +{"id":"test-502","title":"Dependency B","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-14T03:03:21.383498-07:00","updated_at":"2025-10-14T03:06:42.697908-07:00","closed_at":"2025-10-14T03:06:42.697908-07:00","dependencies":[{"issue_id":"test-502","depends_on_id":"test-503","type":"blocks","created_at":"2025-10-14T03:03:28.973659-07:00","created_by":"stevey"}]} +{"id":"test-503","title":"Shared dependency C","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-14T03:03:21.388441-07:00","updated_at":"2025-10-14T03:06:42.702632-07:00","closed_at":"2025-10-14T03:06:42.702632-07:00"} +{"id":"test-600","title":"Epic test","description":"","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-14T03:06:14.495832-07:00","updated_at":"2025-10-14T03:06:42.706851-07:00","closed_at":"2025-10-14T03:06:42.706851-07:00","dependencies":[{"issue_id":"test-600","depends_on_id":"test-601","type":"parent-child","created_at":"2025-10-14T03:06:15.846921-07:00","created_by":"stevey"},{"issue_id":"test-600","depends_on_id":"test-602","type":"parent-child","created_at":"2025-10-14T03:06:15.851564-07:00","created_by":"stevey"}]} +{"id":"test-601","title":"Task A under epic","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-14T03:06:14.500446-07:00","updated_at":"2025-10-14T03:06:42.71108-07:00","closed_at":"2025-10-14T03:06:42.71108-07:00","dependencies":[{"issue_id":"test-601","depends_on_id":"test-603","type":"blocks","created_at":"2025-10-14T03:06:15.856369-07:00","created_by":"stevey"}]} +{"id":"test-602","title":"Task B under epic","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-14T03:06:14.504917-07:00","updated_at":"2025-10-14T03:06:42.715283-07:00","closed_at":"2025-10-14T03:06:42.715283-07:00","dependencies":[{"issue_id":"test-602","depends_on_id":"test-604","type":"blocks","created_at":"2025-10-14T03:06:15.860979-07:00","created_by":"stevey"}]} +{"id":"test-603","title":"Sub-task under A","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-14T03:06:14.509748-07:00","updated_at":"2025-10-14T03:06:42.719842-07:00","closed_at":"2025-10-14T03:06:42.719842-07:00"} +{"id":"test-604","title":"Sub-task under B","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-14T03:06:14.514628-07:00","updated_at":"2025-10-14T03:06:42.724998-07:00","closed_at":"2025-10-14T03:06:42.724998-07:00"} +{"id":"worker2-500","title":"Another explicit ID","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-13T23:16:29.978183-07:00","updated_at":"2025-10-14T03:04:05.973956-07:00","closed_at":"2025-10-13T23:16:45.231376-07:00"} diff --git a/README.md b/README.md index 044fa5ae..c079522d 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,17 @@ go build -o bd ./cmd/bd sudo mv bd /usr/local/bin/ # or anywhere in your PATH ``` +#### Arch Linux + +```bash +# Install from AUR +yay -S beads-git +# or +paru -S beads-git +``` + +Thanks to [@v4rgas](https://github.com/v4rgas) for maintaining the AUR package! + #### Windows 11 For Windows you must build from source. Assumes git, go-lang and mingw-64 installed and in path. diff --git a/cmd/bd/main.go b/cmd/bd/main.go index 40cf39ba..61fd5445 100644 --- a/cmd/bd/main.go +++ b/cmd/bd/main.go @@ -102,11 +102,6 @@ var rootCmd = &cobra.Command{ } }, PersistentPostRun: func(cmd *cobra.Command, args []string) { - // Signal that store is closing (prevents background flush from accessing closed store) - storeMutex.Lock() - storeActive = false - storeMutex.Unlock() - // Flush any pending changes before closing flushMutex.Lock() needsFlush := isDirty && autoFlushEnabled @@ -116,7 +111,7 @@ var rootCmd = &cobra.Command{ flushTimer.Stop() flushTimer = nil } - isDirty = false + // Don't clear isDirty here - let flushToJSONL do it } flushMutex.Unlock() @@ -125,6 +120,11 @@ var rootCmd = &cobra.Command{ flushToJSONL() } + // Signal that store is closing (prevents background flush from accessing closed store) + storeMutex.Lock() + storeActive = false + storeMutex.Unlock() + if store != nil { _ = store.Close() }