Commit Graph

935 Commits

Author SHA1 Message Date
ruby
5605e590a3 fix(sqlite): prevent FK constraint failure on batch create (GH#956)
Add checkForExistingIDs check to transaction-based batch creation
(sqliteTxStorage.CreateIssues) before calling insertIssues. This
prevents INSERT OR IGNORE from silently skipping duplicate IDs,
which would cause FK constraint failures when recording events
for issues that weren't actually inserted.

Also fixes unrelated test bug: renamed parseCommaSeparated to
parseCommaSeparatedList in validators_test.go.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 22:02:03 -08:00
garnet
1ff8932468 test(rpc): add blocker check tests for close operation (GH#962)
Add two tests to verify that issue blocking/dependencies are enforced
when closing issues via the RPC handler:

- TestHandleClose_BlockerCheck: Verifies closing a blocked issue fails
  when blocker is still open, and --force flag overrides the check
- TestHandleClose_BlockerCheck_ClosedBlocker: Verifies close succeeds
  once the blocking issue is closed

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 22:01:02 -08:00
beads/refinery
50a079d3b7 fix: repair test build failures in types and sqlite packages
- Add TypeRig constant to IssueType enum
- Add IsBuiltIn() method to IssueType for multi-repo hydration trust logic
- Fix parseCommaSeparated -> parseCommaSeparatedList function name in test

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 22:00:32 -08:00
beads/crew/dave
a803da36e1 feat: add 'attests' edge type for skill attestations
Add new DependencyType 'attests' for skill attestations. Enables:
Entity X attests that Entity Y has skill Z at level N.

- Add DepAttests constant to dependency types
- Add AttestsMeta struct for skill, level, date, evidence, notes
- Update IsWellKnown() to include attests
- Add test cases for the new edge type

Foundation for HOP skill portability.

Closes: bd-2papc

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Executed-By: beads/crew/dave
Rig: beads
Role: crew
2026-01-10 19:33:47 -08:00
beads/crew/dave
ceb5769c75 feat: add owner field for human attribution in HOP CV chains
Add 'owner' field to Issue struct for tracking the human responsible
for the issue, distinct from 'created_by' which tracks the executor.
Owner is populated from git author email (GIT_AUTHOR_EMAIL or git
config user.email), per Decision 008 for CV accumulation.

Changes:
- Add Owner field to types.Issue with omitempty JSON tag
- Include Owner in content hash computation
- Add owner column migration (036_owner_column.go)
- Update all SQL queries to include owner field
- Add getOwner() helper using git author email fallback chain
- Populate owner in bd create command
- Add owner to RPC CreateArgs protocol

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Executed-By: beads/crew/dave
Rig: beads
Role: crew
2026-01-10 19:28:08 -08:00
Erick Matsen
3f2b693bea fix: respect hierarchy.max-depth config setting (GH#995) (#997)
* fix: respect hierarchy.max-depth config setting (GH#995)

The hierarchy.max-depth config setting was being ignored because storage
implementations had the depth limit hardcoded to 3. This fix:

- Registers hierarchy.max-depth default (3) in config initialization
- Adds hierarchy.max-depth to yaml-only keys for config.yaml storage
- Updates SQLite and Memory storage to read max depth from config
- Adds validation to reject hierarchy.max-depth values < 1
- Adds tests for configurable hierarchy depth

Users can now set deeper hierarchies:
  bd config set hierarchy.max-depth 10

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: extract shared CheckHierarchyDepth function (GH#995)

- Extract duplicated depth-checking logic to types.CheckHierarchyDepth()
- Update sqlite and memory storage backends to use shared function
- Add t.Cleanup() for proper test isolation in sqlite test
- Add equivalent test coverage for memory storage backend
- Add comprehensive unit tests for CheckHierarchyDepth function

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 13:36:52 -08:00
dave
69dae103db fix: add timeout to daemon request context to prevent indefinite hangs
reqCtx() now applies the server's requestTimeout (default 30s) to the
context returned for request handlers. This prevents bd list and other
commands from hanging indefinitely when database operations stall.

The fix ensures:
- All RPC handlers get a context with a deadline
- Database operations (using QueryContext) honor context cancellation
- reconnectMu read locks are released when context times out

Fixes: bd-p76kv

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Executed-By: beads/crew/dave
Rig: beads
Role: crew
2026-01-10 13:35:30 -08:00
giles
b844a3b656 fix: Windows infinite loop in findLocalBeadsDir and findOriginalBeadsDir (GH#996)
Same fix as PR #991 for FindBeadsDir() - the loop condition
dir != "/" && dir != "." doesn't handle Windows drive roots.
On Windows, filepath.Dir("C:\\") returns "C:\\", not "/" or ".".

Changed both functions to check parent == dir to detect filesystem root,
which works correctly on both Unix and Windows.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 13:34:53 -08:00
wolf
3ecffa111b fix: relocate daemon socket for deep paths (GH#1001)
On Unix systems, socket paths are limited to 104 chars (macOS) or 108 chars
(Linux). Deep workspace paths like /Volumes/External Drive/Dropbox/...
would exceed this limit and cause daemon startup failures.

This fix:
- Adds ShortSocketPath() which computes /tmp/beads-{hash}/bd.sock for
  paths that would exceed the limit
- Keeps backward compatibility: short paths still use .beads/bd.sock
- Updates daemon discovery to check both locations
- Uses SHA256 hash of canonical workspace path for unique directories

Closes GH#1001

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 12:30:31 -08:00
wolf
7c83187bdd fix: use SearchIssues for ID resolution (GH#942)
Use SearchIssues with filter.IDs instead of GetIssue in ResolvePartialID.
This fixes inconsistencies where bd list could find issues that bd show
could not, due to subtle query differences between the two code paths.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 00:37:29 -08:00
fang
ecde3f2fd1 fix(windows): daemon stop/kill now uses proper Windows API (GH#992)
On Windows, the daemon stop command was failing with "exit status 1" because
`taskkill` without `/F` flag does not work for console processes that do not
have windows to receive close messages.

Changes:
- Use `os.Process.Kill()` which calls Windows `TerminateProcess` API
- This is the reliable way to terminate processes on Windows
- The graceful RPC shutdown is already attempted before falling back to kill
- Updated error messages to be platform-agnostic (removed SIGTERM/SIGKILL)

The fix uses Go cross-platform process APIs instead of shelling out to
external commands, which is more reliable and portable.

Closes #992

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 23:04:55 -08:00
beads/crew/dave
ee34003f02 fix: SQLite uses DELETE mode on WSL2 Windows filesystem (GH#920)
Auto-detect WSL2 environment with Windows filesystem paths (/mnt/c/, etc.)
and fall back to DELETE journal mode instead of WAL. SQLite WAL mode
does not work reliably across the WSL2/Windows 9P filesystem boundary
due to shared-memory limitations.

Detection checks:
1. Path matches /mnt/[a-z]/ pattern (Windows drive mount)
2. /proc/version contains microsoft or wsl

Fixes #920

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Executed-By: beads/crew/dave
Rig: beads
Role: crew
2026-01-09 23:03:03 -08:00
grip
351f4c1dd7 fix(sync): initialize store after daemon disconnect (GH#984)
The sync command was closing the daemon connection without initializing
the direct store, leaving store=nil. This caused errors in post-checkout
hook when running bd sync --import-only.

Fixed by using fallbackToDirectMode() which properly closes daemon and
initializes the store.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 22:59:15 -08:00
wolf
0777bb907c fix: prevent FK constraint errors on concurrent issue creation (GH#956)
Root cause: CreateIssue used INSERT OR IGNORE which could silently skip
the insert (e.g., on duplicate ID from hash collision), then fail with
FOREIGN KEY constraint error when trying to record the creation event.

Fix: Add insertIssueStrict() that uses plain INSERT (fails on duplicates)
and use it for CreateIssue in both queries.go and transaction.go. The
existing insertIssue() with INSERT OR IGNORE is preserved for import
scenarios where duplicates are expected.

Added test TestCreateIssueDuplicateID to verify duplicate IDs are properly
rejected instead of silently ignored.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 22:59:06 -08:00
fang
a851104203 fix: prevent closing issues with open blockers (GH#962)
Added IsBlocked method to Storage interface that checks if an issue is
in the blocked_issues_cache and returns the blocking issue IDs.

The close command now checks for blockers before allowing an issue to
be closed:
- If an issue has open blockers, closing is blocked with an error message
- The --force flag overrides this check
- Works in both daemon mode (RPC) and direct storage mode
- Also handles cross-rig routed IDs

This addresses the bug where agents could close a bead even when it
depends on an open bug/issue.

Closes #962

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 22:57:07 -08:00
beads/crew/giles
4009fc6709 fix: restore Gas Town types (agent, role, rig, convoy, slot) (GH#941)
v0.46.0 removed these types breaking gt install/doctor/sling/convoy commands.
This restores them as built-in types so `bd create --type=agent` works again.

Fixes GH#941

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 22:26:50 -08:00
Jamie
336eaa74e3 fix: bd init hangs on Windows when not in a git repository (#991)
Traversing up to C:\ creates infinite loop.
2026-01-09 21:17:06 -08:00
Steve Yegge
a7a686e9f1 Merge pull request #967 from rsnodgrass/bd-improvements
Visual UX improvements for list, graph, and show commands. Adds design system documentation.
2026-01-09 18:42:43 -08:00
beads/crew/emma
576a517c59 feat(multirepo): trust non-built-in types during hydration (bd-9ji4z)
Implements federation trust model for multi-repo type validation:
- Built-in types are validated (catch typos)
- Non-built-in types trusted from source repos

Changes:
- Add IssueType.IsBuiltIn() method
- Add Issue.ValidateForImport() for trust-based validation
- Update upsertIssueInTx to use ValidateForImport

Closes: bd-dqwuf, bd-alpw2 | Epic: bd-9ji4z

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 14:12:48 -08:00
shendsaliaga
c988c76b08 Fix migrate sync failing in git worktree environments (#970)
Two issues caused `bd migrate sync` to fail when run from a git worktree:

1. Used GetGitDir() instead of GetGitCommonDir() for worktree path
   - GetGitDir() returns the worktree-specific path (.bare/worktrees/main)
   - GetGitCommonDir() returns the shared git dir (.bare) where new
     worktrees can actually be created

2. Used strings.Index instead of LastIndex in GetRepoRoot()
   - When user paths contain "worktrees" (e.g., ~/Development/worktrees/),
     Index finds the first occurrence and incorrectly strips the path
   - LastIndex finds git's internal /worktrees/ directory

Added GetGitCommonDir() to internal/git/gitdir.go for reuse.

Fixes GH#639 (remaining unfixed callsite in migrate_sync.go)
2026-01-09 11:01:56 -08:00
beads/crew/dave
2ee0995f51 feat(rpc): add AllowStale option to List API (bd-dpkdm)
Add AllowStale field to ListArgs struct to support resilient hook detection.
When set, callers signal they accept potentially stale data rather than
failing on staleness check errors.

This enables gastown checkSlungWork() to fall back gracefully when the
beads database is out of sync with JSONL (common after concurrent agent syncs).

- Add AllowStale bool to ListArgs in internal/rpc/protocol.go
- Pass --allow-stale flag through to RPC in cmd/bd/list.go

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Executed-By: beads/crew/dave
Rig: beads
Role: crew
2026-01-09 00:42:13 -08:00
Ryan Snodgrass
cfd1f39e1e feat(ux): visual improvements for list tree, graph, and show commands
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>
2026-01-08 20:50:56 -08:00
Peter Chanthamynavong
4486e0e7bd fix(rpc): add --due and --defer handling to daemon mode (GH#952) (#953)
Reviewed by beads/crew/wolf. Fixes daemon mode silently ignoring --due and --defer flags. Adds comprehensive tests including TestDualPathParity for regression prevention.
2026-01-08 14:36:47 -08:00
Peter Chanthamynavong
65214b7693 fix(rpc): return JSON data for dep add/remove in daemon mode (#961)
* test(rpc): add failing tests for dep add/remove JSON output (GH#952)

- Add TestDepAdd_JSONOutput: verify Response.Data contains JSON
- Add TestDepRemove_JSONOutput: verify Response.Data contains JSON

Tests prove bug exists: handlers return Response{Success: true}
without populating Data field.

* fix(rpc): return JSON data for dep add/remove in daemon mode (GH#952)

Problem:
- bd dep add/remove --json returned empty output in daemon mode
- handleDepAdd() and handleSimpleStoreOp() didn't populate Response.Data

Solution:
- handleDepAdd: add Data field with JSON result
- handleSimpleStoreOp: add optional responseData callback parameter
- handleDepRemove: provide response data callback
- Label handlers: pass nil (maintain current behavior)
2026-01-08 14:36:07 -08:00
emma
370b946360 fix(create): parse DeferUntil in daemon handleCreate (GH#950)
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>
2026-01-07 21:31:40 -08:00
Andrey Taranov
e0b613d5b1 fix(sync): validate custom types in batch issue creation (#943)
Fix validation in batch issue creation to check custom types

Previously only validated custom statuses, causing sync to fail when JSONL
contained issues with types removed from core (agent, role, rig, convoy, slot).

Fixes: validation failed for issue: invalid issue type: agent
2026-01-07 20:45:58 -08:00
Paddo
5254ade346 feat(linear): add project_id filter for sync (#938)
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
2026-01-07 20:45:00 -08:00
Andrey Taranov
1a64654c48 fix(sync): force-add .beads in worktree for contributor mode (#947)
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>
2026-01-07 17:40:09 -08:00
dave
a70c3a8cbe feat: extract Gas Town types from beads core (bd-i54l)
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
2026-01-06 22:18:37 -08:00
beads/crew/dave
b7358f17bf feat(types): add custom type support to beads config (bd-649s)
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
2026-01-06 21:30:58 -08:00
beads/crew/dave
5dfb838d60 feat(completion): optimize ID prefix filtering and add completions to more commands
Improvements to shell completions from PR #935:

1. Add IDPrefix field to IssueFilter for efficient database-level filtering
   - Queries are now filtered at SQL level instead of fetching all issues
   - Updated sqlite, transaction, and memory stores to support IDPrefix

2. Add ValidArgsFunction to additional commands:
   - dep (add, remove, list, tree)
   - comments, comment (add)
   - delete
   - graph
   - label (add, remove, list)
   - duplicate, supersede
   - audit
   - move
   - relate, unrelate
   - refile
   - gate (show, resolve, add-waiter)

🤖 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
2026-01-06 19:05:34 -08:00
furiosa
bf378650f4 feat(types): add rig identity bead type (gt-zmznh)
- 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>
2026-01-06 18:55:45 -08:00
beads/crew/giles
2fb6fd074a fix(ci): address Windows test failures and timeout
- 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>
2026-01-06 12:59:26 -08:00
Ryan
ffe0dca2a3 feat(daemon): unify auto-sync config for simpler agent workflows (#904)
* feat(daemon): unify auto-sync config for simpler agent workflows

## Problem

Agents running `bd sync` at session end caused delays in the Claude Code
"event loop", slowing development. The daemon was already auto-exporting
DB→JSONL instantly, but auto-commit and auto-push weren't enabled by
default when sync-branch was configured - requiring manual `bd sync`.

Additionally, having three separate config options (auto-commit, auto-push,
auto-pull) was confusing and could get out of sync.

## Solution

Simplify to two intuitive sync modes:

1. **Read/Write Mode** (`daemon.auto-sync: true` or `BEADS_AUTO_SYNC=true`)
   - Enables auto-commit + auto-push + auto-pull
   - Full bidirectional sync - eliminates need for manual `bd sync`
   - Default when sync-branch is configured

2. **Read-Only Mode** (`daemon.auto-pull: true` or `BEADS_AUTO_PULL=true`)
   - Only receives updates from team
   - Does NOT auto-publish changes
   - Useful for experimental work or manual review before sharing

## Benefits

- **Faster agent workflows**: No more `bd sync` delays at session end
- **Simpler config**: Two modes instead of three separate toggles
- **Backward compatible**: Legacy auto_commit/auto_push settings still work
  (treated as auto-sync=true)
- **Adaptive `bd prime`**: Session close protocol adapts when daemon is
  auto-syncing (shows simplified 4-step git workflow, no `bd sync`)
- **Doctor warnings**: `bd doctor` warns about deprecated legacy config

## Changes

- cmd/bd/daemon.go: Add loadDaemonAutoSettings() with unified config logic
- cmd/bd/doctor.go: Add CheckLegacyDaemonConfig call
- cmd/bd/doctor/daemon.go: Add CheckDaemonAutoSync, CheckLegacyDaemonConfig
- cmd/bd/init_team.go: Use daemon.auto-sync in team wizard
- cmd/bd/prime.go: Detect daemon auto-sync, adapt session close protocol
- cmd/bd/prime_test.go: Add stubIsDaemonAutoSyncing for testing

* docs: add comprehensive daemon technical analysis

Add daemon-summary.md documenting the beads daemon architecture,
memory analysis (explaining the 30-35MB footprint), platform support
comparison, historical problems and fixes, and architectural guidance
for other projects implementing similar daemon patterns.

Key sections:
- Architecture deep dive with component diagrams
- Memory breakdown (SQLite WASM runtime is the main contributor)
- Platform support matrix (macOS/Linux full, Windows partial)
- Historical bugs and their fixes with reusable patterns
- Analysis of daemon usefulness without database (verdict: low value)
- Expert-reviewed improvement proposals (3 recommended, 3 skipped)
- Technical design patterns for other implementations

* feat: add cross-platform CI matrix and dual-mode test framework

Cross-Platform CI:
- Add Windows, macOS, Linux matrix to catch platform-specific bugs
- Linux: full tests with race detector and coverage
- macOS: full tests with race detector
- Windows: full tests without race detector (performance)
- Catches bugs like GH#880 (macOS path casing) and GH#387 (Windows daemon)

Dual-Mode Test Framework (cmd/bd/dual_mode_test.go):
- Runs tests in both direct mode and daemon mode
- Prevents recurring bug pattern (GH#719, GH#751, bd-fu83)
- Provides DualModeTestEnv with helper methods for common operations
- Includes 5 example tests demonstrating the pattern

Documentation:
- Add dual-mode testing section to CONTRIBUTING.md
- Document RunDualModeTest API and available helpers

Test Fixes:
- Fix sync_local_only_test.go gitPull/gitPush calls
- Add gate_no_daemon_test.go for beads-70c4 investigation

* fix(test): isolate TestFindBeadsDir tests with BEADS_DIR env var

The tests were finding the real project's .beads directory instead of
the temp directory because FindBeadsDir() walks up the directory tree.
Using BEADS_DIR env var provides proper test isolation.

* fix(test): stop daemon before running test suite guard

The test suite guard checks that tests don't modify the real repo's .beads
directory. However, a background daemon running auto-sync would touch
issues.jsonl during test execution, causing false positives.

Changes:
- Set BEADS_NO_DAEMON=1 to prevent daemon auto-start from tests
- Stop any running daemon for the repo before taking the "before" snapshot
- Uses exec to call `bd daemon --stop` to avoid import cycle issues

* chore: revert .beads/issues.jsonl to upstream/main

Per CONTRIBUTING.md, .beads/issues.jsonl should not be modified in PRs.
2026-01-06 12:52:19 -08:00
beads/crew/fang
7b0f398f11 fix(lint): address gosec, misspell, and unparam warnings
- gate.go: fix "cancelled" → "canceled" misspelling, add #nosec for
  validated GitHub IDs in exec.Command, mark checkTimer escalated as
  intentionally false, rename unused ctx param
- sync_divergence.go: add #nosec for git commands with validated paths,
  mark unused path param
- sync_branch.go: add #nosec for .git/info/exclude permissions
- setup.go: add #nosec for config file permissions
- recipes.go: add #nosec for validated config file paths
- external_deps.go: add #nosec for SQL with generated placeholders

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 22:06:52 -08:00
Peter Chanthamynavong
e7d543af55 fix(sync): persist sync branch to yaml and database (GH#909) (#910)
Problem:
- Sync branch configuration was not consistently saved across storage types
- State divergence between database and config.yaml files

Solution:
- Update Set to write configuration to both yaml and database backends
- Add regression test for yaml configuration persistence

Impact:
- Guarantees configuration consistency across system reboots
- Prevents sync settings from being lost when reading from yaml
2026-01-05 19:11:55 -08:00
emma
9b84ef73dd fix(sync): atomic export and force-push detection (bd-3bhl, bd-4hh5)
bd-3bhl: Add sync rollback on git commit failure
- Use exportToJSONLDeferred() instead of exportToJSONL() for atomic sync
- Call finalizeExport() only after git commit succeeds
- Rollback JSONL from git HEAD on commit failure
- Add rollbackJSONLFromGit() helper function
- Coverage: regular commit, sync branch, external beads repo paths

bd-4hh5: Fix false-positive force-push detection
- Use explicit refspec in CheckForcePush fetch
- +refs/heads/beads-sync:refs/remotes/origin/beads-sync
- Ensures tracking ref is always created/updated
- Fixes stale ref comparison causing false positives

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 23:14:11 -08:00
dave
6730fce9b1 feat(setup): refactor to recipe-based architecture (bd-i3ed)
Replace tool-specific setup commands with a generic recipe-based system.
New tools become config entries, not code changes.

Changes:
- Add internal/recipes/ package with Recipe type and built-in recipes
- Add --list flag to show available recipes
- Add --print flag to output template to stdout
- Add -o flag to write template to arbitrary path
- Add --add flag to save custom recipes to .beads/recipes.toml
- Add built-in recipes: windsurf, cody, kilocode (new)
- Legacy recipes (cursor, claude, gemini, aider, factory) continue to work

The recipe system enables:
- Adding new tool support without code changes
- User-defined recipes in .beads/recipes.toml
- Shared template across all file-based integrations

🤖 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
2026-01-04 21:57:09 -08:00
John Hogenmiller
c41d3e2b5e fix: bd ready now shows in_progress issues (#894)
The RPC server's handleReady() was explicitly setting Status to
StatusOpen, which overrode the intended behavior where an empty Status
field matches both 'open' and 'in_progress' issues.

Removed the Status field assignment so it remains empty (zero value),
allowing the SQLite storage layer to correctly return both statuses
as documented in the help text.

Fixes #5aml
2026-01-04 17:29:54 -08:00
beads/crew/emma
a1079fcbe1 fix(git): use case-insensitive path comparison for worktree validation (GH#880)
On macOS with case-insensitive filesystem, path casing differences between
the daemon socket path and git worktree registry caused sync failures.

Changed isValidWorktree() to use utils.PathsEqual() which handles
case-insensitivity on macOS/Windows, matching the fix already applied
to daemon registry in GH#869.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 16:11:37 -08:00
garnet
9d69099803 fix(slot): add cross-beads prefix routing to bd slot set (bd-hmeb)
When setting a slot to a bead from a different beads database
(e.g., setting an hq-* role bead on a gt-* agent bead), the command
now uses prefix-based routing via routes.jsonl to resolve the bead
in the correct database.

Previously, bd slot set only looked in the local database, failing
to find cross-db references like hq-polecat-role from rig beads.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 15:21:36 -08:00
beads/crew/dave
7b90678afe fix: canonicalize path case on macOS for git worktree operations (GH#880)
bd sync fails with exit status 128 when the daemon is started from a
terminal with different path casing than what git has stored. This
happens on macOS case-insensitive filesystem when directory names
are renamed (e.g., MyProject to myproject) but terminal sessions
retain the old casing.

The fix uses realpath(1) on macOS to get the true filesystem case
when canonicalizing paths:
- CanonicalizePath() now calls realpath on macOS
- git.GetRepoRoot() canonicalizes repoRoot via canonicalizeCase()
- syncbranch.GetRepoRoot() uses utils.CanonicalizePath()

This ensures git worktree paths match exactly, preventing the
exit status 128 errors from git operations.

🤖 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
2026-01-04 13:54:07 -08:00
beads/crew/fang
fbc93e3de2 fix: prevent sparse checkout config from leaking to main repo (GH#886)
Use git sparse-checkout command instead of manually setting
core.sparseCheckout config. The sparse-checkout command properly
scopes the setting to the worktree via extensions.worktreeConfig,
avoiding the confusing sparse checkout message in git status.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 13:52:29 -08:00
topaz
b789b99537 fix(daemon): normalize paths for case-insensitive filesystems (GH#880)
On macOS (HFS+/APFS), `bd sync` would fail with exit status 128 when
the daemon was started from a terminal session with different path
casing than what git had stored for the worktree (e.g., /Users/.../
MyProject vs /Users/.../myproject).

Fixed by normalizing workspace paths using `filepath.EvalSymlinks()`
before storing in the registry and comparing during lookups:

- registry.Register(): Canonicalizes workspace path before storing
- registry.Unregister(): Canonicalizes paths before comparison
- FindDaemonByWorkspace(): Canonicalizes paths before lookup

This ensures consistent path matching across case-insensitive
filesystems since EvalSymlinks returns the actual filesystem casing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 11:50:46 -08:00
quartz
563f7e875d fix(merge): preserve close_reason field during merge/sync (GH#891)
The close_reason and closed_by_session fields were being silently dropped
during 3-way merge operations because the simplified Issue struct in
internal/merge/merge.go was missing these fields.

Changes:
- Add CloseReason and ClosedBySession fields to merge.Issue struct
- Implement merge logic that preserves these fields when status is closed
- Use timestamp-based conflict resolution (later closed_at wins)
- Clear close metadata when status becomes non-closed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 11:33:32 -08:00
beads/crew/grip
df66ecfe9e fix(worktree): disable sparse checkout on main repo after worktree creation (GH#886)
Git 2.38+ enables core.sparseCheckout on the main repo as a side effect
of worktree creation, causing confusing git status message:
"You are in a sparse checkout with 100% of tracked files present."

The fix explicitly disables sparse checkout on the main repo after
creating the beads worktree. This doesn't affect the worktree's sparse
checkout functionality since the patterns are already applied during
checkout.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 11:24:47 -08:00
web3dev1337
661556ae62 feat: add multi-prefix support via allowed_prefixes config (#881)
feat: add multi-prefix support via allowed_prefixes config

Adds support for allowing multiple prefixes in a beads database via the
allowed_prefixes config key. This is needed for Gas Town which uses different
prefixes for different purposes (hq-, gt-, rig-specific prefixes).

Usage: bd config set allowed_prefixes "gt,hq,hmc"

PR #881 by @web3dev1337
2026-01-04 11:13:44 -08:00
wolf
9880eaf734 feat(config): support daemon.auto_* settings in config.yaml (GH#871)
Allow team-wide auto-sync configuration via config.yaml instead of SQLite.
This enables teams to share auto-commit/auto-push settings through version control.

Changes:
- Add daemon.auto_commit, daemon.auto_push, daemon.auto_pull to YamlOnlyKeys
- Add daemon.* prefix to YAML-only prefixes
- Update daemon startup to read from config.yaml first, then fall back to SQLite
- Update bd init --team to write daemon settings to config.yaml

Usage:
  # In .beads/config.yaml (version controlled, shared by team)
  daemon.auto_commit: true
  daemon.auto_push: true

  # Or via bd config set
  bd config set daemon.auto_commit true

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 10:42:22 -08:00
emma
4468ff030f feat(sync): add BD_DEBUG_SYNC env for protection debugging
Adds debug logging when timestamp-aware protection triggers, controlled
by BD_DEBUG_SYNC environment variable. Helps diagnose sync issues.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 10:41:57 -08:00
emma
62e4eaf7c1 fix(sync): make snapshot protection timestamp-aware (GH#865)
The --protect-left-snapshot mechanism was protecting ALL local issues
by ID alone, ignoring timestamps. This caused newer remote changes to
be incorrectly skipped during cross-worktree sync.

Changes:
- Add BuildIDToTimestampMap() to SnapshotManager for timestamp-aware
  snapshot reading
- Change ProtectLocalExportIDs from map[string]bool to map[string]time.Time
- Add shouldProtectFromUpdate() helper that compares timestamps
- Only protect if local snapshot is newer than incoming; allow update
  if incoming is newer

This fixes data loss scenarios where:
1. Main worktree closes issue at 11:31
2. Test worktree syncs and incorrectly skips the update
3. Test worktree then pushes stale open state, overwriting mains changes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 13:27:36 -08:00