- Add repo_mtimes table to track JSONL file modification times
- Implement HydrateFromMultiRepo() with mtime-based skip optimization
- Support tilde expansion for repo paths in config
- Add source_repo column via migration (not in base schema)
- Fix schema to allow migration on existing databases
- Comprehensive test coverage for hydration logic
- Resurrect missing parent issues bd-cb64c226 and bd-cbed9619
Implementation:
- internal/storage/sqlite/multirepo.go - Core hydration logic
- internal/storage/sqlite/multirepo_test.go - Test coverage
- docs/MULTI_REPO_HYDRATION.md - Documentation
Schema changes:
- source_repo column added via migration only (not base schema)
- repo_mtimes table for mtime caching
- All SELECT queries updated to include source_repo
Database recovery:
- Restored from 17 to 285 issues
- Created placeholder parents for orphaned hierarchical children
Amp-Thread-ID: https://ampcode.com/threads/T-faa1339a-14b2-426c-8e18-aa8be6f5cde6
Co-authored-by: Amp <amp@ampcode.com>
- Add GetIssueByExternalRef() query function to storage interface and implementations
- Update DetectCollisions() to prioritize external_ref matching over ID matching
- Modify upsertIssues() to handle external_ref matches in import logic
- Add index on external_ref column for performance
- Add comprehensive tests for external_ref matching in both collision detection and import
- Enables re-syncing from external systems (Jira, GitHub, Linear) without duplicates
- Preserves local issues (no external_ref) from being overwritten
- Removed nextSequentialID() and getIDMode() functions
- Removed issue_counters table from schema
- Made SyncAllCounters() a no-op for backward compatibility
- Simplified ID generation to hash-only (adaptive length)
- Removed id_mode config setting
- Removed sequential ID tests and migration code
- Updated CONFIG.md and AGENTS.md to remove sequential ID references
Follow-up bd-2a70 will remove obsolete test files and renumber command.
- Add compacted_at_commit field to Issue type (bd-405)
- Add database schema and migration for new field
- Create GetCurrentCommitHash() helper function
- Update ApplyCompaction to store git commit hash (bd-395)
- Update compaction calls to capture current commit
- Update tests to verify commit hash storage
- All tests passing
Amp-Thread-ID: https://ampcode.com/threads/T-5518cccb-7fc9-4dcd-ba5a-e22cd10e45d7
Co-authored-by: Amp <amp@ampcode.com>
- Add closed_at field to Issue type with JSON marshaling
- Implement closed_at timestamp in SQLite storage layer
- Update import/export to handle closed_at field
- Add comprehensive tests for closed_at functionality
- Maintain backward compatibility with existing databases
Amp-Thread-ID: https://ampcode.com/threads/T-f3a7799b-f91e-4432-a690-aae0aed364b3
Co-authored-by: Amp <amp@ampcode.com>
The ready_issues VIEW was using old logic that didn't propagate blocking
through parent-child hierarchies. This caused inconsistency with the
GetReadyWork() function for users querying via sqlite3 CLI.
Changes:
- Updated VIEW to use same recursive CTE as GetReadyWork()
- Added test to verify VIEW and function produce identical results
- No migration needed (CREATE VIEW IF NOT EXISTS handles recreation)
The VIEW is documented in WORKFLOW.md for direct SQL queries and is now
consistent with the function-based API.
Resolves: bd-60
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The hierarchical blocking query recursively joins on dependencies with
a type filter. Without a composite index, SQLite must scan all
dependencies for a given depends_on_id and filter by type afterward.
With 10k+ issues and many dependencies per issue, this could cause
noticeable slowdowns in ready work calculations.
Changes:
- Added idx_dependencies_depends_on_type composite index to schema
- Added automatic migration for existing databases
- Index creation is silent and requires no user intervention
The recursive CTE now efficiently seeks (depends_on_id, type) pairs
directly instead of post-filtering.
Resolves: bd-59
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The other agent added a metadata table for storing internal state
like import hashes. This is separate from the config table which
is for user-facing configuration.
🤖 Generated by other agent
Add nullable external_ref TEXT field to link bd issues with external
systems like GitHub Issues, Jira, etc. Includes automatic schema
migration for backward compatibility.
Changes:
- Added external_ref column to issues table with feature-based migration
- Updated Issue struct with ExternalRef *string field
- Added --external-ref flag to bd create and bd update commands
- Updated all SQL queries across the codebase to include external_ref:
- GetIssue, CreateIssue, UpdateIssue, SearchIssues
- GetDependencies, GetDependents, GetDependencyTree
- GetReadyWork, GetBlockedIssues, GetIssuesByLabel
- Added external_ref handling in import/export logic
- Follows existing patterns for nullable fields (sql.NullString)
This enables tracking relationships between bd issues and external
systems without requiring changes to existing databases or JSONL files.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace the in-memory nextID counter with an atomic database-backed
counter using the issue_counters table. This fixes race conditions
when multiple processes create issues concurrently.
Changes:
- Add issue_counters table with atomic INSERT...ON CONFLICT pattern
- Remove in-memory nextID field and sync.Mutex from SQLiteStorage
- Implement getNextIDForPrefix() for atomic ID generation
- Update CreateIssue() to use database counter instead of memory
- Update RemapCollisions() to use database counter for collision resolution
- Clean up old planning and bug documentation files
Fixes the multi-process ID generation race condition tested in
cmd/bd/race_test.go.
Optimize auto-flush by tracking which issues have changed instead of
exporting the entire database on every flush. For large projects with
1000+ issues, this provides significant performance improvements.
Changes:
- Add dirty_issues table to schema with issue_id and marked_at columns
- Implement dirty tracking functions in new dirty.go file:
* MarkIssueDirty() - Mark single issue as needing export
* MarkIssuesDirty() - Batch mark multiple issues efficiently
* GetDirtyIssues() - Query which issues need export
* ClearDirtyIssues() - Clear tracking after successful export
* GetDirtyIssueCount() - Monitor dirty issue count
- Update all CRUD operations to mark affected issues as dirty:
* CreateIssue, UpdateIssue, DeleteIssue
* AddDependency, RemoveDependency (marks both issues)
* AddLabel, RemoveLabel, AddEvent
- Modify export to support incremental mode:
* Add --incremental flag to export only dirty issues
* Used by auto-flush for performance
* Full export still available without flag
- Add Storage interface methods for dirty tracking
Performance impact: With incremental export, large databases only write
changed issues instead of regenerating entire JSONL file on every
auto-flush.
Closes bd-39
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This is a fundamental architectural shift from binary SQLite to JSONL as
the source of truth for git workflows.
## New Features
- `bd export --format=jsonl` - Export issues to JSON Lines format
- `bd import` - Import issues from JSONL (create new, update existing)
- `--skip-existing` flag for import to only create new issues
## Architecture Change
**Before:** Binary SQLite database committed to git
**After:** JSONL text files as source of truth, SQLite as ephemeral cache
Benefits:
- Git-friendly text format with clean diffs
- AI-resolvable merge conflicts (append-only is 95% conflict-free)
- Human-readable issue tracking in git
- No binary merge conflicts
## Documentation
- Updated README with JSONL-first workflow and git hooks
- Added TEXT_FORMATS.md analyzing JSONL vs CSV vs binary
- Updated GIT_WORKFLOW.md with historical context
- .gitignore now excludes *.db, includes .beads/*.jsonl
## Implementation Details
- Export sorts issues by ID for consistent diffs
- Import handles both creates and updates atomically
- Proper handling of pointer fields (EstimatedMinutes)
- All tests passing
## Breaking Changes
- Database files (*.db) should now be gitignored
- Use export/import workflow for git collaboration
- Git hooks recommended for automation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Core features:
- Dependency-aware issue tracking with SQLite backend
- Ready work detection (issues with no open blockers)
- Dependency tree visualization
- Cycle detection and prevention
- Full audit trail
- CLI with colored output
Security and correctness fixes applied:
- Fixed SQL injection vulnerability in UpdateIssue (whitelisted fields)
- Fixed race condition in ID generation (added mutex)
- Fixed cycle detection to return full paths (not just issue IDs)
- Added cycle prevention in AddDependency (validates before commit)
- Added comprehensive input validation (priority, status, types, etc.)
- Fixed N+1 query in GetBlockedIssues (using GROUP_CONCAT)
- Improved query building in GetReadyWork (proper string joining)
- Fixed P0 priority filter bug (using Changed() instead of value check)
All critical and major issues from code review have been addressed.
🤖 Generated with Claude Code