This implements sync branch integrity guards that detect when the remote
sync branch has been force-pushed since the last sync, preventing silent
data corruption.
Changes:
- Add internal/syncbranch/integrity.go with:
- CheckForcePush() - detects force-push via stored remote SHA comparison
- UpdateStoredRemoteSHA() - stores current remote SHA after successful sync
- ClearStoredRemoteSHA() - clears stored SHA when resetting
- GetStoredRemoteSHA() - retrieves stored SHA for inspection
- Update cmd/bd/sync.go to:
- Add --accept-rebase flag for non-interactive reset to remote
- Add force-push detection before sync branch pull operations
- Prompt user for confirmation when force-push detected
- Update stored remote SHA after successful sync
The implementation:
1. Tracks the remote sync branch commit SHA in config after each sync
2. On subsequent syncs, checks if stored SHA is ancestor of current remote
3. If not (force-push detected), warns user with details and prompts
4. User can accept reset or abort to investigate manually
5. --accept-rebase flag allows scripted/non-interactive recovery
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Addresses the self-hosting recursion problem where contributors using
beads-the-tool on beads-the-project leak personal issues into PRs.
Design recommends auto-routing (Approach 4):
- Detect user role via git remote URL (SSH=maintainer, HTTPS=contributor)
- Route contributor issues to ~/.beads-planning automatically
- Zero-friction default with explicit override available
Key finding: bd-6x6g needs implementation - routing is calculated but
not actually used to switch target repo in bd create.
Enables bd-lfak (PR preflight checks) to implement pollution detection.
(bd-umbf)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add comprehensive JSONL Issue Schema section to docs/ARCHITECTURE.md
documenting all exported fields including close_reason
- Add TestCloseReasonRoundTrip test in export_import_test.go to verify
close_reason is preserved through JSONL export/import cycle
Closes: bd-lxzx
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When no issue ID is provided to `bd update` or `bd close`, use the last
touched issue from the most recent create, update, show, or close operation.
This addresses the common workflow where you create an issue and then
immediately want to add more details (like changing priority from P2 to P4)
without re-typing the issue ID.
Implementation:
- New file last_touched.go with Get/Set/Clear functions
- Store last touched ID in .beads/last-touched (gitignored)
- Track on create, update, show, and close operations
- Allow update/close with zero args to use last touched
(bd-s2t)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
BUG: BD_ACTOR env var was only read in --no-db mode (lines 352-360)
and daemon RPC path. Normal direct mode and JSONL-only mode detection
paths fell back to $USER without checking BD_ACTOR.
Fix: Add explicit os.Getenv("BD_ACTOR") check in both:
- JSONL-only mode detection path (lines 393-402)
- Normal direct mode path (lines 440-450)
(gt-6r18e.2)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When config.yaml has malformed YAML, getLocalSyncBranch and
isNoDbModeConfigured were silently returning empty/false with no
feedback, making debugging difficult. Now they log a warning via
debug.Logf when YAML parsing fails.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
BUG: BD_ACTOR env var was only read in --no-db mode (lines 352-360)
and daemon RPC path. Normal direct mode and JSONL-only mode detection
paths fell back to $USER without checking BD_ACTOR.
Fix: Add explicit os.Getenv("BD_ACTOR") check in both:
- JSONL-only mode detection path (lines 393-402)
- Normal direct mode path (lines 440-450)
(gt-6r18e.2)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The bug: In a bare repo + worktrees setup, jsonlRelPath was calculated
relative to the project root (containing all worktrees), resulting in
paths like "main/.beads/issues.jsonl". But the sync branch worktree uses
sparse checkout for .beads/*, so files are at ".beads/issues.jsonl".
This caused SyncJSONLToWorktreeWithOptions to write to the wrong location
(e.g., worktree/main/.beads/ instead of worktree/.beads/), so changes
made locally never reached the sync branch worktree.
#785 fixed the reverse direction (worktree → local) by adding
normalizeBeadsRelPath(), but the local → worktree direction was missed.
Fix:
- Export NormalizeBeadsRelPath() (uppercase) for cross-package use
- Apply normalization in SyncJSONLToWorktreeWithOptions for dstPath
- Apply normalization in daemon_sync_branch.go for worktreeJSONLPath
in both commit and pull paths
- Add unit tests for the normalization function
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add SQLite read-only mode for commands that only query data (list, ready,
show, stats, blocked, count, search, graph, duplicates, comments, export).
Changes:
- Add NewReadOnly() and NewReadOnlyWithTimeout() to sqlite package
- Opens with mode=ro to prevent any file writes
- Skips WAL pragma, schema init, and migrations
- Skips WAL checkpoint on Close()
- Update main.go to detect read-only commands and use appropriate opener
- Skip auto-migrate, FlushManager, and auto-import for read-only commands
- Add tests verifying file mtime is unchanged after read operations
This fixes the issue where file watchers (like beads-ui) would go into
infinite loops because bd list/show/ready modified the database file.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Two issues fixed:
1. `bd init` was auto-detecting current branch (e.g., main) as sync.branch
when no --branch flag was specified. This caused worktree conflicts.
2. Added validation to reject main/master as sync.branch values.
When sync.branch is set to main, the worktree mechanism creates a checkout
of main at .git/beads-worktrees/main/, which prevents git checkout main
from working in the user's working directory.
The sync branch feature should use a dedicated branch like 'beads-sync'.
🤖 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
db.Exec was being passed %s format specifiers directly in the SQL
string, but db.Exec does not do printf-style formatting - it uses the
variadic args as SQL parameter bindings. This caused the literal %s
to be sent to SQLite, which failed with near percent: syntax error.
Fixed by using fmt.Sprintf to interpolate the column expressions into
the SQL string before passing to db.Exec.
Added regression test that creates an old-schema database with edge
columns (replies_to, relates_to, duplicate_of, superseded_by) and
verifies migration 022 completes successfully.
Fixes#809
Generated with Claude Code
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This addresses the code smell of 20+ global variables in main.go by:
1. Creating CommandContext struct in context.go that groups all runtime state:
- Configuration (DBPath, Actor, JSONOutput, etc.)
- Runtime state (Store, DaemonClient, HookRunner, etc.)
- Auto-flush/import state
- Version tracking
- Profiling handles
2. Adding accessor functions (getStore, getActor, getDaemonClient, etc.)
that provide backward-compatible access to the state while allowing
gradual migration to CommandContext.
3. Updating direct_mode.go to demonstrate the migration pattern using
accessor functions instead of direct global access.
4. Adding test isolation helpers (ensureCleanGlobalState, enableTestModeGlobals)
to prevent test interference when multiple tests manipulate global state.
Benefits:
- Reduces global count from 20+ to 1 (cmdCtx)
- Better testability (can inject mock contexts)
- Clearer state ownership (all state in one place)
- Thread safety (mutexes grouped with the data they protect)
Note: Two pre-existing test failures (TestTrackBdVersion_*) are unrelated to
this change and fail both with and without these modifications.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds TypeEvent issue type for recording operational state changes as
immutable beads. Events capture:
- event_category: namespaced category (e.g., patrol.muted, agent.started)
- event_actor: entity URI who caused the event
- event_target: entity URI or bead ID affected
- event_payload: event-specific JSON data
Changes:
- Add TypeEvent constant and IsValid() support in types.go
- Add event fields to Issue struct with ComputeContentHash support
- Add --event-category/actor/target/payload flags to bd create
- Add event fields to RPC CreateArgs and UpdateArgs
- Add migration 033_event_fields to add columns to issues table
- Update insertIssue and queries to include event fields
- Fix migrations_test.go for new column requirements
This enables:
- bd activity --follow showing events
- bd list --type=event --target=agent:deacon
- Full audit trail for operational state
- HOP-compatible transaction records
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add actual timestamp comparison to detect conflicts during Jira sync:
- Add fetchJiraIssueTimestamp() to fetch a single issue's updated timestamp from Jira REST API
- Add extractJiraKey() to parse Jira issue key from external_ref URLs
- Add parseJiraTimestamp() to parse Jira's ISO 8601 timestamp format
- Update detectJiraConflicts() to fetch and compare Jira timestamps instead of marking all locally-updated issues as conflicts
- Update resolveConflictsByTimestamp() to show actual timestamp comparison results
- Update reimportConflicts() to display both local and Jira timestamps
Now only issues that have been modified on BOTH sides since the last sync are reported as conflicts, reducing false positives.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The test was previously skipped because it called importFromJSONL which spawns
a subprocess. During tests, os.Executable() returns the test binary rather
than the bd binary, causing the subprocess to fail.
Changes:
- Remove t.Skip() and TODO comment
- Parse JSONL directly using encoding/json instead of subprocess
- Call importIssuesCore directly instead of importFromJSONL
- Update DB count expectation to reflect actual import behavior (additive)
The core ZFC fix behavior is preserved: when divergence is detected,
import runs and export is skipped to protect the JSONL source of truth.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds agent-optimized output mode for `bd list` triggered by:
- BD_AGENT_MODE=1 environment variable (explicit)
- CLAUDE_CODE environment variable (auto-detect)
Agent mode provides:
- Ultra-compact format: just "ID: Title" per line
- Lower default limit (20 vs 50) for context efficiency
- No colors, no emojis, no pager
- Defaults to open/in_progress only (existing behavior)
(bd-x2ht)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add composable issue validators to internal/validation package:
- IssueValidator type with Chain() composition function
- Exists(), NotTemplate(), NotPinned(), NotClosed(), NotHooked() validators
- HasStatus(), HasType() for checking allowed values
- ForUpdate(), ForClose(), ForDelete(), ForReopen() convenience chains
Update cmd/bd/show_unit_helpers.go to use centralized validators instead
of duplicated inline validation logic. This enables consistent validation
across all commands with a single source of truth.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When debug mode is enabled, the merge system now logs a message when
an expired tombstone loses to a live issue (resurrection occurs).
This helps understand why previously closed issues reappear.
Example output: "Issue bd-abc resurrected (tombstone expired)"
Changes:
- Add debug parameter to Merge3WayWithTTL and merge3Way functions
- Add debug logging in all 4 resurrection code paths
- Update tests to pass new debug parameter (bd-nl2)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added StatusClosed constant derived from types.StatusClosed alongside
the existing StatusTombstone constant. Replaced hardcoded "closed"
strings with the constant for compile-time type checking consistency.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements convenience commands for the labels-as-state pattern:
- `bd state <id> <dimension>` - Query current state value from labels
- `bd state list <id>` - List all state dimensions on an issue
- `bd set-state <id> <dimension>=<value> --reason "..."` - Atomically:
1. Create event bead (source of truth)
2. Remove old dimension label
3. Add new dimension:value label (cache)
Common dimensions: patrol, mode, health, status
Convention: <dimension>:<value> (e.g., patrol:active, mode:degraded)
Updated docs/CLI_REFERENCE.md with new State section.
Updated docs/LABELS.md to reflect implemented helpers.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds comprehensive documentation for using labels as a state cache:
- Convention: <dimension>:<value> (e.g., patrol:muted)
- Pattern: Create event bead (history) + update labels (cache)
- Common dimensions table (patrol, mode, status, health, lock)
- State transition examples with audit trail
- Querying and best practices
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added actor field to RPC client and set it before daemon requests.
This ensures status changes (like pinned events) show who performed
the action in bd activity output.
Changes:
- Added actor field to Client struct
- Added SetActor method to set actor for audit trail
- Modified ExecuteWithCwd to include actor in RPC requests
- Updated main.go to call SetActor after daemon connection
Fixes gt-1ydd9
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds support for event beads that capture operational state transitions
as immutable records. Events are a new issue type with fields:
- event_kind: namespaced category (patrol.muted, agent.started)
- actor: entity URI who caused the event
- target: entity URI or bead ID affected
- payload: event-specific JSON data
This enables:
- bd activity --follow showing events
- bd list --type=event --target=agent:deacon
- Full audit trail for operational state
- HOP-compatible transaction records
🤖 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 new DependencyType constants: until, caused-by, validates
- Add --refs flag to bd show for reverse reference lookups
- Group refs by type with appropriate emojis
- Update tests for new dependency types
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Documents the convention for using labels as cached operational state
on role beads: <dimension>:<value> format (e.g., patrol:muted, mode:degraded).
Pattern: create event bead (source of truth) then update role bead labels
(fast lookup cache). Includes best practices, common dimensions, and
notes future helper commands (bd state, bd set-state).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Post-merge cleanup of PR #805:
1. Extract duplicate error classification logic into classifyDatabaseError()
helper function (was duplicated in two places in database.go)
2. Fix semantic conflict between --force and --source=db flags:
- --force implies "database is broken, rebuild from JSONL"
- --source=db implies "use database as source of truth"
- These are contradictory; now errors with clear message
- --force with --source=auto or --source=jsonl works as expected
🤖 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 TTY detection to automatically disable ANSI colors when stdout is
piped or redirected. Respects standard conventions:
- NO_COLOR environment variable (no-color.org)
- CLICOLOR=0 disables color
- CLICOLOR_FORCE enables color even in non-TTY
Also adds ShouldUseEmoji() helper controlled by BD_NO_EMOJI.
Pager already disabled non-TTY in previous work (bd-jdz3).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add two new RPC endpoints to allow CLI commands to work in daemon mode:
1. GetConfig (OpGetConfig) - Retrieves config values from the daemon database.
Used by bd create to validate issue prefix in daemon mode.
2. MolStale (OpMolStale) - Finds stale molecules (complete-but-unclosed
epics). Used by bd mol stale command in daemon mode.
Changes:
- internal/rpc/protocol.go: Add operation constants and request/response types
- internal/rpc/client.go: Add client methods GetConfig() and MolStale()
- internal/rpc/server_issues_epics.go: Add handler implementations
- internal/rpc/server_routing_validation_diagnostics.go: Register handlers
- cmd/bd/create.go: Use GetConfig RPC instead of skipping validation
- cmd/bd/mol_stale.go: Use MolStale RPC instead of requiring --no-daemon
- internal/rpc/coverage_test.go: Add tests for new endpoints
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>