Wait for CI

Monitor GitHub Actions for release completion.

https://github.com/steveyegge/beads/actions

Expected time: 5-10 minutes

Watch for:
- Build artifacts (all platforms)
- Test suite pass
- npm publish
- PyPI publish


Add test files for internal/storage

The internal/storage package has no test files at all. This package provides the storage interface abstraction.

Current coverage: N/A (no test files)
Target: Add basic interface tests


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.*


Merge: bd-phtv

branch: polecat/Pinner
target: main
source_issue: bd-phtv
rig: beads


Exclude pinned issues from bd blocked

Update bd blocked to exclude pinned issues. Pinned issues are context markers and should not appear in the blocked work list.


Commit release

Stage and commit all version changes.

```bash
git add -A
git commit -m "chore: Bump version to 0.39.0"
```

Review the commit to ensure all expected files are included.


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


Work on gt-8tmz.36: Validate expanded step IDs are unique...

Work on gt-8tmz.36: Validate expanded step IDs are unique. After ApplyExpansions in internal/formula/expand.go, new steps can be created that might have duplicate IDs. Add validation in ApplyExpansions to check for duplicate step IDs after expansion. If duplicates found, return an error with the duplicate IDs. Add test in expand_test.go. When done, commit and push to main.


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 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)


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.


activity --follow: Silent error handling

In activity.go:175-179, when the daemon is down or errors occur during polling in --follow mode, errors are silently ignored:

```go
newEvents, err := fetchMutations(lastPoll)
if err != nil {
    // Daemon might be down, continue trying
    continue
}
```

This means:
- Users won't know if the daemon is unreachable
- Could appear frozen when actually failing
- No indication of lost events

Should at least show a warning after N consecutive failures, or show '...' indicator to show polling status.

Discovered during code review of bd-xo1o implementation.


Molecule execution state management

Implement molecule execution state tracking.

## State Location

```
.beads/molecules/<mol-id>.state.yaml
```

## State Schema

```yaml
id: mol-deacon-patrol
formula: mol-deacon-patrol  # Source formula
bonded_at: ISO timestamp
bonded_by: entity who created it

# Execution state
status: running | paused | completed | failed
current_step: step-id
started_at: ISO timestamp
completed_at: ISO timestamp (if done)

# Loop tracking
reset_count: 0
last_reset_at: null

# Per-step state
steps:
  inbox-check:
    status: completed | in_progress | pending
    started_at: ...
    completed_at: ...
  spawn-work:
    status: pending
  self-inspect:
    status: pending

# Variables (from formula instantiation)
variables:
  rig: gastown
  issue_id: gt-xxx
```

## Operations

- CreateState(molID, formula, variables) - Initialize state
- LoadState(molID) - Read current state
- SaveState(molID, state) - Write state
- AdvanceStep(molID) - Mark current complete, find next
- ResetState(molID) - Reset all steps to pending

## Files

- internal/mol/state.go
- internal/mol/types.go


bd validate - Comprehensive health check

Run all validation checks in one command.

Checks:
- Duplicates
- Orphaned dependencies
- Test pollution
- Git conflicts

Supports --fix-all for auto-repair.

Depends on bd-cbed9619.1, bd-0dcea000, bd-31aab707, bd-9826b69a.

Files: cmd/bd/validate.go (new)


Improve test coverage for internal/rpc (47.5% → 60%)

The RPC package has only 47.5% test coverage. RPC is the communication layer for daemon operations.

Current coverage: 47.5%
Target coverage: 60%


Add bd mol run command (bond + assign + pin)

bd mol run = bond + assign root to caller + pin to startup mail. This is the Gas Town integration point. When agent restarts, check startup mail, find pinned molecule root, query bd ready for next step. Makes molecules immortal.


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.


Merge: bd-likt

branch: polecat/Gater
target: main
source_issue: bd-likt
rig: beads


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.


Update CHANGELOG.md with release notes

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


bd mol reset: Reset molecule to initial state for looping

Implement bd mol reset for patrol loop behavior.

## Command

```bash
bd mol reset <mol-id>
```

## Behavior

1. Load molecule state from .beads/molecules/<mol-id>.state.yaml
2. Reset all step states to pending
3. Clear current_step (or set to first step)
4. Preserve: bonded_at, bonded_by, variables
5. Update: reset_count++, last_reset_at

## Use Case: Deacon Patrol Loop

```
inbox-check → spawn-work → self-inspect → mol-reset → (loop)
```

The Deacon runs its patrol, then resets the molecule to start fresh.
No gt handoff needed unless context is high.

## State After Reset

```yaml
id: mol-deacon-patrol
status: running
current_step: inbox-check  # Back to first
reset_count: 5
last_reset_at: 2025-12-24T...
steps:
  inbox-check: pending      # All reset
  spawn-work: pending
  self-inspect: pending
```

## Files

- cmd/bd/mol_reset.go
- internal/mol/state.go (add Reset method)


Issue lifecycle hooks (on-close, on-complete)

Add hooks that fire on issue state transitions, enabling automation like closing linked GitHub issues.

## Problem

We have `external_ref` to link beads issues to external systems (GitHub, Linear, Jira), but no mechanism to trigger actions when issues close. Currently:

```
bd-u2sc (external_ref: gh-692) closes → nothing happens
```

## Proposed Solution

### Phase 1: Shell Hooks

Add `.beads-hooks/on-close.sh` (and similar lifecycle hooks):

```bash
# .beads-hooks/on-close.sh
# Called by bd close with issue JSON on stdin
#\!/bin/bash
issue=$(cat)
external_ref=$(echo "$issue" | jq -r '.external_ref // empty')
if [[ "$external_ref" == gh-* ]]; then
    number="${external_ref#gh-}"
    gh issue close "$number" --repo steveyegge/beads \
      --comment "Completed via beads epic $(echo $issue | jq -r .id)"
fi
```

### Lifecycle Events

| Event | Trigger | Use Cases |
|-------|---------|-----------|
| `on-close` | Issue closed | Close external refs, notify, archive |
| `on-complete` | Epic children all done | Roll-up completion, close parent refs |
| `on-status-change` | Any status transition | Sync to external systems |

### Phase 2: Molecule Completion Handlers

Molecules could define completion actions:

```yaml
name: github-issue-tracker
on_complete:
  - action: shell
    command: gh issue close {{external_ref}} --repo {{repo}}
  - action: mail
    to: mayor/
    subject: "Epic {{id}} completed"
```

### Phase 3: Gas Town Integration

For full Gas Town deployments:
- Witness observes closures via beads events
- Routes to integration agents via mail
- Agents handle external system interactions

## Implementation Notes

- Hooks should be async (don't block bd close)
- Pass full issue JSON to hook via stdin
- Support hook timeout and failure handling
- Consider `--no-hooks` flag for bulk operations

## Related

- `external_ref` field already exists (GH#142)
- Cross-project deps: bd-h807, bd-d9mu
- Git hooks: .beads-hooks/ pattern established

## Use Cases

1. **GitHub integration**: Close GH issues when beads epic completes
2. **Linear sync**: Update Linear status when beads status changes
3. **Notifications**: Send mail/Slack when high-priority issues close
4. **Audit**: Log all closures to external system


bd mol publish: Push formula to GitHub repo

Publish a formula to a GitHub repository for sharing.

## Usage
```bash
# Create new repo and publish
bd mol publish mol-my-workflow --repo github.com/myorg/mol-my-workflow

# Update existing repo
bd mol publish mol-my-workflow --repo github.com/myorg/mol-my-workflow --tag v1.1.0
```

## Implementation
1. Export proto to formula.json (if not already a file)
2. Validate formula structure
3. Create GitHub repo if --create flag (uses `gh repo create`)
4. Copy formula.json to repo
5. Generate README.md from formula description
6. Commit and push
7. Create git tag if --tag specified
8. Add mol-formula topic to repo

## Flags
- `--repo <url>` - Target GitHub repo (required)
- `--tag <version>` - Create version tag
- `--create` - Create repo if doesn't exist
- `--private` - Create as private repo

## Workflow
```bash
# Full publish flow
bd mol distill my-epic --name my-workflow
bd mol promote bd-proto-xxx --as my-workflow
bd mol publish mol-my-workflow --repo github.com/me/mol-my-workflow --create --tag v1.0.0
```


Test createTombstone and deleteIssue wrappers

Add tests for the createTombstone and deleteIssue wrapper functions in cmd/bd/delete.go.

## Functions under test
- createTombstone (cmd/bd/delete.go:335) - Wrapper around SQLite CreateTombstone
- deleteIssue (cmd/bd/delete.go:349) - Wrapper around SQLite DeleteIssue

## Test scenarios for createTombstone
1. Successful tombstone creation
2. Tombstone with reason and actor tracking
3. Error when issue doesn't exist
4. Verify tombstone status set correctly
5. Verify audit trail recorded
6. Rollback/error handling

## Test scenarios for deleteIssue
1. Successful issue deletion
2. Error on non-existent issue
3. Verify issue removed from database
4. Error handling when storage backend doesn't support delete

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

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


Warn on invalid depends_on references in workflow templates

workflow.go:780-781 silently skips invalid dependency names. Should log a warning when a depends_on reference doesn't match any task ID in the template.


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.


bd wisp list command

Add bd wisp list command to show ephemeral molecules.

## Usage
```bash
bd wisp list              # List all wisps in current context
bd wisp list --json       # JSON output
bd wisp list --all        # Include orphaned wisps
```

## Output
- Shows in-progress ephemeral molecules
- Columns: ID, Title, Started, Last Update, Status
- Warns about orphaned wisps (old updated_at)

## Implementation
- New 'wisp' command group
- Read from .beads-ephemeral/issues.jsonl
- Filter to ephemeral:true issues


Consider caching external dep resolution results

Each call to GetReadyWork re-checks all external dependencies by:
1. Querying for external deps in the local database
2. Opening each external project's database
3. Querying for closed issues with provides: labels

For workloads with many external deps or slow external databases, this adds latency on every bd ready call.

Potential optimizations:
- In-memory TTL cache for external dep status (e.g., 60 second TTL)
- Store resolved status in a local cache table with timestamp
- Batch resolution of common project/capability pairs

This is not urgent - current implementation is correct and performant for typical workloads. Only becomes an issue with many external deps across many projects.


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)


Update CHANGELOG.md with release notes

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


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
```


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.


bd doctor --fix destroys child→parent dependencies without confirmation

GH#740: User reports that `bd doctor --fix` removed their intentional child→parent dependencies, calling them an 'anti-pattern'.

The fix in `cmd/bd/doctor/fix/validation.go` (ChildParentDependencies function) automatically deletes dependencies where a child issue depends on its parent epic.

**Problem**: This assumes all such dependencies are mistakes, but users may intentionally want children blocked by their parent (e.g., 'don't start subtasks until parent is fully scoped').

**Solution options**:
1. Remove this fix entirely (let users manage their own deps)
2. Require explicit opt-in flag like `--fix-child-parent`
3. Add confirmation prompt before destructive action
4. Add `--dry-run` to preview what would be removed
5. Only warn, never auto-fix

**Files involved**:
- `cmd/bd/doctor/validation.go:311-382` (check)
- `cmd/bd/doctor/fix/validation.go:165-227` (fix)


Make merge requests ephemeral wisps instead of permanent issues

## Problem

Merge requests (MRs) are currently created as regular beads issues (type: merge-request). This means they:
- Sync to JSONL and propagate via git
- Accumulate in the issue database indefinitely
- Clutter `bd list` output with closed MRs
- Create permanent records for inherently transient artifacts

MRs are process artifacts, not work products. They exist briefly while code awaits merge, then their purpose is fulfilled. The git merge commit and GitHub PR (if applicable) provide the permanent audit trail - the beads MR is redundant.

## Proposed Solution

Make MRs ephemeral wisps that exist only during the merge process:

1. **Create MRs as wisps**: When a polecat completes work and requests merge, create the MR in `.beads-wisp/` instead of `.beads/`

2. **Refinery visibility**: This works because all clones within a rig share the same database:
   ```
   beads/              ← Rig root
   ├── .beads/         ← Permanent issues (synced to JSONL)
   ├── .beads-wisp/    ← Ephemeral wisps (NOT synced)
   ├── crew/dave/      ← Uses rig's shared DB
   ├── polecats/*/     ← Uses rig's shared DB
   └── refinery/       ← Uses rig's shared DB
   ```
   The refinery can see wisp MRs immediately - same SQLite database.

3. **On merge completion**: Burn the wisp (delete without digest). The git merge commit IS the permanent record. No digest needed since:
   - Digest wouldn't be smaller than the MR itself (~200-300 bytes either way)
   - Git history provides complete audit trail
   - GitHub PR (if used) provides discussion/approval record

4. **On merge rejection/abandonment**: Burn the wisp. Optionally notify the source polecat via mail.

## Benefits

- **Clean JSONL**: MRs never pollute the permanent issue history
- **No accumulation**: Wisps are burned on completion, no cleanup needed
- **Correct semantics**: Wisps are for "operational ephemera" - MRs fit perfectly
- **Reduced sync churn**: Fewer JSONL updates, faster `bd sync`
- **Cleaner queries**: `bd list` shows work items, not process artifacts

## Implementation Notes

### Where MRs are created

Currently MRs are created by the witness or polecat when work is ready for merge. This code needs to:
- Set `wisp: true` on the MR issue
- Or use a dedicated wisp creation path

### Refinery changes

The refinery queries for pending MRs to process. It needs to:
- Query wisp storage as well as (or instead of) permanent storage
- Use `bd mol burn` or equivalent to delete processed MRs

### What about cross-rig MRs?

If an MR needs to be visible outside the rig (e.g., external collaborators):
- They would see the GitHub PR anyway
- Or we could create a permanent "merge completed" notification issue
- But this is likely unnecessary - MRs are internal coordination

### Migration

Existing MRs in permanent storage:
- Can be cleaned up with `bd cleanup` or manual deletion
- Or left to age out naturally
- No migration of open MRs needed (they'll complete under old system

## Alternatives Considered

1. **Auto-cleanup of closed MRs**: Keep MRs as permanent issues but auto-delete after 24h. Simpler but still creates sync churn and temporary JSONL pollution.

2. **MRs as mail only**: Polecat sends mail to refinery with merge details, no MR issue at all. Loses queryability (bd-801b [P2] [merge-request] closed - Merge: bd-bqcc
bd-pvu0 [P2] [merge-request] closed - Merge: bd-4opy
bd-i0rx [P2] [merge-request] closed - Merge: bd-ao0s
bd-u0sb [P2] [merge-request] closed - Merge: bd-uqfn
bd-8e0q [P2] [merge-request] closed - Merge: beads-ocs
bd-hvng [P2] [merge-request] closed - Merge: bd-w193
bd-4sfl [P2] [merge-request] closed - Merge: bd-14ie
bd-sumr [P2] [merge-request] closed - Merge: bd-t4sb
bd-3x9o [P2] [merge-request] closed - Merge: bd-by0d
bd-whgv [P2] [merge-request] closed - Merge: bd-401h
bd-f3ll [P2] [merge-request] closed - Merge: bd-ot0w
bd-fmdy [P3] [merge-request] closed - Merge: bd-kzda).

3. **Separate merge queue**: Refinery maintains internal state for pending merges, not in beads at all. Clean but requires new infrastructure.

Wisps are the cleanest solution - they already exist, have the right semantics, and require minimal changes.

## Related

- Wisp architecture:
- Current MR creation: witness/refinery code paths
- bd-pvu0, bd-801b: Example MRs currently in permanent storage
EOF
)


Test message

Hello world


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].


gt spawn/crew setup should create .beads/redirect for worktrees

Crew clones and polecats need a .beads/redirect file pointing to the shared beads database (../../mayor/rig/.beads). Currently:

- redirect files can get deleted by git clean
- not auto-created during gt spawn or worktree setup
- missing redirects cause 'no beads database found' errors

Found missing in: gastown/joe, beads/zoey (after git clean)

Fix options:
1. gt spawn creates redirect during worktree setup
2. gt prime regenerates missing redirects
3. bd commands auto-detect worktree and find shared beads

This should be standard Gas Town rig configuration.


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.


bd ready resolves external dependencies

Extend bd ready to check external blocked_by references:

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

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

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

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


Restart daemons

Restart bd daemons to pick up new version.

```bash
bd daemons killall
```

Daemons will auto-restart with new version on next bd command.

Verify:
```bash
bd daemons list
```


mol-beads-release

Release checklist for beads version {{version}}.

This molecule ensures all release steps are completed properly.
Variable: {{version}} - target version (e.g., 0.35.0)

## Step: update-release-notes
Update cmd/bd/info.go with release notes for {{version}}.

Add a new VersionChange entry at the top of versionChanges slice:
```go
{
    Version: "{{version}}",
    Date:    "YYYY-MM-DD",
    Changes: []string{
        "NEW: Feature description",
        "FIX: Bug fix description",
        "IMPROVED: Enhancement description",
    },
},
```

Run `git log --oneline v<previous>..HEAD` to see what changed.

## Step: update-changelog
Update CHANGELOG.md with detailed release notes.

Add a new section after [Unreleased]:
```markdown
## [{{version}}] - YYYY-MM-DD

### Added
- **Feature name** (issue-id) - Description

### Changed
- **Change description** (issue-id)

### Fixed
- **Bug fix** (issue-id) - Description
```

Sort by importance, not chronologically.
Needs: update-release-notes

## Step: bump-version
Run the version bump script.

```bash
./scripts/bump-version.sh {{version}}
```

This updates version in all files:
- cmd/bd/version.go
- .claude-plugin/*.json
- integrations/beads-mcp/pyproject.toml
- npm-package/package.json
- Hook templates

Needs: update-changelog

## Step: run-tests
Run tests and verify lint passes.

```bash
go test -short ./...
```

CI will run full lint, but fix any obvious issues first.
Needs: bump-version

## Step: commit-release
Commit the release changes.

```bash
git add -A
git commit -m "chore: bump version to v{{version}}"
```

Needs: run-tests

## Step: push-and-tag
Push commit and create release tag.

```bash
git push origin main
git tag v{{version}}
git push origin v{{version}}
```

This triggers GitHub Actions release workflow.
Needs: commit-release

## Step: wait-for-ci
Wait for GitHub Actions to complete.

Monitor: https://github.com/steveyegge/beads/actions

CI will:
- Build binaries via GoReleaser
- Create GitHub Release with assets
- Publish to npm (@beads/bd)
- Publish to PyPI (beads-mcp)
- Update Homebrew tap

Wait until all jobs succeed (~5-10 min).
Needs: push-and-tag

## Step: verify-release
Verify the release is complete.

```bash
# Check GitHub release
gh release view v{{version}}

# Check Homebrew
brew update && brew info steveyegge/beads/bd

# Check npm
npm view @beads/bd version

# Check PyPI
pip index versions beads-mcp
```

Needs: wait-for-ci

## Step: update-local
Update local installations with proper codesigning (macOS).

```bash
# Build from source in mayor/rig (canonical build location)
cd ~/gt/beads/mayor/rig
git pull
go build -o bd ./cmd/bd

# Sign and install (macOS requires codesigning to avoid "Killed: 9")
# Uses fix-gt script which handles both gt and bd binaries
fix-gt

# Or manually sign if fix-gt not available:
# xattr -cr bd && codesign -f -s - bd
# cp bd ~/go/bin/bd && codesign -f -s - ~/go/bin/bd
# cp bd ~/.local/bin/bd && codesign -f -s - ~/.local/bin/bd

# Install MCP locally
pip install -e integrations/beads-mcp

# Restart daemons
pkill -f "bd daemon" || true
```

Verify: `bd --version` shows {{version}}
Needs: verify-release

## Step: manual-publish
(Optional) Manual publish if CI failed.

```bash
# npm (requires npm login)
./scripts/bump-version.sh {{version}} --publish-npm

# PyPI (requires TWINE credentials)
./scripts/bump-version.sh {{version}} --publish-pypi

# Or both
./scripts/bump-version.sh {{version}} --publish-all
```

Only needed if CI publishing failed.
Needs: wait-for-ci


bd sync fails with orphaned issues and duplicate ID conflict

After fixing the deleted_at TEXT column scanning bug (commit 18b1eb2), bd sync still fails with two issues:

1. Orphan Detection Warning: 12 orphaned child issues whose parents no longer exist (bd-cb64c226.* and bd-cbed9619.*)

2. Import Failure: UNIQUE constraint failed for bd-360 - this tombstone exists in both DB and JSONL

Error: "Import failed: error creating depth-0 issues: bulk insert issues: failed to insert issue bd-360: sqlite3: constraint failed: UNIQUE constraint failed: issues.id"

Fix options:
- Delete orphaned child issues with bd delete
- Resolve bd-360 duplicate (in deletions.jsonl vs tombstone in DB)
- Reset sync branch: git branch -f beads-sync main && git push --force-with-lease origin beads-sync

Fixed tombstone constraint violation bug. When deleting closed issues, the CHECK constraint (status = 'closed') = (closed_at IS NOT NULL) was violated because CreateTombstone didn't clear closed_at. Fix: set closed_at = NULL in tombstone creation SQL.

The sync data corruption (orphaned issues in beads-sync branch) requires manual cleanup: reset sync branch with 'git branch -f beads-sync main && git push --force-with-lease origin beads-sync'


Push commit and create release tag.

Push commit and create release tag.

```bash
git push origin main
git tag v0.37.0
git push origin v0.37.0
```

This triggers GitHub Actions release workflow.

instantiated_from: bd-mol-xga
step: push-and-tag


Distinct prefixes for protos, molecules, wisps

Template/workflow entities should have visually distinct prefixes from regular issues.

**Problem:**
- Protos (bd-7bs4) look like regular issues - invites squashing
- Molecules (poured instances) also use bd- prefix
- Wisps are in separate DB but still use bd- when referenced

**Proposed Prefixes:**
- `proto-` for templates (e.g., proto-release, proto-review)
- `mol-` for active molecules (poured from protos)
- `wisp-` for ephemeral wisps (vapor phase)

**Benefits:**
- Instant visual recognition of entity type
- Prevents accidental modification of templates
- Clear lifecycle: proto → mol → wisp → digest

**Implementation options:**
1. Separate databases with different prefixes
2. Issue type determines prefix generation
3. Naming convention enforced by bd pour/wisp commands


Add GetMoleculeProgress RPC endpoint

New RPC endpoint to get detailed progress for a specific molecule. Returns: moleculeID, title, assignee, and list of steps with their status (done/current/ready/blocked), start/close times. Used when user expands a worker in the activity feed TUI.


Consolidate git context into single cached struct

Code review finding from bd-7di fix.

Currently there are 3 separate caches:
- isWorktreeOnce/isWorktreeResult
- mainRepoRootOnce/mainRepoRootResult/mainRepoRootErr
- repoRootOnce/repoRootResult

These have redundant git calls - e.g. both isWorktreeUncached() and getMainRepoRootUncached() call getGitDirNoError("--git-common-dir").

Could consolidate into a single cached struct:
```go
type gitContext struct {
    gitDir     string
    commonDir  string
    repoRoot   string
    isWorktree bool
}
```

This would reduce git calls further and simplify ResetCaches().

File: internal/git/gitdir.go


beads-release

Beads release workflow - from version bump to verified release.

This formula orchestrates a complete release cycle:
1. Preflight checks (clean git, up to date)
2. Documentation updates (CHANGELOG, info.go)
3. Version bump (all components)
4. Git operations (commit, tag, push)
5. CI verification (GitHub Actions)
6. Artifact verification (GitHub, npm, PyPI)
7. Local installation update
8. Daemon restart

## Usage

```bash
bd wisp create beads-release --var version=0.37.0
```

Or assign to a polecat:
```bash
gt sling beads/polecats/p1 --formula beads-release --var version=0.37.0
```


bd mol search: Find formulas using GitHub API

Search for formulas in the Mol Mall using GitHub's search API.

## Usage
```bash
bd mol search "code review"           # Free text search
bd mol search --topic molecule         # By GitHub topic
bd mol search --org anthropics         # By organization
bd mol search --stars ">10"            # By popularity
```

## Implementation
1. Use GitHub Search API: `/search/repositories`
2. Filter by topic:mol-formula or naming convention
3. Parse results, show name/description/stars/version
4. Support pagination for large result sets

## Output
```
NAME                              STARS  DESCRIPTION
github.com/anthropics/mol-code-review  42  AI-assisted code review workflow
github.com/gastown/mol-polecat-work    12  Standard polecat work lifecycle
```

## Discovery Convention
Repos should have:
- Topic: `mol-formula` or `beads-molecule`
- Name starting with `mol-`
- formula.json in root


sync branch not match config

./bd sync
→ Exporting pending changes to JSONL...
→ No changes to commit
→ Pulling from sync branch 'gh-386'...
Error pulling from sync branch: failed to create worktree: failed to create worktree parent directory: mkdir /var/home/matt/dev/beads/worktree-db-fail/.git: not a directory
matt@blufin-framation ~/d/b/worktree-db-fail (worktree-db-fail) [1]> bd config list

Configuration:
  auto_compact_enabled = false
  compact_batch_size = 50
  compact_model = claude-3-5-haiku-20241022
  compact_parallel_workers = 5
  compact_tier1_days = 30
  compact_tier1_dep_levels = 2
  compact_tier2_commits = 100
  compact_tier2_days = 90
  compact_tier2_dep_levels = 5
  compaction_enabled = false
  issue_prefix = worktree-db-fail
  sync.branch = worktree-db-fail


test hash length


mol-beads-release

attached_args: Release v0.38.0 - execute each step in order, verify before proceeding to next

Release checklist for beads version 0.38.0.

This molecule ensures all release steps are completed properly.
Variable: 0.38.0 - target version (e.g., 0.35.0)

## Step: update-release-notes
Update cmd/bd/info.go with release notes for 0.38.0.

Add a new VersionChange entry at the top of versionChanges slice:
```go
{
    Version: "0.38.0",
    Date:    "YYYY-MM-DD",
    Changes: []string{
        "NEW: Feature description",
        "FIX: Bug fix description",
        "IMPROVED: Enhancement description",
    },
},
```

Run `git log --oneline v<previous>..HEAD` to see what changed.

## Step: update-changelog
Update CHANGELOG.md with detailed release notes.

Add a new section after [Unreleased]:
```markdown
## [0.38.0] - YYYY-MM-DD

### Added
- **Feature name** (issue-id) - Description

### Changed
- **Change description** (issue-id)

### Fixed
- **Bug fix** (issue-id) - Description
```

Sort by importance, not chronologically.
Needs: update-release-notes

## Step: bump-version
Run the version bump script.

```bash
./scripts/bump-version.sh 0.38.0
```

This updates version in all files:
- cmd/bd/version.go
- .claude-plugin/*.json
- integrations/beads-mcp/pyproject.toml
- npm-package/package.json
- Hook templates

Needs: update-changelog

## Step: run-tests
Run tests and verify lint passes.

```bash
go test -short ./...
```

CI will run full lint, but fix any obvious issues first.
Needs: bump-version

## Step: commit-release
Commit the release changes.

```bash
git add -A
git commit -m "chore: bump version to v0.38.0"
```

Needs: run-tests

## Step: push-and-tag
Push commit and create release tag.

```bash
git push origin main
git tag v0.38.0
git push origin v0.38.0
```

This triggers GitHub Actions release workflow.
Needs: commit-release

## Step: wait-for-ci
Wait for GitHub Actions to complete.

Monitor: https://github.com/steveyegge/beads/actions

CI will:
- Build binaries via GoReleaser
- Create GitHub Release with assets
- Publish to npm (@beads/bd)
- Publish to PyPI (beads-mcp)
- Update Homebrew tap

Wait until all jobs succeed (~5-10 min).
Needs: push-and-tag

## Step: verify-release
Verify the release is complete.

```bash
# Check GitHub release
gh release view v0.38.0

# Check Homebrew
brew update && brew info steveyegge/beads/bd

# Check npm
npm view @beads/bd version

# Check PyPI
pip index versions beads-mcp
```

Needs: wait-for-ci

## Step: update-local
Update local installations.

```bash
# Upgrade Homebrew
brew upgrade steveyegge/beads/bd

# Or install from source
./scripts/bump-version.sh 0.38.0 --install

# Install MCP locally
pip install -e integrations/beads-mcp

# Restart daemons
pkill -f "bd daemon" || true
```

Verify: `bd --version` shows 0.38.0
Needs: verify-release

## Step: manual-publish
(Optional) Manual publish if CI failed.

```bash
# npm (requires npm login)
./scripts/bump-version.sh 0.38.0 --publish-npm

# PyPI (requires TWINE credentials)
./scripts/bump-version.sh 0.38.0 --publish-pypi

# Or both
./scripts/bump-version.sh 0.38.0 --publish-all
```

Only needed if CI publishing failed.
Needs: wait-for-ci


Test actor direct


Test hook


Code smell: Issue struct is a God Object (50+ fields)

attached_args: Refactor Issue struct God Object

The Issue struct in internal/types/types.go has 50+ fields covering many different concerns:

- Basic issue tracking (ID, Title, Description, Status, Priority)
- Messaging/communication (Sender, Ephemeral, etc.)
- Agent identity (HookBead, RoleBead, AgentState, RoleType, Rig)
- Gate/async coordination (AwaitType, AwaitID, Timeout, Waiters)
- Source tracing (SourceFormula, SourceLocation)
- HOP validation/entities (Creator, Validations)
- Compaction (CompactionLevel, CompactedAt, OriginalSize)
- Tombstones (DeletedAt, DeletedBy, DeleteReason)

Consider:
1. Extracting field groups into embedded structs (e.g., AgentFields, GateFields)
2. Using composition pattern to make the struct more modular
3. At minimum, grouping related fields together with section comments

Location: internal/types/types.go:12-82


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%


Update local installations.

Update local installations.

```bash
# Upgrade Homebrew
brew upgrade steveyegge/beads/bd

# Or install from source
./scripts/bump-version.sh 0.37.0 --install

# Install MCP locally
pip install -e integrations/beads-mcp

# Restart daemons
pkill -f "bd daemon" || true
```

Verify: `bd --version` shows 0.37.0

instantiated_from: bd-mol-xga
step: update-local


Verify npm package

Confirm npm package published.

```bash
npm show @beads/bd version
```

Should show 0.39.0.

Also check: https://www.npmjs.com/package/@beads/bd


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.


Pinned field available in beads v0.37.0

Hey max,

Heads up on your mail overhaul work:

1. **Pinned field is available** - beads v0.37.0 (released by dave earlier) includes the pinned field on issues. You'll want to add this to BeadsMessage in types.go.

2. **Database migration** - Check if existing .beads databases need migration to support the pinned field. Run `bd doctor` to see if it flags anything.

3. **Sorting task** - Once you have the pinned field, gt-ngu1 (pinned beads first in mail inbox) needs implementing. Since messages now come from `bd list --type=message`, you'll need to either:
   - Sort in listBeads() after fetching, or
   - Ensure bd list returns pinned items first (may already do this?)

Check what version of bd you're building against.

-- Mayor


bd mol current: soft cursor showing current/next step

Add bd mol current command for molecule navigation orientation.

## Usage

bd mol current [mol-id]

If mol-id given, show status for that molecule.
If not given, infer from in_progress issues assigned to current agent.

## Output

You're working on molecule gt-abc (Feature X)

  [done] gt-abc.1: Design
  [done] gt-abc.2: Scaffold
  [done] gt-abc.3: Implement
  [current] gt-abc.4: Write tests [in_progress] <- YOU ARE HERE
  [pending] gt-abc.5: Documentation
  [pending] gt-abc.6: Exit decision

Progress: 3/6 steps complete

## Key behaviors
- Shows full molecule structure with status indicators
- Highlights current in_progress step
- If no in_progress, highlights first ready step
- Works without explicit cursor tracking (inferred from state)

## Implementation notes
- Query children of mol-id
- Sort by dependency order
- Find first in_progress or first ready
- Format with status indicators

## Gas Town integration
- gt-lz13: Update templates with nav workflow
- gt-um6q: Update docs with nav workflow


Add bd agent state command for ZFC-compliant state reporting

Add command for agents to write their own state to agent beads.

```bash
bd agent state <agent-id> <state>
# Example: bd agent state gt-mayor running
# States: idle | running | stuck | stopped | dead
```

Implementation:
1. Lookup agent bead by ID (type=agent)
2. Update agent_state field in description
3. Update last_activity timestamp
4. Trigger bd sync if configured

Also add:
- bd agent heartbeat <agent-id> - just updates last_activity
- bd agent show <agent-id> - show agent bead details

This is the ZFC-compliant way for agents to self-report state.

Cross-ref: gt-p2vyo in gastown


Deferred HOP schema additions (P2/P3)

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

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

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


Merge: bd-gqxd

branch: polecat/furiosa
target: main
source_issue: bd-gqxd
rig: beads


Merge: bd-thgk

branch: polecat/Compactor
target: main
source_issue: bd-thgk
rig: beads


Add content-addressable identity to Issue type

**Summary:** Added content-addressable identity to Issue type by implementing a ContentHash field that generates a unique SHA256 fingerprint based on semantic issue content. This resolves issue identification challenges when multiple system instances create issues with identical IDs but different contents.

**Key Decisions:**
- Use SHA256 for content hashing
- Hash excludes ID and timestamps
- Compute hash automatically at creation/import time
- Add database column for hash storage

**Resolution:** Successfully implemented a deterministic content hashing mechanism that enables reliable issue identification across distributed systems, improving data integrity and collision detection.


Witness Patrol

Per-rig worker monitor patrol loop with progressive nudging.


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.


Run bump-version.sh

./scripts/bump-version.sh {{version}}


Update docs for import bug fix

Update AGENTS.md, README.md, TROUBLESHOOTING.md with import.orphan_handling config documentation. Document resurrection behavior, tombstones, config modes. Add troubleshooting section for import failures with deleted parents.


Improve test coverage for cmd/bd CLI (26.2% → 50%)

The main CLI package (cmd/bd) has only 26.2% test coverage. CLI commands should have at least 50% coverage to ensure reliability.

Key areas with low/no coverage:
- daemon_autostart.go (multiple 0% functions)
- compact.go (several 0% functions)
- Various command handlers

Current coverage: 26.2%
Target coverage: 50%

## Progress Update (2025-12-23)

### Tests Added
Added 683 lines of new tests across 3 files:
- cmd/bd/daemon_config_test.go (144 lines)
- cmd/bd/utils_test.go (484 lines)
- cmd/bd/autostart_test.go (55 additional lines)

### Functions Now Tested
- daemon_config.go: ensureBeadsDir, getPIDFilePath, getLogFilePath, getSocketPathForPID
- daemon_autostart.go: determineSocketPath, isDaemonRunningQuiet
- activity.go: printEvent
- cleanup.go: showCleanupDeprecationHint
- upgrade.go: pluralize
- wisp.go: formatTimeAgo
- list.go: pinIndicator, sortIssues
- hooks.go: FormatHookWarnings, isRebaseInProgress, hasBeadsJSONL
- template.go: extractIDSuffix
- thanks.go: getContributorsSorted

### Coverage Results
- Before: 22.5%
- After: 23.1%
- Delta: +0.6%

### Remaining Work
Most remaining untested code (77%) involves:
1. Daemon/RPC operations (runDaemonLoop, tryAutoStartDaemon, etc.)
2. Command handlers that require database/daemon setup
3. Git operations (runPreCommitHook, runPostMergeHook, etc.)

To reach 50%, would need to:
- Add integration tests with mocked daemon
- Add scripttest tests for command handlers
- Add more database-dependent tests

Commit: 4f949c19


Code Review Followup Summary: PR #481 + PR #551

## Merged PRs Summary

### PR #551: Persist close_reason to issues table
- ✅ Merged successfully
- ✅ Bug fix: close_reason now persisted in database column (not just events table)
- ✅ Comprehensive test coverage added
- ✅ Handles reopen case (clearing close_reason)

**Followup Issues Filed:**
- bd-lxzx: Document close_reason in JSONL export format
- bd-077e: Update CLI documentation for close_reason field

---

### PR #481: Context Engineering Optimizations (80-90% context reduction)
- ✅ Merged successfully
- ✅ Lazy tool discovery: discover_tools() + get_tool_info()
- ✅ Minimal issue models: IssueMinimal (~80% smaller than full Issue)
- ✅ Result compaction: Auto-compacts results >20 items
- ✅ All 28 tests passing
- ⚠ Breaking change: ready() and list() return type changed

**Followup Issues Filed:**
- bd-b318: Add integration tests for CompactedResult
- bd-4u2b: Make compaction settings configurable (THRESHOLD, PREVIEW_COUNT)
- bd-2kf8: Document CompactedResult response format in CONTEXT_ENGINEERING.md
- bd-pdr2: Document backwards compatibility considerations

---

## Overall Assessment

Both PRs are production-ready with solid implementations. All critical functionality works and tests pass. Followup issues focus on:
1. Documentation improvements (5 issues)
2. Integration test coverage (1 issue)
3. Configuration flexibility (1 issue)
4. Backwards compatibility guidance (1 issue)

No critical bugs or design issues found.

## Review Completed By
Code review process completed. Issues auto-created for tracking improvements.


Work on gt-8tmz.10: Rename Engineer in Box to Shiny. Rena...

Work on gt-8tmz.10: Rename Engineer in Box to Shiny. Rename mol-engineer-in-box references to mol-shiny or just 'shiny'. Update docs and code in internal/formula/ and .beads/formulas/. When done: 1) bd close gt-8tmz.10, 2) bd sync, 3) git push, 4) gt mq submit


Re: Thread Test 2

Got your message. Testing reply feature.


Protos should have distinct prefix (e.g., proto-)

Currently protos use the same bd- prefix as regular issues, making them visually indistinguishable. When you see bd-7bs4 it looks like work to squash, not a reusable template.

**Problem:**
- Protos look like regular issues
- No visual signal that something is a template vs active work
- Easy to accidentally close/modify protos thinking they're issues

**Proposed Solution:**
- Protos should have their own prefix (e.g., `proto-`, `mol-`, or `tpl-`)
- Could be a separate database/storage for the proto library
- Or a convention where proto IDs are generated differently

**Alternatives:**
1. Separate proto database with `proto-` prefix
2. Special ID format for protos (e.g., `bd:proto:release`)
3. Visual indicator in bd list/show output (already have labels, but not enough)

**Current workaround:** Label with `template` and `molecule`, but IDs still look like regular issues.


Merge: bd-dtl8

branch: polecat/dag
target: main
source_issue: bd-dtl8
rig: beads


Routing bypassed in daemon mode

## Bug

Prefix-based routing (routes.jsonl) only works in direct mode. When the daemon is running, it bypasses routing logic because:

1. Daemon mode resolves IDs via RPC (`daemonClient.ResolveID`)
2. Daemon uses its own store, which only knows about local beads
3. The routing logic in `resolveAndGetIssueWithRouting` is only called in direct mode

## Reproduction

```bash
# With daemon running:
cd ~/gt
bd show gt-1py3y  # Fails - daemon can't find it

# With daemon bypassed:
bd --no-daemon show gt-1py3y  # Works - uses routing
```

## Fix Options

### Option A: Client-side routing detection (Recommended)
Before calling daemon RPC, check if the ID prefix matches a route to a different beads dir. If so, use direct mode with routing for that ID.

```go
// In show.go, before daemon mode:
if daemonClient != nil && needsRouting(id) {
    // Fall back to direct mode for this ID
    result, err := resolveAndGetIssueWithRouting(ctx, store, id)
    ...
}
```

### Option B: Daemon-side routing
Add routing support to the daemon RPC server. More complex - daemon would need to:
- Load routes.jsonl on startup
- Open connections to multiple databases
- Route requests based on ID prefix

### Option C: Hybrid
Daemon returns "not found + prefix hint", client retries with routing.

## Recommendation

Option A is simplest. The client already has routing logic; just use it when we detect a routed prefix.


gt mq list shows empty when MRs exist


Merge: bd-ao0s

branch: polecat/rictus
target: main
source_issue: bd-ao0s
rig: beads


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.


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


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.


Create and push git tag v{{version}}

Create the release tag and push it:

```bash
git tag v{{version}}
git push origin v{{version}}
```

This triggers the GoReleaser GitHub Action to build release binaries.


Document pinned status in CLI_REFERENCE.md

## Task

The `pinned` status is a valid issue status but is not documented in CLI_REFERENCE.md.

## Current Status Values (from types.go:295-301)

- open
- in_progress
- blocked
- deferred
- closed
- tombstone
- **pinned** ← undocumented

## Definition

`StatusPinned Status = "pinned" // Persistent bead that stays open indefinitely (bd-6v2)`

## Where to Document

Add to the 'Issue Types' or create a new 'Issue Statuses' section in docs/CLI_REFERENCE.md.

## Related

The pinned status is heavily used by gt for hook management (`--status=pinned`).


test pin issue


Fix G104 errors unhandled in internal/storage/sqlite/queries.go:1181

Linting issue: G104: Errors unhandled (gosec) at internal/storage/sqlite/queries.go:1181:4. Error: rows.Close()


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.


Preflight: Check git status

Ensure working tree is clean before starting release.

```bash
git status
```

If there are uncommitted changes, either:
- Commit them first
- Stash them: `git stash`
- Abort and resolve


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.


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


Gate await fields cleared by auto-flush/auto-import cycle

## Problem

When creating a gate with `--await` fields (e.g., `gh:run:123`), the await_type and await_id are initially stored correctly in the SQLite database. However, they get cleared (set to empty strings) during subsequent bd commands due to the auto-flush/auto-import cycle.

## Reproduction Steps

1. Create a gate with await:
   ```
   bd gate create --molecule test-mol --await gh:run:20517738002
   ```
   Output shows correct `await_type: gh:run, await_id: 20517738002`

2. Check database - fields are present

3. Run any bd command (e.g., `bd list`)

4. Check database again - await_type and await_id are now empty

## Root Cause

Gates are wisps (ephemeral issues). During the auto-flush cycle:
1. Auto-flush exports issues to JSONL (filtering out wisps)
2. Auto-import reads JSONL and updates DB rows
3. The update clears fields that weren't in the JSONL (including await fields)

## Workaround

Using `--no-auto-import --no-auto-flush` flags preserves the fields, but this isn't practical for normal use.

## Impact

GitHub gate evaluation (`bd gate eval`) cannot work because by the time eval runs, the await fields have been cleared.

## Suggested Fix

Either:
1. Don't clear await fields during auto-import if they weren't in the source
2. Store wisp fields separately from the main JSONL export
3. Include wisps in export but filter them at sync time


Refinery Patrol

Merge queue processor patrol loop with verification gates.


Add computed .parent field to JSON output for convenience

Currently parent is only in dependencies[]. Add a top-level .parent field to JSON/JSONL output that extracts the parent-child dependency for easier querying.

Example:
```bash
# Current (works but verbose):
bd show <id> --json | jq '.[0].dependencies[] | select(.dependency_type == "parent-child") | .id'

# Desired:
bd show <id> --json | jq '.[0].parent'
```

Low priority enhancement.


Code smell: Multiple CLI command files exceed 1000 lines

Several CLI command files are very large and could benefit from splitting:

| File | Lines | Notes |
|------|-------|-------|
| init.go | 1928 | Multiple init modes, contributor/team setup |
| show.go | 1592 | Display formatting, tree views, output modes |
| doctor.go | 1295 | Many health checks |
| sync.go | 1201 | Sync branch operations |
| compact.go | 1199 | Compaction logic |
| linear.go | 1190 | Linear integration |
| main.go | 1148 | Entry point and globals |

Consider:
1. Splitting init.go into init_core.go, init_contributor.go (already exists), init_team.go (already exists)
2. Moving show.go formatters to internal/ui package
3. Doctor checks could be individual files under doctor/ subpackage (already started)

Location: cmd/bd/*.go


Support --reason flag in daemon mode for reopen command

The reopen.go command has a TODO at line 61 to add reason as a comment once RPC supports AddComment. Currently --reason flag is ignored in daemon mode with a warning.


Witness Patrol

Per-rig worker monitor patrol loop with progressive nudging.


Update cmd/bd/info.go with release notes for 0.37.0.

Add a new VersionChange entry at the top of versionChanges slice:
```go
{
    Version: "0.37.0",
    Date:    "YYYY-MM-DD",
    Changes: []string{
        "NEW: Feature description",
        "FIX: Bug fix description",
        "IMPROVED: Enhancement description",
    },
},
```

Run `git log --oneline v<previous>..HEAD` to see what changed.

instantiated_from: bd-mol-xga
step: update-release-notes


Add git operations for --hard reset

Implement git integration for hard reset mode.

## Operations Needed
1. `git rm -rf .beads/*.jsonl` - remove data files from index
2. `git commit -m 'beads: reset to clean state'` - commit removal
3. After re-init: `git add .beads/` and commit fresh state

## Edge Cases to Handle
- Uncommitted changes in .beads/ - warn or error
- Detached HEAD state - warn, maybe block
- Git not initialized - skip git ops, warn
- Git operations fail mid-way - clear error messaging

## Interface
```go
type GitState struct {
    IsRepo       bool
    IsDirty      bool   // uncommitted changes in .beads/
    IsDetached   bool   // detached HEAD
    Branch       string // current branch name
}

func CheckGitState(beadsDir string) (*GitState, error)
func GitRemoveBeads(beadsDir string) error
func GitCommitReset(message string) error
func GitAddAndCommit(beadsDir, message string) error
```

## Location
`internal/reset/git.go` - keep with reset package for now

Note: Codebase has no central git package. internal/compact/git.go is compact-specific.
Future refactoring could extract shared git utilities, but YAGNI for now.


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.


Gate eval: Consider rate limiting for GitHub API calls

Each gate evaluation makes a network call to GitHub API via gh CLI. With many gates, this could hit API rate limits.

Future improvements:
1. Batch queries where possible
2. Add caching with TTL for recently-checked gates
3. Exponential backoff on rate limit errors

Low priority - unlikely to be an issue until we have many concurrent gates.


Deacon Patrol

Mayor's daemon patrol loop for handling callbacks, health checks, and cleanup.


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.


Verify release artifacts

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


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


Implement bd mol stale command

Add command to detect complete-but-unclosed molecules.

**Definition of stale:**
A molecule is stale if:
1. All children are closed (Completed >= Total)
2. Root issue is still open
3. Not assigned to anyone
4. Not pinned to any hook
5. AND it's blocking other assigned work (graph pressure)

**Command design:**
```bash
bd mol stale              # List stale mols
bd mol stale --json       # Machine-readable
bd mol stale --blocking   # Only show those blocking other work
bd mol stale --all        # Include orphaned-but-not-blocking
```

**Output:**
```
Stale molecules (complete but unclosed, blocking work):

  bd-xyz  "Version bump v0.36.0"  (blocking: bd-abc, bd-def)
    → Close with: bd close bd-xyz
    → Or squash: bd mol squash bd-xyz

Orphaned molecules (complete but unclosed, not blocking):
  bd-uvw  "Old patrol cycle"
    → Consider: bd mol burn bd-uvw
```

**Implementation:**
1. Query all open issues with children (potential mols)
2. Compute progress for each (Completed vs Total)
3. Filter to complete ones
4. Check assigned_to field
5. Check pinned status (may need gt integration)
6. Check if blocking other assigned work

Does NOT use time-based staleness. Graph pressure only.


Run bd doctor at end of bd init to verify setup

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


Support external: prefix in blocked_by field

Allow blocked_by to include external project references:

```bash
bd update gt-xyz --blocked-by="external:beads:mol-run-assignee"
```

Syntax: `external:<project>:<capability>`
- project: name from external_projects config
- capability: matches provides:<capability> label in target project

Storage: Store as-is in blocked_by array. Resolution happens at query time.

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


Monitor npm publish

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

Verify at: https://www.npmjs.com/package/@anthropics/claude-code-beads-plugin/v/0.30.4

Check:
```bash
npm view @anthropics/claude-code-beads-plugin@0.30.4 version
```

```verify
npm view @anthropics/claude-code-beads-plugin@0.30.4 version 2>/dev/null | grep -q '0.30.4'
```


Gate eval: Add error visibility for gh CLI failures

Currently evalGHRunGate and evalGHPRGate silently swallow errors when the gh CLI fails (lines 738-741, 780-783 in gate.go).

This makes debugging difficult - if gh isn't installed, auth fails, or network issues occur, gates silently stall forever with no indication of why.

Options:
1. Add debug logging when gh fails
2. Return error info in the skipped list for aggregate reporting
3. Add a --verbose flag to gate eval that shows failures

Low priority since the fail-safe behavior (don't close gate on error) is correct.


Merge: bd-io8c

branch: polecat/Syncer
target: main
source_issue: bd-io8c
rig: beads


Run tests and verify lint passes.

Run tests and verify lint passes.

```bash
go test -short ./...
```

CI will run full lint, but fix any obvious issues first.

instantiated_from: bd-mol-xga
step: run-tests


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 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.


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.


Centralize error handling patterns in storage layer

80+ instances of inconsistent error handling across sqlite.go with mix of %w, %v, and no wrapping.

Location: internal/storage/sqlite/sqlite.go (throughout)

Problem:
- Some use fmt.Errorf("op failed: %w", err) - correct wrapping
- Some use fmt.Errorf("op failed: %v", err) - loses error chain
- Some return err directly - no context
- Hard to debug production issues
- Can't distinguish error types

Solution: Create internal/storage/sqlite/errors.go:
- Define sentinel errors (ErrNotFound, ErrInvalidID, etc.)
- Create wrapDBError(op string, err error) helper
- Convert sql.ErrNoRows to ErrNotFound
- Always wrap with operation context

Impact: Lost error context; inconsistent messages; hard to debug

Effort: 5-7 hours


Polymorphic bond command: bd mol bond A B

Implement proto-to-proto bonding to create compound protos.

COMMAND: bd mol bond proto-feature proto-testing [--as proto-feature-tested] [--type sequential]

BEHAVIOR:
- Load both proto subgraphs
- Create new compound proto with combined structure
- B's root becomes child of A's root (sequential) or sibling (parallel)
- Wire dependencies: B depends on A's leaf nodes (sequential) or runs parallel
- Store bonded_from metadata for lineage tracking

FLAGS:
- --as NAME: Custom ID for compound proto (default: generates hash)
- --type: sequential (default) or parallel
- --dry-run: Preview compound structure

OUTPUT:
- New compound proto in catalog
- Shows combined variable requirements

UPDATE: bond is now polymorphic - handles proto+proto, proto+mol, and mol+mol based on operand types. Separate 'attach' command eliminated.


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.


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 Agent


Add thread-safety warning to git.ResetCaches() doc comment

Code review finding from bd-7di fix.

ResetCaches() reassigns sync.Once values which is not thread-safe. While this is only used in tests (which are single-threaded), the function is exported and could be misused.

Add a warning comment:
```go
// ResetCaches resets all cached git information.
// WARNING: Not thread-safe. Only call from single-threaded test contexts.
```

File: internal/git/gitdir.go


Re: Thread Test 2

Great! Thread is working well.


Merge: bd-ykd9

branch: polecat/Doctor
target: main
source_issue: bd-ykd9
rig: beads


Version Bump: 0.30.7

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


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.


Merge: bd-9usz

branch: polecat/slit
target: main
source_issue: bd-9usz
rig: beads


Execute molecule bd-mol-xga: Release beads 0.37.0


bd merge omits priority:0 due to omitempty JSON tag

GitHub issue #671. The merge code in internal/merge/merge.go uses 'omitempty' on the Priority field, which causes priority:0 (P0/critical) to be dropped from JSON output since 0 is Go's zero value for int. Fix: either remove omitempty from Priority field or use a pointer (*int). This affects the git merge driver and causes P0 issues to lose their priority.


CLI API Audit for OSS Launch

Comprehensive CLI API audit before OSS launch.

## Tasks
1. Review gt command groupings - propose consolidation
2. Review bd command groupings
3. Document gt vs bd ownership boundaries
4. Identify naming inconsistencies
5. Document flag vs subcommand criteria

## Context
- Pre-OSS launch cleanup
- Goal: clean, consistent, discoverable CLI surface


Digest: Version Bump: test-squash

## Molecule Execution Summary

**Molecule**: Version Bump: test-squash
**Steps**: 8

**Completed**: 0/8

---

### Steps

1. **[open]** Verify release artifacts
   Check GitHub releases page - binaries for darwin/linux/windows should be available

2. **[open]** Commit and push release
   git add -A && git commit && git push to trigger CI

3. **[open]** Update CHANGELOG.md with release notes
   Add meaningful release notes to CHANGELOG.md describing what changed in test-squash

4. **[open]** Wait for CI to pass
   Monitor GitHub Actions - all checks must pass before release artifacts are built

5. **[open]** Restart running daemons
   Kill and restart any running bd daemons to pick up new version: pkill -f 'bd daemon' && bd daemon --start

6. **[open]** Update local installation
   Run install script or brew upgrade to get new version locally: curl -fsSL .../install.sh | bash

7. **[open]** Run bump-version.sh test-squash
   Run ./scripts/bump-version.sh test-squash to update version in all files

8. **[open]** Update info.go versionChanges
   Add entry to versionChanges in cmd/bd/info.go with agent-actionable changes for test-squash


Add unit tests for reset package

Comprehensive unit tests for internal/reset package.

## Test Cases

### ValidateState tests
- .beads/ exists → success
- .beads/ missing → appropriate error
- git dirty state detection

### CountImpact tests
- Empty .beads/ → zero counts
- With issues → correct count (open vs closed)
- With tombstones → correct count
- Returns HasUncommitted correctly

### Backup tests
- Creates backup with correct timestamp format
- Preserves all files and permissions
- Returns correct path
- Handles missing .beads/ gracefully
- Errors on pre-existing backup dir

### Git operation tests
- CheckGitState detects dirty, detached, not-a-repo
- GitRemoveBeads removes correct files
- GitCommitReset creates commit with message
- Operations skip gracefully when not in git repo

### Reset tests (with mocks/temp dirs)
- Soft reset removes files, calls init
- Hard reset includes git operations
- Dry run doesn't modify anything
- SkipInit flag prevents re-initialization
- Daemon killall is called
- Backup is created when requested

## Approach
- Can start with interface definitions (TDD style)
- Use testify for assertions
- Create temp directories for isolation
- Mock git operations where needed
- Test completion depends on implementation tasks

## File Location
`internal/reset/reset_test.go`
`internal/reset/backup_test.go`
`internal/reset/git_test.go`


Test role bead


Cross-rig external dependency support

Support dependencies on issues in other rigs/repos.

## Use Case

Gas Town issues often depend on Beads issues (and vice versa). Currently we use labels like `external:beads/bd-xxx` as documentation, but:
- `bd blocked` doesn't recognize external deps
- `bd ready` doesn't filter them out
- No way to query cross-rig status

## Proposed UX

### Adding external deps
```bash
# New syntax for bd dep add
bd dep add gt-a07f external:beads:bd-kwjh

# Or maybe cleaner
bd dep add gt-a07f --external beads:bd-kwjh
```

### Showing blocked status
```bash
bd blocked
# → gt-a07f blocked by external:beads:bd-kwjh (unverified)

# With optional cross-rig query
bd blocked --resolve-external
# → gt-a07f blocked by external:beads:bd-kwjh (closed) ← unblocked!
```

### Storage
Could use:
- Special dependency type: `type: external`
- Label convention: `external:rig:id`
- New field: `external_deps: ["beads:bd-kwjh"]`

## Implementation Notes

Cross-rig queries would need:
- Known rig locations (config or discovery)
- Read-only beads access to external rigs
- Caching to avoid repeated queries

For MVP, just recognizing external deps and marking them as 'unverified' blockers would be valuable.


Verify PyPI package

Confirm PyPI package published.

```bash
pip index versions beads-mcp 2>/dev/null | head -3
```

Or check: https://pypi.org/project/beads-mcp/

Should show 0.39.0.


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.


Gate await fields cleared by --no-daemon CLI access (not multi-repo)


Merge: bd-n386

branch: polecat/immortan
target: main
source_issue: bd-n386
rig: beads


mol-beads-release

Release checklist for beads version 0.99.0.

This molecule ensures all release steps are completed properly.
Variable: 0.99.0 - target version (e.g., 0.35.0)

## Step: update-release-notes
Update cmd/bd/info.go with release notes for 0.99.0.

Add a new VersionChange entry at the top of versionChanges slice:
```go
{
    Version: "0.99.0",
    Date:    "YYYY-MM-DD",
    Changes: []string{
        "NEW: Feature description",
        "FIX: Bug fix description",
        "IMPROVED: Enhancement description",
    },
},
```

Run `git log --oneline v<previous>..HEAD` to see what changed.

## Step: update-changelog
Update CHANGELOG.md with detailed release notes.

Add a new section after [Unreleased]:
```markdown
## [0.99.0] - YYYY-MM-DD

### Added
- **Feature name** (issue-id) - Description

### Changed
- **Change description** (issue-id)

### Fixed
- **Bug fix** (issue-id) - Description
```

Sort by importance, not chronologically.
Needs: update-release-notes

## Step: bump-version
Run the version bump script.

```bash
./scripts/bump-version.sh 0.99.0
```

This updates version in all files:
- cmd/bd/version.go
- .claude-plugin/*.json
- integrations/beads-mcp/pyproject.toml
- npm-package/package.json
- Hook templates

Needs: update-changelog

## Step: run-tests
Run tests and verify lint passes.

```bash
go test -short ./...
```

CI will run full lint, but fix any obvious issues first.
Needs: bump-version

## Step: commit-release
Commit the release changes.

```bash
git add -A
git commit -m "chore: bump version to v0.99.0"
```

Needs: run-tests

## Step: push-and-tag
Push commit and create release tag.

```bash
git push origin main
git tag v0.99.0
git push origin v0.99.0
```

This triggers GitHub Actions release workflow.
Needs: commit-release

## Step: wait-for-ci
Wait for GitHub Actions to complete.

Monitor: https://github.com/steveyegge/beads/actions

CI will:
- Build binaries via GoReleaser
- Create GitHub Release with assets
- Publish to npm (@beads/bd)
- Publish to PyPI (beads-mcp)
- Update Homebrew tap

Wait until all jobs succeed (~5-10 min).
Needs: push-and-tag

## Step: verify-release
Verify the release is complete.

```bash
# Check GitHub release
gh release view v0.99.0

# Check Homebrew
brew update && brew info steveyegge/beads/bd

# Check npm
npm view @beads/bd version

# Check PyPI
pip index versions beads-mcp
```

Needs: wait-for-ci

## Step: update-local
Update local installations.

```bash
# Upgrade Homebrew
brew upgrade steveyegge/beads/bd

# Or install from source
./scripts/bump-version.sh 0.99.0 --install

# Install MCP locally
pip install -e integrations/beads-mcp

# Restart daemons
pkill -f "bd daemon" || true
```

Verify: `bd --version` shows 0.99.0
Needs: verify-release

## Step: manual-publish
(Optional) Manual publish if CI failed.

```bash
# npm (requires npm login)
./scripts/bump-version.sh 0.99.0 --publish-npm

# PyPI (requires TWINE credentials)
./scripts/bump-version.sh 0.99.0 --publish-pypi

# Or both
./scripts/bump-version.sh 0.99.0 --publish-all
```

Only needed if CI publishing failed.
Needs: wait-for-ci


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
```


Test Thread

Initial message for threading test


Add close_reason to JSONL export format documentation

PR #551 now persists close_reason to the database, but there's a question about whether this field should be exported to JSONL format.

## Current State
- close_reason is stored in issues.close_reason column
- close_reason is also stored in events table (audit trail)
- The JSONL export format may or may not include close_reason

## Questions
1. Should close_reason be exported to JSONL format?
2. If yes, where should it go (root level or nested in events)?
3. Should there be any special handling to avoid duplication?
4. How should close_reason be handled during JSONL import?

## Why This Matters
- JSONL is the git-friendly sync format
- Other beads instances import from JSONL
- close_reason is meaningful data that should be preserved across clones

## Suggested Action
- Check if close_reason is currently exported in JSONL
- If not, add it to the export schema
- Document the field in JSONL format spec
- Add tests for round-trip (export -> import -> verify close_reason)


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)


bd ship command for publishing capabilities

Add `bd ship <capability>` command that:

1. Finds issue with `export:<capability>` label
2. Validates issue is closed (or --force to override)
3. Adds `provides:<capability>` label
4. Protects `provides:*` namespace (only bd ship can add these labels)

Example:
```bash
bd ship mol-run-assignee
# Output: Shipped mol-run-assignee (bd-xyz)
```

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


bd create --rig flag for cross-rig issue filing

## Problem

To create an issue in a different rig, you must cd to that rig's directory. This is clunky when coordinating across rigs.

## Proposed Solution

Add a --rig flag to bd create that leverages existing routes.jsonl:

```bash
# From anywhere in town
bd create --rig beads --title="bug report" --type=bug

# Equivalent to:
cd ~/gt/beads/mayor/rig && bd create --title="..."
```

## How it works

1. Parse --rig flag (rig name, not prefix)
2. Look up rig in routes.jsonl to find beads location
3. Determine prefix from rig config
4. Create issue in that location with auto-generated ID

## Why elegant

- Leverages existing routing infrastructure
- Rig names are human-memorable (not cryptic prefixes)
- Works from anywhere in town
- Prefix auto-determined from rig config
- Reads naturally: "create in beads"

## Alternative

Also consider --prefix for power users who know prefixes:
```bash
bd create --prefix bd "Title here"
```


Update documentation for CLI consolidation

## Task
Update all documentation to reflect CLI consolidation changes.

## Files requiring updates

### Primary docs
- docs/CLI_REFERENCE.md - Major updates
  - Add admin section (cleanup, compact, reset)
  - Update migrate section (subcommands)
  - Update formula section (add cook)
  - Remove/update standalone command references

### Secondary docs
- docs/DELETIONS.md - migrate-tombstones → migrate tombstones, compact → admin compact
- docs/FAQ.md - compact → admin compact
- docs/QUICKSTART.md - compact, cleanup → admin compact, admin cleanup
- docs/TROUBLESHOOTING.md - compact → admin compact
- docs/CONFIG.md - compact → admin compact
- docs/INSTALLING.md - quickstart reference
- docs/EXTENDING.md - quickstart reference

### Skills docs
- skills/beads/SKILL.md - compact, quickstart references
- skills/beads/references/CLI_REFERENCE.md - mirror main CLI_REFERENCE.md

### Other docs
- commands/quickstart.md - update or remove
- commands/compact.md - update to admin compact
- examples/compaction/README.md - update examples
- README.md - quickstart reference
- CHANGELOG.md - add consolidation changes section

## Implementation notes
- Keep backwards compatibility notices where aliases exist
- Update command examples to use new paths
- Consider adding deprecation warnings section


Cross-project dependency support

Enable tracking dependencies across project boundaries.

## Mechanism
- Producer: `bd ship <capability>` adds `provides:<capability>` label
- Consumer: `blocked_by: external:<project>:<capability>`
- Resolution: `bd ready` checks external deps via config

## Design Doc
See: gastown/docs/cross-project-deps.md

## Children
- bd-eijl: bd ship command
- bd-om4a: external: prefix in blocked_by
- bd-66w1: external_projects config
- bd-zmmy: bd ready resolution


Implement core reset package (internal/reset)

Create the core reset logic in internal/reset/ package.

## Responsibilities
- ResetOptions struct with all flag options
- CountImpact() - count issues/tombstones that will be deleted
- ValidateState() - check .beads/ exists, check git dirty state
- ExecuteReset() - main reset logic (without CLI concerns)
- Integrate with daemon killall

## Interface Design
```go
type ResetOptions struct {
    Hard      bool   // Include git operations (git rm, commit)
    Backup    bool   // Create backup before reset
    DryRun    bool   // Preview only, don't execute
    SkipInit  bool   // Don't re-initialize after reset
}

type ResetResult struct {
    IssuesDeleted     int
    TombstonesDeleted int
    BackupPath        string  // if backup was created
    DaemonsKilled     int
}

type ImpactSummary struct {
    IssueCount      int
    OpenCount       int
    ClosedCount     int
    TombstoneCount  int
    HasUncommitted  bool  // git dirty state
}

func Reset(opts ResetOptions) (*ResetResult, error)
func CountImpact() (*ImpactSummary, error)
func ValidateState() error
```

## IMPORTANT: CLI vs Core Separation
- `Force` (skip confirmation) is NOT in ResetOptions - that's a CLI concern
- Core always executes when called; CLI decides whether to prompt first
- Keep CLI-agnostic: no prompts, no colored output, no user interaction
- Return errors for CLI to handle with user-friendly messages
- Unit testable in isolation

## Dependencies
- Uses daemon.KillAllDaemons() from internal/daemon/
- Calls bd init logic after reset (unless SkipInit)


Code smell: Duplicated issue type switch in cook.go

The same switch statement for mapping step type to IssueType appears twice in cook.go:

Location 1 (line 425):
```go
switch step.Type {
case "task":
    issueType = types.TypeTask
case "bug":
    issueType = types.TypeBug
// ...
}
```

Location 2 (line 764): Identical switch statement.

Should extract to a helper function:
```go
func stepTypeToIssueType(stepType string) types.IssueType {
    switch stepType {
    case "task": return types.TypeTask
    case "bug": return types.TypeBug
    // ...
    default: return types.TypeTask
    }
}
```

Location: cmd/bd/cook.go:425 and cmd/bd/cook.go:764


Rename ephemeral → wisp throughout codebase

## The Change

Rename 'ephemeral' to 'wisp' throughout the beads codebase.

## Why

**Ephemeral** is:
- 4 syllables (too long)
- Greek/academic (doesn't match bond/burn/squash)
- Overused in tech (K8s, networking, storage)
- Passive/descriptive

**Wisp** is:
- 1 syllable (matches bond/burn/squash)
- Evocative - you can SEE a wisp
- Steam engine metaphor - Gas Town is engines, steam wisps rise and dissipate
- Will-o'-the-wisp - transient spirits that guide then vanish
- Unique - nobody else uses it

## The Steam Engine Metaphor

```
Engine does work → generates steam
Steam wisps rise → execution trace
Steam condenses → digest (distillate)
Steam dissipates → cleaned up (burned)
```

## Full Vocabulary

| Term | Meaning |
|------|---------|
| bond | Attach proto to work (creates wisps) |
| wisp | Temporary execution step |
| squash | Condense wisps into digest |
| burn | Destroy wisps without record |
| digest | Permanent condensed record |

## Changes Required

### Code
- `Ephemeral bool` → `Wisp bool` in types/issue.go
- `--ephemeral` flag → remove (wisp is default)
- `--persistent` flag → keep as opt-out
- `bd cleanup --ephemeral` → `bd cleanup --wisps`
- Update all references in mol_*.go files

### Docs
- Update all documentation
- Update CLAUDE.md examples
- Update CLI help text

### Database Migration
- Add migration to rename field (or keep internal name, just change API)

## Example Usage After

```bash
bd mol bond mol-polecat-work   # Creates wisps (default)
bd mol bond mol-xxx --persistent  # Creates permanent issues
bd mol squash bd-xxx           # Condenses wisps → digest
bd cleanup --wisps             # Clean old wisps
bd list --wisps                # Show wisp issues
```


Add close_reason field to CLI schema and documentation

PR #551 persists close_reason, but the CLI documentation may not mention this field as part of the issue schema.

## Current State
- close_reason is now persisted in database
- `bd show --json` will return close_reason in JSON output
- Documentation may not reflect this new field

## What's Missing
- CLI reference documentation for close_reason field
- Schema documentation showing close_reason is a top-level issue field
- Example output showing close_reason in bd show --json
- bd close command documentation should mention close_reason parameter is optional

## Suggested Action
1. Update README.md or CLI reference docs to list close_reason as an issue field
2. Add example to bd close documentation
3. Update any type definitions or schema specs
4. Consider adding close_reason to verbose list output (bd list --verbose)


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.


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.


Merge: bd-ot0w

branch: polecat/dementus
target: main
source_issue: bd-ot0w
rig: beads


Molecule bonding: composable workflow templates

Vision: Molecules should be composable like LEGO bricks or Mad Max war rig sections. Bonding lets you attach molecules together to create compound workflows.

THREE BONDING CONTEXTS:
1. Template-time: bd mol bond A B → Create reusable compound proto
2. Spawn-time: bd mol spawn A --attach B → Attach modules when instantiating
3. Runtime: bd mol attach epic B → Add to running workflow

BOND TYPES:
- Sequential: B after A completes (feature → deploy)
- Parallel: B runs alongside A (feature + docs)
- Conditional: B only if A fails (feature → hotfix)

BOND POINTS (Attachment Sites):
- Default: B depends on A root epic completion
- Explicit: --after issue-id for specific attachment
- Future: Named bond points in proto definitions

VARIABLE FLOW:
- Shared namespace between bonded molecules
- Warn on variable name conflicts
- Future: explicit mapping with --map

DATA MODEL: Issues track bonded_from to preserve compound lineage.

SUCCESS CRITERIA:
- Can bond two protos into a compound proto
- Can spawn with --attach for on-the-fly composition
- Can attach molecules to running workflows
- Compound structure visible in bd mol show
- Variables flow correctly between bonded molecules


Investigate Claude Code crash logging improvements

## Problem

Claude Code doesn't leave useful crash logs when it terminates unexpectedly. Investigation of a crash on 2025-12-26 showed:

- Debug logs in ~/.claude/debug/ just stop mid-stream with no error/exit message
- No signal handlers appear to log SIGTERM/SIGKILL/SIGINT
- No dedicated crash log file exists
- When Node.js crashes hard or gets killed, there's no record of why

## What we found

- Session debug log (02080b1a-...) stopped at 22:58:40 UTC mid-operation
- No 'exit', 'error', 'crash', 'signal' entries at end of file
- macOS DiagnosticReports showed Chrome crashes but no Node crashes
- System logs showed no relevant kill/OOM events

## Desired improvements

1. Exit handlers that log graceful shutdown
2. Signal handlers that log SIGTERM/SIGINT before exiting
3. A dedicated crash log or at least a 'last known state' file
4. Possibly CLI flags to enable verbose crash debugging

## Investigation paths

- Check if Claude Code has --debug or similar flags
- Look at Node.js crash handling best practices
- Consider if we can wrap claude invocations to capture crashes

## Related

This came up while investigating why a crew worker session crashed at end of a code review task.


Performance Validation

Confirm no performance regression from cache removal


Witness Patrol

Per-rig worker monitor patrol loop with progressive nudging.


Restart daemons

Restart bd daemons to pick up new version.

```bash
bd daemons killall
```

Daemons will auto-restart with new version on next bd command.

Verify:
```bash
bd daemons list
```


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)


Tier 3: AI-powered squash summarization

## Design: Agent-Provided Summarization (Inversion of Control)

bd is a tool FOR agents, not an agent itself. The calling agent provides
the summary; bd just stores it.

### API

```bash
# Agent generates summary, passes to bd
bd mol squash bd-xxx --summary "Agent-generated summary here"

# Without --summary, falls back to basic concatenation
bd mol squash bd-xxx
```

### Gas Town Integration Pattern

```go
// In polecat completion handler or witness
raw := exec.Command("bd", "mol", "show", molID, "--json").Output()
summary := callHaiku(buildSummaryPrompt(raw))  // agent's job
exec.Command("bd", "mol", "squash", molID, "--summary", summary).Run()
```

### Why This Design

| Concern | bd's job | Agent's job |
|---------|----------|-------------|
| Store data | ✅ | |
| Query data | ✅ | |
| Generate summaries | | ✅ |
| Call LLMs | | ✅ |
| Manage API keys | | ✅ |

### Implementation Status

- [x] --summary flag added to bd mol squash
- [x] Tests for agent-provided summary
- [ ] Gas Town integration (separate task)

### Acceptance Criteria

- ✅ bd mol squash --summary uses provided text
- ✅ Without --summary, falls back to concatenation
- ✅ No LLM calls in bd itself


Update version to {{version}} in version.go

Edit cmd/bd/version.go line 17:

```go
Version = "{{version}}"
```

Verify with: `grep 'Version =' cmd/bd/version.go`


RemoveDependency fails on external deps - FK violation in dirty_issues

In dependencies.go:225, RemoveDependency marks BOTH issueID and dependsOnID as dirty. For external refs (e.g., external:project:capability), dependsOnID doesn't exist in the issues table. This causes FK violation since dirty_issues.issue_id has FK constraint to issues.id.

Fix: Check if dependsOnID starts with 'external:' and only mark source issue as dirty, matching the logic in AddDependency (lines 162-170).

Repro: bd dep rm <issue> external:project:capability


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
```


Replace map[string]interface{} with typed JSON response structs

Many CLI commands use map[string]interface{} for JSON output which loses type safety and compile-time error detection.

Files with map[string]interface{}:
- cmd/bd/compact.go (10+ instances)
- cmd/bd/cleanup.go
- cmd/bd/daemons.go
- cmd/bd/daemon_lifecycle.go

Example fix:
```go
// Before
result := map[string]interface{}{
    "status": "ok",
    "count": 42,
}

// After
type CompactResponse struct {
    Status string `json:"status"`
    Count  int    `json:"count"`
}
result := CompactResponse{Status: "ok", Count: 42}
```

Benefits:
- Compile-time type checking
- IDE autocompletion
- Easier refactoring
- Self-documenting API


(Optional) Manual publish if CI failed.

(Optional) Manual publish if CI failed.

```bash
# npm (requires npm login)
./scripts/bump-version.sh 0.37.0 --publish-npm

# PyPI (requires TWINE credentials)
./scripts/bump-version.sh 0.37.0 --publish-pypi

# Or both
./scripts/bump-version.sh 0.37.0 --publish-all
```

Only needed if CI publishing failed.

instantiated_from: bd-mol-xga
step: manual-publish


Import reports misleading '0 created, 0 updated' when actually importing all issues

When running 'bd import' on a fresh database (no existing issues), the command reports 'Import complete: 0 created, 0 updated' even though it successfully imported all issues from the JSONL file.

**Steps to reproduce:**
1. Delete .beads/beads.db
2. Run: bd import .beads/issues.jsonl
3. Observe output: 'Import complete: 0 created, 0 updated'
4. Run: bd list
5. Confirm: All issues are actually present in the database

**Expected behavior:**
Report the actual number of issues imported, e.g., 'Import complete: 523 created, 0 updated'

**Actual behavior:**
'Import complete: 0 created, 0 updated' (misleading - makes user think import failed)

**Impact:**
- Users think import failed when it succeeded
- Confusing during database sync operations (e.g., after git pull)
- Makes debugging harder (can't tell if import actually worked)

**Context:**
Discovered during VC session when syncing database after git pull. The misleading message caused confusion about whether the database was properly synced with the canonical JSONL file.


test hook pin fix


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

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

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

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

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


Merge: bd-qioh

branch: polecat/Errata
target: main
source_issue: bd-qioh
rig: beads


wish: a 'continue' or similar cmd/flag which means alter last issue

so many time I create an issue and then have another thought: 'oh, before I did X and it crashed there was ZZZ happening' or 'actually that is P4 not P2'. It would be nice if when `bd {cmd}` is used without a {title} or {id} it just adds or updates the most recently touched issue.


Add .beads-backup-* pattern to gitignore template

Update the gitignore template in doctor package to include backup directories.

## Change
Add `.beads-backup-*/` to the GitignoreTemplate in `cmd/bd/doctor/gitignore.go`

## Why
Backup directories created by `bd reset --backup` should not be committed to git.
They are local-only recovery tools.

## File
`cmd/bd/doctor/gitignore.go` - look for GitignoreTemplate constant


bd wisp gc command

Add bd wisp gc command to garbage collect orphaned wisps.

## Usage
```bash
bd wisp gc                # Clean orphaned wisps
bd wisp gc --dry-run      # Show what would be cleaned
bd wisp gc --age 1h       # Custom orphan threshold (default: 1h)
```

## Orphan Detection
A wisp is orphaned if:
- process_id field exists AND process is dead
- OR updated_at older than threshold AND not complete
- AND molecule status is not complete/abandoned

## Behavior
- Delete orphaned wisps (no digest created)
- Report count of cleaned wisps
- --dry-run shows candidates without deleting

## Implementation
- Add 'gc' subcommand to wisp group
- Process detection via os.FindProcess or /proc
- Configurable age threshold


Create version-bump template as native Beads

Migrate the version-bump workflow from YAML to a native Beads template:

1. Create epic with template label: Release {{version}}
2. Create child tasks for each step (update version files, changelog, commit, push, publish)
3. Set up dependencies between tasks
4. Add verification commands in task descriptions

This serves as both migration and validation of the new system.


Create and push tag

git tag v{{version}} && git push origin main && git push origin v{{version}}


Investigate incremental blocked_issues_cache updates at scale

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

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

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

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

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

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