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>
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>
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>
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
- 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>
* 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.
Add BenchmarkRebuildBlockedCache_Large and _XLarge to measure cache
rebuild performance in isolation.
Results show cache rebuild takes ~773ms at 10K issues and ~1.3s at 20K,
significantly slower than the ~50ms originally estimated in the issue.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Optimize CheckExternalDeps to group refs by project and open each
external DB only once, checking all capabilities in a single query.
Before: If 10 issues depend on external:gastown:cap1, we opened
gastown's DB 10 times.
After: We open each external project's DB once, query for all
capabilities needed from that project, then close.
Also added deduplication in filterByExternalDeps to collect all
unique refs before checking, avoiding redundant checks for the
same ref across multiple issues.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements automatic discovery of GitHub workflow run IDs for gates
awaiting CI/CD completion. This enables the Refinery patrol to
auto-populate await_id for gh:run gates that were created without one.
Changes:
- Add `bd gate discover` command that:
- Finds open gh:run gates without await_id
- Queries recent GitHub workflow runs via gh CLI
- Matches runs to gates using heuristics (branch, commit, time)
- Updates gates with discovered run IDs
- Add `--await-id` flag to `bd update` for manual setting
- Add AwaitID to UpdateArgs in RPC protocol
- Add await_id to allowedUpdateFields in storage layer
Matching heuristics (scored, highest match wins):
- Commit SHA match: +100 points
- Branch match: +50 points
- Time proximity (<5min: +30, <10min: +20, <30min: +10)
- In-progress/queued status: +5 points
Usage:
bd gate discover # Auto-discover for all matching gates
bd gate discover --dry-run # Preview without updating
bd gate discover --branch main --limit 10
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(dates): add due date schema and --due flag
- Add due_at and defer_until columns to issues table via migration 035
- Implement --due flag on create command with ISO date parsing
- Extend RPC protocol and daemon to pass DueAt from CLI to storage
- Display DueAt and DeferUntil in show command output
- Update Issue type with new date fields
Users can now set due dates when creating issues, enabling deadline-based
task management.
* feat(dates): add compact duration parser (+6h, +1d, +2w)
- Create internal/timeparsing package with layered parser architecture
- Implement parseCompactDuration with regex pattern [+-]?\d+[hdwmy]
- Add comprehensive test suite (22 cases) for duration parsing
- Integrate into create.go with fallback to ISO format
Supports hours (h), days (d), weeks (w), months (m), and years (y).
Negative values allowed for past dates.
* feat(dates): add NLP parsing for natural language dates
Integrate olebedev/when library for natural language time expressions.
The layered parser now handles: compact duration → absolute formats → NLP.
Changes:
- Add olebedev/when dependency for NLP parsing
- Implement ParseNaturalLanguage and ParseRelativeTime functions
- Reorder layers: absolute formats before NLP to avoid misinterpretation
- Simplify create.go to use unified ParseRelativeTime
- Add comprehensive NLP test coverage (22 test cases)
Supports: tomorrow, next monday, in 3 days, 3 days ago
* feat(dates): add --defer flag to create/update/defer commands
Add time-based deferral support alongside existing status-based defer.
Issues can now be hidden from bd ready until a specific time.
Changes:
- Add --defer flag to bd create (sets defer_until on creation)
- Add --due and --defer flags to bd update (modify existing issues)
- Add --until flag to bd defer (combines status=deferred with defer_until)
- Add DueAt/DeferUntil fields to UpdateArgs in protocol.go
Supports: +1h, tomorrow, next monday, 2025-01-15
* feat(dates): add defer_until filtering to ready command
Add time-based deferral support to bd ready:
- Add --include-deferred flag to show issues with future defer_until
- Filter out issues where defer_until > now by default
- Update undefer to clear defer_until alongside status change
- Add IncludeDeferred to WorkFilter and RPC ReadyArgs
Part of GH#820: Relative Date Parsing (Phase 5)
* feat(dates): add polish and tests for relative date parsing
Add user-facing warnings when defer date is in the past to help catch
common mistakes. Expand help text with format examples and document
the olebedev/when September parsing quirk.
Tests:
- TestCreateSuite/WithDueAt, WithDeferUntil, WithBothDueAndDefer
- TestReadyWorkDeferUntil (ExcludesFutureDeferredByDefault, IncludeDeferredShowsAll)
Docs:
- CLAUDE.md quick reference updated with new flags
- Help text examples for --due, --defer on create/update
Closes: Phase 6 of beads-820-relative-dates spec
* feat(list): add time-based query filters for defer/due dates
Add --deferred, --defer-before, --defer-after, --due-before, --due-after,
and --overdue flags to bd list command. All date filters now support
relative time expressions (+6h, tomorrow, next monday) via the
timeparsing package.
Filters:
- --deferred: issues with defer_until set
- --defer-before/after: filter by defer_until date range
- --due-before/after: filter by due_at date range
- --overdue: due_at in past AND status != closed
Existing date filters (--created-after, etc.) now also support relative
time expressions through updated parseTimeFlag().
* build(nix): update vendorHash for olebedev/when dependency
The olebedev/when library was added for natural language date parsing
(GH#820). This changes go.sum, requiring an updated vendorHash in the
Nix flake configuration.
This implements Phase 1 of the Step.Gate feature (bd-7zka.2):
- bd cook now creates gate issues for steps with gate fields
- Gate issues have type=gate and block the gated step via dependency
- bd list filters out gate issues by default (use --include-gates to show)
- New bd gate command with list and resolve subcommands
Gate types supported in Phase 1:
- human: Manual closure via bd close or bd gate resolve
Implementation details:
- createGateIssue() in cook.go creates gate issues with proper metadata
- collectSteps() creates gate dependencies when processing gated steps
- IssueFilter.ExcludeTypes added to storage layer for type-based filtering
- Gate command provides dedicated UX for gate management
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds closed_by_session tracking for entity CV building per Gas Town
decision 009-session-events-architecture.md.
Changes:
- Add ClosedBySession field to Issue struct
- Add closed_by_session column to issues table (migration 034)
- Add --session flag to bd close command
- Support CLAUDE_SESSION_ID env var as fallback
- Add --session flag to bd update for status=closed
- Display closed_by_session in bd show output
- Update Storage interface to include session parameter in CloseIssue
🤖 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
Adds a new `bd mol progress` command that shows molecule progress using
indexed queries instead of loading all steps into memory. This makes it
suitable for mega-molecules with millions of steps.
Features:
- Efficient SQL-based counting via idx_dependencies_depends_on_type index
- Progress display: completed / total (percentage)
- Current step identification
- Rate calculation from closure timestamps
- ETA estimation
- JSON output support
New storage interface method: GetMoleculeProgress(ctx, moleculeID)
🤖 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>
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>
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>
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 TypeConvoy to issue types for cross-project tracking
- Implement reactive completion: when all tracked issues close,
convoy auto-closes with reason "All tracked issues completed"
- Uses 'tracks' dependency type (non-blocking, cross-prefix capable)
- Update help text for --type flag in list/create commands
- Add test for convoy reactive completion 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
Changes:
- Default to excluding closed issues (use --all to include)
- Default limit of 50 issues (use --limit 0 for unlimited)
- --all flag now overrides the closed filter
This addresses agent context blowout from seeing hundreds of closed issues.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When the database has orphaned foreign key references (dependencies or labels
pointing to non-existent issues), the migration invariant check would fail,
preventing the database from opening. This created a chicken-and-egg problem:
1. bd doctor --fix tries to open the database
2. Opening triggers migrations with invariant checks
3. Invariant check fails due to orphaned refs
4. Fix never runs because database won't open
The fix adds CleanOrphanedRefs() that runs BEFORE captureSnapshot() in
RunMigrations. This automatically cleans up orphaned dependencies and labels
(preserving external:* refs), allowing the database to open normally.
Added test coverage for the cleanup function.
Separates semantics of 'pinned' (identity records) from work-on-hook:
- 'pinned' = domain table / identity record (agents, roles) - non-blocking
- 'hooked' = work on agent's hook (GUPP-driven) - blocks dependents
Changes:
- Add StatusHooked constant to types.go
- Update all blocking queries to include 'hooked' status
- Add cyan styling for 'hooked' in UI output
- Create migration 032 to convert pinned work items to hooked
Generated with Claude Code
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add mol_type field to beads for swarm coordination:
- Values: 'swarm' (multi-polecat), 'patrol' (recurring ops), 'work' (default)
- Nullable, defaults to empty string (treated as 'work')
Changes:
- Add mol_type column to SQLite schema and migration 031
- Add MolType type with IsValid() validation in types.go
- Update insertIssue/GetIssue to handle mol_type
- Add --mol-type flag to create command
- Add mol_type filtering to list and ready commands
- Update RPC protocol for daemon mode support
- Update test schema in migrations_test.go
🤝 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New commands and features:
- bd worktree for parallel development
- bd slot commands for agent bead slot management
- bd agent state for ZFC-compliant state reporting
- bd doctor --deep for full graph integrity validation
- Agent bead support (type=agent, type=role, migration 030)
- Computed .parent field in JSON output
- Auto-bypass daemon for wisp operations
- Pour warning for vapor-phase formulas
Performance:
- O(2^n) → O(V+E) cycle detection (GH#775)
Fixes:
- Import hash mismatch warnings
- Test updates for version tracking thresholds
- Migration test updated for new agent schema fields
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Strip (bd-xxx), (gt-xxx) suffixes from code comments and changelog
entries. The descriptions remain meaningful without the ephemeral
issue IDs.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace the recursive SQL CTE in DetectCycles with Go-layer DFS using
shared visited set. The previous implementation enumerated all paths
through the dependency graph, causing exponential blowup with diamond
patterns (multiple issues depending on the same target).
Changes:
- Add loadDependencyGraph() to load deps as adjacency list in one query
- Implement DFS cycle detection with recStack for back-edge detection
- Add normalizeCycle() for consistent cycle deduplication
- Add DetectCycles-specific benchmarks (Linear, Dense, Tree graphs)
- Use direct SQL INSERT in benchmarks to bypass AddDependency overhead
Performance improvement on dense graph (500 nodes, 2500 edges):
- Before: >120s timeout
- After: 1.6ms
Benchmarks:
- DetectCycles_Linear_1000: 0.84ms (1000 nodes, 999 edges)
- DetectCycles_Dense_500: 1.59ms (500 nodes, ~2500 edges)
- DetectCycles_Tree_1000: 0.85ms (1000 nodes, 999 edges)
Add slot management commands:
- bd slot set <agent> <slot> <bead> - set slot (error if occupied)
- bd slot clear <agent> <slot> - clear slot
- bd slot show <agent> - show all slots
These enforce cardinality constraints for agent bead slots.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add nolint:unparam for readOnly param in sqlite_open.go
- Handle cmd.Help() error in wisp.go
- Handle rows.Close() error in migration 028
- Handle targetStore.Close() error in create.go
- Update Nix vendorHash for current dependencies
Cherry-picked from PR #769
Analysis found these commands are dead code:
- gt never calls `bd pin` - uses `bd update --status=pinned` instead
- Beads.Pin() wrapper exists but is never called
- bd hook functionality duplicated by gt mol status
- Code comment says "pinned field is cosmetic for bd hook visibility"
Removed:
- cmd/bd/pin.go
- cmd/bd/unpin.go
- cmd/bd/hook.go
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The migration was using SELECT * which fails when migrating databases
that predate the created_by column (34 columns vs 35). Now explicitly
lists columns and provides empty default for created_by if missing.
Also fixes missed Wisp→Ephemeral rename in multirepo_test.go.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Migration 028 lacked an idempotency check, causing it to fail on databases
where the migration had already been applied. The migration would attempt
to copy data from issues to issues_new, but both tables had the same CHECK
constraint, causing the insert to fail.
Added check for "status = 'tombstone'" in the table schema to detect if
the migration has already been applied and skip if so.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Wisps are ephemeral issues used for patrol/operational cycles and should
not appear in `bd ready` output as trackable work items. Added ephemeral
exclusion filter to both the GetReadyWork() function and ready_issues VIEW.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Migration 028 (tombstone_closed_at) recreates the issues table but was
missing the created_by column that exists in schema.go. This caused
`SELECT * FROM issues` to fail with column count mismatch on fresh DBs.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a created_by field to track who created each issue, similar to how
comments have an author field.
- Add CreatedBy string field to Issue struct
- Add migration 029 to add created_by column to issues table
- Update all SELECT/INSERT/Scan statements across storage layer
- Populate created_by in bd create from actor chain
- Display created_by in bd show output
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, tombstones could not have a closed_at timestamp due to:
1. Go validation: `if status != closed && closed_at != nil` failed
2. SQL CHECK constraint: `(status = 'closed') = (closed_at IS NOT NULL)`
This caused import failures for tombstones that were closed before being
deleted - a valid scenario where we want to preserve the historical
closed_at timestamp for audit purposes.
Changes:
- internal/types/types.go: Updated validation to allow tombstones with
closed_at (line 253)
- internal/storage/sqlite/schema.go: Updated CHECK constraint to allow
closed AND tombstone statuses to have closed_at
- internal/storage/sqlite/migrations/028_tombstone_closed_at.go: Migration
to update existing databases with the new constraint
- .beads/issues.jsonl: Fixed bd-6s61 status from 'closed' to 'tombstone'
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Expands the inline comment to serve as a reference for when to use the
COALESCE(NULLIF(?, zero), column) defensive idiom in JSONL imports.
Pattern protects clone-local state (pinned, gate fields) from being
overwritten when importing JSONL where omitempty causes zero values to
represent "field absent" rather than "field is zero".
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Apply COALESCE(NULLIF(...)) pattern to await_type, await_id, timeout_ns,
and waiters fields in upsertIssueInTx. This prevents gate await fields
from being cleared when importing issues from JSONL that don't have
these fields (since gates are wisps and aren't exported to JSONL.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
EOF
)
* feat(ready,blocked): Add --parent flag for scoping by epic/bead descendants
Add --parent flag to `bd ready` and `bd blocked` CLI commands and MCP tools
to filter results to all descendants of a specific epic or bead.
## Backward Compatibility
- CLI: New optional --parent flag; existing usage unchanged
- RPC: New `blocked` operation added (was missing); existing operations unchanged
- MCP: New optional `parent` parameter; existing calls work as before
- Storage interface: GetBlockedIssues signature changed to accept WorkFilter
- All callers updated to pass empty filter for existing behavior
- Empty WorkFilter{} returns identical results to previous implementation
## Implementation Details
SQLite uses recursive CTE to traverse parent-child hierarchy:
WITH RECURSIVE descendants AS (
SELECT issue_id FROM dependencies
WHERE type = 'parent-child' AND depends_on_id = ?
UNION ALL
SELECT d.issue_id FROM dependencies d
JOIN descendants dt ON d.depends_on_id = dt.issue_id
WHERE d.type = 'parent-child'
)
SELECT issue_id FROM descendants
MemoryStorage implements equivalent recursive traversal with visited-set
cycle protection via collectDescendants helper.
Parent filter composes with existing filters (priority, labels, assignee, etc.)
as an additional WHERE clause - all filters are AND'd together.
## RPC Blocked Support
MCP beads_blocked() existed but daemon client raised NotImplementedError.
Added OpBlocked and handleBlocked to enable daemon RPC path, which was
previously broken. Now both CLI and daemon clients work for blocked queries.
## Changes
- internal/types/types.go: Add ParentID *string to WorkFilter
- internal/storage/sqlite/ready.go: Add recursive CTE for parent filtering
- internal/storage/memory/memory.go: Add getAllDescendants/collectDescendants
- internal/storage/storage.go: Update GetBlockedIssues interface signature
- cmd/bd/ready.go: Add --parent flag to ready and blocked commands
- internal/rpc/protocol.go: Add OpBlocked constant and BlockedArgs type
- internal/rpc/server_issues_epics.go: Add handleBlocked RPC handler
- internal/rpc/client.go: Add Blocked client method
- integrations/beads-mcp/: Add BlockedParams model and parent parameter
## Usage
bd ready --parent bd-abc # All ready descendants
bd ready --parent bd-abc --priority 1 # Combined with other filters
bd blocked --parent bd-abc # All blocked descendants
## Testing
Added 4 test cases for parent filtering:
- TestParentIDFilterDescendants: Verifies recursive traversal (grandchildren)
- TestParentIDWithOtherFilters: Verifies composition with priority filter
- TestParentIDWithBlockedDescendants: Verifies blocked issues excluded from ready
- TestParentIDEmptyParent: Verifies empty result for childless parent
* fix: Correct blockedCmd indentation and suppress gosec false positive
- Fix syntax error from incorrect indentation in blockedCmd Run function
- Add nolint:gosec comment for GetBlockedIssues SQL formatting (G201)
The filterSQL variable contains only parameterized WHERE clauses with
? placeholders, not user input