bd list --tree:
- Use actual parent-child dependencies instead of dotted ID hierarchy
- Treat epic dependencies as parent-child relationships
- Sort children by priority (P0 first)
- Fix tree display in daemon mode with read-only store access
bd graph:
- Add --all flag to show dependency graph of all open issues
- Add --compact flag for tree-style rendering (reduces 44+ lines to 13)
- Fix "needs:N" cognitive noise by using semantic colors
- Add blocks:N indicator with semantic red coloring
bd show:
- Tufte-aligned header with status icon, priority, and type badges
- Add glamour markdown rendering with auto light/dark mode detection
- Cap markdown line width at 100 chars for readability
- Mute entire row for closed dependencies (work done, no attention needed)
Design system:
- Add shared status icons (○ ◐ ● ✓ ❄) with semantic colors
- Implement priority colors: P0 red, P1 orange, P2 muted gold, P3-P4 neutral
- Add TrueColor profile for distinct hex color rendering
- Type badges for epic (purple) and bug (red)
Design principles:
- Semantic colors only for actionable items
- Closed items fade (muted gray)
- Icons > text labels for better scanability
Co-Authored-By: SageOx <ox@sageox.ai>
Problem:
- When dbPath is set to relative fallback (".beads/beads.db"),
findJSONLPath() returns a relative path
- daemon_sync_branch.go calls filepath.Rel(absolutePath, relativePath)
which fails with: "Rel: can't make .beads/issues.jsonl relative to ..."
Solution:
- Canonicalize dbPath at assignment in main.go:471 (source fix)
- Add defensive guard in findJSONLPath() (defense-in-depth)
- Use utils.CanonicalizePath() for OS-agnostic handling
(symlinks, case normalization on macOS)
Testing:
- Add TestFindJSONLPath_RelativeDbPath (tracer bullet for bug)
- Add edge case tests for BEADS_JSONL and empty dbPath
- All sync mode tests pass including daemon E2E
Reviewed by beads/crew/wolf. Fixes daemon mode silently ignoring --due and --defer flags. Adds comprehensive tests including TestDualPathParity for regression prevention.
Adds runBDInProcessAllowError helper and dry-run test coverage.
Interrupted work - committing to preserve progress.
Co-Authored-By: Claude <noreply@anthropic.com>
Implements a new command to resolve git merge conflict markers in JSONL files.
Features:
- Mechanical mode (default): deterministic merge using updated_at timestamps
- Closed status wins over open
- Higher priority (lower number) wins
- Notes are concatenated when different
- Dependencies are unioned
- Dry-run mode to preview changes
- JSON output for agent integration
- Automatic backup creation before changes
The command defaults to resolving .beads/beads.jsonl but accepts any file path.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When an external hook manager config file (like .pre-commit-config.yaml) exists
but the actual hooks are bd shims, doctor now correctly reports OK instead of
warning that the manager doesn't call bd.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The daemon's handleCreate was parsing DueAt but ignoring the DeferUntil
field from CreateArgs. This caused --defer flag to be silently dropped
when using daemon mode.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(sync): implement pull-first synchronization strategy
- Add --pull-first flag and logic to sync command
- Introduce 3-way merge stub for issue synchronization
- Add concurrent edit tests for the pull-first flow
Ensures local changes are reconciled with remote updates before pushing to prevent data loss.
* feat(sync): implement 3-way merge and state tracking
- Implement 3-way merge algorithm for issue synchronization
- Add base state storage to track changes between syncs
- Add comprehensive tests for merge logic and persistence
Ensures data consistency and prevents data loss during concurrent
issue updates.
* feat(sync): implement field-level conflict merging
- Implement field-level merge logic for issue conflicts
- Add unit tests for field-level merge strategies
Reduces manual intervention by automatically resolving overlapping updates at the field level.
* refactor(sync): simplify sync flow by removing ZFC checks
The previous sync implementation relied on Zero-False-Convergence (ZFC)
staleness checks which are redundant following the transition to
structural 3-way merging. This legacy logic added complexity and
maintenance overhead without providing additional safety.
This commit introduces a streamlined sync pipeline:
- Remove ZFC staleness validation from primary sync flow
- Update safety documentation to reflect current merge strategy
- Eliminate deprecated unit tests associated with ZFC logic
These changes reduce codebase complexity while maintaining data
integrity through the robust structural 3-way merge implementation.
* feat(sync): default to pull-first sync workflow
- Set pull-first as the primary synchronization workflow
- Refactor core sync logic for better maintainability
- Update concurrent edit tests to validate 3-way merge logic
Reduces merge conflicts by ensuring local state is current before pushing changes.
* refactor(sync): clean up lint issues in merge code
- Remove unused error return from MergeIssues (never returned error)
- Use _ prefix for unused _base parameter in mergeFieldLevel
- Update callers to not expect error from MergeIssues
- Keep nolint:gosec for trusted internal file path
* test(sync): add mode compatibility and upgrade safety tests
Add tests addressing Steve's PR #918 review concerns:
- TestSyncBranchModeWithPullFirst: Verifies sync-branch config
storage and git branch creation work with pull-first
- TestExternalBeadsDirWithPullFirst: Verifies external BEADS_DIR
detection and pullFromExternalBeadsRepo
- TestUpgradeFromOldSync: Validates upgrade safety when
sync_base.jsonl doesn't exist (first sync after upgrade)
- TestMergeIssuesWithBaseState: Comprehensive 3-way merge cases
- TestLabelUnionMerge: Verifies labels use union (no data loss)
Key upgrade behavior validated:
- base=nil (no sync_base.jsonl) safely handles all cases
- Local-only issues kept (StrategyLocal)
- Remote-only issues kept (StrategyRemote)
- Overlapping issues merged (LWW scalars, union labels)
* fix(sync): report line numbers for malformed JSON
Problem:
- JSON decoding errors when loading sync base state lacked line numbers
- Difficult to identify location of syntax errors in large state files
Solution:
- Include line number reporting in JSON decoder errors during state loading
- Add regression tests for malformed sync base file scenarios
Impact:
- Users receive actionable feedback for corrupted state files
- Faster troubleshooting of manual configuration errors
* fix(sync): warn on large clock skew during sync
Problem:
- Unsynchronized clocks between systems could lead to silent merge errors
- No mechanism existed to alert users of significant timestamp drift
Solution:
- Implement clock skew detection during sync merge
- Log a warning when large timestamp differences are found
- Add comprehensive unit tests for skew reporting
Impact:
- Users are alerted to potential synchronization risks
- Easier debugging of time-related merge issues
* fix(sync): defer state update until remote push succeeds
Problem:
- Base state updated before confirming remote push completion
- Failed pushes resulted in inconsistent local state tracking
Solution:
- Defer base state update until after the remote push succeeds
Impact:
- Ensures local state accurately reflects remote repository status
- Prevents state desynchronization during network or push failures
* fix(sync): prevent concurrent sync operations
Problem:
- Multiple sync processes could run simultaneously
- Overlapping operations risk data corruption and race conditions
Solution:
- Implement file-based locking using gofrs/flock
- Add integration tests to verify locking behavior
Impact:
- Guarantees execution of a single sync process at a time
- Eliminates potential for data inconsistency during sync
* docs: document sync architecture and merge model
- Detail the 3-way merge model logic
- Describe the core synchronization architecture principles
* fix(lint): explicitly ignore lock.Unlock return value
errcheck linter flagged bare defer lock.Unlock() calls. Wrap in
anonymous function with explicit _ assignment to acknowledge
intentional ignore of unlock errors during cleanup.
* fix(lint): add sync_merge.go to G304 exclusions
The loadBaseState and saveBaseState functions use file paths derived
from trusted internal sources (beadsDir parameter from config). Add
to existing G304 exclusion list for safe JSONL file operations.
* feat(sync): integrate sync-branch into pull-first flow
When sync.branch is configured, doPullFirstSync now:
- Calls PullFromSyncBranch before merge
- Calls CommitToSyncBranch after export
This ensures sync-branch mode uses the correct branch for
pull/push operations.
* test(sync): add E2E tests for sync-branch and external BEADS_DIR
Adds comprehensive end-to-end tests:
- TestSyncBranchE2E: verifies pull→merge→commit flow with remote changes
- TestExternalBeadsDirE2E: verifies sync with separate beads repository
- TestExternalBeadsDirDetection: edge cases for repo detection
- TestCommitToExternalBeadsRepo: commit handling
* refactor(sync): remove unused rollbackJSONLFromGit
Function was defined but never called. Pull-first flow saves base
state after successful push, making this safety net unnecessary.
* test(sync): add export-only mode E2E test
Add TestExportOnlySync to cover --no-pull flag which was the only
untested sync mode. This completes full mode coverage:
- Normal (pull-first): sync_test.go, sync_merge_test.go
- Sync-branch: sync_modes_test.go:TestSyncBranchE2E (PR#918)
- External BEADS_DIR: sync_external_test.go (PR#918)
- From-main: sync_branch_priority_test.go
- Local-only: sync_local_only_test.go
- Export-only: sync_modes_test.go:TestExportOnlySync (this commit)
Refs: #911
* docs(sync): add sync modes reference section
Document all 6 sync modes with triggers, flows, and use cases.
Include mode selection decision tree and test coverage matrix.
Co-authored-by: Claude <noreply@anthropic.com>
* test(sync): upgrade sync-branch E2E tests to bare repo
- Replace mocked repository with real bare repo setup
- Implement multi-machine simulation in sync tests
- Refactor test logic to handle distributed states
Coverage: sync-branch end-to-end scenarios
* test(sync): add daemon sync-branch E2E tests
- Implement E2E tests for daemon sync-branch flow
- Add test cases for force-overwrite scenarios
Coverage: daemon sync-branch workflow in cmd/bd
* docs(sync): document sync-branch paths and E2E architecture
- Describe sync-branch CLI and Daemon execution flow
- Document the end-to-end test architecture
* build(nix): update vendorHash for gofrs/flock dependency
New dependency added for file-based sync locking changes the
Go module checksum.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Use flush-only workflow when no git remote is configured
Detects local-only repos (no git remote) and provides appropriate instructions:
- bd sync --flush-only instead of full git workflow
- Clear note about local-only storage
- Prevents confusing git errors for non-git users
Stop existing daemons before binary replacement during install
Prevents file lock race condition by gracefully stopping bd daemons
before replacing the binary. Safe for fresh installs (skips if bd not found).
Fix git hooks failing when daemon is running
Git hooks were calling bd sync without --no-daemon, causing inline import to fail
with 'no database store available' because daemon mode only initializes daemonClient.
Fix: Add --no-daemon to all bd sync calls in git hooks to ensure direct mode.
Add project_id filter for Linear sync
When linear.project_id is configured, bd linear sync will only fetch issues
belonging to that project instead of all team issues.
Closes#937
In contributor mode (bd init --contributor), .beads/ is excluded in
.git/info/exclude to prevent committing upstream issue databases.
However, this exclusion applies to ALL worktrees, including the sync
worktree where .beads/ must be committed.
The fix adds -f flag to git add in commitInWorktree() to force-add
files even when gitignored. This follows the existing pattern in
beads where -f is used for worktree operations (git worktree add -f).
Fixes: bd sync failing with "git add failed in worktree: exit status 1"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Adds --dry-run flag that shows what would be created without actually
creating the issue. Useful for scripting and validation.
- Shows preview in human-readable format by default
- Outputs full issue JSON with --json flag (empty ID, not placeholder string)
- Skips all side effects (hooks, labels, dependencies)
- Works with --rig/--prefix flags (shows target rig)
- Errors gracefully with --file flag (not supported)
- Includes event fields when --type=event
- Add Option 3 to local-install step: build from source with macOS codesigning
- Clarify run-bump-script step: bump-version.sh is the authority for release mechanics
- Document --all flag includes --install --mcp-local --restart-daemons
- Add reference to ./scripts/bump-version.sh --help
When bd gate check encounters a gh:run gate with a non-numeric await_id
(workflow name hint like release.yml), it now auto-discovers the run ID:
- Queries GitHub directly with gh run list --workflow=X
- Takes the most recent run (deterministic: newest-first from API)
- Updates the gates await_id and proceeds with status check
This is ZFC-compliant: most recent run of workflow X is purely mechanical,
no heuristic scoring. Agents no longer need to run bd gate discover manually.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a formula specifies a gate with id="release.yml", the AwaitID
now properly functions as a workflow name hint:
- gate discover: finds gates where AwaitID is empty OR non-numeric
- gate discover: filters matching runs by workflow name when hint present
- gate check: gracefully handles non-numeric AwaitID with clear message
Added isNumericRunID/isNumericID helpers and tests for the new behavior.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Executed-By: beads/crew/dave
Rig: beads
Role: crew
The test for "slightly outdated version" was using 0.35.0, which is now
10 minor versions behind the current 0.45.0. This exceeds the threshold
for "very old" (>=10 minor versions), causing the test to fail.
Updated the test version from 0.35.0 to 0.43.0 to stay within the
"slightly outdated" range (2 minor versions behind).
(bd-iw11)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove Gas Town-specific issue types (agent, role, rig, convoy, slot)
from beads core. These types are now identified by labels instead:
- gt:agent, gt:role, gt:rig, gt:convoy, gt:slot
Changes:
- internal/types/types.go: Remove TypeAgent, TypeRole, TypeRig, TypeConvoy, TypeSlot constants
- cmd/bd/agent.go: Create agents with TypeTask + gt:agent label
- cmd/bd/merge_slot.go: Create slots with TypeTask + gt:slot label
- internal/storage/sqlite/queries.go, transaction.go: Query convoys by gt:convoy label
- internal/rpc/server_issues_epics.go: Check gt:agent label for role_type/rig label auto-add
- cmd/bd/create.go: Check gt:agent label for role_type/rig label auto-add
- internal/ui/styles.go: Remove agent/role/rig type colors
- cmd/bd/export_obsidian.go: Remove agent/role/rig/convoy type tag mappings
- Update all affected tests
This enables beads to be a generic issue tracker while Gas Town
uses labels for its specific type semantics.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Executed-By: beads/crew/dave
Rig: beads
Role: crew
Add types.custom config key mirroring the status.custom pattern:
- Add CustomTypeConfigKey constant and GetCustomTypes() to storage interface
- Add IssueType.IsValidWithCustom() method for validation
- Add ValidateWithCustom() to Issue for combined status/type validation
- Update all validation call sites to use GetCustomTypes()
- Rename parseCustomStatuses to parseCommaSeparated for reuse
This enables Gas Town to register custom types like agent/role/rig/convoy
without hardcoding them in beads core, supporting the type extraction epic.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Executed-By: beads/crew/dave
Rig: beads
Role: crew
PR #904 incorrectly changed Windows from smoke tests to full `go test ./...`
which times out (see bd-bmev). Windows full tests take 20+ minutes vs ~1min
for smoke tests.
Restore the original approach:
- Linux/macOS: full test suite with `go test ./...`
- Windows: smoke tests only (build + basic CRUD commands)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add #nosec G304 comment to parseJSONLFile in rename_prefix.go
- Mark unused noGitHistory param in importFromJSONLInline (mirrors import.go pattern)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The daemon socket tests relied on an external assertion library, which
increased the module's dependency footprint and deviated from Go's
idiomatic testing patterns.
This commit introduces a leaner testing approach using the standard
library:
- Replace testify/assert calls with standard if checks and t.Errorf
- Remove testify and associated indirects from go.mod
These changes preserve existing test behavior while simplifying the
build process and reducing external maintenance overhead.
* fix(doctor): handle 's' status in combined git flags
Problem:
- Git status detection failed when 's' was combined with other flags
- Branch synchronization checks produced incorrect results due to missing flag parsing
Solution:
- Update detection logic to correctly identify the 's' status within combined flag strings
Impact:
- Ensures branch synchronization state is accurately reported during doctor checks
* test(doctor): add unit tests for git flag parsing
- Extract git flag parsing logic into parseGitLsFilesFlag helper
- Add unit tests for git flag parsing logic
Coverage: Git flag parsing in sync_branch.go
The parseJSONLFile function reads user-specified JSONL files
which is safe for this context.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add BD_SOCKET environment variable support to override daemon socket path,
enabling parallel test isolation via t.TempDir() + t.Setenv().
Changes:
- getSocketPath() checks BD_SOCKET first, falls back to dbPath-derived path
- getSocketPathForPID() checks BD_SOCKET first (for consistency)
- Add daemon_socket_test.go with isolation pattern examples
This is a minimal tracer bullet to validate the approach before
expanding to full test isolation infrastructure.
Backward compatible: default behavior unchanged without env var set.
Add intelligent shell completions that query the database to provide
issue ID suggestions with titles for commands that take IDs as arguments.
Changes:
- Add issueIDCompletion function that queries storage for all issues
- Register completion for show, update, close, edit, defer, undefer, reopen
- Add comprehensive test suite with 3 test cases
- Completions display ID with title as description (ID\tTitle format)
The completion function opens the database (read-only) and filters issues
based on the partially typed prefix, providing a better UX for commands
that require issue IDs.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add TypeRig constant to IssueType enum
- Update IsValid() method to include TypeRig
- Add UI color (orange) and style for rig type
- Update CLI flag descriptions in create and update commands
- Add Obsidian export tag for rig type
- Add comprehensive test cases for rig and other newer types
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When running `bd sync --import-only` from a directory with `.beads/redirect`,
the subprocess-based import could fail to update staleness metadata correctly
because the subprocess might resolve paths differently than the parent process.
The fix uses inline import (calling importIssuesCore directly) instead of
spawning a subprocess. This ensures:
1. The same store and dbPath are used throughout
2. Path resolution is consistent with the parent process
3. Staleness metadata is updated correctly in the redirected database
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Problem:
- Sync branch setup occurred before the config file was initialized
- Persistence only targeted the database, leading to loss on re-init
Solution:
- Reorder initialization to create the config file before sync setup
- Synchronize sync branch state to both config file and database
Impact:
- Settings are preserved across re-initialization and DB clears
- Better consistency between file and database state
Fixes: #927 (Bug 3)
- Add daemon_autostart.go, doctor/fix/sync_branch.go to G304 exclusions
- Add setup.go to G306 exclusions (config files need 0644)
- Add gate.go, gate_discover.go to G204 exclusions (gh/gt CLI calls)
- Add misspell exclusion for "cancelled" in gate.go (matches GitHub API)
- Increase Windows test timeout to 30m (was timing out at 20m)
These exclusions complement the #nosec annotations already in the code.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Extract inode function to platform-specific files (inode_unix.go,
inode_windows.go) to fix syscall.Stat_t compile error on Windows
- Add skipOnWindows helper and skip Unix permission/symlink tests
on Windows where chmod semantics differ
- Increase Windows test timeout from 10m to 20m since full test
suite runs slower without race detector
Fixes Windows CI failures introduced when PR #904 expanded Windows
testing from smoke tests to full test suite.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>