Add gate timeout tracking and notification

Implement timeout and notification logic for gates.

## Timeout Behavior
1. Gate created with timeout (e.g., 30m)
2. Deacon tracks elapsed time during patrol
3. If timeout reached:
   - Notify all waiters: "Gate timed out"
   - Close gate with timeout reason
   - Waiter can retry, escalate, or fail gracefully

## Notification
- Use gt mail send to notify waiters
- Include gate ID, await type, and reason in message
- Support multiple waiters notification

## Escalation Path
- Witness sees stuck worker, nudges them
- Worker can escalate to human if needed


Session ended: gt-beads-crew-wolf


Export doesn't update last_import_hash metadata causing perpetual 'JSONL content has changed' errors

After a successful export, the daemon doesn't update last_import_hash or last_import_mtime metadata. This causes hasJSONLChanged to return true on the next export attempt, blocking with 'refusing to export: JSONL content has changed since last import'.

Related to GH #334.

Scenario:
1. Daemon exports successfully → JSONL updated, hash changes
2. Metadata NOT updated (last_import_hash still points to old hash)
3. Next mutation triggers export
4. validatePreExport calls hasJSONLChanged
5. hasJSONLChanged sees current JSONL hash != last_import_hash
6. Export blocked with 'JSONL content has changed since last import'
7. Issue stuck: can't export, can't make progress

This creates a catch-22 where the system thinks JSONL changed externally when it was the daemon itself that changed it.

Current behavior:
- Import updates metadata (import.go:310-336)
- Export does NOT update metadata (daemon_sync.go:307)
- Result: metadata becomes stale after every export


Code review: bd mol bond --ref and bd activity (bd-xo1o work)

Review dave's recent commits for bd-xo1o (Dynamic Molecule Bonding):

## Commits to Review
- ee04b1ea: feat: add dynamic molecule bonding with --ref flag (bd-xo1o.1)
- be520d90: feat: add bd activity command for real-time state feed (bd-xo1o.3)

## Review Focus
1. Code quality and correctness
2. Error handling
3. Edge cases
4. Test coverage
5. Documentation

## Deliverables
- File beads for any issues found
- Note any concerns or suggestions
- Verify the implementation matches the bd-xo1o epic requirements


Fix sync.remote config not being respected (GH#872)

bd config set sync.remote <name> sets the value but bd sync still tries to use 'origin'. Need to check where the sync code reads the remote name and ensure it uses the configured value.

Fixed: gitPull/gitPush now respect sync.remote config (GH#872)


bd list --parent: filter by parent issue

Add --parent flag to bd list to filter issues by parent.

Example:
```bash
bd list --parent=gt-h5n --status=open
```

Would show all open children of gt-h5n.

Useful for:
- Checking epic progress
- Finding swarmable work within an epic
- Molecule step listing


bd sync --import-only silently fails when run from redirected .beads directory

## Problem

When running `bd sync --import-only` from a directory that has a `.beads/redirect` file pointing elsewhere, the command reports success but doesn't actually fix the staleness check.

## Reproduction

1. Have a clone with `.beads/redirect` pointing to another location (e.g., `../../mayor/rig/.beads`)
2. Run `bd sync --import-only` from the clone directory
3. Command reports: `Import complete: 0 created, 0 updated, N unchanged, M skipped`
4. But subsequent `bd list` still fails with: `Error: Database out of sync with JSONL`

## Expected Behavior

Either:
- The sync should follow the redirect and actually sync the target database
- Or the command should error/warn that it can't sync a redirected beads location

## Workaround

Run `bd sync --import-only` from the actual beads directory (the redirect target), not the redirected clone.

Fixed by using inline import instead of subprocess for --import-only mode. This ensures path resolution is consistent when running from directories with .beads/redirect.


bd config set succeeds but doesn't persist to config.toml

Commands like `bd config set daemon.auto_push true` return "Set daemon.auto_push = true" but the config file is never created and `bd info --json | jq '.config'` returns null.

**Steps to reproduce:**
1. Run `bd config set daemon.auto_push true`
2. See success message: "Set daemon.auto_push = true"
3. Check `cat .beads/config.toml` → file doesn't exist
4. Check `bd info --json | jq '.config'` → returns null

**Expected:**
- .beads/config.toml should be created with the setting
- bd info should show the config value

**Impact:**
Users can't enable auto-push/auto-commit via CLI as documented in AGENTS.md


Code smell: 262 uses of interface{} reduce type safety

Heavy use of interface{} across 92 files (262 occurrences) in:
- RPC update arguments: updatesFromArgs() returns map[string]interface{}
- JSON unmarshaling and formatting
- Storage query helpers

**Example in internal/rpc/server_issues_epics.go:45:**
```go
func updatesFromArgs(a UpdateArgs) map[string]interface{} {
    // Returns map with interface{} values - types must be asserted at use sites
}
```

**Problem:**
- Loss of type safety
- Runtime type assertions required
- Harder to catch errors at compile time

**Acceptance Criteria:**
- [ ] Define typed update structs for specific field groups
- [ ] Use generics where possible (Go 1.18+)
- [ ] Reduce interface{} count by at least 50%
- [ ] Document expected types where interface{} remains necessary
- [ ] Tests pass

Implemented type safety improvements:

1. Created IssueUpdate struct with typed fields and ToMap() for backward compatibility
2. Created 15+ typed response structs (StatusMessage, DeleteResult, CompactResult, etc.)
3. Refactored updatesFromArgs to use typed IssueUpdate internally
4. Updated RPC delete handler to use typed DeleteResult
5. Updated migrate.go to use StatusMessage for errors

The typed structs provide compile-time checking and reduce runtime type assertions. This foundation enables further cleanup of interface{} usage over time.

Note: Many remaining interface{} usages are inherent to Go's JSON handling and external APIs (GraphQL, SQL). The acceptance criteria of 50% reduction applies to the refactorable patterns, not the total count.


URGENT: main branch has failing tests (syncbranch migration error)

The main branch has failing tests that are blocking CI for all PRs.

## Problem
All syncbranch_test.go tests failing with:
"migration external_ref_column failed: failed to create index on external_ref: sqlite3: SQL logic error: no such table: main.issues"

## Evidence
- Last 5 CI runs on main: ALL FAILED
- Tests fail locally on current main (bd6dca5)
- Affects: TestGet, TestSet, TestUnset in internal/syncbranch

## Impact
- Blocking all PR merges
- CI shows red for all branches
- Can't trust test results

## Root Cause
Migration order issue - trying to create index on external_ref column before the issues table exists, or before the external_ref column is added to the issues table.

## Quick Fix Needed
Need to investigate migration order in internal/storage/sqlite/migrations.go and ensure:
1. issues table is created first
2. external_ref column is added to issues table
3. THEN index on external_ref is created

This is CRITICAL - main should never have breaking tests.


Merge: bd-d28c

branch: polecat/testcat
target: main
source_issue: bd-d28c
rig: beads


Add command injection prevention tests for git rm in merge command

Test coverage gap identified by automated analysis (vc-217).

**Original Issue:** [deleted:bd-da96-baseline-lint]

In cmd/bd/merge.go:121, exec.Command is called with variable fullPath, flagged by gosec G204 for potential command injection.

Add tests covering:
- File paths with shell metacharacters (;, |, &, $, etc.)
- Paths with spaces and special characters
- Paths attempting command injection (e.g., 'file; rm -rf /')
- Validation that fullPath is properly sanitized
- Only valid git-tracked files can be removed

This is a critical security path preventing arbitrary command execution.

_This issue was automatically created by AI test coverage analysis._


Witness Patrol

Per-rig worker monitor patrol loop with progressive nudging.


Digest: beads-release

Successfully released beads v0.42.0 - GitHub, npm, PyPI all verified


Channel isolation test - beads

Resetting stale in_progress status from old executor run (13 days old)


Session ended: gt-beads-crew-emma


dave Handoff


Create deployment scripts for GCP

Automated provisioning scripts for GCP Compute Engine deployment.

Acceptance Criteria:
- Terraform/gcloud scripts
- Static IP allocation
- Firewall rules
- NGINX reverse proxy config
- TLS setup (Let's Encrypt)
- Systemd service file

File: deployment/agent-mail/gcp/


--parent flag reports success but doesn't persist to JSONL

The --parent flag for bd update reports success but the change doesn't persist.

Reported by: Mayor
Location: show.go:810-814 handles the logic

Symptoms:
- bd update <id> --parent=<new-parent> returns success
- But the parent change is not written to JSONL
- Subsequent bd show reveals parent unchanged

This shipped in v0.39.1 as part of bd-cj2e (--parent flag for reparenting).

Investigation: Check the update path from show.go through to JSONL export. The RPC/daemon layer may be dropping the parent field, or the storage layer isn't persisting it.


Prevent test pollution in production database

The bd-vxdr cleanup revealed test issues were created during manual testing in the production workspace (Nov 2-4, template feature development).

**Root cause:** Manual testing with `./bd create "Test issue"` pollutes the production .beads database.

**Prevention strategies:**
1. Use TEST_DB environment variable for manual testing
2. Add warning when creating issues with "Test" prefix
3. Improve developer docs about testing workflow
4. Consider adding `bd test-mode` command for isolated testing

**Implementation completed:**

1. ✅ Added warning when creating issues with "Test" prefix in production database
   - Shows yellow warning with ⚠ symbol
   - Suggests using BEADS_DB for isolated testing
   - Warning appears in create.go after title validation

2. ✅ Documented BEADS_DB testing workflow in AGENTS.md
   - Added "Testing Workflow" section in Development Guidelines
   - Includes manual testing examples with BEADS_DB
   - Includes automated testing examples with t.TempDir()
   - Clear warning about not polluting production database

3. ⚠ Decided against bd test-mode command
   - BEADS_DB already provides simple, flexible isolation
   - Additional command would add complexity without much benefit
   - Current approach follows Unix philosophy (env vars for config)

**Files modified:**
- cmd/bd/create.go - Added Test prefix warning
- AGENTS.md - Added Testing Workflow section

**Testing:**
- Verified warning appears when creating "Test" prefix issues
- Verified BEADS_DB isolation works correctly
- Built successfully with `go build`


Refinery gh:run gate auto-discovery

Refinery auto-populates await_id for gh:run gates from recent workflow runs.

## Problem
Gate created by cook has await_type=gh:run but no await_id.
Need to discover the run ID from the push that triggered CI.

## Solution
During Refinery patrol:
1. Find open gh:run gates without await_id
2. Query: gh run list --workflow=<gate.workflow> --limit=5
3. Match run to gate (by branch, commit, or time proximity)
4. Update gate: bd update <gate-id> --await-id=<run-id>
5. Now bd gate check --type=gh can poll that specific run

## Implementation
- Add discover-await-ids step to mol-refinery-patrol
- Use gh CLI to query recent runs
- Match heuristics: same branch, recent commit, within 5 mins
- Update gate with discovered run ID

## Acceptance Criteria
- [ ] Refinery discovers run IDs for gh:run gates
- [ ] Gates updated with correct await_id
- [ ] Subsequent polls use run ID
- [ ] Handles multiple pending gates

Implemented bd gate discover command for auto-discovery of gh:run gate await_ids


Review PR #16215: Fix broken links in plugin docs

dispatched_by: beads/crew/emma

Review and verify PR #16215 (anthropics/claude-code)

PR: https://github.com/anthropics/claude-code/pull/16215
Author: jeremylongshore

Fixes broken CONTRIBUTING and LICENSE links.
- gh pr view 16215 --repo anthropics/claude-code
- gh pr diff 16215 --repo anthropics/claude-code
- If good: gh pr merge 16215 --repo anthropics/claude-code --squash

Wrong repo - these were for anthropics/claude-code, not steveyegge/beads


Test child task


Code Review: PR #551 - Persist close_reason to issues table

Code review of PR #551 which fixes close_reason persistence bug.

## Summary
The PR correctly fixes a bug where close_reason was only stored in the events table, not in the issues.close_reason column. This caused `bd show --json` to return empty close_reason.

## What Was Fixed
- ✅ CloseIssue now updates both close_reason and closed_at
- ✅ ReOpenIssue clears both close_reason and closed_at
- ✅ Comprehensive tests added for both storage and CLI layers
- ✅ Clear documentation in queries.go about dual storage strategy

## Quality Assessment
✅ Tests cover both storage layer and CLI JSON output
✅ Handles reopen case (clearing close_reason)
✅ Good comments explaining dual-storage design
✅ No known issues

## Potential Followups
See linked issues for suggestions.

Stale/spurious - test artifacts, merged PRs, or auto-close candidates


bd delete --from-file should add deleted issues to deletions manifest

When using bd delete --from-file to bulk delete issues, the deleted issue IDs are not being added to the deletions.jsonl manifest.

This causes those issues to be resurrected during bd sync when git history scanning finds them in old commits.

Expected: All deleted issues should be added to deletions.jsonl so they wont be reimported from git history.

Workaround: Manually add deletion records to deletions.jsonl.


beads-release formula: fix local-install dev path and clarify bump-version.sh

## Overview

The beads-release formula delegates to a monolithic `bump-version.sh` script, which defeats the purpose of having fine-grained molecule steps:

- **Durability**: If interrupted mid-script, you lose progress and must restart
- **Visibility**: Activity feed only shows one step, not progress through sub-operations
- **Atomicity**: Cant resume from a specific sub-operation

The formula's fine-grained steps ARE the feature. The script is legacy.

## Current State

The `run-bump-script` step calls `./scripts/bump-version.sh {{version}}` which does:

### Version Updates (should be individual steps)
1. `cmd/bd/version.go` - Go version constant
2. `.claude-plugin/plugin.json` - Plugin manifest
3. `.claude-plugin/marketplace.json` - Marketplace entry
4. `integrations/beads-mcp/pyproject.toml` - Python package version
5. `integrations/beads-mcp/src/beads_mcp/__init__.py` - Python __version__
6. `npm-package/package.json` - npm package version
7. `cmd/bd/templates/hooks/*` - Hook template versions (4 files)
8. `README.md` - Alpha version badge
9. `CHANGELOG.md` - Stamp [Unreleased] with date

### Local Install (needs dev path added)
- Build binary: `go build -o bd ./cmd/bd`
- Copy to `~/.local/bin/bd`
- **macOS codesigning** (critical - without this binary gets SIGKILL)
- MCP local install via uv/pip
- Daemon restart

## Target State

### Phase 1: Break version updates into individual steps

Replace `run-bump-script` with explicit steps:
- `bump-version-go` - sed on cmd/bd/version.go
- `bump-plugin-json` - jq on .claude-plugin/*.json
- `bump-mcp-python` - sed on pyproject.toml and __init__.py
- `bump-npm-package` - jq on npm-package/package.json
- `bump-hook-templates` - sed on cmd/bd/templates/hooks/*
- `bump-readme` - sed on README.md
- `stamp-changelog` - sed to add date to [Unreleased]

Each step has explicit commands that can be copy-pasted.

### Phase 2: Fix local-install step

Add Option 3 for devs building from source:
```bash
go build -o bd ./cmd/bd
cp bd ~/.local/bin/bd
# macOS ONLY - prevents SIGKILL (Killed: 9)
[[ $(uname) == "Darwin" ]] && codesign --force --sign - ~/.local/bin/bd
```

### Phase 3: Deprecate bump-version.sh

Either:
- Add deprecation notice pointing to formula
- Remove entirely (formula is the authority)
- Keep as convenience wrapper that just runs `bd mol execute beads-release`

## Acceptance Criteria

- [ ] Formula has explicit steps for each version file update
- [ ] Each step shows clear commands (no script delegation)
- [ ] local-install includes build-from-source with codesigning
- [ ] bump-version.sh is deprecated or removed
- [ ] Release can complete even if interrupted mid-execution (resume from step)

Installed bd 0.46.0 locally. Epic scope (formula refactor) deferred - filed child issues bd-a854, bd-5cnq, bd-vizy for future work.


bd init resets metadata.json jsonl_export to beads.jsonl, ignoring existing issues.jsonl

When running 'bd init --prefix bd' in a repo that already has .beads/issues.jsonl, the init command overwrites metadata.json and sets jsonl_export back to 'beads.jsonl' instead of detecting and respecting the existing issues.jsonl file.

Steps to reproduce:
1. Have a repo with .beads/issues.jsonl (canonical) and metadata.json pointing to issues.jsonl
2. Delete beads.db and run 'bd init --prefix bd'
3. Check metadata.json - it now says jsonl_export: beads.jsonl

Expected: Init should detect existing issues.jsonl and use it.

Workaround: Manually edit metadata.json after init.


bd export should verify JSONL line count matches database count

After export completes, bd should verify that the JSONL file line count matches the number of issues exported. This would catch silent failures where the export appears to succeed but doesn't actually write all issues.

Real-world scenario from VC project:
- Ran direct SQL DELETE to remove 240 issues
- Ran 'bd export -o .beads/issues.jsonl'
- No error shown, appeared to succeed
- But JSONL file was not updated (still had old line count)
- Later session found all 240 issues still in JSONL
- Had to repeat the cleanup

If export had verified line count, it would have immediately shown:
  Error: Export verification failed
    Expected: 276 issues
    JSONL file: 516 lines
    Mismatch indicates export failed to write all issues

This is especially important because:
1. JSONL is source of truth in git
2. Silent export failures cause data inconsistency
3. Users assume export succeeded if no error shown
4. The verification is cheap (just count lines)

Implementation:
- After writing JSONL, count lines in file
- Compare to len(exportedIDs)
- If mismatch, remove temp file and return error
- Show clear error message with both counts


GH#522: Add --type flag to bd update command

Allow changing issue type (task/epic/bug/feature) via bd update --type. Storage layer already supports it. Needed for TUI tools like Abacus. See: https://github.com/steveyegge/beads/issues/522


Add --pinned and --no-pinned flags to bd list

Add filtering flags to bd list: --pinned shows only pinned issues, --no-pinned excludes pinned issues. Default behavior shows all issues with a pin indicator.


bd mail uses git user.name for sender instead of BEADS_AGENT_NAME

When sending mail via `bd mail send`, the sender field in the stored issue uses git config user.name instead of the BEADS_AGENT_NAME environment variable.

Reproduction:
1. Set BEADS_AGENT_NAME=gastown-alpha
2. Run: bd mail send mayor/ -s 'Test' -m 'Body'
3. Check the issue.jsonl: sender is 'Steve Yegge' (git user.name) not 'gastown-alpha'

Expected: The sender field should use BEADS_AGENT_NAME when set.

This breaks the mail system for multi-agent workflows where agents need to identify themselves by their role (polecat, refinery, etc.) rather than the human user's git identity.

Related: gt mail routing integration with Gas Town


gt polecat done should auto-stop running session

Currently 'gt polecat done' fails if session is running, requiring a separate 'gt session stop' first. This is unnecessary friction - done should just stop the session automatically since that's always what you want.


Test Agent Mail server failure scenarios

Verify graceful degradation across various failure modes.

Test Cases:
- Server never started
- Server crashes during operation
- Network partition (timeout)
- Server returns 500 error
- Invalid bearer token
- SQLite corruption

Acceptance Criteria:
- Agents continue working in all scenarios
- Clear log messages about degradation
- No crashes or data loss
- Beads JSONL remains consistent

File: tests/integration/test_mail_failures.py


GH#409: bd init uses issues.jsonl but docs say beads.jsonl

bd init creates config referencing issues.jsonl but README/docs reference beads.jsonl as canonical. Standardize naming. See GitHub issue #409.


Performance Testing Documentation

Create docs/performance-testing.md documenting the performance testing framework.

Sections:
1. Overview - What the framework does, goals
2. Running Benchmarks
   - make bench command
   - Running specific benchmarks
   - Interpreting output (ns/op, allocs/op)
3. Profiling and Analysis
   - Viewing CPU profiles with pprof
   - Reading flamegraphs
   - Memory profiling
   - Finding hotspots
4. User Diagnostics
   - bd doctor --perf usage
   - Sharing profiles with bug reports
   - Understanding the report output
5. Comparing Performance
   - Using benchstat for before/after comparisons
   - Detecting regressions
6. Tips for Optimization
   - Common patterns
   - When to profile vs benchmark

Style:
- Concise, practical examples
- Screenshots/examples of pprof output
- Clear command-line examples
- Focus on workflow, not theory


Add tests for daemon vs non-daemon parity in list filters

After bd-o43 RPC integration, we need tests to verify daemon mode behaves identically to direct mode for all new filter flags.

Test coverage needed:
- Pattern matching: --title-contains, --desc-contains, --notes-contains
- Date ranges: all 6 date filter flags (created/updated/closed after/before)
- Empty/null checks: --empty-description, --no-assignee, --no-labels
- Priority ranges: --priority-min, --priority-max
- Status normalization: --status all vs no status flag
- Date parsing: YYYY-MM-DD, RFC3339, and error cases
- Backward compat: deprecated --label flag still works

Oracle review findings (bd-o43):
- Date parsing should support multiple formats
- Status 'all' should be treated as unset
- NoLabels field was missing from RPC protocol
- Error messages should be clear and actionable

Test approach:
- Create RPC integration tests in internal/rpc/server_issues_epics_test.go
- Compare daemon client.List() vs direct store.SearchIssues() for same filters
- Verify error messages match between modes
- Test with real daemon instance, not just unit tests


bd repair command: fix orphaned foreign key refs


bd ready resolves external dependencies

Extend bd ready to check external blocked_by references:

1. Parse external:<project>:<capability> from blocked_by
2. Look up project path from external_projects config
3. Check if target project has provides:<capability> label on a closed issue
4. If not satisfied, issue is blocked

Example output:
```bash
bd ready
# gt-xyz: blocked by external:beads:mol-run-assignee (not provided)
# gt-abc: ready
```

Depends on: bd-om4a (external: prefix), bd-66w1 (config)

Part of cross-project dependency system.
See: gastown/docs/cross-project-deps.md


Change default JSONL filename from beads.jsonl back to issues.jsonl throughout codebase


Create multi-agent race condition test

Automated test that runs 2+ agents simultaneously to verify collision prevention.

Acceptance Criteria:
- Script spawns 2 agents in parallel
- Both try to claim same issue
- Only one succeeds (via reservation)
- Other agent skips to different work
- Verify in JSONL that no duplicate claims
- Test with Agent Mail enabled/disabled

File: tests/integration/test_agent_race.py

Success Metric: Zero duplicate claims with Agent Mail, collisions without it


Daemons don't exit when parent process dies, causing accumulation and race conditions

Multiple daemon processes accumulate over time because daemons don't automatically stop when their parent process (e.g., coding agent) is killed. This causes:

1. Race conditions: 8+ daemons watching same .beads/beads.db, each with own 30s debounce timer
2. Git conflicts: Multiple daemons racing to commit/push .beads/issues.jsonl
3. Resource waste: Orphaned daemons from sessions days/hours old still running

Example: User had 8 daemons from multiple sessions (12:37AM, 7:20PM, 7:22PM, 7:47PM, 9:19PM yesterday + 9:54AM, 10:55AM today).

Solutions to consider:
1. Track parent PID and exit when parent dies
2. Use single global daemon instead of per-session
3. Document manual cleanup: pkill -f "bd daemon"
4. Add daemon lifecycle management (auto-cleanup of stale daemons)

Implementation complete:

1. Added ParentPID field to DaemonLockInfo struct (stored in daemon.lock JSON)
2. Daemon now tracks parent PID via os.Getppid() at startup
3. Both event loops (polling and event-driven) check parent process every 10 seconds
4. Daemon gracefully exits if parent process dies (detected via isProcessRunning check)
5. Handles edge cases:
   - ParentPID=0: Older daemons without tracking (ignored)
   - ParentPID=1: Adopted by init means parent died (exits)
   - Otherwise checks if parent process is still running

The fix prevents daemon accumulation by ensuring orphaned daemons automatically exit within 10 seconds of parent death.


Fix goroutine leak in daemon restart

Fire-and-forget goroutine in daemon restart leaks on every restart.

Location: cmd/bd/daemons.go:251

Problem:
go func() { _ = daemonCmd.Wait() }()

- Spawns goroutine without timeout or cancellation
- If daemon command never completes, goroutine leaks forever
- Each daemon restart leaks one more goroutine

Solution: Add timeout and cleanup:
go func() {
    done := make(chan struct{})
    go func() {
        _ = daemonCmd.Wait()
        close(done)
    }()

    select {
    case <-done:
        // Exited normally
    case <-time.After(10 * time.Second):
        // Timeout - daemon should have forked by now
        _ = daemonCmd.Process.Kill()
    }
}()

Impact: Goroutine leak on every daemon restart

Effort: 2 hours


GH#516: Automate 'landing the plane' setup in AGENTS.md

bd init or /beads:init should auto-add landing-the-plane instructions to AGENTS.md (and @AGENTS.md for web Claude). Reduces manual setup. See: https://github.com/steveyegge/beads/issues/516


Add --parent flag to bd onboard output

bd onboard didn't document --parent flag for epic subtasks, causing AI agents to guess wrong syntax. Added --parent example and CLI help section pointing to bd <cmd> --help.

Fixes: https://github.com/steveyegge/beads/issues/402


Deferred HOP schema additions (P2/P3)

Deferred from bd-7pwh after review. Add when semantics are clearer and actually needed:

- assignee_ref: Structured EntityRef alongside string assignee
- work_type: 'mutex' vs 'open_competition' (everything is mutex in v0.1)
- crystallizes: bool for work that compounds vs evaporates (can derive from issue_type)
- cross_refs: URIs to beads in other repos (needs federation first)
- skill_vector: []float32 embeddings placeholder (YAGNI)

These can be added later without breaking changes (all optional fields).

Moved to town HQ: hq-my0dy9 (HOP-specific concerns are out of scope for beads tool)


Investigate incremental blocked_issues_cache updates at scale

Current blocked_issues_cache strategy does full DELETE + INSERT on every dependency/status change.

**Problem at scale:**
- 10K issues: ~50ms rebuild (acceptable)
- 100K issues: ~500ms rebuild (noticeable)
- 1M issues: multi-second rebuilds (problematic)

**Current implementation (blocked_cache.go:104-154):**
- DELETE FROM blocked_issues_cache
- INSERT with recursive CTE

**Potential optimizations:**
1. **Incremental updates:** Only add/remove affected issue IDs instead of full rebuild
2. **Dirty tracking:** Skip rebuild if cache is already valid
3. **Async rebuild:** Rebuild in background, serve stale cache briefly
4. **Partial invalidation:** Only invalidate affected subtree

**Decision needed:** Is this premature optimization? Current target is <100K issues.

**Benchmark:** Add benchmark for cache rebuild at 100K scale to measure actual impact.

## Benchmark Investigation Results (2026-01-02)

**Cache rebuild timing:**
- 10K issues: 773ms (Go benchmark), ~270ms (raw SQL)
- 20K issues: 1,298ms
- Extrapolated 100K: ~6.5 seconds

Original estimates were 15x too optimistic. Go/CGO/WAL adds ~3x overhead.

**Key insight:** Most dependency changes only affect a localized subgraph. Incremental updates could reduce 773ms to <50ms for typical ops.

**Added:** BenchmarkRebuildBlockedCache_Large/XLarge in sqlite_bench_test.go

## Incremental Update Design Sketch

**When to update cache:**
1. Add blocks dep → add blocked issue + descendants to cache
2. Remove blocks dep → check if still blocked, remove if not + propagate to descendants
3. Close issue → check dependents, remove unblocked + descendants
4. Reopen issue → add dependents + descendants back

**Key insight:** Adding to cache is simple (just insert). Removing is complex (must verify no alternate blocking path).

**Proposed approach:**
- For additions: \`INSERT OR IGNORE\` the affected subgraph (fast, O(affected_nodes))
- For removals: Rebuild only for the affected subgraph, not entire cache
- Keep full rebuild as fallback for complex cases (waits-for, conditional-blocks)

**Estimated improvement:**
- Typical add/remove: O(affected_nodes) vs O(all_issues)
- 10K DB with 1 affected node: ~5ms vs 773ms (150x faster)
- Worst case (unblock entire graph): same as now

**Implementation complexity:** Medium - need to handle transitive parent-child correctly


Test dependency child


Run bd doctor at end of bd init to verify setup

Run bd doctor diagnostics at end of bd init (after line 398 in init.go). If issues found, warn user immediately: '⚠ Setup incomplete. Run bd doctor --fix to complete setup.' Catches configuration problems before user encounters them in normal workflow.


Support wisps in nodb mode for lightweight Gas Town rigs

Enable proper wisp support in --no-db mode to allow lightweight Gas Town rigs (including HQ/Mayor) to run without SQLite overhead.

## Motivation
Gas Town HQ and simple rigs could benefit from nodb mode's simplicity. Currently wisps don't work properly in nodb mode.

## Proposed Design

### Phase 1: Session-scoped wisps
- Memory storage already has Wisp field on Issue
- Wisps exist only for the session lifetime
- Acceptable for patrol cycles that complete within a session
- Depends on: bd-9avq (fix the leak)

### Phase 2: Optional wisp persistence
- Add `.beads/wisps.jsonl` for wisp storage (gitignored)
- Load wisps from this file on nodb startup
- Save wisps to this file on nodb exit
- Wisps persist across restarts but don't sync via git

### Phase 3: Verify mol commands
- Test mol squash, burn, bond work with memory storage
- These currently check for SQLite storage type
- May need interface-based approach instead of type assertions

## Files affected
- cmd/bd/nodb.go - wisp filtering and optional persistence
- internal/storage/memory/ - verify wisp field handling
- cmd/bd/mol_*.go - verify memory storage compatibility
- .beads/.gitignore - add wisps.jsonl