The daemon is SQLite-specific (handles JSONL sync to git). Dolt has its
own sync mechanism via sql-server and doesn't need the daemon.
Previously, Dolt server mode returned SingleProcessOnly=false (because
multiple bd processes CAN connect to the same SQL server), which
incorrectly triggered daemon auto-start. The daemon would then fail
with 'DAEMON NOT SUPPORTED WITH DOLT BACKEND' warning on every command.
Now we check isDoltBackend() directly instead of relying on the
SingleProcessOnly capability, which has different semantics.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Executed-By: mayor
Role: mayor
The Dolt stats subdatabase at .dolt/stats/.dolt/noms/LOCK was causing
"cannot update manifest: database is read only" errors after crashes.
Changes:
- cleanupStaleDoltLock now also cleans stats and oldgen subdatabase LOCKs
- Add dolt_stats_stop() call to fully stop stats background worker
- Set dolt_stats_auto_refresh_interval=0 to prevent stats restart
Fixes bd-dolt.1
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Executed-By: mayor
Role: mayor
Add stale_closed_issues_days config option to metadata.json:
- 0 (default): Check disabled - repos keep unlimited beads
- >0: Enable check with specified day threshold
Design philosophy: Time-based cleanup is a crude proxy for the real
concern (database size). Disabled by default since a repo with 100
closed issues from 5 years ago doesn't need cleanup.
Also adds a warning when check is disabled but database has >10,000
closed issues, recommending users enable the threshold.
Co-Authored-By: SageOx <ox@sageox.ai>
Executed-By: beads/crew/emma
Rig: beads
Role: crew
Port the adaptive ID length algorithm from SQLite to Dolt backend.
The ID length now scales from 3-8 characters based on database size
using birthday paradox collision probability calculations.
- Add adaptive_length.go with length computation based on issue count
- Update generateIssueID to use adaptive length with nonce fallback
- Add collision detection and retry logic matching SQLite behavior
Fixes bd-c40999
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Executed-By: mayor
Role: mayor
- Add sync state files to .gitignore (.sync.lock, sync_base.jsonl)
- Add types.custom to config.yaml for Gas Town type fallback
- Remove metadata.json from .gitignore (it should be tracked)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Executed-By: mayor
Role: mayor
Previously `make install` used `go install` which put the binary in ~/go/bin
without codesigning, while PATH used ~/.local/bin - causing chronic stale
binary issues. Now install depends on build (which codesigns on macOS) and
copies to the correct location.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Executed-By: mayor
Role: mayor
Shim hooks (bd-shim marker) delegate to 'bd hook' command which already
handles Dolt backend correctly. Update both doctor check and migration
warning to recognize shim hooks as OK.
Only inline hooks (older style with embedded logic) need the explicit
Dolt backend check in the shell script.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Two improvements for Dolt backend users with stale git hooks:
1. Migration warning: When running 'bd migrate --to-dolt', warn if
installed hooks lack the Dolt backend check and suggest reinstalling.
2. Doctor check: New CheckGitHooksDoltCompatibility() detects when
hooks exist but lack the Dolt skip logic, surfacing the error with
a clear fix message.
Both changes help users who migrated to Dolt but have pre-migration
hooks that try to run JSONL sync (which fails with Dolt backend).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Pre-commit and post-merge git hooks were unconditionally running
bd sync/import for JSONL sync, which fails with Dolt backend.
Now both hooks check metadata.json for backend type and exit early
if Dolt is configured. Dolt uses its own sync mechanism.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The guardDaemonStartForDolt check was only applied to the 'bd daemon start'
subcommand, but the deprecated 'bd daemon --start' flag path bypassed it.
This adds the same guard check to the deprecated path so both entry points
consistently refuse to start the daemon when Dolt backend is configured.
The --federation flag still allows Dolt since it enables dolt sql-server
mode which supports multi-writer access.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
SQLite-era instruction causing agents to run deprecated bd sync.
With Dolt backend, there is no sync - database is live.
Part of hq-e4eefc (Dolt migration epic)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add complete documentation for Dolt backend covering:
- Migration from SQLite to Dolt
- Contributor onboarding (bootstrap on clone)
- Troubleshooting common issues
- Recovery procedures
- Server mode setup and management
- Git hooks integration
- Configuration reference
Also improve server mode error handling to suggest gt dolt start
when connection is refused.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When the Dolt database connection is temporarily unavailable (e.g.,
stale connection, server restart), GetCustomTypes() and GetCustomStatuses()
now fall back to reading from config.yaml instead of failing.
This matches the SQLite storage behavior and fixes the stop hook
failure where `gt costs record` would fail with "invalid issue type: event"
when the Dolt connection was broken.
The fallback is checked in two cases:
1. When database query returns an error
2. When database has no custom types/statuses configured
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Daemon now refuses to start when dolt backend is configured
(dolt uses sql-server mode, not the SQLite daemon)
- Add same-directory check in GetRoutedStorageWithOpener to avoid
opening duplicate connections when routing resolves to current dir
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add two new filter flags to the export command:
- --id: Filter by specific issue IDs (comma-separated)
- --parent: Filter by parent issue ID (shows children)
Also fix safety checks (empty DB, staleness) to skip when filters
are active, since filtered exports intentionally produce subsets.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add extensive test coverage for the Dolt storage implementation:
- dependencies_extended_test.go: Extended dependency operation tests
- dolt_benchmark_test.go: Performance benchmarks for Dolt operations
- history_test.go: Version history query tests
- labels_test.go: Label operation tests
These tests validate Dolt backend correctness and provide performance
baselines for comparison with SQLite.
Co-authored-by: upstream_syncer <matthew.baker@pihealth.ai>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Refactors UpdateIssue, CloseIssue, CreateTombstone, and DeleteIssues
to use the withTx helper with BEGIN IMMEDIATE instead of BeginTx.
This completes the GH#1272 fix by ensuring all write transactions
acquire write locks early, preventing deadlocks.
Changes:
- UpdateIssue: now uses withTx and markDirty helper
- CloseIssue: now uses withTx and markDirty helper
- CreateTombstone: now uses withTx and markDirty helper
- DeleteIssues: now uses withTx with dbExecutor interface
- Helper functions (resolveDeleteSet, expandWithDependents,
validateNoDependents, etc.) changed from *sql.Tx to dbExecutor
This is a P3 follow-up to the P1 sqlite lock fix (PR #1274).
Closes: bd-fgzp
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
When no steps are in_progress, bd mol current now checks for molecules
bonded to hooked issues via blocks dependencies. This fixes the case
where a molecule is attached to an agent's hook but no steps have been
claimed yet.
The fix adds findHookedMolecules() as a fallback after findInProgressMolecules()
returns empty. It queries for hooked issues assigned to the agent and checks
for blocks dependencies pointing to molecules (epics or template-labeled issues).
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat(update): add --append-notes flag (bd-b5qu)
Add --append-notes flag that appends to existing notes with a newline
separator instead of overwriting. This prevents data loss in workflows
where multiple steps need to add info to notes (e.g., tackle workflows).
- Errors if both --notes and --append-notes specified
- Handles both daemon and direct mode paths
- Combines existing notes + newline + new content
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* test(update): add tests for --append-notes flag
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat: update to use core tap for beads installation
Signed-off-by: Rui Chen <rui@chenrui.dev>
* remove custom tap related code and refs
Signed-off-by: Rui Chen <rui@chenrui.dev>
---------
Signed-off-by: Rui Chen <rui@chenrui.dev>
The daemon server's handleList was returning dependency counts but not
the actual dependency records. This complements PR #1296 which fixed
the direct CLI path.
Code paths now fixed:
- Direct (--no-daemon): cmd/bd/list.go (PR #1296)
- Daemon (default): internal/rpc/server_issues_epics.go (this PR)
Fixes bd-d240
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix(gate): use GateWait RPC for add-waiter command
bd gate add-waiter was calling Update RPC which rejects waiters
field (not in allowedUpdateFields). Changed to use existing GateWait
RPC that handles waiters correctly.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(storage): allow waiters field in UpdateIssue
Add waiters to allowedUpdateFields whitelist and handle JSON
serialization for the array field. This enables bd gate add-waiter
to work in direct mode (--no-daemon).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(storage/dolt): allow waiters field in UpdateIssue
Mirror the SQLite fix: add waiters to allowed fields and handle JSON
serialization for the array field.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix(daemon): skip export when sync-branch matches current
Prevent redundant export operations by checking if the daemon's sync
branch matches the current active branch.
Previously, the daemon would attempt to perform an export even when
already on the target branch. This logic now skips the export step in
such cases to avoid unnecessary overhead and potential conflicts.
Includes a new integration test to verify the guard logic.
* fix(daemon): prevent sync on guarded branches
Add checks to verify if a branch is guarded before performing automated
sync cycles, auto-imports, or branch-specific commit and pull operations.
This prevents the daemon from modifying protected branches or running
synchronization tasks where they are restricted.
Includes comprehensive integration tests to verify the guard logic
during sync-branch operations.
* fix(daemon): warn on sync branch misconfiguration at startup
The daemon now checks for sync branch name conflicts during its startup
loop. This provides early feedback if the sync branch is configured
in a way that might conflict with existing branches or other settings.
The warnIfSyncBranchMisconfigured function performs the validation
and logs a warning to the console. Integration tests verify that
the daemon correctly identifies and reports these misconfigurations
at initialization.
* fix(sync): read sync.mode from yaml first, then database
bd config set sync.mode writes to config.yaml (because sync.* is a
yaml-only prefix), but GetSyncMode() only read from the database.
This caused dolt-native mode to be ignored - JSONL export still
happened because the database had no sync.mode value.
Now GetSyncMode() checks config.yaml first (via config.GetSyncMode()),
falling back to database for backward compatibility.
Fixes: oss-5ca279
* fix(init): respect BEADS_DIR environment variable
Problem:
- `bd init` ignored BEADS_DIR when checking for existing data
- `bd init` created database at CWD/.beads instead of BEADS_DIR
- Contributor wizard used ~/.beads-planning as default, ignoring BEADS_DIR
Solution:
- Add BEADS_DIR check in checkExistingBeadsData() (matches FindBeadsDir pattern)
- Compute beadsDirForInit early, before initDBPath determination
- Use BEADS_DIR as default in contributor wizard when set
- Preserve precedence: --db > BEADS_DB > BEADS_DIR > default
Impact:
- Users with BEADS_DIR set now get consistent behavior across all bd commands
- ACF-style fork tracking (external .beads directory) now works correctly
Fixes: steveyegge/beads#???
* fix(doctor): respect BEADS_DIR environment variable
Also updates documentation to reflect BEADS_DIR support in init and doctor.
Changes:
- doctor.go: Check BEADS_DIR before falling back to CWD
- doctor_test.go: Add tests for BEADS_DIR path resolution
- WORKTREES.md: Document simplified BEADS_DIR+init workflow
- CONTRIBUTOR_NAMESPACE_ISOLATION.md: Note init/doctor BEADS_DIR support
* test(init): add BEADS_DB > BEADS_DIR precedence test
Verifies that BEADS_DB env var takes precedence over BEADS_DIR
when both are set, ensuring the documented precedence order:
--db > BEADS_DB > BEADS_DIR > default
* chore: fill in GH#1277 placeholder in sync_mode comment
Child issues created with --parent were missing from export_hashes table,
which affects integrity tracking and future incremental export features.
This fix ensures SetExportHash() is called for all exported issues:
- Updated ExportResult to include IssueContentHashes map
- Updated finalizeExport() to call SetExportHash() for each exported issue
- Updated exportToJSONLDeferred() to collect content hashes during export
- Updated performIncrementalExport() to collect content hashes for dirty issues
- Updated exportToJSONLWithStore() to call SetExportHash() after export
- Updated daemon's handleExport() to call SetExportHash() after export
Added test TestExportPopulatesExportHashes to verify the fix works for
both regular and hierarchical (child) issue IDs.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
The handleRename function was being called with the raw storage.Storage
interface inside upsertIssuesTx, which runs within a transaction. When
handleRename called store.DeleteIssue() or store.CreateIssue(), these
methods attempted to start new transactions via withTx/BEGIN IMMEDIATE,
causing a deadlock since SQLite cannot nest BEGIN IMMEDIATE transactions.
This fix:
- Adds handleRenameTx that accepts storage.Transaction and uses tx methods
- Updates the call site in upsertIssuesTx to use handleRenameTx(ctx, tx, ...)
The non-transactional upsertIssues continues to use handleRename for
backends that don't support transactions.
Fixes nested transaction deadlock during bd sync when issue renames occur.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Make beads the DEFAULT for ALL task tracking
- Advise avoiding TodoWrite, TaskCreate, and markdown files for task tracking
- Add workflow guidance: create beads issue BEFORE writing code, mark in_progress when starting
Previously, `bd show` displayed all dependencies under "DEPENDS ON"
regardless of their type. This was confusing because parent-child
relationships (used for molecule/step hierarchy) appeared as if they
were blocking dependencies.
This fix:
- Groups dependencies by type in both daemon and non-daemon modes
- Shows parent-child deps under "PARENT" heading
- Shows blocking deps under "DEPENDS ON" heading
- Shows related deps under "RELATED" heading
- Shows discovered-from deps under "DISCOVERED FROM" heading
The fix applies the same filtering pattern already used for Dependents
(which correctly grouped CHILDREN, BLOCKS, RELATED, DISCOVERED) to the
Dependencies section.
Fixes: bd-69d7
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Previously, `bd list --json` only included dependency_count and
dependent_count but not the actual dependency records. This broke
callers like `gt hook --json` that need to know what each issue
depends on to determine ready steps.
Now populates issue.Dependencies using GetAllDependencyRecords,
matching the behavior of `bd show --json`.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- FindDatabasePath now handles Dolt server mode (no local dir required)
- main.go uses NewFromConfigWithOptions for Dolt to read server settings
- Routing uses factory via callback to respect backend configuration
- Handle Dolt "database exists" error (error 1007) gracefully
Previously, Dolt server mode failed because:
1. FindDatabasePath required a local directory to exist
2. main.go bypassed server mode config when creating Dolt storage
3. Routing always opened SQLite regardless of backend config
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add dolt_mode, dolt_server_host, dolt_server_port fields to configfile.Config
- Add IsDoltServerMode(), GetDoltServerHost(), GetDoltServerPort() helpers
- Update factory to read server mode config and set Options accordingly
- Skip bootstrap in server mode (database lives on server)
- Pass Database name to dolt.Config for USE statement after connecting
- Disable dolt stats collection to avoid lock issues in embedded mode
This enables bd to connect to a running dolt sql-server (started via
'gt dolt start') instead of using embedded mode, allowing multi-client
access without file locking conflicts.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Skip Bootstrap when ServerMode is true (bootstrap is for embedded cold-start)
- Fix doltExists() to follow symlinks using os.Stat
- Pass database name from metadata.json to DoltStore config
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When an issue ID starts with dashes (e.g., gt--kzx), it can be
misinterpreted by Cobra's argument parser. The new --id flag allows
these IDs to be passed safely:
bd show --id=gt--xyz
Multiple --id flags can be used, and they can be combined with
positional arguments.
Closes: bd-ix0ak
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use ui.RenderPassIcon, ui.RenderWarnIcon, ui.RenderFailIcon, etc. for
consistent styling with the rest of the doctor command output.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use parameterized query for INFORMATION_SCHEMA lookup (SQL injection)
- Add isValidIdentifier() to validate database names before USE statement
- Add password support via BEADS_DOLT_PASSWORD env var
- Remove unused variable declaration
- Add unit tests for identifier validation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds bd doctor --server to diagnose Dolt server mode connections:
- Server reachability (TCP connect to host:port)
- Dolt version check (verifies it is Dolt, not vanilla MySQL)
- Database exists and is accessible
- Schema compatible (can query beads tables)
- Connection pool health metrics
Supports --json for machine-readable output.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Code review fix: In server mode, Dolt connects to an external sql-server
and should NOT be single-process-only. The whole point of server mode is
to enable multi-writer access.
Changes:
- Add Config.GetCapabilities() method that considers server mode
- Update daemon_guard, daemon_autostart, daemons, main to use GetCapabilities()
- Add TestGetCapabilities test
- Update init command help text to document server mode flags
The existing CapabilitiesForBackend(string) is kept for backward compatibility
but now includes a note to use Config.GetCapabilities() when the full config
is available.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Dolt server mode configuration to metadata.json for multi-writer access:
- Add DoltMode, DoltServerHost, DoltServerPort, DoltServerUser fields to Config
- Add helper methods with sensible defaults (127.0.0.1:3306, root user)
- Update factory to read server mode config and pass to dolt.Config
- Add --server, --server-host, --server-port, --server-user flags to bd init
- Validate that --server requires --backend dolt
- Add comprehensive tests for server mode configuration
Example metadata.json for server mode:
{
"backend": "dolt",
"database": "dolt",
"dolt_mode": "server",
"dolt_server_host": "192.168.1.100",
"dolt_server_port": 3306,
"dolt_server_user": "beads"
}
Password should be set via BEADS_DOLT_PASSWORD env var for security.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds Dolt auto-commit functionality for write commands and sets explicit commit authors.
Includes fix for race condition in commandDidWrite (converted to atomic.Bool).
Original PR: #1267 by @coffeegoddd
Co-authored-by: Dustin Brown <dustin@dolthub.com>
The original PR added retry logic on top of BEGIN IMMEDIATE, but this caused
multi-minute hangs because:
1. Connection has busy_timeout=30s set via pragma
2. Each BEGIN IMMEDIATE waits up to 30s before returning SQLITE_BUSY
3. With 5 retries, worst case was 5 × 30s = 150+ seconds
The fix removes the retry loop since SQLite's busy_timeout already handles
retries internally. BEGIN IMMEDIATE still acquires the write lock early,
preventing deadlocks - we just let busy_timeout handle contention.
Root cause analysis in bd-9ldm.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update withTx to use BEGIN IMMEDIATE with exponential backoff retry
on SQLITE_BUSY errors. This prevents "database is locked" failures
during concurrent operations (daemon + CLI, multi-agent workflows).
Changes:
- withTx now uses beginImmediateWithRetry (same pattern as RunInTransaction)
- Add dbExecutor interface for helper functions that work with both
*sql.Tx and *sql.Conn
- Update all withTx callers to use *sql.Conn
- Refactor DeleteIssue to use withTx (fixes the specific error in auto-import)
- Update markIssuesDirtyTx to accept dbExecutor interface
Affected paths:
- MarkIssuesDirty, ClearDirtyIssuesByID (dirty.go)
- AddDependency, RemoveDependency (dependencies.go)
- executeLabelOperation (labels.go)
- AddComment (events.go)
- ApplyCompaction (compact.go)
- DeleteIssue (queries.go)
Note: Some direct BeginTx calls in queries.go (CloseIssue, UpdateIssue,
ReopenIssue, DeleteIssues) still use the old pattern and could be
refactored in a follow-up.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>