The test was failing on Windows CI because of insufficient time resolution
between creating an issue and adding a comment. Both operations could
complete within the same time unit, causing identical timestamps.
Added a 2ms sleep between operations to ensure updated_at is strictly
after the original timestamp, even on systems with lower time resolution.
Fixes: bd-pi7u
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixes daemon and bd sync to honor BEADS_SYNC_BRANCH environment variable
as documented in PROTECTED_BRANCHES.md for CI/CD temporary overrides.
Changes:
- Updated internal/syncbranch.Get() to prioritize env var over DB config
- Both daemon sync and bd sync CLI now use syncbranch.Get()
- Added comprehensive tests for env var override behavior
- Validates branch names using git-style rules
This enables CI/CD workflows to override sync branch per-job without
mutating database config.
Based on PR #364 by Charles P. Cross <cpdata@users.noreply.github.com>
Co-authored-by: Charles P. Cross <cpdata@users.noreply.github.com>
The canonical beads database name is issues.jsonl. Tens of thousands of users
have issues.jsonl, and beads.jsonl was only used by the Beads project itself
due to git history pollution.
Changes:
- Updated bd doctor to warn about beads.jsonl instead of issues.jsonl
- Changed default config from beads.jsonl to issues.jsonl
- Reversed precedence in checkGitForIssues to prefer issues.jsonl
- Updated git merge driver config to use issues.jsonl
- Updated all tests to expect issues.jsonl as the default
issues.jsonl is now the canonical default; beads.jsonl is legacy
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Updates test and documentation to reflect the intentional change from
issues.jsonl to beads.jsonl (commit 7b865eb from Nov 20, 2025).
Fixes GH #356🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements bd-au0.2, completing all P0 tasks in the command standardization epic.
Changes:
- Add --add-label, --remove-label, --set-labels flags to bd update
- Support multiple labels via repeatable flags
- Implement in both daemon and direct modes
- Add comprehensive tests for all label operations
The bd update command now supports:
bd update <id> --add-label <label> # Add one or more labels
bd update <id> --remove-label <label> # Remove one or more labels
bd update <id> --set-labels <labels> # Replace all labels
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements a new 'bd count' command that provides efficient issue counting
with filtering and grouping capabilities.
Features:
- Basic count: Returns total count of issues matching filters
- All filtering options from 'bd list' (status, priority, type, assignee, labels, dates, etc.)
- Grouping via --by-* flags: status, priority, type, assignee, label
- JSON output support for both simple and grouped counts
- Both daemon and direct mode support
Implementation:
- Added OpCount operation and CountArgs to RPC protocol
- Added Count() method to RPC client
- Implemented handleCount() server-side handler with optimized bulk label fetching
- Created cmd/bd/count.go with full CLI implementation
Performance optimization:
- Pre-fetches all labels in a single query when using --by-label to avoid N+1 queries
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixes a bug where FindAllDatabases() would return the same database
multiple times when symlinks were present in the directory hierarchy.
The issue occurred because the function walked up the directory tree
without resolving symlinks or checking if a database had already been
discovered. This led to confusing warnings about "multiple databases"
even when only one physical database existed.
Changes:
- Added symlink resolution using filepath.EvalSymlinks()
- Implemented deduplication using a seen map with canonical paths
- Added comprehensive tests for symlink scenarios
This ensures that each unique database is reported exactly once,
regardless of how many symlinks point to it in the directory tree.
Resolves duplicate database warnings when symlinks are present.
Updated all test files to pass context.Background() as the first parameter
to sqlite.New() calls to match the updated function signature.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Multiple test files were still using the old sqlite.New(path) signature
instead of the new sqlite.New(ctx, path) signature. This was causing
compilation failures in the test suite.
Fixed files:
- internal/importer/importer_test.go
- internal/importer/external_ref_test.go
- internal/importer/timestamp_test.go
- internal/rpc/limits_test.go
- internal/rpc/list_filters_test.go
- internal/rpc/rpc_test.go
- internal/rpc/status_test.go
- internal/syncbranch/syncbranch_test.go
Identified and tagged obviously-slow integration tests with
`//go:build integration` to exclude them from default test runs.
This is step 1 of fixing test performance. The real fix is in
bd-1rh: refactoring tests to use shared DB setup instead of
creating 279 separate databases.
Tagged files:
- cmd/bd: 8 files (CLI tests, git ops, performance benchmarks)
- internal: 8 files (integration tests, E2E tests)
Issues:
- bd-1rh: Main issue tracking test performance
- bd-c49: Audit all tests and create grouping plan (next step)
- bd-y6d: POC refactor of create_test.go
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit addresses critical code review findings from bd-dvd and bd-ymj fixes:
## Completed Tasks
### bd-ar2.1: Extract duplicated metadata update code
- Created `updateExportMetadata()` helper function
- Eliminated 22-line duplication between createExportFunc and createSyncFunc
- Single source of truth for metadata updates
### bd-ar2.2: Add multi-repo support to export metadata updates
- Added per-repo metadata key tracking with keySuffix parameter
- Both export and sync functions now update metadata for all repos
### bd-ar2.3: Fix tests to use actual daemon functions
- TestExportUpdatesMetadata now calls updateExportMetadata() directly
- Added TestUpdateExportMetadataMultiRepo() for multi-repo testing
- Fixed export_mtime_test.go tests to call updateExportMetadata()
### bd-ar2.9: Fix variable shadowing in GetNextChildID
- Changed `err` to `resurrectErr` to avoid shadowing
- Improves code clarity and passes linter checks
### bd-ar2.10: Fix hasJSONLChanged to support per-repo keys
- Updated hasJSONLChanged() to accept keySuffix parameter
- Reads metadata with correct per-repo keys
- All callers updated (validatePreExport, daemon import, sync command)
### bd-ar2.11: Use stable repo identifiers instead of paths
- Added getRepoKeyForPath() helper function
- Uses stable identifiers like ".", "../frontend" instead of absolute paths
- Metadata keys now portable across machines and clones
- Prevents orphaned metadata when repos are moved
## Files Changed
- cmd/bd/daemon_sync.go: Helper functions, metadata updates
- cmd/bd/integrity.go: hasJSONLChanged() with keySuffix support
- cmd/bd/sync.go: Updated to use getRepoKeyForPath()
- cmd/bd/*_test.go: Tests updated for new signatures
- internal/storage/sqlite/hash_ids.go: Fixed variable shadowing
## Testing
All export, sync, and integrity tests pass.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Bug 1 (bd-dvd): GetNextChildID now attempts parent resurrection from JSONL
before failing. Added TryResurrectParent call to match CreateIssue behavior.
Bug 2 (bd-ymj): Export now updates last_import_hash metadata to prevent
'JSONL content has changed' errors on subsequent exports.
Files changed:
- internal/storage/sqlite/hash_ids.go: Add resurrection attempt
- cmd/bd/daemon_sync.go: Add metadata updates after export
- Tests added for both fixes
- Fixed pre-existing bug in integrity_content_test.go
Follow-up work tracked in epic bd-ar2 (9 issues for improvements).
Fixes GH #334
Complete implementation of signal-aware context propagation for graceful
cancellation across all commands and storage operations.
Key changes:
1. Signal-aware contexts (bd-rtp):
- Added rootCtx/rootCancel in main.go using signal.NotifyContext()
- Set up in PersistentPreRun, cancelled in PersistentPostRun
- Daemon uses same pattern in runDaemonLoop()
- Handles SIGINT/SIGTERM for graceful shutdown
2. Context propagation (bd-yb8):
- All commands now use rootCtx instead of context.Background()
- sqlite.New() receives context for cancellable operations
- Database operations respect context cancellation
- Storage layer propagates context through all queries
3. Cancellation tests (bd-2o2):
- Added import_cancellation_test.go with comprehensive tests
- Added export cancellation test in export_test.go
- Tests verify database integrity after cancellation
- All cancellation tests passing
Fixes applied during review:
- Fixed rootCtx lifecycle (removed premature defer from PersistentPreRun)
- Fixed test context contamination (reset rootCtx in test cleanup)
- Fixed export tests missing context setup
Impact:
- Pressing Ctrl+C during import/export now cancels gracefully
- No database corruption or hanging transactions
- Clean shutdown of all operations
Tested:
- go build ./cmd/bd ✓
- go test ./cmd/bd -run TestImportCancellation ✓
- go test ./cmd/bd -run TestExportCommand ✓
- Manual Ctrl+C testing verified
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Extracted repeated priority and ID validation patterns from CLI commands
into reusable functions in internal/validation/bead.go.
Changes:
- Added ValidatePriority(): Combines parsing and error handling
- Added ValidateIDFormat(): Validates ID format and extracts prefix
- Added ValidatePrefix(): Validates prefix matching with database config
- Updated create.go and show.go to use new validation functions
- Simplified force flag logic to always call ValidatePrefix()
- Added comprehensive tests for all validation functions
- Added TODO comment for daemon mode validation enhancement
Results:
- Reduced code duplication by ~20 lines
- Centralized validation logic for easier maintenance
- Consistent error messages across all commands
- All tests passing
Fixes bd-g5p7
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Problem:
In direct mode, bd list was making a separate GetLabels() call for
each issue when displaying labels. With 538 issues, this resulted in
538 separate database queries.
While investigating the reported 5+ second slowness, discovered this
N+1 query issue that would impact performance with many issues.
Solution:
1. Added GetLabelsForIssues(issueIDs []string) to Storage interface
2. Implemented bulk fetch in SQLite (already existed, now exposed)
3. Implemented bulk fetch in MemoryStorage
4. Updated list.go to fetch all labels in single query
Changes:
- internal/storage/storage.go: Add GetLabelsForIssues to interface
- internal/storage/memory/memory.go: Implement GetLabelsForIssues
- cmd/bd/list.go: Use bulk fetching in all output modes
Impact:
Eliminates N queries for labels, replacing with 1 bulk query.
This optimization applies to direct mode only (daemon mode already
uses bulk operations via RPC).
Note: The reported 5s slowness was actually caused by daemon auto-start
timeout. Use --no-daemon flag or run 'bd migrate --update-repo-id' to
resolve the legacy database issue causing daemon startup failures.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Ensures cache stays synchronized with dependency and status changes
by calling invalidateBlockedCache() at all mutation points (bd-5qim).
Cache invalidation points:
- AddDependency: when type is 'blocks' or 'parent-child'
- RemoveDependency: when removed dep was 'blocks' or 'parent-child'
- UpdateIssue: when status field changes
- CloseIssue: always (closed issues don't block)
The invalidation strategy is full cache rebuild on any change,
which is fast enough (<1ms for 10K issues) and keeps the logic simple.
Only 'blocks' and 'parent-child' dependency types affect blocking,
so 'relates-to' and other types skip invalidation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replaces expensive recursive CTE query with simple cache lookup,
achieving 96% performance improvement on 10K databases (bd-5qim).
Performance results:
- Before: ~752ms (recursive CTE on every call)
- After: ~29ms (cache lookup + filters)
- Target: <50ms ✓
The query now uses a simple NOT EXISTS check against the
blocked_issues_cache table instead of computing the full
blocked issue tree on every call.
Cache is maintained by invalidateBlockedCache() called on
dependency and status changes (added in next commit).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Introduces a materialized cache table to store blocked issue IDs,
replacing the expensive recursive CTE computation that was causing
~752ms query times on 10K databases (bd-5qim).
The cache is maintained via invalidation on dependency and status
changes, reducing GetReadyWork from O(n²) recursive traversal to
O(1) cache lookup.
Technical details:
- New blocked_issues_cache table with single issue_id column
- ON DELETE CASCADE ensures automatic cleanup
- Migration populates cache using existing recursive CTE logic
- rebuildBlockedCache() fully rebuilds cache on invalidation
- execer interface allows both *sql.DB and *sql.Tx usage
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Created internal/storage/sqlite/errors.go with:
- Sentinel errors: ErrNotFound, ErrInvalidID, ErrConflict, ErrCycle
- wrapDBError helpers that auto-convert sql.ErrNoRows to ErrNotFound
- Type-safe error checking with errors.Is() compatibility
Updated error handling across storage layer:
- dirty.go: Added context to error returns, converted sql.ErrNoRows checks
- util.go: Updated withTx to use wrapDBError
- batch_ops.go: Added context wrapping to batch operations
- dependencies.go: Wrapped errors from markIssuesDirtyTx calls
- ids.go: Added error wrapping for ID validation
Also restored sqlite.go that was accidentally deleted in previous commit.
All tests pass. Provides consistent error wrapping with operation context
for better debugging.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Created internal/validation package for centralized validation logic
- Created cmd/bd/flags.go for shared flag registration
- Updated create and update commands to use shared logic
- Added support for 'P1' style priority to update command
- Added tests for validation logic
Amp-Thread-ID: https://ampcode.com/threads/T-c8d369a3-32f0-42a0-96d1-fd589e89bd6b
Co-authored-by: Amp <amp@ampcode.com>
* fix: address critical resource leaks and error handling issues
Fixes 5 critical and high-priority issues identified in codebase analysis:
1. bd-vavh: Fix row iterator resource leak in recursive dependency queries
- Move defer rows.Close() to execute on all code paths
- Previously leaked connections on scan errors
- Location: internal/storage/sqlite/sqlite.go:1121-1145
2. bd-qhws: Configure database connection pool limits for daemon mode
- Set MaxOpenConns to runtime.NumCPU() + 1 for file-based databases
- Prevents connection exhaustion under concurrent RPC load
- Only affects daemon mode (long-running server)
- Location: internal/storage/sqlite/sqlite.go:108-125
3. bd-jo38: Add WaitGroup tracking to FileWatcher goroutines
- Track goroutines with sync.WaitGroup for graceful shutdown
- Wait for goroutines to finish before cleanup in Close()
- Prevents race condition on debouncer access during shutdown
- Location: cmd/bd/daemon_watcher.go (Start, startPolling, Close)
4. bd-2d5r: Fix silent error handling in RPC response writing
- writeResponse now returns errors instead of ignoring them
- Prevents sending partial JSON and client hangs
- Closes connection on marshal/write errors
- Location: internal/rpc/server_lifecycle_conn.go:227-246
5. bd-zqmb: Fix goroutine leak in daemon restart
- Add 10-second timeout to daemon Wait() goroutine
- Kill process if it doesn't fork within timeout
- Prevents goroutine accumulation on restart failures
- Location: cmd/bd/daemons.go:250-268
All changes follow Go best practices and maintain backward compatibility.
* Add feature request for .beads/README.md generation during init
Created bd-m7ge to automatically generate a promotional/documentation
README in the .beads directory when running 'bd init'. This will help
advertise Beads in open source repositories and provide quick reference
documentation for developers using AI coding agents.
The README will include:
- Brief explanation of Beads (AI-native issue tracking)
- Link to steveyegge/beads repository
- Quick reference of essential commands
- Compelling messaging to encourage adoption
- Add fast path for exact ID matches in ResolvePartialID
- Properly unmarshal ResolveID RPC responses used by `bd show`
Summary:
--------
Fixes regression introduced after v0.23.1 where `bd show <issue_id>`,
`bd update <issue_id>`, and `bd close <issue_id>` commands failed with
"operation failed: issue not found" errors even when the issue existed
in the database.
Root Cause:
-----------
The daemon's ResolveID RPC handler (handleResolveID in
internal/rpc/server_issues_epics.go) returns a JSON-encoded string
containing the resolved issue ID. For example, when resolving "ao-izl",
the RPC response contains the JSON string: "ao-izl" (with quotes).
After v0.23.1, the show/update/close commands in cmd/bd/show.go were
changed to use string(resp.Data) to extract the resolved ID, which
treats the raw bytes as a string without decoding the JSON. This caused
the resolved ID to literally be "ao-izl" (including the quotes),
which then failed to match the actual issue ID ao-izl (without quotes)
when passed to subsequent Show/Update/Close RPC calls.
In v0.23.1 (commit 77dcf55), the code correctly unmarshaled the JSON:
var resolvedID string
if err := json.Unmarshal(resp.Data, &resolvedID); err != nil {
// handle error
}
This unmarshal step was removed in later commits, causing the regression.
Fix:
----
Restored the JSON unmarshaling step in three places in cmd/bd/show.go:
1. showCmd - line 37-42
2. updateCmd - line 400-405
3. closeCmd - line 723-728
Each now properly decodes the JSON string response before using the
resolved ID in subsequent RPC calls.
Testing:
--------
- Verified `bd show <issue-id-with-prefix>` works correctly in both daemon and direct modes
- Tested with newly created issues to ensure the fix works for all IDs
- All Go tests pass (go test ./... -short)
- Confirmed behavior matches v0.23.1 working binary
The fix ensures that issue ID resolution works correctly regardless of
whether the ID prefix matches the configured issue_prefix.
The ID disambiguation logic treated 'offlinebrew-3d0' as ambiguous when
child IDs like 'offlinebrew-3d0.1' existed. Now the system:
1. Checks for exact full ID matches first (issue.ID == input)
2. Checks for exact hash matches (handling cross-prefix scenarios)
3. Only falls back to substring matching if no exact match is found
Added test cases verifying:
- 'offlinebrew-3d0' matches exactly, not ambiguously with children
- '3d0' without prefix still resolves to exact match
Amp-Thread-ID: https://ampcode.com/threads/T-5358ea57-e9ea-49e9-aedf-7044ebf8b52a
Co-authored-by: Amp <amp@ampcode.com>
When using 'bd create --parent <id>', the system now automatically
creates a parent-child dependency linking the child to the parent.
This fixes epic status reporting which was showing zero children.
Fixes#318 (bd-jijf)
Changes:
- cmd/bd/create.go: Add parent-child dependency after issue creation
- internal/rpc/server_issues_epics.go: Add same fix for daemon mode
Tested:
- Created epic with children, verified epic status shows correct count
- Verified closing all children makes epic eligible for closure
- All tests pass
Amp-Thread-ID: https://ampcode.com/threads/T-f1a1aee1-03bd-4e62-a63c-c1d339f8300b
Co-authored-by: Amp <amp@ampcode.com>
* feat: add performance testing framework foundation
Implements foundation for comprehensive performance testing and user
diagnostics for beads databases at 10K-20K scale.
Components added:
- Fixture generator (internal/testutil/fixtures/) for realistic test data
* LargeSQLite/XLargeSQLite: 10K/20K issues with epic hierarchies
* LargeFromJSONL/XLargeFromJSONL: test JSONL import path
* Realistic cross-linked dependencies, labels, assignees
* Reproducible with seeded RNG
- User diagnostics (bd doctor --perf) for field performance data
* Collects platform info (OS, arch, Go/SQLite versions)
* Measures key operation timings (ready, list, show, search)
* Generates CPU profiles for bug reports
* Clean separation in cmd/bd/doctor/perf.go
Test data characteristics:
- 10% epics, 30% features, 60% tasks
- 4-level hierarchies (Epic → Feature → Task → Subtask)
- 20% cross-epic blocking dependencies
- Realistic status/priority/label distributions
Supports bd-l954 (Performance Testing Framework epic)
Closes bd-6ed8, bd-q59i
* perf: optimize GetReadyWork with compound index (20x speedup)
Add compound index on dependencies(depends_on_id, type, issue_id) to
eliminate performance bottleneck in GetReadyWork recursive CTE query.
Performance improvements (10K issue database):
- GetReadyWork: 752ms → 36.6ms (20.5x faster)
- Target: <50ms ✓ ACHIEVED
- 20K database: ~1500ms → 79.4ms (19x faster)
Benchmark infrastructure enhancements:
- Add dataset caching in /tmp/beads-bench-cache/ to avoid regenerating
10K-20K issues on every benchmark run (first run: ~2min, subsequent: <5s)
- Add progress logging during fixture generation (shows 10%, 20%... completion)
- Add database size logging (17.5 MB for 10K, 35.1 MB for 20K)
- Document rationale for only benchmarking large datasets (>10K issues)
- Add CPU/trace profiling with --profile flag for performance debugging
Schema changes:
- internal/storage/sqlite/schema.go: Add idx_dependencies_depends_on_type_issue
New files:
- internal/storage/sqlite/bench_helpers_test.go: Reusable benchmark setup with caching
- internal/storage/sqlite/sqlite_bench_test.go: Comprehensive benchmarks for critical operations
- Makefile: Convenient benchmark execution (make bench-quick, make bench)
Related:
- Resolves bd-5qim (optimize GetReadyWork performance)
- Builds on bd-6ed8 (fixture generator), bd-q59i (bd doctor --perf)
* perf: add WASM compilation cache to eliminate cold-start overhead
Configure wazero compilation cache for ncruces/go-sqlite3 to avoid
~220ms JIT compilation on every process start.
Cache configuration:
- Location: ~/.cache/beads/wasm/ (platform-specific via os.UserCacheDir)
- Automatic version management: wazero keys entries by its version
- Fallback: in-memory cache if directory creation fails
- No cleanup needed: old versions are harmless (~5-10MB each)
Performance impact:
- First run: ~220ms (populate cache)
- Subsequent runs: ~20ms (load from cache)
- Savings: ~200ms per cold start
Cache invalidation:
- Automatic when wazero version changes (upgrades use new cache dir)
- Manual cleanup: rm -rf ~/.cache/beads/wasm/ (safe to delete anytime)
This complements daemon mode:
- Daemon mode: eliminates startup cost by keeping process alive
- WASM cache: reduces startup cost for one-off commands or daemon restarts
Changes:
- internal/storage/sqlite/sqlite.go: Add init() with cache setup
* refactor: improve maintainability of performance testing code
Extract common patterns and eliminate duplication across benchmarks, fixture generation, and performance diagnostics. Replace magic numbers with explicit configuration to improve readability and make it easier to tune test parameters.
* docs: clarify profiling behavior and add missing documentation
Add explanatory comments for profiling setup to clarify why --profile
forces direct mode (captures actual database operations instead of RPC
overhead) and document the stopCPUProfile function's role in flushing
profile data to disk. Also fix gosec G104 linter warning by explicitly
ignoring Close() error during cleanup.
* fix: prevent bench-quick from running indefinitely
Added //go:build bench tags and skipped timeout-prone benchmarks to
prevent make bench-quick from running for hours.
Changes:
- Add //go:build bench tag to cycle_bench_test.go and compact_bench_test.go
- Skip Dense graph benchmarks (documented to timeout >120s)
- Fix compact benchmark prefix: bd- → bd (validation expects prefix without trailing dash)
Before: make bench-quick ran for 3.5+ hours (12,699s) before manual interrupt
After: make bench-quick completes in ~25 seconds
The Dense graph benchmarks are known to timeout and represent rare edge
cases that don't need optimization for typical workflows.
- Force single connection for all in-memory databases (including file::memory:)
- Close rows before executing statements in external_ref migration
- Prevents connection pool deadlock with MaxOpenConns(1)
- Fixes test failures in syncbranch_test.go
Add external_ref field to CreateArgs and UpdateArgs RPC protocol
structs to enable linking issues to external systems (GitHub, Jira,
Shortcut, etc.) when using daemon mode.
Changes:
- Add ExternalRef field to rpc.CreateArgs and rpc.UpdateArgs
- Update bd create/update commands to pass external_ref via RPC
- Update daemon handlers to process external_ref field
- Add integration tests for create and update operations
The --external-ref flag now works correctly in both daemon and direct modes.
Fixes https://github.com/steveyegge/beads/issues/303
Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Happy <yesreply@happy.engineering>
The schema initialization was trying to create an index on the external_ref
column before the migration that adds the column runs. This caused 'no such
column: external_ref' errors when opening very old databases (pre-0.17.5).
Solution: Move the index creation into the migration that adds the column.
Fixes#284
Amp-Thread-ID: https://ampcode.com/threads/T-2744d5a7-168f-4ef6-bcab-926db846de20
Co-authored-by: Amp <amp@ampcode.com>