Kill running daemons

Stop all bd daemons before release:

```bash
pkill -f 'bd.*daemon' || true
sleep 1
pgrep -lf 'bd.*daemon'  # Should show nothing
```


Update info.go versionChanges

Add entry to versionChanges in cmd/bd/info.go with agent-actionable changes for {{version}}


Implement global N-way collision resolution algorithm

**Summary:** Replaced pairwise collision resolution with a global N-way algorithm that deterministically resolves issue ID conflicts across multiple clones. The new approach groups collisions, deduplicates by content hash, and assigns sequential IDs to ensure consistent synchronization.

**Key Decisions:**
- Use content hash for global, stable sorting
- Group collisions by base ID
- Assign sequential IDs based on sorted unique versions
- Eliminate order-dependent remapping logic

**Resolution:** Implemented ResolveNWayCollisions function that guarantees deterministic issue ID assignment across multiple synchronization scenarios, solving the core challenge of maintaining consistency in distributed systems with potential conflicts.


Work on beads-2vn: Add simple built-in beads viewer (GH#6...

Work on beads-2vn: Add simple built-in beads viewer (GH#654). Add bd list --pretty with --watch flag, tree view with priority/status symbols. When done, submit MR (not PR) to integration branch for Refinery.


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

Add --type flag to bd update for changing issue type (task/epic/bug/feature). Storage layer already supports it. See GitHub issue #522.


Auto-migrate database on CLI version bump

When CLI is upgraded (e.g., 0.24.0 → 0.24.1), database version becomes stale. Add auto-migration in PersistentPreRun or daemon startup. Check dbVersion != CLIVersion and run bd migrate automatically. Fixes recurring UX issue where bd doctor shows version mismatch after every CLI upgrade.


Phase 2.2: Switch bdt storage to TOON format

Currently bdt stores issues in JSONL format in issues.toon file. Phase 2.2 must implement actual TOON format storage - this is the fundamental goal of the bdtoon project.

## Current State (Phase 2.1)
- issues.toon stores JSONL (intermediate format)
- --toon flag allows output in TOON format for LLM consumption
- Problem: We're not actually using TOON as the fundamental storage format

## Required Work (Phase 2.2)
1. Switch issue file I/O to write TOON format instead of JSONL
   - Update cmd/bdt/storage.go to use EncodeTOON for writing
   - Update cmd/bdt/storage.go to decode TOON (currently decodes JSON)
   - Ensure round-trip: write TOON → read TOON → write TOON is byte-identical

2. Update command implementations
   - cmd/bdt/create.go: Write newly created issues to TOON format
   - cmd/bdt/list.go: Read issues from TOON format
   - cmd/bdt/show.go: Read from TOON format
   - cmd/bdt/import.go: Convert imported JSONL to TOON
   - cmd/bdt/export.go: Export TOON to JSONL (for bd compatibility)

3. Implement TOON parser that handles gotoon's encoder-only limitation
   - Since gotoon doesn't decode TOON, need custom TOON→JSON decoder
   - OR continue storing TOON but decoding via intermediate JSON conversion

4. Git merge driver optimization
   - TOON is line-oriented, better for 3-way merges than binary formats
   - Configure git merge driver for .toon files

5. Comprehensive testing
   - Round-trip tests: Issue → TOON → storage → read → Issue
   - Merge conflict resolution tests with TOON format
   - Large issue set performance tests

## Success Criteria
- issues.toon stores actual TOON format (not JSONL)
- bdt list reads from TOON file
- bdt create writes to TOON file
- Round-trip: create issue → list → show returns identical data
- All 65+ tests still passing
- Performance comparable to JSONL storage


Add tests for dependency management

Key dependency functions like mergeBidirectionalTrees, GetDependencyTree, and DetectCycles have low or no coverage. These are essential for maintaining data integrity in the dependency graph.


Merge: beads-ocs

branch: polecat/valkyrie
target: main
source_issue: beads-ocs
rig: beads


Widespread double JSON encoding bug in daemon mode RPC calls

Multiple CLI commands had the same double JSON encoding bug found in bd-1048. All commands that called ResolveID via RPC used string(resp.Data) instead of properly unmarshaling the JSON response. This caused IDs to retain JSON quotes ("bd-1048" instead of bd-1048), which then got double-encoded when passed to subsequent RPC calls.

Affected commands:
- bd show (3 instances)
- bd dep add/remove/tree (5 instances)
- bd label add/remove/list (3 instances)
- bd reopen (1 instance)

Root cause: resp.Data is json.RawMessage (already JSON-encoded), so string() conversion preserves quotes.

Fix: Replace all string(resp.Data) with json.Unmarshal(resp.Data, &id) for proper deserialization.

All commands now tested and working correctly with daemon mode.


enhance 'bd status' to show recent activity

It would be nice to be able to quickly view the last N changes in the database, to see wha's recently been worked on. I'm imagining something like 'bd status activity'.


Improve test coverage for internal/daemon (27.3% → 60%)

The daemon package has only 27.3% test coverage. The daemon is critical for background operations and reliability.

Key areas needing tests:
- Daemon autostart logic
- Socket handling
- PID file management
- Health checks

Current coverage: 27.3%
Target coverage: 60%


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.


Restart daemon with {{version}}

Restart the bd daemon to pick up new version:

```bash
bd daemon --stop
bd daemon --start
bd daemon --health  # Verify Version: {{version}}
```


Test issue 2


Fix daemon/direct mode inconsistency in relate and duplicate commands

The relate.go and duplicate.go commands have inconsistent daemon/direct mode handling:

When daemonClient is connected, they resolve IDs via RPC but then perform updates directly via store.UpdateIssue(), bypassing the daemon.

Affected locations:
- relate.go:125-139 (runRelate update)
- relate.go:235-246 (runUnrelate update)
- duplicate.go:120 (runDuplicate update)
- duplicate.go:207 (runSupersede update)

Should either use RPC for updates when daemon is running, or document why direct access is intentional.


bd init should stop running daemon to avoid stale cache

When running bd init, any running daemon continues with stale cached data, causing bd stats and other commands to show old counts.

Repro:
1. Have daemon running with 788 issues cached
2. Clean JSONL to 128 issues, delete db, run bd init
3. bd stats still shows 788 (daemon cache)
4. Must manually run bd daemon --stop

Fix: bd init should automatically stop any running daemon before reinitializing.


Improve test coverage for cmd/bd/setup (28.4% → 50%)

The setup package has only 28.4% test coverage. Setup commands are critical for first-time user experience.

Current coverage: 28.4%
Target coverage: 50%


Review PR #512: clarify bd ready docs

Review and merge PR #512 from aspiers. This PR clarifies what bd ready does after git pull in README.md. Simple 1-line change. URL: https://github.com/anthropics/beads/pull/512


Schema: Add message type and new fields

Add to internal/storage/sqlite/schema.go and models:

New issue_type value:
- message

New optional fields on Issue struct:
- Sender string (who sent this)
- Ephemeral bool (can be bulk-deleted)
- RepliesTo string (issue ID for threading)
- RelatesTo []string (issue IDs for knowledge graph)
- Duplicates string (canonical issue ID)
- SupersededBy string (replacement issue ID)

Update:
- internal/storage/sqlite/schema.go - add columns
- internal/models/issue.go - add fields to struct
- internal/storage/sqlite/sqlite.go - CRUD operations
- Create migration from v0.30.1

Ensure backward compatibility - all new fields optional.


Merge: bd-t4sb

branch: polecat/capable
target: main
source_issue: bd-t4sb
rig: beads


Push version bump to GitHub

git push origin main - triggers CI but no release yet.


Investigate TestRoutingIntegration failure

TestRoutingIntegration/maintainer_with_SSH_remote failed during pre-commit check with "expected role maintainer, got contributor".
This occurred while running `go test -short ./...` on darwin/arm64.
The failure appears unrelated to storage/sqlite changes.
Need to investigate if this is a flaky test or environmental issue.


Mail Commands: bd mail send/inbox/read/ack

Implement core mail commands in cmd/bd/mail.go

Commands:
- bd mail send <recipient> -s 'Subject' -m 'Body' [--urgent]
  - Creates issue with type=message, sender=identity, assignee=recipient
  - --urgent sets priority=0

- bd mail inbox [--from <sender>] [--priority <n>]
  - Lists open messages where assignee=my identity
  - Sorted by priority, then date

- bd mail read <id>
  - Shows full message content (subject, body, sender, timestamp)
  - Does NOT close (separate from ack)

- bd mail ack <id>
  - Marks message as read by closing it
  - Can ack multiple: bd mail ack <id1> <id2> ...

Requires: Identity configuration (bd-kwro.7)


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.


Commit changes and create v0.30.4 tag

```bash
git add -A
git commit -m "chore: Bump version to 0.30.4"
git tag -a v0.30.4 -m "Release v0.30.4"
```

```verify
git describe --tags --exact-match HEAD 2>/dev/null | grep -q 'v0.30.4'
```


Beads Messaging & Knowledge Graph (v0.30.2)

Add messaging semantics and extended graph links to Beads, enabling it to serve as
the universal substrate for knowledge work - issues, messages, documents, and threads
as nodes in a queryable graph.

## Motivation

Gas Town (GGT) needs inter-agent communication. Rather than a separate mail system,
collapse messaging into Beads - one system, one sync, one query interface, all in git.

This also positions Beads as a foundation for:
- Company-wide issue tracking (like Notion)
- Threaded conversations (like Reddit/Slack)
- Knowledge graphs with loose associations
- Arbitrary workflow UIs built on top

## New Issue Type

**message** - ephemeral communication between workers
- sender: who sent it
- assignee: recipient
- priority: P0 (urgent) to P4 (routine)
- status: open (unread) -> closed (read)
- ephemeral: true = can be bulk-deleted after swarm

## New Graph Links

**replies_to** - conversation threading
- Messages reply to messages
- Enables Reddit-style nested threads
- Different from parent_id (not hierarchy, its conversation flow)

**relates_to** - loose see also associations
- Bidirectional knowledge graph edges
- Not blocking, not hierarchical, just related
- Enables discovery and traversal

**duplicates** - deduplication at scale
- Mark issue B as duplicate of canonical issue A
- Close B, link to A
- Essential for large issue databases

**supersedes** - version chains
- Design Doc v2 supersedes Design Doc v1
- Track evolution of artifacts

## New Fields (optional, any issue type)

- sender (string) - who created this (for messages)
- ephemeral (boolean) - can be bulk-deleted when closed

## New Commands

Messaging:
- bd mail send <recipient> -s Subject -m Body
- bd mail inbox (list open messages for me)
- bd mail read <id> (show message content)
- bd mail ack <id> (mark as read/close)
- bd mail reply <id> -m Response (reply to thread)

Graph links:
- bd relate <id1> <id2> (create relates_to link)
- bd duplicate <id> --of <canonical> (mark as duplicate)
- bd supersede <id> --with <new> (mark superseded)

Cleanup:
- bd cleanup --ephemeral (delete closed ephemeral issues)

## Identity Configuration

Workers need identity for sender field:
- BEADS_IDENTITY env var
- Or .beads/config.json: identity field

## Hooks (for GGT integration)

Beads as platform - extensible without knowing about GGT.
Hook files in .beads/hooks/:
- on_create (runs after bd create)
- on_update (runs after bd update)
- on_close (runs after bd close)
- on_message (runs after bd mail send)

GGT registers hooks to notify daemons of new messages.

## Schema Changes (Migration Required)

Add to issue schema:
- type: message (new valid type)
- sender: string (optional)
- ephemeral: boolean (optional)
- replies_to: string (issue ID, optional)
- relates_to: []string (issue IDs, optional)
- duplicates: string (canonical issue ID, optional)
- superseded_by: string (new issue ID, optional)

Migration adds fields as optional - existing beads unchanged.

## Success Criteria

1. bd mail send/inbox/read/ack/reply work end-to-end
2. replies_to creates proper thread structure
3. relates_to, duplicates, supersedes links queryable
4. Hooks fire on create/update/close/message
5. Identity configurable via env or config
6. Migration preserves all existing data
7. All new features have tests


Work on beads-ldv: Fix bd graph crashes with nil pointer ...

Work on beads-ldv: Fix bd graph crashes with nil pointer dereference (GH#657). Fix nil pointer in computeDependencyCounts at graph.go:428. When done, submit MR (not PR) to integration branch for Refinery.


Update LINTING.md with current baseline

After cleanup, document the remaining acceptable baseline in LINTING.md so we can track regression.


Run check-versions.sh - all must pass

Run the version consistency check:
```bash
./scripts/check-versions.sh
```

All versions must match 0.30.4.

```verify
./scripts/check-versions.sh
```


Improve clean vs cleanup command naming/documentation

Clarify the difference between bd clean and bd cleanup to reduce user confusion.

**Current state:**
- bd clean: Remove temporary artifacts (.beads/bd.sock, logs, etc.)
- bd cleanup: Delete old closed issues from database

**Options:**
1. Rename for clarity:
   - bd clean → bd clean-temp
   - bd cleanup → bd cleanup-issues

2. Keep names but improve help text and documentation

3. Add prominent warnings in help output

**Preferred approach:** Option 2 (improve documentation)
- Update short/long descriptions in commands
- Add examples to help text
- Update README.md
- Add cross-references in help output

**Files to modify:**
- cmd/bd/clean.go
- cmd/bd/cleanup.go
- README.md or ADVANCED.md


Update CHANGELOG.md with release notes

Add meaningful release notes to CHANGELOG.md describing what changed in {{version}}


Performance Validation

Confirm no performance regression from cache removal


Run tests and linting

go test -short ./... && golangci-lint run ./...


Unify template.go and mol.go under bd mol

Consolidate the two DAG-template systems into one under the mol command. mol.go (on rictus branch) has the right UX (catalog/show/bond), template.go has the mechanics. Merge them, deprecate bd template commands.


Monitor PyPI publish

Watch the PyPI publish action:
https://github.com/steveyegge/beads/actions/workflows/pypi-publish.yml

Verify at: https://pypi.org/project/beads-mcp/0.30.4/

Check:
```bash
pip index versions beads-mcp 2>/dev/null | grep -q '0.30.4'
```

```verify
pip index versions beads-mcp 2>/dev/null | grep -q '0.30.4' || curl -s https://pypi.org/pypi/beads-mcp/json | jq -e '.releases["0.30.4"]'
```


Add bd daemon --stop-all command to kill all daemon processes

Currently there's no easy way to stop all running bd daemon processes. Users must resort to pkill -f 'bd daemon' or similar shell commands.

Add a --stop-all flag to bd daemon that:
1. Finds all running bd daemon processes (not just the current repo's daemon)
2. Gracefully stops them all
3. Reports how many were stopped

This is useful when:
- Multiple daemons are running and causing race conditions
- User wants a clean slate before running bd sync
- Debugging daemon-related issues


Test message

This is a test message body


Improve version bump molecule with missing steps

During v0.32.1 release, discovered missing steps in the release molecule:

**Missing from molecule:**
1. Rebuild ~/go/bin/bd (only did ~/.local/bin/bd)
2. Install beads-mcp from local source: `uv tool install --reinstall ./integrations/beads-mcp`
3. Restart daemons with `bd daemons killall`
4. (Optional) Publish beads-mcp to PyPI

**Current molecule steps (bd-6s61):**
1. Update CHANGELOG.md
2. Update info.go versionChanges
3. Run bump-version.sh
4. Run tests and linting
5. Update local installation
6. Commit and push release
7. Wait for CI
8. Verify release artifacts

**Proposed additions:**
- After "Update local installation": rebuild BOTH ~/.local/bin/bd AND ~/go/bin/bd
- Add: "Install beads-mcp from source" step
- Add: "Restart daemons" step
- Add: "Verify all versions match" step that checks all artifacts

**Also learned:**
- Must run from mayor/rig to avoid git conflicts with bd sync (already documented in bump-version.sh)

CORRECTION: npm publishing IS automated and working!

**Package naming:**
- OLD: `beads` (npm) - deprecated, stuck at 0.2.1
- CURRENT: `@beads/bd` (npm) - scoped package, auto-published by CI

**How it works:**
- CI uses OIDC trusted publishing (no token needed)
- Workflow: .github/workflows/release.yml → publish-npm job
- Permissions: `id-token: write` enables GitHub OIDC
- To install: `npm install -g @beads/bd` (not `npm install beads`)

**All publishing is automated on tag push:**
1. GitHub Release - goreleaser ✓
2. PyPI - publish-pypi job ✓
3. Homebrew - update-homebrew job ✓
4. npm (@beads/bd) - publish-npm job ✓

**Remaining molecule improvements (local steps only):**
- Rebuild BOTH ~/.local/bin/bd AND ~/go/bin/bd
- Install beads-mcp from source: `uv tool install --reinstall ./integrations/beads-mcp`
- Restart daemons: `bd daemons killall`
- Run from mayor/rig to avoid git conflicts with bd sync
- Final verification step to check all local versions match


Update Homebrew formula

Update the Homebrew tap with new version:

```bash
./scripts/update-homebrew.sh {{version}}
```

This script waits for GitHub Actions to complete (~5 min), then updates the formula with new SHA256 hashes.


Add MCP server functions for repair commands

**Summary:** Added MCP server repair functions for agent dependency management, system validation, and pollution detection. Implemented across BdClientBase, BdCliClient, and daemon clients to enhance system diagnostics and self-healing capabilities.

**Key Decisions:**
- Expose repair_deps(), detect_pollution(), validate() via MCP server
- Create abstract method stubs with fallback to CLI execution
- Use @mcp.tool decorators for function registration

**Resolution:** Successfully implemented comprehensive repair command infrastructure, enabling more robust system health monitoring and automated remediation with full CLI and daemon support.

Implemented all three MCP server functions:

1. **repair_deps(fix=False)** - Find/fix orphaned dependencies
2. **detect_pollution(clean=False)** - Detect/clean test issues
3. **validate(checks=None, fix_all=False)** - Run comprehensive health checks

Changes:
- Added abstract methods to BdClientBase
- Implemented in BdCliClient (CLI execution)
- Added NotImplementedError stubs in BdDaemonClient (falls back to CLI)
- Created wrapper functions in tools.py
- Registered @mcp.tool decorators in server.py

All commands tested and working with --no-daemon flag.


GH#505: Add bd reset/wipe command

Add command to cleanly reset/wipe beads database. User reports painful manual process to start fresh. See GitHub issue #505.


Update local installation

Run install script or brew upgrade to get new version locally: curl -fsSL .../install.sh | bash


Update documentation for template system

Update AGENTS.md and help text to document the new template system:

- How to create a template (epic + template label + child issues)
- How to define variables (just use {{name}} placeholders)
- How to instantiate (bd template instantiate)
- Migration from YAML workflows (if any users had custom ones)


Split monolithic sqlite.go into focused files

internal/storage/sqlite/sqlite.go is 1050 lines containing initialization, 20+ CRUD methods, query building, and schema management.

Split into:
- store.go: Store struct & initialization (150 lines)
- bead_queries.go: Bead CRUD (300 lines)
- work_queries.go: Work queries (200 lines)
- stats_queries.go: Statistics (150 lines)
- schema.go: Schema & migrations (150 lines)
- helpers.go: Common utilities (100 lines)

Impact: Impossible to understand at a glance; hard to find specific functionality; high cognitive load

Effort: 6-8 hours


GH#444: Fix inconsistent status naming in_progress vs in-progress

Documentation uses in-progress (hyphen) but code expects in_progress (underscore). Update all docs to use canonical in_progress. See GitHub issue #444.


Release v{{version}}

Version bump workflow for beads release {{version}}.

## Variables
- `{{version}}` - The new version number (e.g., 0.31.0)
- `{{date}}` - Release date (YYYY-MM-DD format)

## Workflow Steps
1. Kill running daemons
2. Run tests and linting
3. Bump version in all files (10 files total)
4. Update cmd/bd/info.go with release notes
5. Commit and push version bump
6. Create and push git tag
7. Update Homebrew formula
8. Upgrade local Homebrew installation
9. Verify installation

## Files Updated by bump-version.sh
- cmd/bd/version.go
- .claude-plugin/plugin.json
- .claude-plugin/marketplace.json
- integrations/beads-mcp/pyproject.toml
- integrations/beads-mcp/src/beads_mcp/__init__.py
- README.md
- npm-package/package.json
- cmd/bd/templates/hooks/* (4 files)
- CHANGELOG.md

## Manual Step Required
- cmd/bd/info.go - Add versionChanges entry with release notes


Work on beads-wkt: Output control parameters for MCP tool...

Work on beads-wkt: Output control parameters for MCP tools (GH#622). Add brief, fields, max_description_length params to ready/list/show. When done, submit MR (not PR) to integration branch for Refinery.


Add integration tests for RPC server and event loops

After adding basic unit tests for daemon utilities, the complex daemon functions still need integration tests:

Core daemon lifecycle:
- startRPCServer: Initializes and starts RPC server with proper error handling
- runEventLoop: Polling-based sync loop with parent monitoring and signal handling
- runDaemonLoop: Main daemon initialization and setup

Health checking:
- isDaemonHealthy: Checks daemon responsiveness and health metrics
- checkDaemonHealth: Periodic health verification

These require more complex test infrastructure (mock RPC, test contexts, signal handling) and should be tackled after the unit test foundation is in place.


Implement backup functionality for reset

Add backup capability that can be used by reset command.

## Functionality
- Copy .beads/ to .beads-backup-{timestamp}/
- Timestamp format: YYYYMMDD-HHMMSS
- Preserve file permissions
- Return backup path for user feedback

## Location
`internal/reset/backup.go` - keep with reset package for now (YAGNI)

## Interface
```go
func CreateBackup(beadsDir string) (backupPath string, err error)
```

## Notes
- Simple recursive file copy, no compression needed
- Error if backup dir already exists (unlikely with timestamp)
- Backup directories SHOULD be gitignored
- Add `.beads-backup-*/` pattern to .beads/.gitignore template in doctor package
- Consider: ListBackups() for future `bd backup list` command (not for this PR)


bd preflight: PR readiness checks for contributors

## Vision

Encode project-specific institutional knowledge into executable checks. CONTRIBUTING.md is documentation that's read once and forgotten; `bd preflight` is documentation that runs at exactly the right moment.

## Problem Statement

Contributors face a "last mile" problem - they do the work but stumble on project-specific gotchas at PR time:
- Nix vendorHash gets stale when go.sum changes
- Beads artifacts leak into PRs (see bd-umbf for namespace solution)
- Version mismatches between version.go and default.nix
- Tests/lint not run locally before pushing
- Other project-specific checks that only surface when CI fails

These are too obscure to remember, exist in docs nobody reads end-to-end, and waste CI round-trips.

## Why beads?

Beads already has a foothold in the contributor workflow. It knows:
- Git state (staged files, branch, dirty status)
- Project structure
- The specific issue being worked on
- Project-specific configuration

## Proposed Interface

### Tier 1: Checklist Mode (v1)

    $ bd preflight
    PR Readiness Checklist:

    [ ] Tests pass: go test -short ./...
    [ ] Lint passes: golangci-lint run ./...
    [ ] No beads pollution: check .beads/issues.jsonl diff
    [ ] Nix hash current: go.sum unchanged or vendorHash updated
    [ ] Version sync: version.go matches default.nix

    Run 'bd preflight --check' to validate automatically.

### Tier 2: Check Mode (v2)

    $ bd preflight --check
    ✓ Tests pass
    ✓ Lint passes
    ⚠ Beads pollution: 3 issues in diff - are these project issues or personal?
    ✗ Nix hash stale: go.sum changed, vendorHash needs update
      Fix: sha256-KRR6dXzsSw8OmEHGBEVDBOoIgfoZ2p0541T9ayjGHlI=
    ✓ Version sync

    1 error, 1 warning. Run 'bd preflight --fix' to auto-fix where possible.

### Tier 3: Fix Mode (v3)

    $ bd preflight --fix
    ✓ Updated vendorHash in default.nix
    ⚠ Cannot auto-fix beads pollution - manual review needed

## Checks to Implement

| Check | Description | Auto-fixable |
|-------|-------------|--------------|
| tests | Run go test -short ./... | No |
| lint | Run golangci-lint | Partial (gofmt) |
| beads-pollution | Detect personal issues in diff | No (see bd-umbf) |
| nix-hash | Detect stale vendorHash | Yes (if nix available) |
| version-sync | version.go matches default.nix | Yes |
| no-debug | No TODO/FIXME/console.log | Warn only |
| clean-stage | No unintended files staged | Warn only |

## Future: Configuration

Make checks configurable per-project via .beads/preflight.yaml:

    preflight:
      checks:
        - name: tests
          run: go test -short ./...
          required: true
        - name: no-secrets
          pattern: "**/*.env"
          staged: deny
        - name: custom-check
          run: ./scripts/validate.sh

This lets any project using beads define their own preflight checks.

## Implementation Phases

### Phase 1: Static Checklist
- Implement bd preflight with hardcoded checklist for beads
- No execution, just prints what to check
- Update CONTRIBUTING.md to reference it

### Phase 2: Automated Checks
- Implement bd preflight --check
- Run tests, lint, detect stale hashes
- Clear pass/fail/warn output

### Phase 3: Auto-fix
- Implement bd preflight --fix
- Fix vendorHash, version sync
- Integrate with bd-umbf solution for pollution

### Phase 4: Configuration
- .beads/preflight.yaml support
- Make it useful for other projects using beads
- Plugin/hook system for custom checks

## Dependencies

- bd-umbf: Namespace isolation for beads pollution (blocking for full solution)

## Success Metrics

- Fewer CI failures on first PR push
- Reduced "fix nix hash" commits
- Contributors report preflight caught issues before CI


Thread Test

Testing the thread feature


Work on beads-eub: Consolidated context tool for MCP serv...

Work on beads-eub: Consolidated context tool for MCP server (GH#636). Merge set_context, where_am_i, init into single 'context' tool. When done, submit MR (not PR) to integration branch for Refinery.


Add tests for mol spawn --attach

Code review (bd-obep) found no tests for the spawn --attach functionality.

**Test cases needed:**
1. Basic attach - spawn proto with one --attach
2. Multiple attachments - spawn with --attach A --attach B
3. Attach types - verify sequential vs parallel bonding
4. Error case: attaching non-proto (missing template label)
5. Variable aggregation - vars from primary + attachments combined
6. Dry-run output includes attachment info

**Implementation notes:**
- Tests should use in-memory storage
- Create test protos, spawn with attachments, verify dependency structure
- Check that sequential uses 'blocks' type, parallel uses 'parent-child'


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.


Test suite hangs/never finishes

Running 'go test ./... -count=1' hangs indefinitely. The full test suite never completes, making it difficult to verify changes. Need to investigate which tests are hanging and fix or add timeouts.


Hooks System

Implement hook system for extensibility.

Hook directory: .beads/hooks/
Hook files (executable scripts):
- on_create - runs after bd create
- on_update - runs after bd update
- on_close - runs after bd close
- on_message - runs after bd mail send

Hook invocation:
- Pass issue ID as first argument
- Pass event type as second argument
- Pass JSON issue data on stdin
- Run asynchronously (dont block command)

Example hook (GGT notification):
  #!/bin/bash
  gt notify --event=$2 --issue=$1

This allows GGT to register notification handlers without Beads knowing about GGT.


Fix TestRunSync_Timeout failing on macOS

The hooks timeout test fails because exec.CommandContext doesn't properly terminate child processes of shell scripts on macOS. The test creates a hook that runs 'sleep 60' with a 500ms timeout, but it waits the full 60 seconds.

Options to fix:
- Use SysProcAttr{Setpgid: true} to create process group and kill the group
- Skip test on darwin with build tag
- Use a different approach for timeout testing

Location: internal/hooks/hooks_test.go:220-253


Add tests for import/export functionality

Import/export functions like ImportIssues, exportToJSONLWithStore, and AutoImportIfNewer have low coverage. These are critical for data integrity and multi-repo synchronization.


Fix unparam unused parameter in cmd/bd/doctor.go:1879

Linting issue: checkGitHooks - path is unused (unparam) at cmd/bd/doctor.go:1879:20. Error: func checkGitHooks(path string) doctorCheck {


Update CHANGELOG.md for 0.30.4

1. Change `## [Unreleased]` to `## [0.30.4] - 2025-12-17`
2. Add new empty `## [Unreleased]` section at top
3. Ensure all changes since 0.30.3 are documented


Correction: Pinned field already in v0.31.0

Quick correction - the Pinned field is already in the current bd v0.31.0:

```go
// In beads internal/types/types.go
Pinned bool `json:"pinned,omitempty"`
```

So you just need to:
1. Add `Pinned bool `json:"pinned,omitempty"`` to BeadsMessage in types.go
2. Sort pinned messages first in listBeads() after fetching

No migration needed - the field is already there.

-- Mayor


Commit and push release

git add -A && git commit -m 'chore: bump version to 0.32.1' && git push


Timer beads for scheduled agent callbacks

## Problem

Agents frequently need to wait for external events (CI completion, PR reviews, artifact builds) but have no good mechanism:
- `sleep N` blocks and is unreliable (often times out at 8+ minutes)
- Polling wastes context and is easy to forget
- No way to survive session restarts

## Proposal: Timer Beads

A new bead type or field that represents a scheduled callback:

### Creating timers
```bash
bd timer create --in 30s --callback "Check CI run 12345" --issue bd-xyz
bd timer create --at "2025-12-20T08:00:00" --callback "Morning standup"
bd timer create --in 5m --on-expire "tmux send-keys -t dave 'bd show bd-xyz'"
```

### Timer storage
- Store in beads (survives restarts)
- Fields: `expires_at`, `callback_description`, `on_expire_command`, `linked_issue`
- Status: pending, fired, cancelled

### Deacon integration
The Deacon daemon monitors timer beads:
1. Wakes on next timer expiry
2. Executes `on_expire` command (e.g., tmux send-keys to interrupt agent)
3. Marks timer as fired
4. Optionally updates linked issue

### Use cases
- CI monitoring: "ping me when build completes"
- PR reviews: "check back in 1 hour"
- Scheduled tasks: "remind me at EOD to sync"
- Blocking waits: agent registers callback instead of sleeping

## Acceptance criteria
- [ ] Timer bead type or field design
- [ ] `bd timer create/list/cancel` commands
- [ ] Deacon timer monitoring loop
- [ ] tmux integration for agent interrupts
- [ ] Survives daemon restarts


doctor --fix should export when DB has more issues than JSONL

When 'bd doctor' detects a count mismatch (DB has more issues than JSONL), it currently recommends 'bd sync --import-only', which imports JSONL into DB. But JSONL is the source of truth, not the DB.

**Current behavior:**
- Doctor detects: DB has 355 issues, JSONL has 292
- Recommends: 'bd sync --import-only'
- User runs it: Returns '0 created, 0 updated' (no-op, because JSONL hasn't changed)
- User is stuck

**Root cause:**
The doctor fix is one-directional (JSONL→DB) when it should be bidirectional. If DB has MORE issues, they haven't been exported yet - the fix should be 'bd export' (DB→JSONL), not import.

**Desired fix:**
In fix.DBJSONLSync(), detect which has more data:
- If DB > JSONL: Run 'bd export' to sync JSONL (since DB is the working copy)
- If JSONL > DB: Run 'bd sync --import-only' to import (JSONL is source of truth)
- If equal but timestamps differ: Detect based on file mtime

This makes 'bd doctor --fix' actually fix the problem instead of being a no-op.


Update Homebrew formula

After GoReleaser completes, the Homebrew tap should be auto-updated.

If manual update needed:
```bash
./scripts/update-homebrew.sh v0.30.4
```

Or manually update steveyegge/homebrew-beads with new SHA256.

Verify:
```bash
brew update
brew info beads
```


Remove unreachable utility functions

Several small utility functions are unreachable:

Files to clean:
1. `internal/storage/sqlite/hash.go` - `computeIssueContentHash` (line 17)
   - Check if entire file can be deleted if only contains this function

2. `internal/config/config.go` - `FileUsed` (line 151)
   - Delete unused config helper

3. `cmd/bd/git_sync_test.go` - `verifyIssueOpen` (line 300)
   - Delete dead test helper

4. `internal/compact/haiku.go` - `HaikuClient.SummarizeTier2` (line 81)
   - Tier 2 summarization not implemented
   - Options: implement feature OR delete method

Impact: Removes 50-100 LOC depending on decisions


bd doctor should recommend bd prime migration for existing repos

bd doctor should detect old beads integration patterns and recommend migrating to bd prime approach.

## Current behavior
- bd doctor checks if Claude hooks are installed globally
- Doesn't check project-level integration (AGENTS.md, CLAUDE.md)
- Doesn't recommend migration for repos using old patterns

## Desired behavior
bd doctor should detect and suggest:

1. **Old slash command pattern detected**
   - Check for /beads:* references in AGENTS.md, CLAUDE.md
   - Suggest: These slash commands are deprecated, use bd prime hooks instead

2. **No agent documentation**
   - Check if AGENTS.md or CLAUDE.md exists
   - Suggest: Run 'bd onboard' or 'bd setup claude' to document workflow

3. **Old MCP-only pattern**
   - Check for instructions to use MCP tools but no bd prime hooks
   - Suggest: Add bd prime hooks for better token efficiency

4. **Migration path**
   - Show: 'Run bd setup claude to add SessionStart/PreCompact hooks'
   - Show: 'Update AGENTS.md to reference bd prime instead of slash commands'

## Example output

⚠ Warning: Old beads integration detected in CLAUDE.md
  Found: /beads:* slash command references (deprecated)
  Recommend: Migrate to bd prime hooks for better token efficiency
  Fix: Run 'bd setup claude' and update CLAUDE.md

💡 Tip: bd prime + hooks reduces token usage by 80-99% vs slash commands
  MCP mode: ~50 tokens vs ~10.5k for full MCP scan
  CLI mode: ~1-2k tokens with automatic context recovery

## Benefits
- Helps existing repos adopt new best practices
- Clear migration path for users
- Better token efficiency messaging


wish: list & ready show issues as hierarchy tree

`bd ready` and `bd list` just show a flat list, and it's up to the reader to parse which ones are dependent or sub-issues of others. It would be much easier to understand if they were shown in a tree format


Improve test coverage

The test suite reports less than 45% code coverage. Identify the specific uncovered areas of the codebase, including modules, functions, or features. Rank them by potential impact on system reliability and business value, from most to least, and provide actionable recommendations for improving coverage in each area.


Add {{version}} to versionChanges in info.go

Add new entry at TOP of versionChanges in cmd/bd/info.go with release notes from CHANGELOG.md. Must do before bump-version.sh --commit.


Ghost resurrection: remote status:closed wins during git merge

During bd sync, the 3-way git merge sometimes keeps remote's status:closed instead of local's status:tombstone. This causes ghost issues to resurrect even when tombstones exist.

Root cause: Git 3-way merge doesn't understand tombstone semantics. If base had closed, local changed to tombstone, and remote has closed, git might keep remote's version.

The early tombstone check in importer.go only prevents CREATION when tombstones exist in DB. But if applyDeletionsFromMerge hard-deletes the tombstones before import runs (because they're not in the merged result), the check doesn't help.

Potential fixes:
1. Make tombstones 'win' in the beads merge driver (internal/merge/merge.go)
2. Don't hard-delete tombstones in applyDeletionsFromMerge if they're in the DB
3. Export tombstones to a separate file that's not subject to merge

Ghost issues: bd-cb64c226.*, bd-cbed9619.*


Upgrade local Homebrew installation

Upgrade bd via Homebrew:

```bash
brew update
brew upgrade bd
/opt/homebrew/bin/bd version  # Verify shows {{version}}
```


Systematic bd sync stability investigation

## Context

bd sync has chronic instability issues that have persisted since inception:
- issues.jsonl is always dirty after push
- bd sync often creates messes requiring manual cleanup
- Problems escalating despite accumulated bug fixes
- Workarounds are getting increasingly draconian

## Goal

Systematically observe and diagnose bd sync failures rather than applying band-aid fixes.

## Approach

1. Start fresh session with latest binary (all fixes applied)
2. Run bd sync and carefully observe what happens
3. Document exact sequence of events when things go wrong
4. File specific issues for each discrete problem identified
5. Track the root causes, not just symptoms

## Test Environment

- Fresh clone or clean state
- Latest bd binary with all bug fixes
- Monitor both local and remote JSONL state
- Check for timing issues, race conditions, merge conflicts

## Success Criteria

- Identify root causes of sync instability
- Create actionable issues for each problem
- Eventually achieve stable bd sync (no manual intervention needed)


Add comments to 30+ silently ignored errors or fix them

Code health review found 30+ instances of error suppression using blank identifier without explanation:

Good examples (with comments):
- merge.go: _ = gitRmCmd.Run() // Ignore errors
- daemon_watcher.go: _ = watcher.Add(...) // Ignore error

Bad examples (no context):
- create.go:213: dbPrefix, _ = store.GetConfig(ctx, "issue_prefix")
- daemon_sync_branch.go: _ = daemonClient.Close()
- migrate_hash_ids.go, version_tracking.go: _ = store.Close()

Fix: Add comments explaining WHY errors are ignored, or handle them properly.


Phase 2.4: Git merge driver optimization for TOON format

Optimize git 3-way merge for TOON line-oriented format.

## Overview
TOON is line-oriented (unlike binary formats), enabling smarter git merge strategies. Implement custom merge driver to handle TOON-specific merge patterns.

## Required Work

### 2.4.1 TOON Merge Driver
- [ ] Create .git/info/attributes entry for *.toon files
- [ ] Implement custom merge driver script/command
- [ ] Handle tabular format row merges (line-based 3-way)
- [ ] Handle YAML-style format merges
- [ ] Conflict markers for unsolvable conflicts

### 2.4.2 Merge Patterns
- [ ] Row addition: both branches add different rows → union
- [ ] Row deletion: one branch deletes, other modifies → conflict (manual review)
- [ ] Row modification: concurrent field changes → intelligent merge or conflict
- [ ] Field ordering changes: ignore (TOON format resilient to order)

### 2.4.3 Testing & Documentation
- [ ] Unit tests for merge scenarios (3-way merge logic)
- [ ] Integration tests with actual git merges
- [ ] Conflict scenario testing
- [ ] Documentation of merge strategy

## Success Criteria
- Git merge handles TOON conflicts intelligently
- Fewer manual merge conflicts than JSONL
- Round-trip preserved through merges
- All 70+ tests still passing
- Git history stays clean (minimal conflict markers)


Fix bd sync race condition with daemon causing dirty working directory

After bd sync completes with sync.branch mode, subsequent bd commands or daemon file watcher would see a hash mismatch and trigger auto-import, which then schedules re-export, dirtying the working directory.

**Root cause:**
1. bd sync exports JSONL with NEW content (hash H1)
2. bd sync updates jsonl_content_hash = H1 in DB
3. bd sync restores JSONL from HEAD (OLD content, hash H0)
4. Now: file hash = H0, DB hash = H1 (MISMATCH)
5. Daemon or next CLI command sees mismatch, imports from OLD JSONL
6. Import triggers re-export → file is dirty

**Fix:**
After restoreBeadsDirFromBranch(), update jsonl_content_hash to match the restored file's hash. This ensures daemon and CLI see file hash = DB hash → no spurious import/export cycle.

Related: bd-c83r (multiple daemon prevention)


Polecats get stuck on interactive shell prompts (cp/mv/rm -i)

During swarm operations, polecats frequently get stuck waiting for interactive prompts from shell commands like:
- cp prompting 'overwrite file? (y/n)'
- mv prompting 'overwrite file? (y/n)'
- rm prompting 'remove file?'

This happens because macOS aliases or shell configs may have -i flags set by default.

Root cause: Claude Code runs commands that trigger interactive confirmation prompts, but cannot respond to them, causing the agent to hang indefinitely.

Observed in: Multiple polecats during GH issues swarm (Dec 2024)
- Derrick, Roustabout, Prospector, Warboy all got stuck on y/n prompts

Suggested fixes:
1. AGENTS.md should instruct agents to always use -f flag with cp/mv/rm
2. Polecat startup could set shell aliases to use non-interactive versions
3. bd prime hook could include guidance about non-interactive commands
4. Consider detecting stuck prompts and auto-recovering


Documentation for messaging and graph links

Document all new features.

Files to update:
- README.md - brief mention of messaging capability
- AGENTS.md - update for AI agents using bd mail
- docs/messaging.md (new) - full messaging reference
- docs/graph-links.md (new) - graph link reference
- CHANGELOG.md - v0.30.2 release notes

Topics to cover:
- Mail commands with examples
- Graph link types and use cases
- Identity configuration
- Hooks setup for notifications
- Migration notes


Add date and priority filters to bd search

Add filter parity with bd list for consistent querying.

**Missing filters to add:**
- --priority, --priority-min, --priority-max
- --created-after, --created-before
- --updated-after, --updated-before
- --closed-after, --closed-before
- --empty-description, --no-assignee, --no-labels
- --desc-contains, --notes-contains

**Files to modify:**
- cmd/bd/search.go
- internal/rpc/protocol.go (SearchArgs)
- internal/storage/storage.go (Search method)

**Testing:**
- All filter combinations
- Date format parsing
- Daemon and direct mode


Sync race: rebase-based divergence recovery resurrects tombstones

## Problem
When two repos sync simultaneously, tombstones can be resurrected:

1. Repo A deletes issue (creates tombstone), pushes to sync branch
2. Repo B (with 'closed' status) exports and tries to push
3. Push fails (non-fast-forward)
4. fetchAndRebaseInWorktree does git rebase
5. Git rebase applies B's 'closed' patch on top of A's 'tombstone'
6. TEXT-level rebase doesn't invoke beads merge driver
7. 'closed' overwrites 'tombstone' = resurrection

## Root Cause
CommitToSyncBranch uses git rebase for divergence recovery, but rebase is text-level, not content-level. The proper content-level merge in PullFromSyncBranch handles tombstones correctly, but it runs AFTER the problematic push.

## Proposed Fix
Option 1: Don't push in CommitToSyncBranch - let PullFromSyncBranch handle merge+push
Option 2: Replace git rebase with content-level merge in fetchAndRebaseInWorktree
Option 3: Reorder sync steps: Export → Pull/Merge → Commit → Push

## Workaround Applied
Excluded tombstones from orphan detection warnings (commit 1e97d9cc).

See also: bd-3852 (Add orphan detection migration)


Phase 1.1: TOON Library Integration - Add gotoon dependency

Add gotoon (github.com/alpkeskin/gotoon) to go.mod and create internal/toon wrapper package for TOON encoding/decoding. This enables bdtoon to encode Issue structs to TOON format and decode TOON back to issues.

## Subtasks
1. Add gotoon dependency: go get github.com/alpkeskin/gotoon
2. Create internal/toon package with wrapper functions
3. Write encode tests for Issue struct round-trip conversion
4. Write decode tests for TOON to Issue conversion
5. Add gotoon API options to wrapper (indent, delimiter, length markers)

## Success Criteria
- go.mod includes gotoon dependency
- internal/toon/encode.go exports EncodeTOON(issues) ([]byte, error)
- internal/toon/decode.go exports DecodeTOON(data []byte) ([]Issue, error)
- Round-trip tests verify Issue → TOON → Issue produces identical data
- Tests pass with: go test ./internal/toon -v


Fix G304 potential file inclusion in cmd/bd/tips.go:259

Linting issue: G304: Potential file inclusion via variable (gosec) at cmd/bd/tips.go:259:18. Error: if data, err := os.ReadFile(settingsPath); err == nil {


Implement transaction retry logic for SQLITE_BUSY

BEGIN IMMEDIATE fails immediately on SQLITE_BUSY instead of retrying with exponential backoff.

Location: internal/storage/sqlite/sqlite.go:223-225

Problem:
- Under concurrent write load, BEGIN IMMEDIATE can fail with SQLITE_BUSY
- Current implementation fails immediately instead of retrying
- Results in spurious failures under normal concurrent usage

Solution: Implement exponential backoff retry:
- Retry up to N times (e.g., 5)
- Backoff: 10ms, 20ms, 40ms, 80ms, 160ms
- Check for context cancellation between retries
- Only retry on SQLITE_BUSY/database locked errors

Impact: Spurious failures under concurrent write load

Effort: 3 hours


Final release verification

Verify all release artifacts are accessible:

- [ ] `bd --version` shows 0.30.4
- [ ] `bd version --daemon` shows 0.30.4
- [ ] GitHub release exists: https://github.com/steveyegge/beads/releases/tag/v0.30.4
- [ ] `brew upgrade beads && bd --version` shows 0.30.4 (if using Homebrew)
- [ ] `pip show beads-mcp` shows 0.30.4
- [ ] npm package available at 0.30.4
- [ ] `bd info --whats-new` shows 0.30.4 notes

Run final checks:
```bash
bd --version
bd version --daemon
pip show beads-mcp | grep Version
bd info --whats-new
```


Improve bd doctor output formatting for better readability

The current bd doctor output is a wall of text that's hard to process. Consider improvements like:
- Grouping related checks into collapsible sections
- Using color/bold for section headers
- Showing only failures/warnings by default with --verbose for full output
- Better visual hierarchy between major sections
- Summary line at top (e.g., '24 checks passed, 0 warnings, 0 errors')


Update hook templates to 0.30.4

Update bd-hooks-version comment in all 4 hook templates:
- cmd/bd/templates/hooks/pre-commit
- cmd/bd/templates/hooks/post-merge
- cmd/bd/templates/hooks/pre-push
- cmd/bd/templates/hooks/post-checkout

Each should have:
```bash
# bd-hooks-version: 0.30.4
```

```verify
grep -l 'bd-hooks-version: 0.30.4' cmd/bd/templates/hooks/* | wc -l | grep -q '4'
```


Verify release artifacts

Check GitHub releases page - binaries for darwin/linux/windows should be available


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.


Document sync.branch 'always dirty' working tree behavior

## Context

When sync.branch is configured, the .beads/issues.jsonl file in main's working tree is ALWAYS dirty. This is by design:

1. bd sync commits to beads-sync branch (via worktree)
2. bd sync copies JSONL to main's working tree (so CLI commands work)
3. This copy is NOT committed to main (to reduce commit noise)

Contributors who watch main branch history pushed for sync.branch to avoid constant beads commit noise. But users need to understand the trade-off.

## Documentation Needed

Update README.md sync.branch section with:

1. **Clear explanation** of why .beads/ is always dirty on main
2. **"Be Zen about it"** - this is expected, not a bug
3. **Workflow options:**
   - Accept dirty state, use `bd sync --merge` periodically to snapshot to main
   - Or disable sync.branch if clean working tree is more important
4. **Shell alias tip** to hide beads from git status:
   ```bash
   alias gs='git status -- ":!.beads/"'
   ```
5. **When to merge**: releases, milestones, or periodic snapshots

## Related

- bd-7b7h: Fix that allows bd sync --merge to work with dirty .beads/
- bd-elqd: Investigation that identified this as expected behavior


Add bd template list command

Add a convenience command to list available templates:

bd template list

This is equivalent to 'bd list --label=template' but more discoverable.
Could also show variable placeholders found in each template.


Consolidate duplicate path-finding utilities (findJSONLPath, findBeadsDir, findGitRoot)

Code health review found these functions defined in multiple places:

- findJSONLPath() in autoflush.go:45-73 and doctor/fix/migrate.go
- findBeadsDir() in autoimport.go:197-239 (with git worktree handling)
- findGitRoot() in autoimport.go:242-269 (Windows path conversion)

The beads package has public FindBeadsDir() and FindJSONLPath() APIs that should be used consistently.

Impact: Bug fixes need to be applied in multiple places. Git worktree handling may not be replicated everywhere.

Fix: Consolidate all implementations to use the beads package APIs. Remove duplicates.


bd sync --from-main fails: unknown flag --no-git-history


Fix TestImportBugIntegration deadlock in importer_test.go

Code health review found internal/importer/importer_test.go has TestImportBugIntegration skipped with:

TODO: Test hangs due to database deadlock - needs investigation

This indicates a potential unresolved concurrency issue in the importer. The test has been skipped for an unknown duration.

Fix: Investigate the deadlock, fix the underlying issue, and re-enable the test.


Implement or remove ExpectExit/ExpectStdout verification fields

The Verification struct in internal/types/workflow.go has ExpectExit and ExpectStdout fields that are never used by workflowVerifyCmd. Either implement the functionality or remove the dead fields.


Work on beads-ocs: Thin shim hooks to eliminate version d...

Work on beads-ocs: Thin shim hooks to eliminate version drift (GH#615). Replace full hook scripts with thin shims that call bd hooks run. When done, submit MR (not PR) to integration branch for Refinery.


bd graph crashes with --no-daemon on closed issues

The `bd graph` command panics with nil pointer dereference when using `--no-daemon` flag on an issue with closed children.

**Reproduction:**
```bash
bd graph bd-qqc --no-daemon
# panic: runtime error: invalid memory address or nil pointer dereference
# in main.computeDependencyCounts
```

**Stack trace:**
```
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0x20 pc=0x1010bdfb0]

goroutine 1 [running]:
main.computeDependencyCounts(...)
    /Users/stevey/gt/beads/crew/emma/cmd/bd/graph.go:428
main.renderGraph(0x1400033bb80, 0x0)
    /Users/stevey/gt/beads/crew/emma/cmd/bd/graph.go:307 +0x300
```

**Location:** cmd/bd/graph.go:428 - computeDependencyCounts() not handling nil case


Add bd doctor --fix flag to automatically repair issues

Implement a --fix flag for bd doctor that can automatically repair detected issues.

Requirements:
- Add --fix flag to bd doctor command
- Show all fixable issues and prompt for confirmation before applying fixes
- Organize fix implementations under doctor/fix/<type_of_fix>.go
- Each fix type should have its own file (e.g., doctor/fix/hooks.go, doctor/fix/sync.go)
- Display what will be fixed and ask user to confirm (Y/n) before proceeding
- Support fixing issues like:
  - Missing or broken git hooks
  - Sync problems with remote
  - File permission issues
  - Any other auto-repairable issues doctor detects

Implementation notes:
- Maintain separation between detection (existing doctor code) and repair (new fix code)
- Each fix should be idempotent and safe to run multiple times
- Provide clear output about what was fixed
- Log any fixes that fail with actionable error messages


Investigate charmbracelet-based TUI for beads

Now that we've merged the create-form command (PR #603) which uses charmbracelet/huh, investigate whether beads should have a more comprehensive TUI.

Considerations:
- Should this be in core or a separate binary (bd-tui)?
- What functionality would benefit from a TUI? (list view, issue details, search, bulk operations)
- Plugin/extension architecture vs build tags vs separate binary
- Dependency cost vs user experience tradeoff
- Target audience: humans who want interactive workflows vs CLI/scripting users

Related: PR #603 added charmbracelet/huh dependency for create-form command.

Foundation is in place (lipgloss, huh), but not a priority right now


Delete server_cache_storage.go

Remove the entire cache implementation file (~286 lines)


> bd sync --no-daemon
→ Exporting pending changes to JSONL...
→ Committing changes to sync branch 'beads-sync'...
Error committing to sync branch: failed to create worktree: failed to create worktree parent directory: mkdir /var/home/matt/dev/beads/fix-ci/.git: not a directory

**Problem Diagnosed**: The `bd sync` command was failing with "mkdir /var/home/matt/dev/beads/fix-ci/.git: not a directory" because it was being executed from the wrong directory.

**Root Cause**: The command was run from `/var/home/matt/dev/beads` (where the `fix-ci` worktree exists) instead of the main repository directory `/var/home/matt/dev/beads/main`. Since `fix-ci` is a git worktree with a `.git` file (not directory), the worktree creation logic failed when trying to create `<current_dir>/.git/beads-worktrees/<branch>`.

**Solution Verified**: Execute `bd sync` from the main repository directory:
```bash
cd main && bd sync --dry-run
```


Show pin indicator in bd list output

Add a visual indicator (e.g., pin emoji or [P] marker) for pinned issues in bd list output so users can easily identify them.


Fix --as flag: uses title instead of ID in mol bond

In bondProtoProto, the --as flag is documented as 'Custom ID for compound proto' but the implementation uses it as the title, not the issue ID.

**Current behavior (mol.go:637-638):**
```go
if customID != '' {
    compoundTitle = customID  // Used as title, not ID
}
```

**Options:**
1. Change flag description to say 'Custom title' (documentation fix)
2. Actually use it as a custom ID prefix or full ID (feature change)
3. Add separate --title flag and make --as actually set ID

Recommend option 1 for simplest fix - change 'Custom ID' to 'Custom title' in the flag description.


Code review: bd mol bond implementation

Review the mol bond command implementation before shipping.

Focus areas:
1. runMolBond() - polymorphic dispatch logic correctness
2. bondProtoProto() - compound proto creation, dependency wiring
3. bondProtoMol() / bondMolProto() - spawn and attach logic
4. bondMolMol() - joining molecules, lineage tracking
5. BondRef usage - is lineage tracked correctly?
6. Error handling - are all failure modes covered?
7. Edge cases - what could go wrong?

File: cmd/bd/mol.go (lines 485-859)
Commit: 386b513e


Phase 2.5: TOON-based daemon sync

Implement TOON-native daemon sync (replaces JSONL sync machinery).

## Overview
Daemon sync is the final integration point. Replace export/import/merge machinery with TOON-native sync, building on deletion tracking (2.3) and merge optimization (2.4).

## Required Work

### 2.5.1 TOON-based Daemon Sync
- [ ] Understand current JSONL sync machinery (export.go, import.go, merge.go)
- [ ] Replace export step with TOON encoding (EncodeTOON)
- [ ] Replace import step with TOON decoding (DecodeTOON)
- [ ] Replace merge step with TOON-aware 3-way merge
- [ ] Update daemon auto-sync to read/write TOON
- [ ] Verify 5-second debounce still works

### 2.5.2 Deletion Sync Integration
- [ ] Load deletions.toon during import phase
- [ ] Apply deletions after merging issues
- [ ] Ensure deletion TTL respects daemon schedule

### 2.5.3 Testing
- [ ] Unit tests for daemon sync with TOON
- [ ] Integration tests with actual daemon operations
- [ ] Multi-clone sync scenarios with concurrent edits
- [ ] Performance comparison with JSONL sync
- [ ] Long-running daemon stability tests

## Success Criteria
- Daemon reads/writes TOON format (not JSONL)
- Sync latency comparable to JSONL (<100ms)
- All 70+ tests passing
- bdt commands work seamlessly with daemon
- Multi-clone sync scenarios work correctly


Implement content-first idempotent import

**Summary:** Refactored issue import to be content-first and idempotent, ensuring consistent data synchronization across multiple import rounds by prioritizing content hash matching over ID-based updates.

**Key Decisions:**
- Implement content hash as primary matching mechanism
- Create global collision resolution algorithm
- Ensure importing same data multiple times results in no-op

**Resolution:** The new import strategy guarantees predictable convergence across distributed systems, solving rename detection and collision handling while maintaining data integrity during multi-stage imports.


Add empty tasks validation in workflow create

workflow.go:321 will panic if wf.Tasks is empty. Add validation that len(wf.Tasks) > 0 before accessing wf.Tasks[0].


Bump version in all files

Run ./scripts/bump-version.sh {{version}} to update 10 version files. Then run with --commit after info.go is updated.


Auto-detect identity from directory context for bd mail

Currently bd mail inbox defaults to git user name, requiring --identity flag with exact format.

## Problem
- Mail sent to `gastown/crew/max`
- Max runs `bd mail inbox` → defaults to 'Steve Yegge' (git user)
- Max must know to use `--identity 'gastown/crew/max'` with exact slashes

## Proposed Fix
Auto-detect identity from directory context when in a Gas Town workspace:
- In `/Users/stevey/gt/gastown/crew/max`, infer identity = `gastown/crew/max`
- Pattern: `<town>/<rig>/<role>/<name>` → `<rig>/<role>/<name>`

## Additional Improvements
1. Support GT_IDENTITY env var (set by gt crew at / session spawning)
2. Support identity in .beads/config.yaml
3. Normalize format: accept both slashes and dashes as equivalent

## Context
Discovered during crew-to-crew work assignment. Max couldn't see mail despite correct nudge because identity defaulted wrong.


Merge: bd-w193

branch: polecat/nux
target: main
source_issue: bd-w193
rig: beads


False positive detection by Kaspersky Antivirus (Trojan)

Kaspersky Antivirus falsely detects beads (bd.exe v0.23.1) as a Trojan (PDM:Trojan.Win32.Generic) and removes it.
Event: Malicious object detected
Component: System Watcher
Object name: bd.exe


Update cmd/bd/version.go to 0.30.4

Update the Version constant in cmd/bd/version.go:
```go
Version = "0.30.4"
```

```verify
grep -q 'Version = "0.30.4"' cmd/bd/version.go
```


Work on beads-399: Add omitempty to JSONL fields for smal...

Work on beads-399: Add omitempty to JSONL fields for smaller notifications. When done, submit MR (not PR) to integration branch for Refinery.


gt handoff deadlock at handoff.go:125

When running 'gt handoff -m "message"' after successful MR submit, go panics with 'fatal error: all goroutines are asleep - deadlock\!' at handoff.go:125. The shutdown request still appears to be sent successfully but the command crashes. Stack trace shows issue is in runHandoff select statement.


GH#517: Claude sets priority wrong on new install

Claude uses 'medium/high/low' for priority instead of P0-P4. Update bd prime/onboard output to be clearer about priority syntax. See GitHub issue #517.


GH#405: Fix prefix parsing with hyphens - multi-hyphen prefixes parsed incorrectly

Fixed: ExtractIssuePrefix was falling back to first-hyphen for word-like suffixes, breaking multi-hyphen prefixes like 'hacker-news' and 'me-py-toolkit'.


Add 'bd status' command for issue database overview

Implement a bd status command that provides a quick snapshot of the issue database state, similar to how git status shows working tree state.

Expected output: Show summary including counts by state (open, in-progress, blocked, closed), recent activity (last 7 days), and quick overview without needing multiple queries.

Example output showing issue counts, recent activity stats, and pointer to bd list for details.

Proposed options: --all (show all issues), --assigned (show issues assigned to current user), --json (JSON format output)

Use cases: Quick project health check, onboarding for new contributors, integration with shell prompts or CI/CD, daily standup reference


Phase 1.2: Separate bdt executable - Initial structure

Create minimal bdt command structure completely separate from bd. Must not share code, config, or database.

## Subtasks
1. Create cmd/bdt/ directory with main.go
2. Implement bdt version, help, and status commands
3. Configure separate database location: $HOME/.bdt/ (not $HOME/.beads/)
4. Create separate issues file: issues.toon (not issues.jsonl)
5. Update build system:
   - Makefile: Add bdt target
   - .goreleaser.yml: Add bdt binary config

## Files to Create
- cmd/bdt/main.go - Entry point
- cmd/bdt/version.go - Version handling
- cmd/bdt/help.go - Help text (separate from bd)

## Success Criteria
- `make build` produces both `bd` and `bdt` executables
- `bdt version` shows distinct version output from bd
- `bdt --help` shows distinct help text
- bdt uses $HOME/.bdt/ directory (verify with `bdt info`)
- bd and bdt completely isolated (no shared imports beyond stdlib)


Phase 1.3: Basic TOON read/write operations

Add basic TOON read/write operations to bdt executable. Implement create, list, and show commands that use the internal/toon package for encoding/decoding to TOON format.

## Subtasks
1. Implement bdt create command - Create issues and serialize to TOON format
2. Implement bdt list command - Read issues.toon and display all issues
3. Implement bdt show command - Display single issue by ID
4. Add file I/O operations for issues.toon
5. Integrate internal/toon package (EncodeTOON, DecodeJSON)
6. Write tests for create, list, show operations

## Files to Create/Modify
- cmd/bdt/create.go - Create command
- cmd/bdt/list.go - List command
- cmd/bdt/show.go - Show command
- cmd/bdt/storage.go - File I/O helper

## Success Criteria
- bdt create "Issue title" creates and saves to issues.toon
- bdt list displays all issues in human-readable format
- bdt list --json shows JSON output
- bdt show <id> displays single issue
- Issues round-trip correctly: create → list → show
- All tests passing with >80% coverage


GH#402: Add --parent flag documentation to bd onboard

bd onboard output is missing --parent flag for epic subtasks. Agents guess wrong syntax (--deps parent:). See GitHub issue #402.


Respond to GitHub issue #479 with solution

Once bd reset is implemented and released, respond to GitHub issue #479.

## Response should include
- Announce the new bd reset command
- Show basic usage examples
- Link to any documentation
- Thank the user for the feedback

## Example response
```
Thanks for raising this! We've added a `bd reset` command to handle this case.

Usage:
- `bd reset` - Reset to clean state (prompts for confirmation)
- `bd reset --backup` - Create backup first
- `bd reset --hard` - Also clean up git history

This is available in version X.Y.Z.
```

## Notes
- Wait until feature is merged and released
- Consider if issue should be closed or left for user confirmation


Improve CheckStaleness error handling

## Problem

CheckStaleness returns 'false' (not stale) for multiple error conditions instead of returning errors. This masks problems.

**Location:** internal/autoimport/autoimport.go:253-285

## Edge Cases That Return False

1. **Invalid last_import_time format** (line 259-262)
2. **No JSONL file found** (line 267-277)
3. **JSONL stat fails** (line 279-282)

## Fix

Return errors for abnormal conditions:

```go
lastImportTime, err := time.Parse(time.RFC3339, lastImportStr)
if err != nil {
    return false, fmt.Errorf("corrupted last_import_time: %w", err)
}

if jsonlPath == "" {
    return false, fmt.Errorf("no JSONL file found")
}

stat, err := os.Stat(jsonlPath)
if err != nil {
    return false, fmt.Errorf("cannot stat JSONL: %w", err)
}
```

## Impact
Medium - edge cases are rare but should be handled

## Effort
30 minutes - requires updating callers in RPC server


Update CHANGELOG.md with release notes

Add meaningful release notes to CHANGELOG.md describing what changed in 0.30.7


Phase 2.3: TOON deletion tracking

Implement deletion tracking in TOON format.

## Overview
Phase 2.2 switched storage to TOON format. Phase 2.3 adds deletion tracking in TOON format for propagating deletions across clones.

## Required Work

### 2.3.1 Deletion Tracking (TOON Format)
- [ ] Implement deletions.toon file (tracking deleted issue records)
- [ ] Add DeleteTracker struct to record deleted issue IDs and metadata
- [ ] Update bdt delete command to record in deletions.toon
- [ ] Design deletion record format (ID, timestamp, reason, hash)
- [ ] Implement auto-prune of old deletion records (configurable TTL)

### 2.3.2 Sync Propagation
- [ ] Load deletions.toon during import
- [ ] Remove deleted issues from local database when imported from remote
- [ ] Handle edge cases (delete same issue in multiple clones)
- [ ] Deletion ordering and conflict resolution

### 2.3.3 Testing
- [ ] Unit tests for deletion tracking
- [ ] Integration tests for deletion propagation
- [ ] Multi-clone deletion scenarios
- [ ] TTL expiration tests

## Success Criteria
- deletions.toon stores deletion records in TOON format
- Deletions propagate across clones via git sync
- Old records auto-prune after TTL
- All 70+ tests still passing
- bdt delete command works seamlessly


GH#532: bd sync circular error (suggests running bd sync)

bd sync error message recommends running bd sync to fix the bd sync error. Fix error handling to provide useful guidance. See GitHub issue #532.


Consider using types.Status in merge package for type safety

The merge package uses string for status comparison (e.g., result.Status == closed, issue.Status == StatusTombstone). The types package defines Status as a type alias with validation. While the merge package needs its own Issue struct for JSONL flexibility, it could import and use types.Status for constants to get compile-time type checking. Current code: if left == closed || right == closed. Could be: if left == string(types.StatusClosed). This is low priority since string comparison works correctly. Files: internal/merge/merge.go:44, 488, 501-521


Add bd reset command for clean slate restart

Implement a `bd reset` command to reset beads to a clean starting state.

## Context
GitHub issue #479 - users sometimes get beads into an invalid state after updates, and there's no clean way to start fresh. The git backup/restore mechanism that protects against accidental deletion also makes it hard to intentionally reset.

## Design

### Command Interface
```
bd reset [--hard] [--force] [--backup] [--dry-run] [--no-init]
```

| Flag | Effect |
|------|--------|
| `--hard` | Also remove from git index and commit |
| `--force` | Skip confirmation prompt |
| `--backup` | Create `.beads-backup-{timestamp}/` first |
| `--dry-run` | Preview what would happen |
| `--no-init` | Don't re-initialize after clearing |

### Reset Levels
1. **Soft Reset (default)** - Kill daemons, clear .beads/, re-init. Git history unchanged.
2. **Hard Reset (`--hard`)** - Also git rm and commit the removal, then commit fresh state.

### Implementation Flow
1. Validate .beads/ exists
2. If not --force: show impact summary, prompt confirmation
3. If --backup: copy .beads/ to .beads-backup-{timestamp}/
4. Kill daemons
5. If --hard: git rm + commit
6. rm -rf .beads/*
7. If not --no-init: bd init (and git add+commit if --hard)
8. Print summary

### Safety Mechanisms
- Confirmation prompt (skip with --force)
- Impact summary (issue/tombstone counts)
- Backup option
- Dry-run preview
- Git dirty check warning

### Code Structure
- `cmd/bd/reset.go` - CLI command
- `internal/reset/` - Core logic package


Implement `bd setup cursor` for Cursor IDE integration

Create a `bd setup cursor` command that integrates Beads workflow into Cursor IDE via .cursorrules file. Unlike Claude Code (which has hooks), Cursor uses a static rules file to provide context to its AI.


Add daemon-side delete operation tests

Follow-up epic for PR #626: Add comprehensive test coverage for delete operations at the daemon/RPC layer. PR #626 successfully added storage layer tests but identified gaps in daemon-side delete operations and RPC integration testing.

## Scope
Tests needed for:
1. deleteViaDaemon (cmd/bd/delete.go:21) - RPC client-side deletion command
2. Daemon RPC delete handler - Server-side deletion via daemon
3. createTombstone wrapper (cmd/bd/delete.go:335) - Tombstone creation wrapper
4. deleteIssue wrapper (cmd/bd/delete.go:349) - Direct deletion wrapper

## Coverage targets
- Delete via RPC daemon (both success and error paths)
- Cascade deletion through daemon
- Force deletion through daemon
- Dry-run mode validation
- Tombstone creation and verification
- Error handling and edge cases


Add sync resilience guardrails for forced pushes and prefix mismatches

Beads can get into unrecoverable sync states when remote forces pushes occur (e.g., rebases) combined with prefix mismatches from multi-worker scenarios. Add detection, prevention, and auto-recovery features to handle this gracefully.


GH#403: bd doctor --fix circular error message

bd doctor --fix suggests running bd doctor --fix for deletions manifest issue. Fix to provide actual resolution. See GitHub issue #403.


Upgrade beads-mcp to {{version}}

Upgrade the MCP server via pip:

```bash
pip install --upgrade beads-mcp
pip show beads-mcp | grep Version  # Verify {{version}}
```

Note: Restart Claude Code or MCP session to use new version.


Update CHANGELOG.md with release notes

Add release notes for 0.32.1: MCP output control params (#667), pin field fix


Test deleteViaDaemon RPC client integration

Add comprehensive tests for the deleteViaDaemon function (cmd/bd/delete.go:21) which handles client-side RPC deletion calls.

## Function under test
- deleteViaDaemon: CLI command handler that sends delete requests to daemon via RPC

## Test scenarios needed
1. Successful deletion via daemon
2. Cascade deletion through daemon
3. Force deletion through daemon
4. Dry-run mode (no actual deletion)
5. Error handling:
   - Daemon unavailable
   - Invalid issue IDs
   - Dependency conflicts
6. JSON output validation
7. Human-readable output formatting

## Coverage target
Current: 0%
Target: >80%

## Related
- Parent epic: bd-kyll
- Original issue: bd-7z4


Remove all deletions.jsonl code except migration

There's deletions manifest code spread across the entire codebase that should have been removed after tombstone migration:

Files with deletions code (non-migration):
- internal/deletions/ - entire package
- cmd/bd/sync.go - 25+ references, auto-compact, sanitize
- cmd/bd/delete.go - dual-writes to deletions.jsonl
- internal/importer/importer.go - checks deletions manifest
- internal/syncbranch/worktree.go - merges deletions.jsonl
- cmd/bd/doctor/fix/sync.go - cleanupDeletionsManifest
- cmd/bd/doctor/fix/deletions.go - HydrateDeletionsManifest
- cmd/bd/integrity.go - checks deletions for data loss
- cmd/bd/deleted.go - entire command
- cmd/bd/compact.go - pruneDeletionsManifest
- cmd/bd/doctor.go - checkDeletionsManifest
- Plus many more

Action: Aggressively remove all non-migration deletions code. Tombstones are the only deletion mechanism now.


Split internal/storage/sqlite/queries.go (1586 lines)

Code health review found queries.go is too large at 1586 lines with:

- Issue scanning logic duplicated between transaction.go and queries.go
- Timestamp defensive fixes duplicated in CreateIssue, CreateIssues, batch_ops.go
- Multiple similar patterns that should be consolidated

Also: transaction.go at 1284 lines, dependencies.go at 893 lines

Recommendation:
1. Extract common scanning into shared function
2. Consolidate timestamp defensive fixes
3. Split queries.go by domain (CRUD, search, batch, events)


🤝 HANDOFF: v0.31.0 released, molecules discussion

Session completed 0.31.0 release and had important molecules discussion.

## Completed
- v0.31.0 released (deferred status, audit trail, directory labels, etc.)
- Fixed lint issues, hook version markers, codesigning
- All CI green, artifacts verified

## Filed Issues
- bd-usro: Rename template instantiate → bd mol bond
- bd-y8bj: Auto-detect identity for bd mail (P1 bug)
- gt-975: Molecule execution support for polecats/crew
- gt-976: Crew lifecycle support in Deacon

## Key Insight
Molecules are the future - TodoWrite is ephemeral, molecules are persistent institutional memory on the world chain. I tried to use TodoWrite for version bump and missed steps (codesigning, MCP verification). Molecules would have caught this.

## Next Steps
- bd mol bond implementation is priority
- Max has gt-976 for crew lifecycle (enables automated refresh mid-molecule)

Check bd ready and gt-975/976 status.


Update npm-package/package.json to 0.30.4

Update version field in npm-package/package.json:
```json
"version": "0.30.4"
```

```verify
jq -e '.version == "0.30.4"' npm-package/package.json
```


Run tests and verify build

Run the test suite to verify nothing is broken:

```bash
./scripts/test.sh
```

Or manually:
```bash
go build ./cmd/bd/...
go test ./...
```

Fix any failures before proceeding.


Create migration script for edge field to dependency conversion

Migration must:
1. Read existing JSONL with old fields
2. Convert field values to dependency records
3. Write updated JSONL without old fields
4. Handle edge cases (missing refs, duplicates)

Run via: bd migrate or automatic on bd prime


Optimize GetReadyWork performance - 752ms on 10K database (target: <50ms)

# Performance Analysis (10K Issue Database)

Analyzed using CPU profiles from benchmark suite on Apple M2 Pro.

## Operation Performance

| Operation                        | Time    | Allocations | Memory |
|----------------------------------|---------|-------------|--------|
| bd ready (GetReadyWork)          | ~752ms  | 167,466     | 16MB   |
| bd list (SearchIssues no filter) | ~11.6ms | 89,214      | 5.8MB  |
| bd list (SearchIssues filtered)  | ~9.2ms  | 62,365      | 3.5MB  |
| bd create (CreateIssue)          | ~2.6ms  | 146         | 8.6KB  |
| bd update (UpdateIssue)          | ~0.32ms | 364         | 15KB   |
| bd close (UpdateIssue)           | ~0.32ms | 364         | 15KB   |

**Target: <50ms for all operations on 10K database**

**Current issue: GetReadyWork is 15x over target (752ms vs 50ms)**

## Root Cause

GetReadyWork (internal/storage/sqlite/ready.go:90-128) uses recursive CTE to propagate blocking:
- 65x slower than SearchIssues
- Recalculates entire blocked issue tree on every call
- Algorithm:
  1. Find directly blocked issues via 'blocks' dependencies
  2. Recursively propagate blockage to descendants (max depth: 50)
  3. Exclude all blocked issues from results

## CPU Profile Analysis

- Database syscalls (pthread_cond_signal, syscall6): ~75%
- SQLite engine overhead: inherent to recursive CTE
- Application code (query construction): <1%

**Bottleneck is the recursive CTE query execution, not application code.**

## Optimization Recommendations

### High Impact (Likely to achieve <50ms target)

1. **Cache blocked issue calculation**
   - Add `blocked_issues` table updated on dependency changes
   - Trade write complexity for read speed (ready called >> dependency changes)
   - Eliminates recursive CTE on every read

2. **Add/verify database indexes**
   ```sql
   CREATE INDEX IF NOT EXISTS idx_dependencies_blocked
     ON dependencies(issue_id, type, depends_on_id);
   CREATE INDEX IF NOT EXISTS idx_issues_status
     ON issues(status);
   ```

### Medium Impact

3. **Reduce allocations** (167K allocations for GetReadyWork)
   - Profile `scanIssues()` for object pooling opportunities
   - Reuse slice capacity for repeated calls

### Low Impact (Not recommended)
- Query optimization for CRUD operations (already <3ms)
- Connection pooling tuning (not showing in profiles)

## Verification

Run benchmarks to validate optimization:
```bash
make bench-quick
go tool pprof -http=:8080 internal/storage/sqlite/bench-cpu-*.prof
```

Profile files automatically generated in `internal/storage/sqlite/`.


Test message

Hello world


Add --hard flag to bd cleanup to permanently cull tombstones before cutoff date

Currently tombstones persist for 30 days before cleanup prunes them. Need an official way to force-cull tombstones earlier than the default TTL, for scenarios like cleaning house after extended absence where resurrection from old clones is not a concern. Proposed: bd cleanup --hard --older-than N to bypass the 30-day tombstone TTL.


Exclude pinned issues from bd ready

Update bd ready to exclude pinned issues. Pinned issues are context markers, not work items, and should never appear in the ready-to-work list.


Review PR #513: fix hooks install docs

Review and merge PR #513 from aspiers. This PR fixes incorrect docs for how to install git hooks - updates README to use bd hooks install instead of removed install.sh. Simple 1-line change. URL: https://github.com/anthropics/beads/pull/513


Add 0.30.4 to info.go release notes

Update cmd/bd/info.go versionChanges map with release notes for 0.30.4.
Include any workflow-impacting changes for --whats-new output.


mergeDependencies uses union instead of 3-way merge

## Critical Bug

The `mergeDependencies` function in internal/merge/merge.go performs a UNION of left and right dependencies instead of a proper 3-way merge. This causes removed dependencies to be resurrected.

### Root Cause

```go
// Current code (lines 795-816):
func mergeDependencies(left, right []Dependency) []Dependency {
    // Just unions left + right
    // NEVER REMOVES anything
    // Doesn't even look at base!
}
```

And `mergeIssue` (line 579) doesn't pass `base`:
```go
result.Dependencies = mergeDependencies(left.Dependencies, right.Dependencies)
```

### Impact

If:
- Base has dependency D
- Left removes D (intentional)
- Right still has D (stale)

Current: D is in result (resurrection!)
Correct: Left removed it, D should NOT be in result

This breaks Gas Town's workflow and data integrity. Closed means closed.

### Fix

Change `mergeDependencies` to take `base` and do proper 3-way merge:
- If dep was in base and removed by left → exclude (left wins)
- If dep was in base and removed by right → exclude (right wins)
- If dep wasn't in base and added by either → include
- If dep was in base and both still have it → include

Key principle: **REMOVALS ARE AUTHORITATIVE**

### Files to Change

1. internal/merge/merge.go:
   - `mergeDependencies(left, right)` → `mergeDependencies(base, left, right)`
   - `mergeIssue` line 579: pass `base.Dependencies`

### Related

This also explains why `ProtectLocalExportIDs` in importer is defined but never used - the protection was never actually implemented.


🤝 HANDOFF: Review remaining beads PRs

## Current State
Just merged PR #653 (doctor refactor) and added tests to restore coverage.

## Remaining Open PRs to Review
Run `gh pr list --repo steveyegge/beads` to see current list. As of handoff:

1. #655 - feat: Linear Integration (jblwilliams)
2. #651 - feat(audit): agent audit trail (dchichkov)
3. #648 - Stop init creating redundant @AGENTS.md (maphew)
4. #646 - fix(unix): handle Statfs field types (jordanhubbard)
5. #645 - feat: /plan-to-beads Claude Code command (petebytes)
6. #642, #641, #640 - sync branch fixes (cpdata)

## Review Checklist
- Check CI status with `gh pr checks <num> --repo steveyegge/beads`
- Verify no .beads/ data leaking (we have a hook now)
- Review code quality
- Merge good ones, request changes on problematic ones

## Notes
- User wants us to be proactive about merging good PRs
- Can add tests ourselves if coverage drops


GH#519: bd sync fails when sync.branch is currently checked-out branch


Add metadata and thread_id columns to dependencies table

Schema changes:
- ALTER TABLE dependencies ADD COLUMN metadata TEXT DEFAULT '{}'
- ALTER TABLE dependencies ADD COLUMN thread_id TEXT DEFAULT ''
- CREATE INDEX idx_dependencies_thread ON dependencies(thread_id) WHERE thread_id != ''


Restart running daemons

Kill and restart any running bd daemons to pick up new version: pkill -f 'bd daemon' && bd daemon --start


Revert/remove YAML workflow system

Revert the recent commit and remove all YAML workflow code:

1. `git revert aae8407a` (the commit we just pushed with workflow fixes)
2. Remove `cmd/bd/templates/workflows/` directory
3. Remove workflow.go or gut it to minimal stub
4. Remove WorkflowTemplate types from internal/types/workflow.go
5. Remove any workflow-related RPC handlers

Keep only minimal scaffolding if needed for the new template system.


Add tests for delete operations

Core delete functionality including deleteViaDaemon, createTombstone, and deleteIssue functions have 0% coverage. These are critical for data integrity and need comprehensive test coverage.


Standardize error handling: replace direct fmt.Fprintf+os.Exit with FatalError

Code health review found inconsistent error handling patterns:

Pattern A (preferred): FatalError() from errors.go:21-24
Pattern B (inconsistent): Direct fmt.Fprintf(os.Stderr) + os.Exit(1)

Affected files:
- delete.go:35-49 uses direct pattern
- create.go:213 ignores error silently
- Various other commands

Fix: Standardize on FatalError() wrapper for consistent error messages and testability.


Add pinned field to issue schema

Add boolean 'pinned' field to the issue schema. When true, the issue is marked as a persistent context marker that should not be treated as a work item.


Add missing hook calls in mail reply and ack

The mail commands are missing hook calls:

1. runMailReply (mail.go:525-672) creates a message but doesn't call hookRunner.Run(hooks.EventMessage, ...) after creating the reply in direct mode (around line 640)

2. runMailAck (mail.go:432-523) closes messages but doesn't call hookRunner.Run(hooks.EventClose, ...) after closing each message (around line 487 for daemon mode, 493 for direct mode)

This means GGT hooks won't fire for replies or message acknowledgments.


test pin


Version Bump: {{version}}

Release checklist for version {{version}}. This molecule ensures all release steps are completed properly.


BondRef data model for compound lineage

Add data model support for tracking compound molecule lineage.

NEW FIELDS on Issue:
  bonded_from: []BondRef  // For compounds: constituent protos

NEW TYPE:
  type BondRef struct {
      ProtoID   string  // Source proto ID
      BondType  string  // sequential, parallel, conditional
      BondPoint string  // Attachment site (issue ID or empty for root)
  }

JSONL SERIALIZATION:
  {
    "id": "proto-feature-tested",
    "title": "Feature with tests",
    "bonded_from": [
      {"proto_id": "proto-feature", "bond_type": "root"},
      {"proto_id": "proto-testing", "bond_type": "sequential"}
    ],
    ...
  }

QUERIES:
- GetCompoundConstituents(id) → []BondRef
- IsCompound(id) → bool
- GetCompoundsUsing(protoID) → []Issue  // Reverse lookup


Implement subgraph cloning with variable substitution

Core implementation of template instantiation:

1. Add `bd template instantiate <template-id> [--var key=value]...` command
2. Implement subgraph loading:
   - Load template epic
   - Recursively load all children (and their children)
   - Load all dependencies between issues in the subgraph
3. Implement variable substitution:
   - Scan titles and descriptions for `{{name}}` patterns
   - Replace with provided values
   - Error on missing required variables (or prompt interactively)
4. Implement cloning:
   - Generate new IDs for all issues
   - Create cloned issues with substituted text
   - Remap and create dependencies
5. Return the new epic ID

Consider adding `--dry-run` flag to preview what would be created.


Add integration tests for bd reset command

End-to-end integration tests for the reset command.

## Test Scenarios

### Basic reset
1. Init beads, create some issues
2. Run bd reset --force
3. Verify .beads/ is fresh, issues gone

### Hard reset
1. Init beads, create issues, commit
2. Run bd reset --hard --force
3. Verify git history has reset commits

### Backup functionality
1. Init beads, create issues
2. Run bd reset --backup --force
3. Verify backup exists with correct contents
4. Verify main .beads/ is reset

### Dry run
1. Init beads, create issues
2. Run bd reset --dry-run
3. Verify nothing changed

### Confirmation prompt
1. Init beads
2. Run bd reset (no --force)
3. Verify prompts for confirmation
4. Test both y and n responses

## Location
tests/integration/reset_test.go or similar


Default to YES for git hooks and merge driver installation

Currently bd init prompts user to install git hooks and merge driver, but setup is incomplete if user declines. Change to install by default unless --skip-hooks or --skip-merge-driver flags are passed. Better safe defaults. If installation fails, warn user and suggest bd doctor --fix.


Add global verbosity flags (--verbose, --quiet)

Add consistent verbosity controls across all commands.

**Current state:**
- bd init has --quiet flag
- No other commands have verbosity controls
- Debug output controlled by BD_VERBOSE env var

**Proposal:**
Add persistent flags:
- --verbose / -v: Enable debug output
- --quiet / -q: Suppress non-essential output

**Implementation:**
- Add to rootCmd.PersistentFlags()
- Replace BD_VERBOSE checks with flag checks
- Standardize output levels:
  * Quiet: Errors only
  * Normal: Errors + success messages
  * Verbose: Errors + success + debug info

**Files to modify:**
- cmd/bd/main.go (add flags)
- internal/debug/debug.go (respect flags)
- Update all commands to respect quiet mode

**Testing:**
- Verify --verbose shows debug output
- Verify --quiet suppresses normal output
- Ensure errors always show regardless of mode


Update local installation

go build -o ~/.local/bin/bd ./cmd/bd && codesign -s - ~/.local/bin/bd


Support redirect files in .beads/ directory

Gas Town creates polecat worktrees with .beads/redirect files that point to a shared beads database. The bd CLI should:

1. When finding a .beads/ directory, check if it contains a 'redirect' file
2. If redirect exists, read the relative path and use that as the beads directory
3. This allows multiple git worktrees to share a single beads database

Example:
- polecats/alpha/.beads/redirect contains '../../mayor/rig/.beads'
- bd commands from alpha should use mayor/rig/.beads

Currently bd ignores redirect files and either uses the local .beads/ or walks up to find a parent .beads/.

Related: gt-nriy (test message that can't be retrieved due to missing redirect support)


Compound visualization in bd mol show

Enhance bd mol show to display compound structure.

ENHANCEMENTS:
- Show constituent protos and how they're bonded
- Display bond type (sequential/parallel) between components
- Indicate attachment points
- Show combined variable requirements across all protos

EXAMPLE OUTPUT:

  Compound: proto-feature-with-tests
  Bonded from:
    └─ proto-feature (root)
       └─ proto-testing (sequential, after completion)

  Variables: {{name}}, {{version}}, {{test_suite}}

  Structure:
    proto-feature-with-tests
    ├─ Design feature {{name}}
    ├─ Implement core
    ├─ Write unit tests      ← from proto-testing
    └─ Run test suite {{test_suite}}  ← from proto-testing


Verify MCP Server Compatibility

Ensure MCP server works with cache-free daemon


Fix FindBeadsDir to prioritize main repo .beads for worktrees

The FindBeadsDir function should prioritize finding .beads in the main repository root when accessed from a worktree, rather than finding worktree-local .beads directories. This ensures proper sharing of the database across all worktrees.


Work on beads-1ra: Add molecules.jsonl as separate catalo...

Work on beads-1ra: Add molecules.jsonl as separate catalog file for template molecules


Graph Link: duplicates for deduplication

Implement duplicates link type for marking issues as duplicates.

New command:
- bd duplicate <id> --of <canonical> - marks id as duplicate of canonical
- Auto-closes the duplicate issue

Query support:
- bd show <id> shows 'Duplicate of: <canonical>'
- bd list --duplicates shows all duplicate pairs

Storage:
- duplicates column pointing to canonical issue ID

Essential for large issue databases with many similar reports.


Command Set Standardization & Flag Consistency

Comprehensive improvements to bd command set based on 2025 audit findings.

## Background
See docs/command-audit-2025.md for detailed analysis.

## Goals
1. Standardize flag naming and behavior across all commands
2. Add missing flags for feature parity
3. Fix naming confusion
4. Improve consistency in JSON output

## Success Criteria
- All mutating commands support --dry-run (no --preview variants)
- bd update supports label operations
- bd search has filter parity with bd list
- Priority flags accept both int and P0-P4 format everywhere
- JSON output is consistent across all commands


Auto-recovery mode (bd sync --auto-recover)

Add bd sync --auto-recover flag that: detects problematic sync state, backs up .beads/issues.db with timestamp, rebuilds DB from JSONL atomically, verifies consistency, reports what was fixed. Provides safety valve when sync integrity fails.


Update .claude-plugin/plugin.json to 0.30.4

Update version field in .claude-plugin/plugin.json:
```json
"version": "0.30.4"
```

```verify
jq -e '.version == "0.30.4"' .claude-plugin/plugin.json
```


Work on beads-d8h: Fix prefix mismatch false positive wit...

Work on beads-d8h: Fix prefix mismatch false positive with multi-hyphen prefixes like 'asianops-audit-' (GH#422). When done, submit MR (not PR) to integration branch for Refinery.


GH#540: Add silent quick-capture mode (bd q)

Add bd q alias for quick capture that outputs only issue ID. Useful for piping/scripting. See GitHub issue #540.


Review PR #514: fix plugin install docs

Review and merge PR #514 from aspiers. This PR fixes incorrect docs for installing Claude Code plugin from source in docs/PLUGIN.md. Clarifies shell vs Claude Code commands and fixes the . vs ./beads argument issue. URL: https://github.com/anthropics/beads/pull/514


Add orphan detection migration

Create migration to detect orphaned children in existing databases. Query: SELECT id FROM issues WHERE id LIKE '%.%' AND substr(id, 1, instr(id || '.', '.') - 1) NOT IN (SELECT id FROM issues). Log results, let user decide action (delete orphans or convert to top-level).


Run bump-version.sh {{version}}

Run ./scripts/bump-version.sh {{version}} to update version in all files


Beads commands operate on stale database without warning

All beads read operations should validate database is in sync with JSONL before proceeding.

**Current Behavior:**
- Commands can query/read from stale database
- Only mutation operations (like 'bd sync') check if JSONL is newer
- User gets incorrect results without realizing database is out of sync

**Expected Behavior:**
- All beads commands should have pre-flight check for database freshness
- If JSONL is newer than database, refuse to operate with error: "Database out of sync. Run 'bd import' first."
- Same safety check that exists for 'bd sync' should apply to ALL operations

**Impact:**
- Users make decisions based on incomplete/outdated data
- Silent failures lead to confusion (e.g., thinking issues don't exist when they do)
- Similar to running git commands on stale repo without being warned to pull

**Example:**
- Searched for bd-g9eu issue file: not found
- Issue exists in .beads/issues.jsonl (in git)
- Database was stale, but no warning was given
- Led to incorrect conclusion that issue was already closed/deleted

## Implementation Complete

**Phase 1: Created staleness check (cmd/bd/staleness.go)**
- ensureDatabaseFresh() function checks JSONL mtime vs last_import_time
- Returns error with helpful message when database is stale
- Auto-skips in daemon mode (daemon has auto-import)

**Phase 2: Added to all read commands**
- list, show, ready, status, stale, info, duplicates, validate
- Check runs before database queries in direct mode
- Daemon mode already protected via checkAndAutoImportIfStale()

**Phase 3: Code Review Findings**
See follow-up issues:
- bd-XXXX: Add warning when staleness check errors
- bd-YYYY: Improve CheckStaleness error handling
- bd-ZZZZ: Refactor redundant daemon checks (low priority)

**Testing:**
- Build successful: go build ./cmd/bd
- Binary works: ./bd --version
- Ready for manual testing

**Next Steps:**
1. Test with stale database scenario
2. Implement review improvements
3. Close issue when tests pass


Implement bd pin/unpin commands

Add 'bd pin <id>' and 'bd unpin <id>' commands to toggle the pinned status of issues. Should support multiple IDs like other bd commands.


Improve test coverage for cmd/bd/doctor/fix (23.9% → 50%)

The doctor/fix package has only 23.9% test coverage. The doctor fix functionality is important for troubleshooting.

Current coverage: 23.9%
Target coverage: 50%


Consider backwards compatibility for ready() and list() return type change

PR #481 changed the return types of `ready()` and `list()` from `list[Issue]` to `list[IssueMinimal] | CompactedResult`. This is a breaking change for MCP clients.

## Impact Assessment
Breaking change affects:
- Any MCP client expecting `list[Issue]` from ready()
- Any MCP client expecting `list[Issue]` from list()
- Client code that accesses full Issue fields (description, design, acceptance_criteria, timestamps, dependencies, dependents)

## Current Behavior
- ready() returns `list[IssueMinimal] | CompactedResult`
- list() returns `list[IssueMinimal] | CompactedResult`
- show() still returns full `Issue` (good)

## Considerations
**Pros of current approach:**
- Forces clients to use show() for full details (good for context efficiency)
- Simple mental model (always use show for full data)
- Documentation warns about this

**Cons:**
- Clients expecting list[Issue] will break
- No graceful degradation option
- No migration period

## Potential Solutions
1. Add optional parameter `full_details=false` to ready/list (would increase payload)
2. Create separate tools: ready_minimal/list_minimal + ready_full/list_full
3. Accept breaking change and document upgrade path (current approach)
4. Version the MCP server and document migration guide

## Recommendation
Current approach (solution 3) is reasonable if:
- Changelog clearly documents the breaking change
- Migration guide provided to clients
- Error handling is graceful for clients expecting specific fields


Rename 'bond' to 'spawn' for instantiation

Rename the bd mol bond command to bd mol spawn for instantiating protos.

- Rename molBondCmd to molSpawnCmd
- Update command Use/Short/Long descriptions
- Keep 'bond' available for the new bonding feature
- Update all documentation references
- Add 'protomolecule' as easter egg alias for 'proto'


Git merge driver uses invalid placeholders (%L, %R instead of %A, %B)

## Problem

The beads git merge driver is configured with invalid Git placeholders:

```
git config merge.beads.driver "bd merge %A %O %L %R"
```

Git doesn't recognize `%L` or `%R` as valid merge driver placeholders. The valid placeholders are:
- `%O` = base (common ancestor)
- `%A` = current version (ours)
- `%B` = other version (theirs)

## Impact

- Affects ALL users when they have `.beads/beads.jsonl` merge conflicts
- Automatic JSONL merge fails with error: "error reading left file: failed to open file: open 7: no such file or directory"
- Users must manually resolve conflicts instead of getting automatic merge

## Root Cause

The `bd init` command (or wherever the merge driver is configured) is using non-standard placeholders. When Git encounters `%L` and `%R`, it either passes them literally or interprets them incorrectly.

## Fix

Update the merge driver configuration to:
```
git config merge.beads.driver "bd merge %A %O %A %B"
```

Where:
- 1st `%A` = output file (current file, will be overwritten)
- `%O` = base (common ancestor)
- 2nd `%A` = left/current version
- `%B` = right/other version

## Action Items

1. Fix `bd init` (or equivalent setup command) to use correct placeholders
2. Add migration/warning for existing users with misconfigured merge driver
3. Update documentation with correct merge driver setup
4. Consider adding validation when `bd init` is run


Add warning when staleness check errors

## Problem

When ensureDatabaseFresh() calls CheckStaleness() and it errors (corrupted metadata, permission issues, etc.), we silently proceed with potentially stale data.

**Location:** cmd/bd/staleness.go:27-32

**Scenarios:**
- Corrupted metadata table
- Database locked by another process
- Permission issues reading JSONL file
- Invalid last_import_time format in DB

## Current Code

```go
isStale, err := autoimport.CheckStaleness(ctx, store, dbPath)
if err \!= nil {
    // If we can't determine staleness, allow operation to proceed
    // (better to show potentially stale data than block user)
    return nil
}
```

## Fix

```go
isStale, err := autoimport.CheckStaleness(ctx, store, dbPath)
if err \!= nil {
    fmt.Fprintf(os.Stderr, "Warning: Could not verify database freshness: %v\n", err)
    fmt.Fprintf(os.Stderr, "Proceeding anyway. Data may be stale.\n\n")
    return nil
}
```

## Impact
Medium - users should know when staleness check fails

## Effort
Easy - 5 minutes


Work on beads-2nh: Fix gt spawn --issue to find issues in...

Work on beads-2nh: Fix gt spawn --issue to find issues in rig's beads database. When done, submit MR (not PR) to integration branch for Refinery.


Commit and push release

git add -A && git commit && git push to trigger CI