Implement `bd create -f file.md` to parse markdown files and create
multiple issues in one command. This enables drafting features in
markdown and converting them to tracked issues.
Features:
- Parse markdown H2 headers (##) as issue titles
- Support all issue fields via H3 sections (### Priority, ### Type, etc.)
- Handle multiple issues per file
- Comprehensive validation and error handling
- Full test coverage with 5 test cases
Closes bd-91 (GH-9)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
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 <noreply@anthropic.com>
Allow BD_ACTOR environment variable to set the default actor name,
providing a cleaner alternative to the --actor flag for automated
workflows.
Priority order for actor determination:
1. --actor flag (highest)
2. BD_ACTOR environment variable
3. USER environment variable
4. "unknown" (fallback)
Updated --actor flag help text to reflect the new environment variable.
Release notes:
- --deps flag for one-command issue creation (#18)
- External reference tracking for linking to external trackers
- Critical bug fixes (dep tree, auto-import, parallel creation)
- Windows build support and Go extension examples
- Community PRs merged (#8, #10, #12, #14, #15, #17)
See CHANGELOG.md for full details.
Handle edge cases in dependency spec parsing:
- Skip empty dependency specs (e.g., from trailing commas)
- Trim whitespace around type and ID (e.g., 'discovered-from: bd-20')
This makes the flag more forgiving of user input errors.
Implements GH-18: Allow creating issues with dependencies in a single command.
Changes:
- Add --deps flag to bd create command
- Support format: 'type:id' or just 'id' (defaults to 'blocks')
- Multiple dependencies supported via comma-separated values
- Example: bd create "Fix bug" --deps discovered-from:bd-20,blocks:bd-15
- Updated README.md and CLAUDE.md with examples
This improves the UX for AI agents by reducing two commands (create + dep add)
to a single command, making discovered-from workflows much smoother.
Fixes#18🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The auto-import mechanism previously relied on file modification time
comparison between JSONL and DB. This broke in git workflows because
git doesn't preserve original mtimes - pulled files get fresh timestamps.
Changes:
- Added metadata table for internal state storage (separate from config)
- Replaced mtime comparison with SHA256 hash comparison in autoImportIfNewer()
- Store JSONL hash in metadata after both import and export operations
- Added crypto/sha256 and encoding/hex imports
Benefits:
- Git-proof: Works regardless of file timestamps after git pull
- Universal: Works with git, Dropbox, rsync, manual edits
- Efficient: SHA256 is fast (~20ms for 1MB files)
- Accurate: Only imports when content actually changed
- No user action required: Fully automatic and invisible
Testing:
- All existing tests pass
- Manual testing confirms hash-based import triggers on content changes
- Linter warnings are baseline only (documented in LINTING.md)
This fixes issues where parallel agents in git workflows couldn't
find their assigned issues after git pull because auto-import
silently failed due to stale mtimes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
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>
This commit addresses all critical follow-up issues identified in the
code review of PR #8 (atomic counter implementation).
## bd-64: Fix SyncAllCounters performance bottleneck (P0)
- Replace SyncAllCounters() on every CreateIssue with lazy initialization
- Add ensureCounterInitialized() that only scans prefix-specific issues on first use
- Performance improvement: O(n) full table scan → O(1) for subsequent creates
- Add comprehensive tests in lazy_init_test.go
## bd-65: Add migration for issue_counters table (P1)
- Add migrateIssueCountersTable() similar to migrateDirtyIssuesTable()
- Checks if table is empty and syncs from existing issues on first open
- Handles both fresh databases and migrations from old databases
- Add comprehensive tests in migration_test.go (3 scenarios)
## bd-66: Make import counter sync failure fatal (P1)
- Change SyncAllCounters() failure from warning to fatal error in import
- Prevents ID collisions when counter sync fails
- Data integrity > convenience
## bd-67: Update test comments (P2)
- Update TestMultiProcessIDGeneration comments to reflect fix is in place
- Change "With the bug, we expect errors" → "After the fix, all should succeed"
All tests pass. Atomic counter implementation is now production-ready.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
When importing issues with explicit high IDs (e.g., bd-100), the
issue_counters table wasn't being updated. This caused the next
auto-generated issue to collide with existing IDs (bd-4 instead of bd-101).
Changes:
- Add SyncAllCounters() to scan all issues and update counters atomically
- Add SyncCounterForPrefix() for granular counter synchronization
- Call SyncAllCounters() in import command after creating issues
- Add comprehensive tests for counter sync functionality
- Update TestImportCounterSyncAfterHighID to verify fix
The fix uses a single efficient SQL query to prevent ID collisions
with subsequently auto-generated issues.
TestImportCounterSyncAfterHighID demonstrates that importing an issue
with a high explicit ID (bd-100) doesn't sync the auto-increment counter,
causing the next auto-generated ID to be bd-4 instead of bd-101.
This test currently fails and documents the expected behavior.
The quickstart command referenced EXTENDING.md as if it were a local file,
which was confusing for users running bd in their own projects. Now it
clearly points to the upstream documentation with a full GitHub URL.
- Changed from "See EXTENDING.md" to "See database extension docs"
- Added full URL to the original repo's EXTENDING.md
- Preserved the original "integration patterns" context
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
* deps: run go mod tidy
* beads: Add public Go API for bd extensions
Implements a minimal public API to enable Go-based extensions without
exposing internal packages:
**New beads.go package:**
- Exports essential types: Issue, Status, IssueType, WorkFilter
- Provides status and issue type constants
- Exposes NewSQLiteStorage() as main entry point for extensions
- Includes comprehensive package documentation
**Updated EXTENDING.md:**
- Replaced internal package imports with public beads package
- Updated function calls to use new public API
- Changed sqlite.New() to beads.NewSQLiteStorage()
- Updated GetReady() to GetReadyWork() with WorkFilter
This enables clean Go-based orchestration extensions while maintaining
API stability and hiding internal implementation details.
* beads: Refine Go extensions API and documentation
Updates to the public Go API implementation following initial commit:
- Enhanced beads.go with refined extension interface
- Updated EXTENDING.md with clearer documentation
- Modified cmd/bd/main.go to support extension loading
Continues work on enabling Go-based bd extensions.
* Fix EXTENDING.md to use beads.WorkFilter instead of types.WorkFilter
The public API exports WorkFilter as beads.WorkFilter, not types.WorkFilter.
This fixes the code example to match the imports shown.
---------
Co-authored-by: Steve Yegge <steve.yegge@gmail.com>
Updated the list command to display issue type alongside priority and status.
Before:
beads-48 [P1] open
After:
beads-48 [P1] [epic] open
This makes it easier to distinguish between bugs, features, tasks, epics, and
chores at a glance without using --json or bd show.
Fix critical TOCTOU bug where concurrent operations could lose dirty
issue tracking, causing data loss in incremental exports. Also fixes
bug where export with filters would incorrectly clear all dirty issues.
The Problem:
1. GetDirtyIssues() returns [bd-1, bd-2]
2. Concurrent CRUD marks bd-3 dirty
3. Export writes bd-1, bd-2
4. ClearDirtyIssues() deletes ALL (including bd-3)
5. Result: bd-3 never gets exported!
The Fix:
- Add ClearDirtyIssuesByID() that only clears specific issue IDs
- Track which issues were actually exported
- Clear only those specific IDs, not all dirty issues
- Fixes both race condition and filter export bug
Changes:
- internal/storage/sqlite/dirty.go:
* Add ClearDirtyIssuesByID() method
* Add warning to ClearDirtyIssues() about race condition
- internal/storage/storage.go:
* Add ClearDirtyIssuesByID to interface
- cmd/bd/main.go:
* Update auto-flush to use ClearDirtyIssuesByID()
- cmd/bd/export.go:
* Track exported issue IDs
* Use ClearDirtyIssuesByID() instead of ClearDirtyIssues()
Testing:
- Created test-1, test-2, test-3 (all dirty)
- Updated test-2 to in_progress
- Exported with --status open filter (exports only test-1, test-3)
- Verified only test-2 remains dirty ✓
- All existing tests pass ✓
Impact:
- Race condition eliminated - concurrent operations are safe
- Export with filters now works correctly
- No data loss from competing writes
Closes bd-52, bd-53
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
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>
Implements bd-42: Add test coverage for auto-flush feature
Created cmd/bd/main_test.go with 11 comprehensive test functions:
- TestAutoFlushDirtyMarking: Verifies markDirtyAndScheduleFlush() marks DB as dirty
- TestAutoFlushDisabled: Tests --no-auto-flush flag disables feature
- TestAutoFlushDebounce: Tests rapid operations result in single flush
- TestAutoFlushClearState: Tests clearAutoFlushState() resets state
- TestAutoFlushOnExit: Tests flush happens on program exit
- TestAutoFlushConcurrency: Tests concurrent operations don't cause races
- TestAutoFlushStoreInactive: Tests flush skips when store is inactive
- TestAutoFlushJSONLContent: Tests flushed JSONL has correct content
- TestAutoFlushErrorHandling: Tests error scenarios (permissions, etc.)
- TestAutoImportIfNewer: Tests auto-import when JSONL is newer than DB
- TestAutoImportDisabled: Tests --no-auto-import flag disables auto-import
Coverage results:
- markDirtyAndScheduleFlush: 100%
- clearAutoFlushState: 100%
- flushToJSONL: 67.6%
- autoImportIfNewer: 66.1% (up from 0%)
All tests pass. Auto-flush feature is now thoroughly tested.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Three improvements to beads:
1. ID space partitioning (closes bd-24)
- Add --id flag to 'bd create' for explicit ID assignment
- Validates format: prefix-number (e.g., worker1-100)
- Enables parallel agents to partition ID space and avoid conflicts
- Storage layer already supported this, just wired up CLI
2. Auto-flush failure tracking (closes bd-38)
- Track consecutive flush failures with counter and last error
- Show prominent red warning after 3+ consecutive failures
- Reset counter on successful flush
- Users get clear guidance to run manual export if needed
3. Manual export cancels auto-flush timer
- Add clearAutoFlushState() helper function
- bd export now cancels pending auto-flush and clears dirty flag
- Prevents redundant exports when user manually exports
- Also resets failure counter on successful manual export
Documentation updated in README.md and CLAUDE.md with --id flag examples.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added os.MkdirAll(dbDir, 0755) to ensure the .beads directory exists
before attempting to glob for JSONL files. This fixes a bug where
findJSONLPath() would fail silently if the directory doesn't exist yet,
which can happen during new database initialization.
The fix:
- Creates the directory with 0755 permissions if it doesn't exist
- Handles errors gracefully by returning the default path
- Subsequent write operations will still fail with clear errors if
directory creation fails
Closes bd-36
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Adds auto-import feature to complement bd-35's auto-export, completing
the automatic sync workflow for git collaboration.
**Implementation:**
- Auto-import checks if JSONL is newer than DB on command startup
- Silently imports JSONL when modification time is newer
- Skips import command itself to avoid recursion
- Can be disabled with --no-auto-import flag
**Documentation updates:**
- Updated README.md git workflow section
- Updated CLAUDE.md workflow and pro tips
- Updated bd quickstart with auto-sync section
- Updated git hooks README to clarify they're now optional
**Testing:**
- Tested auto-import by touching JSONL and running commands
- Tested auto-export with create/close operations
- Complete workflow verified working
Closes bd-33
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed three critical issues identified in code review:
1. Race condition with store access: Added storeMutex and storeActive
flag to prevent background flush goroutine from accessing closed
store. Background timer now safely checks if store is active before
attempting flush operations.
2. Missing auto-flush in import: Added markDirtyAndScheduleFlush()
call after import completes, ensuring imported issues sync to JSONL.
3. Timer cleanup: Explicitly set flushTimer to nil after Stop() to
prevent resource leaks.
Testing confirmed all fixes working:
- Debounced flush triggers after 5 seconds of inactivity
- Immediate flush on process exit works correctly
- Import operations now trigger auto-flush
- No race conditions detected
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed critical issues identified in code review:
- Fixed invalid Go version (1.25.2 → 1.21) in go.mod
- Fixed unchecked error in import.go JSON unmarshaling
- Fixed unchecked error returns in test cleanup (export_import_test.go, import_collision_test.go)
- Removed duplicate test code in dependencies_test.go via helper function
Added release infrastructure:
- Added 'bd version' command with JSON output support
- Created comprehensive CHANGELOG.md following Keep a Changelog format
- Updated README.md with clear alpha status warnings
All tests passing. Ready for public repository opening.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements --resolve-collisions flag for import command to safely handle ID
collisions during branch merges. When enabled, colliding issues are remapped
to new IDs and all text references and dependencies are automatically updated.
Also adds comprehensive tests, branch-merge example, and documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added dependency support to export/import workflow:
Changes:
- Added GetDependencyRecords() to Storage interface to get raw dependency records
- Extended Issue struct with Dependencies field (omitempty for backward compat)
- Modified export.go to populate dependencies for each issue
- Modified import.go to process dependencies in second pass after all issues exist
- All tests pass
Benefits:
- JSONL is now self-contained with full dependency information
- Enables proper collision resolution in future (bd-12+)
- Idempotent imports: existing dependencies are not duplicated
- Forward references handled: dependencies created after all issues exist
Example output:
{
"id": "bd-10",
"title": "...",
"dependencies": [{
"issue_id": "bd-10",
"depends_on_id": "bd-9",
"type": "parent-child",
"created_at": "...",
"created_by": "stevey"
}]
}
Closes bd-10
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add package comment to cmd/bd/dep.go
- Change directory permissions from 0755 to 0750 in init.go
- Simplify getNextID signature (remove unused error return)
- Configure golangci-lint exclusions for false positives
- Document linting policy in LINTING.md
The remaining ~100 lint warnings are documented false positives:
- 73 errcheck: deferred cleanup (idiomatic Go)
- 17 revive: Cobra interface requirements and naming choices
- 7 gosec: false positives on validated SQL and user file paths
- 2 dupl: acceptable test code duplication
- 1 goconst: test constant repetition
See LINTING.md for full rationale. Contributors should focus on
avoiding NEW issues rather than the documented baseline.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Major improvements to code quality, documentation, and CI:
Code Quality:
- Add golangci-lint configuration with 13 linters
- Fix unchecked error returns in export/import/init
- Refactor duplicate scanIssues code
- Add package comments for all packages
- Add const block comments for exported constants
- Configure errcheck to allow idiomatic defer patterns
Documentation:
- Add comprehensive CONTRIBUTING.md with setup, testing, and workflow
- Fix QUICKSTART.md binary name references (beads → bd)
- Correct default database path documentation
CI/CD:
- Add GitHub Actions workflow for tests and linting
- Enable race detection and coverage reporting
- Automated quality checks on all PRs
All tests passing. Lint issues reduced from 117 to 103 (remaining are
idiomatic patterns and test code). Ready for open-source release.
🤖 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>