- Reduce flush debounce from 5s to 1s (BEADS_FLUSH_DEBOUNCE)
- Reduce daemon poll interval from 10s to 2s
- Makes issue changes sync much faster to JSONL and git
- Set rpc.ServerVersion from Version in daemon startup
- Set rpc.ClientVersion from Version in main.go startup
- Eliminates need to manually update RPC versions
- Both now use 0.0.0 placeholder, overridden at runtime
Amp-Thread-ID: https://ampcode.com/threads/T-03c37f7f-f41e-4b87-8700-d346c21bad30
Co-authored-by: Amp <amp@ampcode.com>
- Extracted auto-import logic from cmd/bd/main.go to internal/autoimport
- Removed global dependencies (store, dbPath) by using parameters
- Uses callback pattern (ImportFunc) for flexible import implementation
- Both CLI and daemon can now call auto-import after detecting staleness
- Added detailed ID remapping output for collision resolution
- Improved error reporting for parse failures
- All tests passing
Amp-Thread-ID: https://ampcode.com/threads/T-b7faaa33-fc52-409f-82b3-28db143b335d
Co-authored-by: Amp <amp@ampcode.com>
- bd-159: Track last_import_time in metadata after auto-import
- bd-160: Add staleness check to daemon before serving requests
- Detects when JSONL mtime > last import time
- Currently logs warning (needs bd-166 for actual import trigger)
- Add lastImportTime field to RPC Server struct with getter/setter
- Add checkAndAutoImportIfStale() method to detect stale JSONL
This is part of bd-158 epic to fix daemon showing stale data after git pull.
Amp-Thread-ID: https://ampcode.com/threads/T-b554e049-aff8-4a24-8bf3-3305483b7f5a
Co-authored-by: Amp <amp@ampcode.com>
- Add SortPolicy type with hybrid, priority, oldest constants
- Add SortPolicy field to WorkFilter
- Implement buildOrderByClause() for SQL generation
- Add --sort flag to bd ready command
- Add comprehensive tests for all 3 sort policies
- Update RPC protocol to support sort policy
- Update documentation with sort policy examples
Enables autonomous systems like VC to use strict priority ordering
while preserving hybrid behavior for interactive use.
Amp-Thread-ID: https://ampcode.com/threads/T-9d7ea9db-8d6d-4498-9daa-48a7e104ce1f
Co-authored-by: Amp <amp@ampcode.com>
- Use windowsOS constant in reinit_test.go
- Use testIssueBD1 constant in compact_test.go and counter_sync_test.go
- Merged duplicate bd-126 into bd-116
- Added CheckpointWAL method to SQLite storage
- Import now checkpoints WAL after completion
- Updates main .db file modification time for staleness detection
- PRAGMA wal_checkpoint(FULL) flushes WAL to main database
- Changed file permissions from 0644 → 0600 for JSONL exports and config files
- Changed directory permissions from 0755 → 0750 in all test code
- Updated .golangci.yml with proper exclusions for false positives
- Reduced gosec warnings from 102 to 22 (all remaining are acceptable)
Closes bd-57
Amp-Thread-ID: https://ampcode.com/threads/T-f754d957-9e42-4e74-861e-57235c7e6436
Co-authored-by: Amp <amp@ampcode.com>
- Added testUserAlice constant for 'alice' in test files
- Added windowsOS constant for 'windows' in test files
- Added testIssueBD1/testIssueBD2 constants for 'bd-1'/'bd-2' in test files
- Added testVersion100 constant for '1.0.0' in version tests
- Added testIssueCustom1 constant for 'custom-1' in lazy init tests
Closes bd-54
Amp-Thread-ID: https://ampcode.com/threads/T-0a4e5d44-2d95-4948-8f4a-d8facf8657c7
Co-authored-by: Amp <amp@ampcode.com>
- Remove flaky MemoryAllocMB assertion that can be 0 due to GC timing on Linux CI
- Keep goroutine count check for basic validation
- Import latest issues from main with collision resolution
- Merge 13 duplicate issues created from parallel work into canonical versions
- Closes bd-100, bd-115, bd-230 (all same flaky test issue)
Amp-Thread-ID: https://ampcode.com/threads/T-50996f50-4b66-49ca-9db4-e1c3ef4d4bc3
Co-authored-by: Amp <amp@ampcode.com>
Fixed all unchecked error returns in production code:
- os.Remove() calls in cleanup paths
- cmd.Wait() in goroutines
- fmt.Fprintf() writes
- Type assertions with proper ok checks
Reduces linter issues from 99 to 88. CI should now pass linting.
- Write PID to daemon.pid when acquiring lock for Windows compatibility
- Increase socket cleanup timeout to 5s for Windows
- Windows can't read locked files, so PID file is required fallback
- Fix PID detection: Open lock file with O_RDWR for Windows LockFileEx
- Fix script tests: Increase timeout to 2-5s for Windows process startup
- Fix uptime test: Use math.Ceil with minimum 1 second to prevent flakiness
- Fix socket cleanup: Add done channel to wait for Start() cleanup completion
All 5 failing Windows tests should now pass.
- Added OpEpicStatus operation to protocol
- Implemented handleEpicStatus() in RPC server
- Added EpicStatus() method to RPC client
- Updated epic.go to use daemon RPC when available
- Server-side filtering for close-eligible reduces RPC payload
- Both 'bd epic status' and 'bd epic close-eligible' now work in daemon mode
Fixes#62
Closes bd-87
Amp-Thread-ID: https://ampcode.com/threads/T-44c6044e-de04-40a0-bac3-b26238c32a17
Co-authored-by: Amp <amp@ampcode.com>
Fixes#114 and #122 by adding --description/-d flag to bd update CLI
and description parameter to MCP update_issue tool.
Changes:
- CLI: Added --description flag to updateCmd
- RPC: Added Description field to UpdateArgs
- Daemon: Updated updatesFromArgs to handle description
- MCP: Added description to update_issue, UpdateIssueParams, and clients
- Storage: description already supported in allowedUpdateFields
Tested in both daemon and direct modes.
Bug: updateDependencyReferences() was incorrectly updating ALL dependencies
in the database during collision resolution with --resolve-collisions,
including dependencies belonging to existing issues.
Root cause: The function checked if dep.IssueID was in idMapping keys
(old imported IDs like 'bd-1'), but those are also the IDs of existing
database issues. This caused existing dependencies to be incorrectly
modified or deleted.
Fix: Changed logic to only update dependencies where IssueID is in
idMapping VALUES (new remapped IDs like 'bd-295'). This ensures only
dependencies from remapped issues are updated, not existing ones.
During normal import flow, this is effectively a no-op since imported
dependencies haven't been added to the database yet when RemapCollisions
runs (they're added later in Phase 5 of import_shared.go).
Changes:
- Updated updateDependencyReferences() in collision.go to build a set
of new remapped IDs and only update dependencies with those IDs
- Added comprehensive documentation explaining the correct semantics
- Added regression tests: TestRemapCollisionsRemapsImportedNotExisting
and TestRemapCollisionsDoesNotUpdateNonexistentDependencies
- Skipped 3 tests that expected the old buggy behavior with clear
notes about why they need to be rewritten
Real-world impact: In one case, 125 dependencies were incorrectly
deleted from 157 existing issues during collision resolution.
Fixes https://github.com/steveyegge/beads/issues/120
Fixes bd-56
- Change validateBatchIssues() to only set timestamps if IsZero()
- Preserves historical timestamps from external systems (Jira, GitHub)
- Fixes dirty git repo after importing unchanged JSONL
- New issues still get current timestamps as before
- Add daemon.lock to .gitignore
Closes bd-55
Fixes#121
Amp-Thread-ID: https://ampcode.com/threads/T-e53c4a96-38dd-440a-9b8d-824992d33a40
Co-authored-by: Amp <amp@ampcode.com>
- Added comprehensive documentation with 5 safety rules and best practices
- Added atomic.Bool closed field for lifecycle tracking
- Added IsClosed() method to check storage state
- All existing tests pass with -race flag
Amp-Thread-ID: https://ampcode.com/threads/T-e10b5206-4acd-4b9c-915d-423f958e350b
Co-authored-by: Amp <amp@ampcode.com>
Implements database platform layer for extensions like VC to create
their own tables in the same SQLite database.
Changes:
- Add UnderlyingDB() *sql.DB to Storage interface
- Implement in SQLiteStorage to expose underlying connection
- Add comprehensive test suite (5 tests, -race clean)
- Tests cover: basic access, extension tables, concurrency,
lifecycle safety, and transaction behavior
This allows VC to host its executor_instances and other tables
alongside beads core tables with proper FK enforcement.
Related issues: bd-57, bd-64, bd-65, bd-66
Amp-Thread-ID: https://ampcode.com/threads/T-a6715beb-fe92-4dee-b931-3c9327124875
Co-authored-by: Amp <amp@ampcode.com>
The createClosedIssue helper was setting ClosedAt to time.Now(), but the
eligibility check uses '<= datetime(now, -0 days)'. This created a race
condition where if nanoseconds elapsed between issue creation and the
query, the issue would fail eligibility checks.
Changed to now.Add(-1*time.Second) to ensure issues are always eligible
when compact_tier1_days is set to 0 for testing.
Fixes bd-18
Amp-Thread-ID: https://ampcode.com/threads/T-bc303dd9-f0e7-4d52-8908-e433d429ac4a
Co-authored-by: Amp <amp@ampcode.com>
Tests were connecting to test daemon but daemon routed to production DB via
findDatabaseForCwd(). Fixed by ensuring tests use isolated .beads directories
and change working directory to tmpDir.
Changes:
- bench_test.go: Added .beads subdir, chdir, and client.dbPath to setupBenchServer
- bench_test.go: Set dbPath for goroutine clients in BenchmarkConcurrentAgents
- comments_test.go: Refactored to use setupTestServer
- version_test.go: Fixed 4 tests to use setupTestServerIsolated with proper isolation
- rpc_test.go: Added setupTestServerIsolated() helper for custom test setup
Verified: RPC test suite runs with no database pollution (151→151 issues)
Amp-Thread-ID: https://ampcode.com/threads/T-348b7ba8-4292-4ed3-b143-0ad07d226c21
Co-authored-by: Amp <amp@ampcode.com>
Add //go:build bench tag to bench_test.go so benchmarks NEVER run
during normal 'go test'. They've polluted production DB multiple times.
Benchmarks only run with: go test -tags=bench -bench=.
Cleaned up 1013 test pollution issues (Agent X Issue Y, Version tests).
Back to 18 real open issues.
Amp-Thread-ID: https://ampcode.com/threads/T-5ad38d33-28ba-4f47-997a-b0d7e0331c26
Co-authored-by: Amp <amp@ampcode.com>
- Added OpExport/OpImport to RPC protocol
- Implemented handleExport() in daemon to export via RPC
- Modified sync command to use daemon export when available
- Prevents nil pointer dereference when daemon is running
- Falls back to direct mode if daemon unavailable
bd-50: Verified all counter sync fixes already implemented
- Import calls SyncAllCounters() after batch operations
- Delete operations sync counters properly
- Renumber resets and syncs counters correctly
- Daemon cache detects external DB changes via mtime
- Added comprehensive tests: TestCounterSyncAfterImport
bd-51: Cleaned up test pollution from production database
- Deleted bd-52 through bd-58 (manual test issues)
- Root cause was user error, not auto-flush bug
- Auto-flush working as designed
- Go tests properly isolated in temp directories
Amp-Thread-ID: https://ampcode.com/threads/T-9dcbc4bb-76fb-4696-a3f4-4af560da6d6c
Co-authored-by: Amp <amp@ampcode.com>
- Call SyncAllCounters() after DeleteIssue and DeleteIssues
- Change SyncAllCounters to use excluded.last_id (allows counter to decrease)
- Delete orphaned counter rows when no issues remain for a prefix
- Add comprehensive tests in counter_sync_test.go
Fixes the issue where deleting issues left counters at high values, causing
new issues to skip IDs. Now counters accurately reflect the max existing ID.
Closes bd-49
Amp-Thread-ID: https://ampcode.com/threads/T-c3bdb8b9-d67b-4de5-901e-7ea76fc9e399
Co-authored-by: Amp <amp@ampcode.com>
- Created TestDatabaseIsolation in internal/rpc/isolation_test.go
- Single-issue test verifies test DB isolation works correctly
- Prevents repeat of stress test pollution incident
- Test passes cleanly without polluting production database
Closes bd-44
Amp-Thread-ID: https://ampcode.com/threads/T-b3e81b42-2498-45b5-9c8b-beb27f7e9550
Co-authored-by: Amp <amp@ampcode.com>
- Deleted internal/rpc/stress_test.go (was polluting production DB)
- Removed 1002 test issues (Agent X Issue Y, Multi-ID tests)
- Back to 99 real issues from 1101 total
- Closes bd-48
The TestStressNoUniqueConstraintViolations test was creating 1000 test
issues in the project's real database instead of its temp database.
Root cause: The RPC client automatically sets req.Cwd to os.Getwd() when
not explicitly provided. The server's getStorageForRequest() then uses
findDatabaseForCwd() to locate and open the database for that working
directory. Since the test ran from the project directory, it discovered
and used .beads/bd.db instead of the temp database.
Fix: Change working directory to the temp directory before running the
test, so the client's automatic Cwd detection points to the temp .beads/
directory instead of the project's.
Also ensures .beads subdirectory exists in temp dir for proper discovery.
The daemon's handleCreate function was ignoring createArgs.Labels and
createArgs.Dependencies, causing labels and deps specified during issue
creation to be lost when using daemon mode.
Added label and dependency processing after issue creation to match
the direct mode behavior in cmd/bd/main.go.
Fixes: #101
Amp-Thread-ID: https://ampcode.com/threads/T-cc80f8d7-264c-446e-b34f-79c4a7713b77
Co-authored-by: Amp <amp@ampcode.com>
- Add dbMtime field to StorageCacheEntry to track DB file modification time
- Check mtime on cache hits and evict stale entries if DB changed externally
- Close and reopen storage when external modifications detected
- Fixes issue where daemon served stale data after direct DB operations
Amp-Thread-ID: https://ampcode.com/threads/T-631d5cca-0b26-47cb-b633-118b788483cf
Co-authored-by: Amp <amp@ampcode.com>
- Add ExpectedDB field to RPC Request
- Server validates client's expected DB matches daemon's DB
- Return clear error on mismatch with both paths
- Old clients (no ExpectedDB) still work with warning
- Add Path() method to storage.Storage interface
- Tests verify cross-database connections rejected
Prevents database pollution when client connects to wrong daemon.
Amp-Thread-ID: https://ampcode.com/threads/T-c4454192-39c6-4c67-96a9-675cbfc4db92
Co-authored-by: Amp <amp@ampcode.com>
- Remove ~/.beads/bd.sock fallback in getSocketPath()
- Always return local socket path (.beads/bd.sock)
- Add migration warning if old global socket exists
- Update AGENTS.md to remove global daemon references
- Document breaking change in CHANGELOG.md
- Fix test isolation: tests now use temp .beads dir and chdir
Prevents cross-project daemon connections and database pollution.
Each project must use its own local daemon.
Amp-Thread-ID: https://ampcode.com/threads/T-c4454192-39c6-4c67-96a9-675cbfc4db92
Co-authored-by: Amp <amp@ampcode.com>