- Add daemon client infrastructure to main.go with TryConnect logic
- Update PersistentPreRun to detect daemon socket and route through RPC
- Add --no-daemon flag to force direct storage mode
- Update all commands (create, update, close, show, list, ready) to use daemon when available
- Maintain backward compatibility with graceful fallback to direct mode
- All commands work identically in both daemon and direct modes
Part of bd-110 daemon architecture implementation.
Amp-Thread-ID: https://ampcode.com/threads/T-bfe2c083-be7c-4064-8673-fa69c22a730e
Co-authored-by: Amp <amp@ampcode.com>
The counter wasn't being properly reset after renumbering because
SyncAllCounters uses MAX(old, new) which kept higher values from
deleted issues.
Solution: Add ResetCounter() method to delete the counter entry,
then SyncAllCounters recreates it from the actual max ID in database.
Now after renumbering 108 issues to bd-1..bd-108, the counter is
correctly set to 108 and next issue will be bd-109.
After renumbering issues to bd-1 through bd-108, the counter was still
at the old value (346), causing next issue to be bd-347 instead of bd-109.
Fix: Call SyncAllCounters after renumbering to recalculate counter from
actual max ID in database.
Problem: Incremental flush merged dirty issues with existing JSONL, leaving
old IDs when issues were renamed (e.g., test-3 remained after renumbering to test-2).
Solution:
- Add needsFullExport flag to force complete JSONL rebuild from DB
- Skip loading existing JSONL when fullExport=true (start with empty map)
- Use markDirtyAndScheduleFullExport() in renumber and rename-prefix commands
- PersistentPostRun flushes immediately before process exits (respects fullExport)
Test: Verified renumber with gaps correctly exports only current IDs to JSONL
- Replace predictable temp IDs (temp-renumber-N) with UUIDs (temp-<uuid>)
- Fetch dependencies before ID updates to preserve them correctly
- Add comprehensive tests for renumbering with ID gaps, dependencies, and text refs
- All tests pass
These commands modify issues in bulk but weren't triggering auto-export
to JSONL. This caused database and JSONL to get out of sync.
Added markDirtyAndScheduleFlush() calls to:
- bd renumber (after renumbering completes)
- bd rename-prefix (after prefix rename completes)
- bd compact (after single/batch compaction)
- bd delete (already had it)
Fixes the issue where massive cleanups weren't exported to JSONL.
Amp-Thread-ID: https://ampcode.com/threads/T-a43dc9fa-e9bc-43c7-9055-33acc08bc642
Co-authored-by: Amp <amp@ampcode.com>
- GetMetadata() failures now set lastHash='' instead of returning early
- Allows auto-import to recover from corrupt/missing metadata
- Prevents auto-import from being permanently disabled
- All tests pass
Amp-Thread-ID: https://ampcode.com/threads/T-4e4a57c4-9ac0-43dc-a78e-b7e88123cc65
Co-authored-by: Amp <amp@ampcode.com>
- Batch fetch all existing issues with SearchIssues() upfront
- Use O(1) map lookup instead of O(n) GetIssue() calls
- Improves performance dramatically with 1000+ issues
- All tests pass
- Add bd restore command to view full history of compacted issues from git
- Command temporarily checks out historical commit, reads JSONL, displays original content
- Read-only operation, no database or git state modification
- Flip ready work sort to created_at ASC (older issues first within priority tier)
- Prevents issue treadmill effect, surfaces old P1s for triage
- Update README.md and AGENTS.md with restore documentation
Closes bd-407, bd-383
- Created autoimport_collision_test.go with 10 new test scenarios
- Added helper functions: createTestDBWithIssues, writeJSONLFile, captureStderr
- Tests cover: multiple collisions, all collisions, exact matches, hash fast path,
parse errors, empty JSONL, new issues only, field conflicts, JSONL not found
- Achieved 75.3% coverage of autoImportIfNewer function
- All 17 auto-import tests passing in ~1 second
- Tests verify collision auto-remapping behavior
Closes bd-401
Amp-Thread-ID: https://ampcode.com/threads/T-d3cbaebd-54e8-425e-8e4a-d41cf5ccd247
Co-authored-by: Amp <amp@ampcode.com>
- Complete test coverage for all major bd commands:
blocked, close, create, dep (add/remove/tree), export, help,
import, init, list, quickstart, ready, show, stats, update, version
- Test data files validate command behavior and output
- Enables automated testing of full CLI workflows
- Implement bd rename-prefix command with --dry-run and --json flags
- Add prefix validation (max 8 chars, lowercase, starts with letter)
- Update all issue IDs and text references atomically per issue
- Update dependencies, labels, events, and counters
- Fix counter merge to use MAX() to prevent ID collisions
- Update snapshot tables for FK integrity
- Add comprehensive tests for validation and rename workflow
- Document in README.md and AGENTS.md
Known limitation: Each issue updates in its own transaction.
A failure mid-way could leave mixed state. Acceptable for
intended use case (infrequent operation on small DBs).
Amp-Thread-ID: https://ampcode.com/threads/T-7e77b779-bd88-44f2-9f0b-a9f2ccd54d38
Co-authored-by: Amp <amp@ampcode.com>
- bd-169: Add -q/--quiet flag to bd init command
- bd-28: Improve error handling in RemoveDependency
- Now checks RowsAffected and returns error if dependency doesn't exist
- New removeDependencyIfExists() helper for collision remapping
- bd-393: CRITICAL - Fix auto-import skipping collisions
- Auto-import was LOSING work from other workers
- Now automatically remaps collisions to new IDs
- Calls RemapCollisions() instead of skipping
All tests pass.
Amp-Thread-ID: https://ampcode.com/threads/T-cba86837-28db-47ce-94eb-67fade82376a
Co-authored-by: Amp <amp@ampcode.com>
- Fix dry-run to not mutate state (no export/clear dirty flags)
- Use os.Executable() for import to avoid path hijacking
- Add preflight checks for merge/rebase in progress
- Add upstream tracking validation with helpful hints
- Use CommandContext for all git operations (enable cancellation)
- Add chmod(0644) to exportToJSONL for consistency with export.go
All critical issues from Oracle review addressed.
- Changed from substring matching to standalone line detection
- Only flags actual Git conflict markers on their own lines
- Prevents false alarms from conflict markers in issue descriptions
- Fixes bd-313
Amp-Thread-ID: https://ampcode.com/threads/T-2acdebf1-e4ce-4534-8538-4e7c4fb84232
Co-authored-by: Amp <amp@ampcode.com>
- Removed restore command from bd show output
- Updated compact help text (removed snapshot claim)
- Fixed COMPACTION.md (removed 'batch restore' from roadmap)
- All compaction UI now correctly states permanent decay
- Add EventCompacted event type constant
- Add compaction fields to Issue struct (CompactionLevel, CompactedAt, OriginalSize)
- Update ApplyCompaction to record compaction events with JSON metadata
- Update bd show to display compaction status with emoji indicators
- Update GetIssue query to load compaction fields
- All tests passing
Amp-Thread-ID: https://ampcode.com/threads/T-3f7946c6-8f5e-4a81-9527-1217041c7b39
Co-authored-by: Amp <amp@ampcode.com>
Snapshots defeated the entire purpose of compaction - if we're keeping
the original content, we're not actually saving any space. Compaction
is about graceful memory decay for agentic databases, not reversible
compression.
Removed:
- CreateSnapshot/GetSnapshots/RestoreFromSnapshot from storage
- --restore flag and functionality from bd compact command
- All snapshot-related tests
- Snapshot struct and related code
The database is ephemeral and meant to decay over time. Compaction
actually reduces database size now.
Closes bd-260 (won't fix - conceptually wrong)
Closes bd-261 (already done in bd-259)
- Add --label/-l flag to filter issues by labels (AND logic)
- Add --title flag to filter issues by title substring
- Add TitleSearch field to IssueFilter type
- Implement label and title filtering in SearchIssues
- Perfect for worktree-specific issue management
Examples:
bd list --label worktree,feature-x
bd list --title "authentication"
bd list --label worktree --title "bug"
Breaks down large functions into smaller, focused helpers to pass gocyclo linter:
Auto-import refactoring:
- Extract parseJSONLIssues() to handle JSONL parsing
- Extract handleCollisions() to detect and report conflicts
- Extract importIssueData() to coordinate issue/dep/label imports
- Extract updateExistingIssue() and createNewIssue() for clarity
- Extract importDependencies() and importLabels() for modularity
Flush refactoring:
- Extract recordFlushFailure() and recordFlushSuccess() for state management
- Extract readExistingJSONL() to isolate file reading logic
- Extract fetchDirtyIssuesFromDB() to separate DB access
- Extract writeIssuesToJSONL() to handle atomic writes
Command improvements:
- Extract executeLabelCommand() to eliminate duplication in label.go
- Extract addLabelsToIssue() helper for label management
- Replace deprecated strings.Title with manual capitalization
Configuration:
- Add gocyclo exception for test files in .golangci.yml
All tests passing, no functionality changes.
* Fix error handling consistency in auto-import and fallback paths
- Add error checking/warnings for auto-import CRUD operations (UpdateIssue, CreateIssue, AddDependency)
- Add error checking/warnings for auto-import label operations (AddLabel, RemoveLabel)
- Add warning when import hash storage fails (prevents unnecessary re-imports)
- Add proper error handling for UserHomeDir with fallback to current directory
These changes make auto-import error handling consistent with manual operations
and prevent silent failures that could confuse users or cause data inconsistencies.
* Remove invalid version property from golangci-lint config
* Fix linter errors: errcheck, unused, goconst, and misspell
- Fix unchecked error returns in ROLLBACK statements
- Fix unchecked type assertion for status field
- Extract LIMIT SQL constant to reduce duplication
- Fix spelling: cancelled -> canceled
- Remove unused ensureCounterInitialized function
- Remove unused parameter in parallel test goroutine
The skipUpdate flag should only apply to existing DB issues, not to
duplicates within the import batch. Batch duplicates always use
last-one-wins semantics.
- Replace CreateIssue loop with single CreateIssues batch call
- Add in-memory de-duplication for duplicate IDs (last one wins)
- 5-15x faster for bulk imports
- All tests pass
- Test add/remove labels
- Test multiple labels and duplicates
- Test label persistence across updates
- Test event creation for label operations
- Test labels with different issue types
- All 10 test cases passing
Enhance Graphviz dot output with status-based fill colors:
- open: white background (default)
- in_progress: light yellow background
- blocked: light coral background
- closed: light gray background with dimmed text
Node labels show: ID, type, priority, title, and status.
Priority is visible in the label (e.g., [bug P0]) but not color-coded
to keep the visualization clean and focused on status.
Add flexible --format flag to 'bd list' command supporting:
- Built-in presets: 'digraph' (basic 'from to' format) and 'dot' (Graphviz)
- Custom Go templates for dependency output
- Template variables: IssueID, DependsOnID, Type, Issue, Dependency
This enables graph analysis with tools like golang.org/x/tools/cmd/digraph while allowing users to customize output format for their specific needs.
Examples:
bd list --format=digraph | digraph nodes
bd list --format=dot | dot -Tsvg -o deps.svg
bd list --format='{{.IssueID}} -> {{.DependsOnID}} [{{.Type}}]'
- 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>
Code review and fixes:
- Increased scanner buffer to 2MB for large JSON lines
- Added line numbers and snippets to parse error messages
- Made non-SQLite fallback conservative (skip import to prevent data loss)
- Improved collision warnings (concise, show first 10 IDs)
- Removed unused autoImportWithoutCollisionDetection function
Status/closed_at invariant enforcement:
- Auto-import now enforces invariant on all creates/updates
- Fixed CreateIssue to respect closed_at field (was ignoring it)
- Closed issues without closed_at get timestamp set automatically
Integration tests:
- TestAutoImportWithCollision: verifies local changes preserved
- TestAutoImportNoCollision: happy path with new issues
- TestAutoImportClosedAtInvariant: enforces invariant
Closes bd-226, bd-230, bd-231
Findings:
- 86/93 closed issues (92%) are missing closed_at timestamps
- All inconsistencies are historical (old issues bd-1 through bd-93)
- No cases of non-closed issues with timestamps
Recommendation: Set closed_at = updated_at for affected issues
Next: Apply cleanup SQL and add constraint