Exclude pinned issues from bd ready

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


Add composite index (status, priority) for common list queries

SearchIssues and GetReadyWork frequently filter by status and sort by priority. Currently uses two separate indexes.

**Common query pattern (queries.go:1646-1647):**
```sql
WHERE status = ?
ORDER BY priority ASC, created_at DESC
```

**Problem:** Index merge or full scan when both columns are used.

**Solution:** Add migration:
```sql
CREATE INDEX IF NOT EXISTS idx_issues_status_priority ON issues(status, priority);
```

**Expected impact:** Faster bd list, bd ready with filters. Particularly noticeable at 10K+ issues.


Make DetectCollisions read-only (separate detection from modification)

**Summary:** The project restructured the collision detection process in the database to separate read-only detection from state modification, eliminating race conditions and improving system reliability. This was achieved by introducing a two-phase approach: first detecting potential collisions, then applying resolution separately.

**Key Decisions:**
- Create read-only DetectCollisions method
- Add RenameDetail to track potential issue renames
- Implement atomic ApplyCollisionResolution function
- Separate detection logic from database modification

**Resolution:** The refactoring creates a more robust, composable collision handling mechanism that prevents partial failures and maintains database consistency during complex issue import scenarios.


Code Review: PR #481 - Context Engineering Optimizations

Comprehensive code review of the merged context engineering PR (PR #481) that reduces MCP context usage by 80-90%.

## Summary
The PR successfully implements lazy tool schema loading and minimal issue models to reduce context window usage. Overall implementation is solid and well-tested.

## Positive Findings
✅ Well-designed models (IssueMinimal, CompactedResult)
✅ Comprehensive test coverage (28 tests, all passing)
✅ Clear documentation and comments
✅ Backward compatibility preserved (show() still returns full Issue)
✅ Sensible defaults (COMPACTION_THRESHOLD=20, PREVIEW_COUNT=5)
✅ Tool catalog complete with all 15 tools documented

## Issues Identified
See linked issues for specific followup tasks.

## Context Engineering Architecture
- discover_tools(): List tool names only (~500 bytes vs ~15KB)
- get_tool_info(name): Get specific tool details on-demand
- IssueMinimal: Lightweight model for list views (~80 bytes vs ~400 bytes)
- CompactedResult: Auto-compacts results with >20 issues
- _to_minimal(): Conversion function (efficient, no N+1 issues)


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


Performance Validation

Confirm no performance regression from cache removal


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)


Merge: bd-likt

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


Upgrade local Homebrew installation

Upgrade bd via Homebrew:

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

**Note**: If `brew upgrade` fails with CLT (Command Line Tools) errors on bleeding-edge macOS versions (e.g., Tahoe 26.x):

```bash
# Reinstall CLT
sudo rm -rf /Library/Developer/CommandLineTools
xcode-select --install
# Wait for GUI installer to complete, then retry brew upgrade
```

Alternative: Skip Homebrew and use go install:
```bash
go install ./cmd/bd
~/go/bin/bd version  # Verify shows {{version}}
```


Merge: bd-uqfn

branch: polecat/cheedo
target: main
source_issue: bd-uqfn
rig: beads


Merge: bd-au0.6

branch: polecat/furiosa
target: main
source_issue: bd-au0.6
rig: beads


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

## Problem

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

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

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

## Impact

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

## Root Cause

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

## Fix

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

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

## Action Items

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


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

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


Support redirect files in .beads/ directory

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

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

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

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

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


Create git tag v{{version}}

Create the release tag:

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

Verify: `git tag | grep {{version}}`


Async Gates for Agent Coordination

Agents need an async primitive for waiting on external events (CI completion, API responses, human approval). Gates are wisp issues that block until external conditions are met, managed by the Deacon.

## Core Concepts

**Gate** = wisp issue that blocks until external condition is met
- Type: gate
- Phase: wisp (never synced, ephemeral)
- Assignee: deacon/ (Deacon monitors it)
- Fields: await_type, await_id, timeout, waiters[]

**Await Types:**
- gh:run:<id> - GitHub Actions run completion
- gh:pr:<id> - PR merged/closed
- timer:<duration> - Simple delay
- human:<prompt> - Human approval required
- mail:<pattern> - Wait for mail matching pattern

## Open Questions
- Should gates live in wisp storage or main storage with wisp flag?
- Do we need a gate catalog (like molecule catalog)?
- Should waits-for dep type work with gates?


Update git hooks

Install the updated hooks:
```bash
bd hooks install
```

Verify hook version:
```bash
grep 'bd-hooks-version' .git/hooks/pre-commit
```

```verify
grep -q 'bd-hooks-version: 0.30.4' .git/hooks/pre-commit 2>/dev/null || echo 'Hooks may not be installed - verify manually'
```


Rename 'bond' to 'spawn' for instantiation

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

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


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.


bd mol run: panic slice bounds out of range in mol_run.go:130

## Problem
bd mol run panics after successfully creating the molecule:

```
✓ Molecule running: created 9 issues
  Root issue: gt-i4lo (pinned, in_progress)
  Assignee: stevey

Next steps:
  bd ready                # Find unblocked work in this molecule
panic: runtime error: slice bounds out of range [:8] with length 7

goroutine 1 [running]:
main.runMolRun(0x1014fc0c0, {0x140001e0f80, 0x1, 0x10089daad?})
  /Users/stevey/gt/beads/crew/dave/cmd/bd/mol_run.go:130 +0xc38
```

## Reproduction
```bash
bd --no-daemon mol run gt-lwuu --var issue=gt-test123
```
Where gt-lwuu is a mol-polecat-work proto with 8 child steps.

## Impact
The molecule IS created successfully - the panic happens after creation when formatting the "Next steps" output.


Update CHANGELOG.md for {{version}}

In CHANGELOG.md:

1. Change `## [Unreleased]` section header to `## [{{version}}] - {{date}}`
2. Add new empty `## [Unreleased]` section above it
3. Review and clean up the changes list

Format:
```markdown
## [Unreleased]

## [{{version}}] - {{date}}

### Added
- ...

### Changed
- ...

### Fixed
- ...
```


Prevent multiple daemons from running on the same repo

Multiple bd daemons running on the same repo clone causes race conditions and data corruption risks.

**Problem:**
- Nothing prevents spawning multiple daemons for the same repository
- Multiple daemons watching the same files can conflict during sync operations
- Observed: 4 daemons running simultaneously caused sync race condition

**Solution:**
Implement daemon singleton enforcement per repo:
1. Use a lock file (e.g., .beads/.daemon.lock) with PID
2. On daemon start, check if lock exists and process is alive
3. If stale lock (dead PID), clean up and acquire lock
4. If active daemon exists, either:
   - Exit with message 'daemon already running (PID xxx)'
   - Or offer --replace flag to kill existing and take over
5. Release lock on graceful shutdown

**Edge cases to handle:**
- Daemon crashes without releasing lock (stale PID detection)
- Multiple repos in same directory tree (each repo gets own lock)
- Race between two daemons starting simultaneously (atomic lock acquisition)


Redesign workflow system: templates as native Beads

## Problem

The current workflow system (YAML templates in cmd/bd/templates/workflows/) is architecturally flawed:

1. **Out-of-band data plane** - YAML files are a parallel system outside Beads itself
2. **Heavyweight DSL** - YAML is gross; even TOML would have been better, but neither is ideal
3. **Not graph-native** - Beads IS already a dependency graph with priorities, so why reinvent it?
4. **Can't use bd commands on templates** - They're opaque YAML, not viewable/editable Beads

## The Right Design

**Templates should be Beads themselves.**

A "workflow template" should be:
- An epic marked as a template (via label, type, or prefix like `tpl-`)
- Child issues with dependencies between them (using normal bd dep)
- Titles and descriptions containing `{{variable}}` placeholders
- Normal priorities that control serialization order

"Instantiation" becomes:
1. Clone the template subgraph (epic + children + dependencies)
2. Substitute variables in titles/descriptions
3. Generate new IDs for all cloned issues
4. Return the new epic ID

## Benefits

- **No YAML** - Templates are just Beads
- **Use existing tools** - `bd show`, `bd edit`, `bd dep` work on templates
- **Graph-native** - Dependencies are real Beads dependencies
- **Simpler codebase** - Remove all the YAML parsing/workflow code
- **Composable** - Templates can reference other templates

## Tasks

1. Delete the YAML workflow system code (revert recent push + remove existing workflow code)
2. Design template marking convention (label? type? id prefix?)
3. Implement `bd template create` or `bd clone --as-template`
4. Implement `bd template instantiate <template-id> --var key=value`
5. Migrate version-bump workflow to native Beads template
6. Update documentation


Add daemon RPC support for gate commands.

## Current State
Gate commands require --no-daemon flag because they use direct SQLite access:
- Gate create needs to write await_type, await_id, timeout_ns, waiters fields
- Gate wait needs to update waiters JSON array
- Daemon RPC doesnt have methods for these operations

## Implementation

### 1. Add RPC methods to internal/rpc/protocol.go

```go
// Gate operations
type GateCreateArgs struct {
    Title     string        \`json:"title"\`
    AwaitType string        \`json:"await_type"\`
    AwaitID   string        \`json:"await_id"\`
    Timeout   time.Duration \`json:"timeout"\`
    Waiters   []string      \`json:"waiters"\`
}

type GateCreateResult struct {
    Issue *types.Issue \`json:"issue"\`
}

type GateListArgs struct {
    All bool \`json:"all"\` // Include closed gates
}

type GateListResult struct {
    Gates []*types.Issue \`json:"gates"\`
}

type GateWaitArgs struct {
    GateID  string   \`json:"gate_id"\`
    Waiters []string \`json:"waiters"\` // Additional waiters to add
}

type GateWaitResult struct {
    Gate        *types.Issue \`json:"gate"\`
    AddedCount  int          \`json:"added_count"\`
}
```

### 2. Add handler methods to internal/daemon/rpc_handler.go

```go
func (h *RPCHandler) GateCreate(ctx context.Context, args *rpc.GateCreateArgs) (*rpc.GateCreateResult, error) {
    now := time.Now()
    gate := &types.Issue{
        Title:     args.Title,
        IssueType: types.TypeGate,
        Status:    types.StatusOpen,
        Priority:  1,
        Assignee:  "deacon/",
        Wisp:      true,
        AwaitType: args.AwaitType,
        AwaitID:   args.AwaitID,
        Timeout:   args.Timeout,
        Waiters:   args.Waiters,
        CreatedAt: now,
        UpdatedAt: now,
    }
    gate.ContentHash = gate.ComputeContentHash()

    if err := h.store.CreateIssue(ctx, gate, h.actor); err != nil {
        return nil, err
    }

    return &rpc.GateCreateResult{Issue: gate}, nil
}

func (h *RPCHandler) GateList(ctx context.Context, args *rpc.GateListArgs) (*rpc.GateListResult, error) {
    gateType := types.TypeGate
    filter := types.IssueFilter{IssueType: &gateType}
    if !args.All {
        openStatus := types.StatusOpen
        filter.Status = &openStatus
    }

    gates, err := h.store.SearchIssues(ctx, "", filter)
    if err != nil {
        return nil, err
    }

    return &rpc.GateListResult{Gates: gates}, nil
}

func (h *RPCHandler) GateWait(ctx context.Context, args *rpc.GateWaitArgs) (*rpc.GateWaitResult, error) {
    gate, err := h.store.GetIssue(ctx, args.GateID)
    if err != nil {
        return nil, err
    }
    if gate.IssueType != types.TypeGate {
        return nil, fmt.Errorf("%s is not a gate", args.GateID)
    }

    // Merge waiters (dedupe)
    waiterSet := make(map[string]bool)
    for _, w := range gate.Waiters {
        waiterSet[w] = true
    }
    added := 0
    for _, w := range args.Waiters {
        if !waiterSet[w] {
            gate.Waiters = append(gate.Waiters, w)
            waiterSet[w] = true
            added++
        }
    }

    if added > 0 {
        // Update via store
        updates := map[string]interface{}{
            "waiters": gate.Waiters,
        }
        if err := h.store.UpdateIssue(ctx, args.GateID, updates, h.actor); err != nil {
            return nil, err
        }
    }

    return &rpc.GateWaitResult{Gate: gate, AddedCount: added}, nil
}
```

### 3. Register methods in daemon

In internal/daemon/server.go, register the new methods:
```go
rpc.RegisterMethod("gate.create", h.GateCreate)
rpc.RegisterMethod("gate.list", h.GateList)
rpc.RegisterMethod("gate.wait", h.GateWait)
```

### 4. Add client methods to internal/rpc/client.go

```go
func (c *Client) GateCreate(ctx context.Context, args *GateCreateArgs) (*GateCreateResult, error) {
    var result GateCreateResult
    err := c.Call(ctx, "gate.create", args, &result)
    return &result, err
}

func (c *Client) GateList(ctx context.Context, args *GateListArgs) (*GateListResult, error) {
    var result GateListResult
    err := c.Call(ctx, "gate.list", args, &result)
    return &result, err
}

func (c *Client) GateWait(ctx context.Context, args *GateWaitArgs) (*GateWaitResult, error) {
    var result GateWaitResult
    err := c.Call(ctx, "gate.wait", args, &result)
    return &result, err
}
```

### 5. Update cmd/bd/gate.go to use daemon

```go
// In gateCreateCmd Run:
if daemonClient != nil {
    result, err := daemonClient.GateCreate(ctx, &rpc.GateCreateArgs{
        Title:     title,
        AwaitType: awaitType,
        AwaitID:   awaitID,
        Timeout:   timeout,
        Waiters:   notifyAddrs,
    })
    if err != nil {
        FatalError("gate create: %v", err)
    }
    gate = result.Issue
} else {
    // Existing direct store code
}
```

## Files to Modify

1. **internal/rpc/protocol.go** - Add Gate*Args/Result types
2. **internal/daemon/rpc_handler.go** - Add handler methods
3. **internal/daemon/server.go** - Register methods
4. **internal/rpc/client.go** - Add client methods
5. **cmd/bd/gate.go** - Use daemon client when available

## Testing

```bash
# Start daemon
bd daemon start

# Test via daemon (should work without --no-daemon)
bd gate create --await timer:5m --notify beads/dave
bd gate list
bd gate wait <id> --notify beads/alice

# Verify daemon handled it
bd daemons logs . | grep gate
```

## Success Criteria
- All gate commands work without --no-daemon
- Same behavior in daemon vs direct mode
- Waiters array updates correctly via RPC
- Tests pass for RPC gate operations


bd doctor: detect issues referenced in commits but still open

Add a doctor check that finds 'orphaned' issues - ones referenced in git commit messages (e.g., 'fix bug (bd-xxx)') but still marked as open in beads.

**Detection logic:**
1. Get all open issue IDs from beads
2. Parse git log for issue ID references matching pattern \(prefix-[a-z0-9.]+\)
3. Report issues that appear in commits but are still open

**Output:**
⚠ Warning: N issues referenced in commits but still open
  bd-xxx: 'Issue title' (commit abc123)
  bd-yyy: 'Issue title' (commit def456)

  These may be implemented but not closed. Run 'bd show <id>' to check.

**Implementation:**
- Add check to doctor/checks.go
- Use git log parsing (already have git utilities)
- Match against configured issue_prefix


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


worktree: any bd command is slow

in a git worktree any bd command is slow, with a 2-3s pause before any results are shown. The identical command with `--no-daemon` is near instant.


Merge: bd-4qfb

branch: polecat/Polish
target: main
source_issue: bd-4qfb
rig: beads


Priority: refactor mol.go then bd squash

Two tasks:

1. bd-cnwx - Refactor mol.go (1200+ lines, split by subcommand)
2. bd-2vh3 - Ephemeral cleanup (bd cleanup --ephemeral)

Refactor first - smaller, unblocks easier review of future mol work.

- Mayor


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

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

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

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

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

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


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


Add external_projects to config schema

Add external_projects mapping to .beads/config.yaml:

```yaml
external_projects:
  beads: ../beads
  gastown: ../gastown
  other: /absolute/path/to/project
```

Used by bd ready and other commands to resolve external: references.

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


Design contributor namespace isolation for beads pollution prevention

## Problem

When contributors work on beads-the-project using beads-the-tool, their personal work-tracking issues leak into PRs. The .beads/issues.jsonl is intentionally tracked (it's the project's issue database), but contributors' local issues pollute the diff.

This is a recursion problem unique to self-hosting projects.

## Possible Solutions to Explore

1. **Contributor namespaces** - Each contributor gets a private prefix (e.g., `bd-steve-xxxx`) that's gitignored or filtered
2. **Separate database** - Contributors use BEADS_DIR pointing elsewhere for personal tracking
3. **Issue ownership/visibility flags** - Mark issues as "local-only" vs "project"
4. **Prefix-based filtering** - Configure which prefixes are committed vs ignored

## Design Considerations

- Should be zero-friction for contributors (no manual setup)
- Must not break existing workflows
- Needs to work with sync/collaboration features
- Consider: what if a "personal" issue graduates to "project" issue?

## Expansion Needed

This is a placeholder. Needs detailed design exploration before implementation.


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


Remove Storage Cache from Server Struct

Eliminate cache fields and use s.storage directly


Protect pinned issues from bd cleanup/compact

Update bd cleanup and bd compact to never delete pinned issues, even if they are closed. Pinned issues should persist indefinitely as reference material.


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.

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

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

# 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


Add tests for delete operations

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


Implement `bd setup cursor` for Cursor IDE integration

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


Add composite index (issue_id, type) on dependencies table

GetBlockedIssues uses EXISTS clauses that filter by issue_id AND type together.

**Query pattern (ready.go:427-429):**
```sql
EXISTS (
  SELECT 1 FROM dependencies d2
  WHERE d2.issue_id = i.id AND d2.type = 'blocks'
)
```

**Problem:** Only idx_dependencies_issue exists. SQLite must filter type after index lookup.

**Solution:** Add migration:
```sql
CREATE INDEX IF NOT EXISTS idx_dependencies_issue_type ON dependencies(issue_id, type);
```

**Note:** This complements the existing idx_dependencies_depends_on_type for the reverse direction.


bd init UX Improvements

bd init leaves users with incomplete setup, requiring manual bd doctor --fix. Issues found: (1) git hooks not installed if user declines prompt, (2) no auto-migration when CLI is upgraded, (3) stale merge driver configs from old versions. Fix by making bd init more robust with better defaults and auto-migration.


Digest: Release v0.34.0 @ 2025-12-22 12:16

Released v0.34.0: wisp commands, chemistry UX, cross-project deps


Test daemon RPC delete handler

Add tests for the daemon-side RPC delete handler that processes delete requests from clients.

## What needs testing
- Daemon's Delete RPC handler implementation
- Processing delete requests from RPC clients
- Cascade deletion at daemon level
- Force deletion at daemon level
- Dry-run mode validation
- Error responses to clients
- Dependency validation before deletion
- Tombstone creation via daemon

## Test scenarios
1. Delete single issue via RPC
2. Delete multiple issues via RPC
3. Cascade deletion of dependents
4. Force delete with orphaned dependents
5. Dry-run returns what would be deleted without actual deletion
6. Error: invalid issue IDs
7. Error: insufficient permissions
8. Error: dependency blocks deletion (without force/cascade)

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


Cleanup: --ephemeral flag

Update bd cleanup to handle ephemeral issues.

New flag:
- bd cleanup --ephemeral - deletes all CLOSED issues with ephemeral=true

Behavior:
- Only deletes if status=closed AND ephemeral=true
- Respects --dry-run flag
- Reports count of deleted ephemeral issues

This allows swarm cleanup to remove transient messages without affecting permanent issues.


Add bd template list command

Add a convenience command to list available templates:

bd template list

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


No logging/debugging for tombstone resurrection events

Per the design document bd-zvg Open Question 1: Should resurrection log a warning? Recommendation was Yes. Currently, when an expired tombstone loses to a live issue (resurrection), there is no logging or debugging output. This makes it hard to understand why an issue reappeared. Recommendation: Add optional debug logging when resurrection occurs, e.g., Issue bd-abc resurrected (tombstone expired). Files: internal/merge/merge.go:359-366, 371-378, 400-405, 410-415


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`


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

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


Fix update-hooks verification in version-bump.yaml

The update-hooks task verification command at version-bump.yaml:358 always succeeds due to '|| echo ...' fallback. Remove the fallback so verification actually fails when hooks aren't installed.


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

Linting issue: checkHooksQuick - path is unused (unparam) at cmd/bd/doctor.go:541:22. Error: func checkHooksQuick(path string) string {


🤝 HANDOFF: v0.31.0 released, molecules discussion

Session completed 0.31.0 release and had important molecules discussion.

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

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

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

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

Check bd ready and gt-975/976 status.


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.


Update beads_mcp/__init__.py to 0.30.4

Update __version__ in integrations/beads-mcp/src/beads_mcp/__init__.py:
```python
__version__ = "0.30.4"
```

```verify
grep -q '__version__ = "0.30.4"' integrations/beads-mcp/src/beads_mcp/__init__.py
```


Test Thread

Initial message for threading test


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

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

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

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

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

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


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.


activity.go: Missing test coverage

The new activity.go command (from bd-xo1o.3) has no test coverage. At minimum, tests should cover:
- parseDurationString() for various formats (5m, 1h, 2d, invalid)
- filterEvents() for --mol and --type filtering
- formatEvent() and getEventDisplay() for all mutation types

Discovered during code review of bd-xo1o implementation.


Improve test coverage for internal/export (37.1% → 60%)

The export package has only 37.1% test coverage. Export functionality needs good coverage to ensure data integrity.

Current coverage: 37.1%
Target coverage: 60%


Add orphan detection migration

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


Design molecule step hooks

Hooks that fire between molecule steps. When a bead in a molecule closes, trigger hook that can spawn agent attention to prompts/requests. This enables reactive orchestration - the molecule drives, hooks respond. Gas Town feature built on Beads data plane.


Gate: timer:1m


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

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


Update info.go versionChanges

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


Restart running daemons

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


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

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


getLocalSyncBranch silently ignores YAML parse errors

In autoimport.go:170-172, YAML parsing errors are silently ignored. If a user has malformed YAML in config.yaml, sync-branch will just silently be empty with no feedback.

Recommendation: Add debug logging since this function is only called during auto-import, and debugging silent failures is painful.

Add: debug.Logf("Warning: failed to parse config.yaml: %v", err)


witness Handoff

attached_molecule: bd-ndye
attached_at: 2025-12-23T12:35:02Z


Monitor GoReleaser CI job

Watch the GoReleaser action:
https://github.com/steveyegge/beads/actions/workflows/release.yml

Should complete in ~10 minutes and create:
- GitHub Release with binaries for all platforms
- Checksums and signatures

Check status:
```bash
gh run list --workflow=release.yml -L 1
gh run watch  # to monitor live
```

Verify release exists:
```bash
gh release view v0.30.4
```

```verify
gh release view v0.30.4 --json tagName -q .tagName | grep -q 'v0.30.4'
```


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

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

Current coverage: 28.4%
Target coverage: 50%


Code review findings: mol squash deletion bypasses tombstones


Test deleteViaDaemon RPC client integration

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

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

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

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

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


Add date and priority filters to bd search for parity with bd list.

## Current State
bd search supports: --status, --type, --assignee, --label, --limit
bd list supports: all of the above PLUS date ranges and priority filters

## Filters to Add

### Priority Filters
```bash
bd search "query" --priority 1           # Exact priority
bd search "query" --priority-min 0       # P0 and above (higher priority)
bd search "query" --priority-max 2       # P2 and below (lower priority)
```

### Date Filters
```bash
bd search "query" --created-after 2025-01-01
bd search "query" --created-before 2025-12-31
bd search "query" --updated-after 2025-01-01
bd search "query" --closed-after 2025-01-01
```

### Content Filters
```bash
bd search "query" --desc-contains "bug"
bd search "query" --notes-contains "todo"
bd search "query" --empty-description    # Issues with no description
bd search "query" --no-assignee          # Unassigned issues
bd search "query" --no-labels            # Issues without labels
```

## Files to Modify

### 1. cmd/bd/search.go
Add flag definitions in init():
```go
searchCmd.Flags().IntP("priority", "p", -1, "Filter by exact priority (0-4)")
searchCmd.Flags().Int("priority-min", -1, "Filter by minimum priority")
searchCmd.Flags().Int("priority-max", -1, "Filter by maximum priority")
searchCmd.Flags().String("created-after", "", "Filter by creation date (YYYY-MM-DD)")
searchCmd.Flags().String("created-before", "", "Filter by creation date")
searchCmd.Flags().String("updated-after", "", "Filter by update date")
searchCmd.Flags().String("updated-before", "", "Filter by update date")
searchCmd.Flags().String("closed-after", "", "Filter by close date")
searchCmd.Flags().String("closed-before", "", "Filter by close date")
searchCmd.Flags().String("desc-contains", "", "Filter by description content")
searchCmd.Flags().String("notes-contains", "", "Filter by notes content")
searchCmd.Flags().Bool("empty-description", false, "Filter issues with empty description")
searchCmd.Flags().Bool("no-assignee", false, "Filter unassigned issues")
searchCmd.Flags().Bool("no-labels", false, "Filter issues without labels")
```

### 2. internal/rpc/protocol.go
Update SearchArgs struct:
```go
type SearchArgs struct {
    Query             string
    Filter            types.IssueFilter
    // Already has most fields via IssueFilter
}
```

Note: types.IssueFilter already has these fields - just need to wire them up!

### 3. cmd/bd/search.go Run function
Parse flags and populate filter:
```go
if priority, _ := cmd.Flags().GetInt("priority"); priority >= 0 {
    filter.Priority = &priority
}
if createdAfter, _ := cmd.Flags().GetString("created-after"); createdAfter != "" {
    t, err := time.Parse("2006-01-02", createdAfter)
    if err != nil {
        FatalError("invalid date format for --created-after: %v", err)
    }
    filter.CreatedAfter = &t
}
// ... similar for other flags
```

## Implementation Steps

1. **Check types.IssueFilter** - verify all needed fields exist
2. **Add flags to search.go** init()
3. **Parse flags** in Run function
4. **Pass to SearchIssues** via filter
5. **Test all combinations**

## Testing
```bash
# Create test issues
bd create "Test P1" -p 1
bd create "Test P2" -p 2 --description "Has description"

# Test filters
bd search "" --priority 1
bd search "" --priority-min 0 --priority-max 1
bd search "" --empty-description
bd search "" --desc-contains "description"
```

## Success Criteria
- All filters work in both direct and daemon mode
- Date parsing handles YYYY-MM-DD format
- --json output includes filtered results
- Help text documents all new flags


GH#405: Prefix parsing with hyphens treats first segment as prefix

Prefix me-py-toolkit gets parsed as just me- when detecting mismatches. Fix prefix parsing to handle multi-hyphen prefixes. See GitHub issue #405.


Unify template.go and mol.go under bd mol

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


Upgrade local Homebrew installation

Upgrade bd via Homebrew:

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


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


Add GetWorkerStatus RPC endpoint

New RPC endpoint to get all workers and their current molecule/step in one call. Returns: assignee, moleculeID, moleculeTitle, currentStep, totalSteps, stepTitle, lastActivity, status. Enables activity feed TUI to show worker state without multiple round trips.


Investigate TestRoutingIntegration failure

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


Test Molecule

A test molecule


Test body-file

This is a test description from a file.

It has multiple lines.


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

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


Merge: bd-u2sc.3

branch: polecat/Modular
target: main
source_issue: bd-u2sc.3
rig: beads


Merge: bd-io8c

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


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


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.


Clean up orphaned child issues (bd-cb64c226.*, bd-cbed9619.*)

## Problem

Every bd command shows warnings about 12 orphaned child issues:
- bd-cb64c226.1, .6, .8, .9, .10, .12, .13
- bd-cbed9619.1, .2, .3, .4, .5

These are hierarchical IDs (parent.child format) where the parent issues no longer exist.

## Impact

- Clutters output of every bd command
- Confusing for users
- Indicates incomplete cleanup of deleted parent issues

## Proposed Solution

1. Delete the orphaned issues since their parents no longer exist:
   ```bash
   bd delete bd-cb64c226.1 bd-cb64c226.6 bd-cb64c226.8 ...
   ```

2. Or convert them to top-level issues if they contain useful content

## Investigation Needed

- What were the parent issues bd-cb64c226 and bd-cbed9619?
- Why were they deleted without their children?
- Should bd delete cascade to children automatically?


bd template commands fail with daemon mode

The `bd template show` and `bd template instantiate` commands fail with 'Error loading template: no database connection' when daemon is running.

**Reproduction:**
```bash
bd daemon --start
bd template show bd-qqc  # Error: no database connection
bd template show bd-qqc --no-daemon  # Works
```

**Expected:** Template commands should work with daemon like other commands.

**Workaround:** Use `--no-daemon` flag.

**Location:** Likely in cmd/bd/template.go - daemon RPC path not implemented for template operations.


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

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


Tier 1: Ephemeral repo routing

Add routing.ephemeral config option to route ephemeral=true issues to separate location.

## Changes Required

1. Add `routing.ephemeral` config option (default: empty = disabled)
2. Update routing logic in `determineRepo()` to check ephemeral flag
3. Update `bd create` to respect ephemeral routing
4. Update import/export for multi-location support
5. Ephemeral repo can be:
   - Separate git repo (~/.beads-ephemeral)
   - Non-git directory (just filesystem)
   - Same repo, different branch (future)

## Config

```bash
bd config set routing.ephemeral "~/.beads-ephemeral"
```

## Acceptance Criteria

- `bd create "test" --ephemeral` creates in ephemeral repo when configured
- `bd list` shows issues from both repos
- Ephemeral repo never synced to remote


Push commit and tag to origin

```bash
git push origin main
git push origin v0.30.4
```

This triggers GitHub Actions:
- GoReleaser build
- PyPI publish
- npm publish

```verify
git ls-remote origin refs/tags/v0.30.4 | grep -q 'v0.30.4'
```


Merge: bd-au0.7

branch: polecat/dementus
target: main
source_issue: bd-au0.7
rig: beads


Improve version bump molecule with missing steps

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

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

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

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

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

CORRECTION: npm publishing IS automated and working!

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

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

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

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


Sync race: rebase-based divergence recovery resurrects tombstones

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

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

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

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

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

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


Remove unreachable utility functions

Several small utility functions are unreachable:

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

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

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

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

Impact: Removes 50-100 LOC depending on decisions


Create git tag v0.33.2

Create the release tag:

```bash
git tag v0.33.2
```

Verify: `git tag | grep 0.33.2`


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


Code Health Review Dec 2025: Technical Debt Cleanup

Epic grouping technical debt identified in the Dec 16, 2025 code health review.

## Overall Health Grade: B (Solid foundation, needs cleanup)

### P1 (High Priority):
- bd-74w1: Consolidate duplicate path-finding utilities
- bd-b6xo: Remove/fix ClearDirtyIssues() race condition
- bd-b3og: Fix TestImportBugIntegration deadlock

### P2 (Medium Priority):
- bd-05a8: Split large files (doctor.go, sync.go)
- bd-qioh: Standardize error handling patterns
- bd-rgyd: Split queries.go (1586 lines)
- bd-9g1z: Fix/remove TestFindJSONLPathDefault

### P3 (Low Priority):
- bd-ork0: Add comments to 30+ ignored errors
- bd-4nqq: Remove dead test code in info_test.go
- bd-dhza: Reduce global state in main.go

## Key Areas:
1. Code duplication in path utilities
2. Large monolithic files (5 files >1000 lines)
3. Global state (25+ variables, 3 deprecated)
4. Silent error suppression (30+ instances)
5. Test gaps and dead test code
6. Atomicity risks in batch operations


Ephemeral issue cleanup and history compaction

## Problem

Beads history grows without bound. Every message, handoff, work assignment
stays in issues.jsonl forever. Enterprise users will balk at "git as database."

## Solution: Two-Tier Cleanup

### Tier 1: Ephemeral Cleanup (v1)

bd cleanup --ephemeral --closed

- Deletes closed issues where ephemeral=true from issues.jsonl
- Safe: only removes explicitly marked ephemeral + closed
- Preserves git history (commits still exist)
- Run after swarm completion

### Tier 2: History Compaction (v2)

bd compact --squash

- Rewrites issues.jsonl to remove tombstones
- Optionally squashes git history (interactive rebase equivalent)
- Preserves Merkle proofs for deleted items
- Advanced: cold storage tiering

## HOP Context

| Layer | HOP Role | Persistence |
|-------|----------|-------------|
| Execution trace | None | Ephemeral |
| Work scaffolding | None | Summarizable |
| Work outcome | CV entry | Permanent |
| Validation record | Stake proof | Permanent |

"Execution is ephemeral. Outcomes are permanent. You can't squash your CV."

## Success Criteria

- After cleanup --ephemeral: issues.jsonl only contains persistent work
- Work outcomes preserved (CV entries)
- Validation records preserved (stake proofs)
- Execution scaffolding removed (transient coordination)

## Implementation Plan (REVISED after code review)

See history/EPHEMERAL_MOLECULES_DESIGN.md for comprehensive design + review.

## Key Simplification

After code review, Tier 1 is MUCH simpler than originally designed:

- **Original**: Separate ephemeral repo with routing.ephemeral config
- **Revised**: Just set Wisp: true in cloneSubgraph()

The wisp field and bd cleanup --wisp already exist\!

## Child Tasks (in dependency order)

1. **bd-2vh3.2**: Tier 1 - Ephemeral spawning (SIMPLIFIED) [READY]
   - Just add Wisp: true to template.go:474
   - Add --persistent flag to opt out
2. **bd-2vh3.3**: Tier 2 - Basic bd mol squash command
3. **bd-2vh3.4**: Tier 3 - AI-powered squash summarization
4. **bd-2vh3.5**: Tier 4 - Auto-squash on molecule completion
5. **bd-2vh3.6**: Tier 5 - JSONL archive rotation (DEFERRED: post-1.0)

## What Already Exists

| Component | Location |
|-----------|----------|
| Ephemeral field | internal/types/types.go:45 |
| bd cleanup --wisp | cmd/bd/cleanup.go:72 |
| cloneSubgraph() | cmd/bd/template.go:456 |
| loadTemplateSubgraph() | cmd/bd/template.go |

## HOP Alignment

'Execution is ephemeral. Outcomes are permanent. You can't squash your CV.'


Sync branch integrity guards

Track sync branch parent commit. If sync branch was force-pushed, warn user and require confirmation before proceeding. Add option to reset to remote if user accepts rebase. Prevents silent corruption from forced pushes.


Update Homebrew formula

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

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

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

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


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.


Timer beads for scheduled agent callbacks

## Problem

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

## Proposal: Timer Beads

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

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

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

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

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

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


test hook pin


Merge: bd-14ie

branch: polecat/toast
target: main
source_issue: bd-14ie
rig: beads


Correction: Pinned field already in v0.31.0

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

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

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

No migration needed - the field is already there.

-- Mayor


Graph Link: replies_to for conversation threading

Implement replies_to link type for message threading.

New command:
- bd mail reply <id> -m 'Response' creates a message with replies_to set

Query support:
- bd show <id> --thread shows full conversation thread
- Thread traversal in storage layer

Storage:
- replies_to column in issues table
- Index for efficient thread queries

This enables Reddit-style nested threads where messages reply to other messages.


Add tests for helper functions (GetDirtyIssueHash, GetAllDependencyRecords, export hashes)

Several utility functions have 0% coverage:
- GetDirtyIssueHash (dirty.go)
- GetAllDependencyRecords (dependencies.go)
- GetExportHash, SetExportHash, ClearAllExportHashes (hash.go)

These are lower priority but should have basic coverage.


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

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

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

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

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

## Potential Followups
See linked issues for suggestions.


Test message

Hello world


Fix multi-round convergence for N-way collisions

**Summary:** Multi-round collision resolution was identified as a critical issue preventing complete synchronization across distributed clones. The problem stemmed from incomplete final pulls that didn't fully propagate all changes between system instances.

**Key Decisions:**
- Implement multi-round sync mechanism
- Ensure bounded convergence (≤N rounds)
- Guarantee idempotent import without data loss

**Resolution:** Developed a sync strategy that ensures all clones converge to the same complete set of issues, unblocking the bd-cbed9619 epic and improving distributed system reliability.


Merge: beads-ocs

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


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

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


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

bd sync tries to create worktree for sync.branch even when already on that branch. Should commit directly instead. See GitHub issue #519.


Run tests and linting

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


bd pin: pinned field overwritten by subsequent bd commands

## Summary

The `bd pin` command correctly sets `pinned=1` in SQLite, but any subsequent `bd` command (including read-only commands like `bd show`) resets `pinned` to 0.

## Reproduction Steps

```bash
bd --no-daemon pin <issue-id> --for=max
sqlite3 .beads/beads.db "SELECT id, pinned FROM issues WHERE id=\"<issue-id>\""
# Shows pinned=1 ✓

bd --no-daemon show <issue-id> --json
sqlite3 .beads/beads.db "SELECT id, pinned FROM issues WHERE id=\"<issue-id>\""
# Shows pinned=0 ✗ WRONG
```

## Root Cause Investigation

### Prime Suspects

1. **JSONL import overwrites DB** - The `pinned` field has `omitempty` so false values arent in JSONL. When JSONL is imported, it overwrites the DB pinned=1 with default pinned=0.

2. **Files to check:**
   - `internal/importer/importer.go` - ImportIssue() may unconditionally set all fields
   - `internal/storage/sqlite/issues.go` - UpsertIssue() may not preserve pinned
   - `cmd/bd/main.go` - ensureStoreActive() may trigger import

### Debug Steps

```bash
# Add debug logging to track what is writing pinned=0
grep -rn "pinned" internal/storage/sqlite/*.go
grep -rn "Pinned" internal/importer/*.go
```

## Likely Fix

In `internal/importer/importer.go` or `internal/storage/sqlite/issues.go`:

```go
// When upserting from JSONL, preserve pinned field if already set
func (s *SQLiteStorage) UpsertIssue(ctx context.Context, issue *types.Issue) error {
    // Check if issue exists and is pinned
    existing, _ := s.GetIssue(ctx, issue.ID)
    if existing != nil && existing.Pinned && !issue.Pinned {
        // Preserve existing pinned status
        issue.Pinned = existing.Pinned
    }
    // ... rest of upsert
}
```

OR the import should skip fields that are omitempty and not present in JSONL:

```go
// In importer, only update fields that are explicitly set in JSONL
// Pinned with omitempty means absent = dont change, not absent = false
```

## Testing

```bash
# After fix:
bd --no-daemon pin <issue-id> --for=max
bd --no-daemon show <issue-id> --json  # Should not reset pinned
bd list --pinned  # Should show the pinned issue
bd hook --agent max  # Should show pinned work
```

## Files to Modify

1. **internal/importer/importer.go** - Preserve pinned on import
2. **internal/storage/sqlite/issues.go** - UpsertIssue preserve pinned
3. **Add test** in internal/importer/importer_test.go

## Success Criteria
- `bd pin` survives subsequent bd commands
- `bd list --pinned` shows pinned issues
- `bd hook --agent X` shows pinned work
- Existing tests still pass


Thread Test 2

Testing direct mode


GetBlockedIssues shows external deps as blocking even when satisfied

GetBlockedIssues (ready.go:385-493) shows external:* refs in the blocked_by list but doesn't check if they're actually satisfied using CheckExternalDep.

This can be confusing - an issue shows as blocked by external:project:capability even if that capability has been shipped (closed issue with provides: label exists).

Options:
1. Call CheckExternalDep for each external ref and filter satisfied ones from blocked_by
2. Add a note in output indicating external deps need lazy resolution
3. Document this is expected behavior (bd blocked shows all deps, bd ready shows resolved state)

Related: GetReadyWork correctly filters by external deps, but GetBlockedIssues doesn't.


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

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


Add bd reset command for clean slate restart

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

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

## Design

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

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

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

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

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

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


Run bump-version.sh test-squash

Run ./scripts/bump-version.sh test-squash to update version in all files


Merge: bd-dtl8

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


Merge: bd-l13p

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


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.


Update local installation

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


Audit and fix JSONL filename mismatches across all repo clones

## Problem

Multiple clones of repos are configured with different JSONL filenames (issues.jsonl vs beads.jsonl), causing:
1. JSONL files to be resurrected after deletion (one clone pushes issues.jsonl, another pushes beads.jsonl)
2. Agents unable to see issues filed by other agents after sync
3. Merge conflicts and data inconsistencies

## Root Cause

When repos were "bd doctored" or initialized at different times, some got issues.jsonl (old default) and others got beads.jsonl (Beads repo specific). These clones push their respective files, creating duplicates.

## Task

Scan all repo clones under ~/src/ (1-2 levels deep) and standardize their JSONL configuration.

### Step 1: Find all beads-enabled repos

```bash
# Find all directories named 'beads' at levels 1-2 under ~/src/
find ~/src -maxdepth 2 -type d -name beads
```

### Step 2: For each repo found, check configuration

For each directory from Step 1, check:
- Does `.beads/metadata.json` exist?
- What is the `jsonl_export` value?
- What JSONL files actually exist in `.beads/`?
- Are there multiple JSONL files (problem!)?

### Step 3: Create audit report

Generate a report showing:
```
Repo Path                           | Config        | Actual Files           | Status
----------------------------------- | ------------- | ---------------------- | --------
~/src/beads                         | beads.jsonl   | beads.jsonl            | OK
~/src/dave/beads                    | issues.jsonl  | issues.jsonl           | MISMATCH
~/src/emma/beads                    | issues.jsonl  | issues.jsonl, beads.jsonl | DUPLICATE!
```

### Step 4: Determine canonical name for each repo

For repos that are the SAME git repository (check `git remote -v`):
- Group them together
- Determine which JSONL filename should be canonical (majority wins, or beads.jsonl for the beads repo itself)
- List which clones need to be updated

### Step 5: Generate fix script

Create a script that for each mismatched clone:
1. Updates `.beads/metadata.json` to use the canonical name
2. If JSONL file needs renaming: `git mv .beads/old.jsonl .beads/new.jsonl`
3. Removes any duplicate JSONL files: `git rm .beads/duplicate.jsonl`
4. Commits the change
5. Syncs: `bd sync`

### Expected Output

1. Audit report showing all repos and their config status
2. List of repos grouped by git remote (same repository)
3. Fix script or manual instructions for standardizing each repo
4. Verification that after fixes, all clones of the same repo use the same JSONL filename

### Edge Cases

- Handle repos without metadata.json (use default discovery)
- Handle repos with no git remote (standalone/local)
- Handle repos that are not git repositories
- Don't modify repos with uncommitted changes (warn instead)

### Success Criteria

- All clones of the same git repository use the same JSONL filename
- No duplicate JSONL files in any repo
- All configurations documented in metadata.json
- bd doctor passes on all repos


Remove all deletions.jsonl code except migration

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

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

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


bd cleanup --hard should skip tombstone creation for true permanent deletion

## Problem

When using bd cleanup --hard --older-than N --force, the command:
1. Deletes closed issues older than N days (converting them to tombstones with NOW timestamp)
2. Then tries to prune tombstones older than N days (finds none because they were just created)

This leaves the database bloated with fresh tombstones that will not be pruned.

## Expected Behavior

In --hard mode, the deletion should be permanent without creating tombstones, since the user explicitly requested bypassing sync safety.

## Workaround

Manually delete from database: sqlite3 .beads/beads.db 'DELETE FROM issues WHERE status=tombstone'

## Fix Options

1. In --hard mode, use a different delete path that does not create tombstones
2. After deleting, immediately prune the just-created tombstones regardless of age
3. Pass a skip_tombstone flag to the delete operation

Option 1 is cleanest - --hard should mean permanent delete without tombstone.


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


gt polecat done should auto-stop running session

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


test pin


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.


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

# Performance Analysis (10K Issue Database)

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

## Operation Performance

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

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

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

## Root Cause

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

## CPU Profile Analysis

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

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

## Optimization Recommendations

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

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

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

### Medium Impact

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

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

## Verification

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

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


Deleted issues resurrect during bd sync (tombstones not propagating)

## Problem

When issues are deleted with bd delete --force, they get deleted from the local DB but resurrect during the next bd sync.

## Reproduction

1. Observe orphan warnings (bd-cb64c226.*, bd-cbed9619.*)
2. Delete them: bd delete bd-cb64c226.1 ... --force
3. Run bd sync
4. Orphan warnings reappear - issues were resurrected!

## Root Cause Hypothesis

The sync branch workflow (beads-sync) has the old state before deletions. When bd sync pulls from beads-sync and copies JSONL to main, the deleted issues are re-imported.

Tombstones may not be properly:
1. Written to beads-sync during export
2. Propagated during pull/merge
3. Honored during import

## Related

- bd-7b7h: chicken-and-egg sync.branch bug (same workflow)
- bd-ncwo: ID-based fallback matching to prevent ghost resurrection

## Files to Investigate

- cmd/bd/sync.go (export/import flow)
- internal/syncbranch/worktree.go (PullFromSyncBranch, copyJSONLToMainRepo)
- internal/importer/ (tombstone handling)


Merge3Way public API does not expose TTL parameter

The public Merge3Way() function in merge.go does not allow callers to configure the tombstone TTL. It hard-codes the default via merge3WayWithTTL(). While merge3WayWithTTL() exists, it is unexported (lowercase). This means the CLI and tests cannot configure TTL at merge time. Use cases: testing with different TTL values, per-repository TTL configuration, debugging with short TTL, supporting --ttl flag in bd merge command (mentioned in design doc bd-zvg). Recommendation: Export Merge3WayWithTTL (rename to uppercase). Files: internal/merge/merge.go:77, 292-298


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.


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


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


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


Remove legacy MCP Agent Mail integration

## Summary

Remove the legacy MCP Agent Mail system that requires an external HTTP server. Keep the native `bd mail` system which stores messages as git-synced issues.

## Background

Two mail systems exist in the codebase:
1. **Legacy Agent Mail** (`bd message`) - External server dependency, complex setup
2. **Native bd mail** (`bd mail`) - Built-in, git-synced, no dependencies

The legacy system causes confusion and is no longer needed. Gas Town's Town Mail will use the native `bd mail` system.

## Files to Delete

### CLI Command
- [ ] `cmd/bd/message.go` - The `bd message` command implementation

### MCP Integration
- [ ] `integrations/beads-mcp/src/beads_mcp/mail.py` - HTTP wrapper for Agent Mail server
- [ ] `integrations/beads-mcp/src/beads_mcp/mail_tools.py` - MCP tool definitions
- [ ] `integrations/beads-mcp/tests/test_mail.py` - Tests for legacy mail

### Documentation
- [ ] `docs/AGENT_MAIL.md`
- [ ] `docs/AGENT_MAIL_QUICKSTART.md`
- [ ] `docs/AGENT_MAIL_DEPLOYMENT.md`
- [ ] `docs/AGENT_MAIL_MULTI_WORKSPACE_SETUP.md`
- [ ] `docs/adr/002-agent-mail-integration.md`

## Code to Update

- [ ] Remove `message` command registration from `cmd/bd/main.go`
- [ ] Remove mail tool imports/registration from MCP server `__init__.py` or `server.py`
- [ ] Check for any other references to Agent Mail in the codebase

## Verification

- [ ] `bd message` command no longer exists
- [ ] `bd mail` command still works
- [ ] MCP server starts without errors
- [ ] Tests pass


Version Bump: 0.32.1

Release checklist for version 0.32.1. Patch release with MCP output control params and pin field fix.


Version Bump: 0.30.7

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


bd mol bond --ephemeral flag

Add --ephemeral flag to bd mol bond command.

## Behavior
- `bd mol bond <proto> --ephemeral` creates molecule in .beads-ephemeral/
- Without flag, creates in .beads/ (current behavior)
- Ephemeral molecules have `ephemeral: true` in their issue record

## Implementation
- Add --ephemeral bool flag to mol bond command
- Route to EphemeralStore when flag set
- Set ephemeral:true on created issue

## Testing
- Test mol bond creates in correct location
- Test ephemeral flag is persisted
- Test regular mol bond still works


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

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

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

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

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

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

Requires: Identity configuration (bd-kwro.7)


GH#692: Code quality and refactoring improvements

Epic for implementing refactoring suggestions from GitHub issue #692 (rsnodgrass). These are code quality improvements that don't change functionality but improve maintainability, type safety, and performance.

Original issue: https://github.com/steveyegge/beads/issues/692

High priority items:
1. Replace map[string]interface{} with typed structs for JSON output
2. Adopt slices.SortFunc instead of sort.Slice (Go 1.21+)
3. Split large files (sync.go, init.go, show.go)
4. Introduce slog for structured logging in daemon

Lower priority:
5. Further CLI helper extraction
6. Preallocate slices in hot paths
7. Polish items (error wrapping, table-driven parsing)


Test issue for pin --for

Testing the pin --for flag


Install 0.30.4 Go binary locally

Rebuild and install the Go binary:
```bash
go install ./cmd/bd
# OR
make install
```

Verify:
```bash
bd --version
```

```verify
bd --version 2>&1 | grep -q '0.30.4'
```


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)


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.


Add EntityRef type for structured entity references

Create EntityRef struct with Name, Platform, Org, ID fields. This is the foundation for HOP entity tracking. Can render as entity://hop/<platform>/<org>/<id> when needed. Add to internal/types/types.go.


Migrate sort.Slice to slices.SortFunc

Go 1.21+ provides slices.SortFunc which is cleaner and slightly faster than sort.Slice.

Found 15+ instances of sort.Slice in:
- cmd/bd/autoflush.go
- cmd/bd/count.go
- cmd/bd/daemon_sync.go
- cmd/bd/doctor.go
- cmd/bd/export.go
- cmd/bd/import.go
- cmd/bd/integrity.go
- cmd/bd/jira.go
- cmd/bd/list.go
- cmd/bd/migrate_hash_ids.go
- cmd/bd/rename_prefix.go
- cmd/bd/show.go

Example migration:
```go
// Before
sort.Slice(issues, func(i, j int) bool {
    return issues[i].Priority < issues[j].Priority
})

// After
slices.SortFunc(issues, func(a, b *types.Issue) int {
    return cmp.Compare(a.Priority, b.Priority)
})
```

Benefits:
- Cleaner 3-way comparison
- Slightly better performance
- Modern idiomatic Go


Add tests for validation functions

Validation functions like ParseIssueType have 0% coverage. These are critical for ensuring data quality and preventing invalid data from entering the system.


Refactor long SQLite test files

The SQLite test files have grown unwieldy. Review and refactor.

## Goals
- Break up large test files into focused modules
- Improve test organization by feature area
- Reduce test duplication
- Make tests easier to maintain and extend

## Areas to Review
- main_test.go (likely the largest)
- Any test files over 500 lines
- Shared test fixtures and helpers
- Test coverage gaps

## Approach
- Group tests by feature (CRUD, sync, queries, transactions)
- Extract common fixtures to test helpers
- Consider table-driven tests where appropriate
- Ensure each test file has clear focus

## Reference
See docs/dev-notes/ for any existing test audit notes


Implement bd close --continue flag

Auto-advance to next step in molecule when closing an issue. Referenced by gt-um6q, gt-lz13. Needed for molecule navigation workflow.


Work on beads-7jl: Fix Windows installer file locking iss...

Work on beads-7jl: Fix Windows installer file locking issue (GH#652). Close file handle before extraction in postinstall.js. When done, submit MR (not PR) to integration branch for Refinery.


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.


Update local installation

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


Fix TestRunSync_Timeout failing on macOS

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

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

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


Run bump-version.sh 0.30.7

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


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.


Run check-versions.sh - all must pass

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

All versions must match 0.30.4.

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


Commit and push release

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


Update hook templates to 0.30.4

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

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

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


Fix beads-9yc: pinned column missing from schema. gt mail...

Fix beads-9yc: pinned column missing from schema. gt mail send fails because some beads DBs lack the pinned column. Add migration to ensure it exists.


Command Set Standardization & Flag Consistency

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

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

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

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


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

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

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

Current coverage: 27.3%
Target coverage: 60%


Add gate checking to Deacon patrol loop

Integrate gate checking into Deacon's patrol cycle.

## Patrol Integration
```go
func (d *Deacon) checkGates(ctx context.Context) {
    gates, _ := d.store.ListOpenGates(ctx)

    for _, gate := range gates {
        // Check timeout
        if time.Since(gate.CreatedAt) > gate.Timeout {
            d.notifyWaiters(gate, "timeout")
            d.closeGate(gate, "timed out")
            continue
        }

        // Check condition
        if d.checkCondition(gate.AwaitType, gate.AwaitID) {
            d.notifyWaiters(gate, "cleared")
            d.closeGate(gate, "condition met")
        }
    }
}
```

## Note
This task is in Gas Town (gt), not beads. May need to be moved there.


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%


Review PR #514: fix plugin install docs

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


test hook pin fix


bd list --parent: filter by parent issue

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

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

Would show all open children of gt-h5n.

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


Wisp storage: ephemeral molecule tracking

Implement ephemeral molecule storage for patrol cycles.

## Architecture

Wisps are ephemeral molecules stored in `.beads-wisps/` (gitignored).
When squashed, they create digests in permanent `.beads/`.

**Storage is per-rig, not per-role**: Witness and Refinery share mayor/rig's
`.beads-wisps/` since they execute from that context.

## Design Doc
See: gastown/mayor/rig/docs/wisp-architecture.md

## Key Requirements

1. **Ephemeral storage**: `.beads-wisps/` directory, gitignored
2. **Bond with --wisp**: Creates in wisps instead of permanent
3. **Squash**: Deletes wisp, creates digest in permanent beads
4. **Burn**: Deletes wisp, no digest
5. **Wisp commands**: `bd wisp list`, `bd wisp gc`

## Storage Locations

| Context | Location |
|---------|----------|
| Rig (Deacon, Witness, Refinery) | mayor/rig/.beads-wisps/ |
| Polecat (if used) | polecats/<name>/.beads-wisps/ |

## Children (to be created)
- bd mol bond --wisp flag
- .beads-wisps/ storage backend
- bd mol squash handles wisp to permanent
- bd wisp list command
- bd wisp gc command (orphan cleanup)


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


Wait for CI to pass

Monitor GitHub Actions - all checks must pass before release artifacts are built


Improve clean vs cleanup command naming/documentation

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

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

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

2. Keep names but improve help text and documentation

3. Add prominent warnings in help output

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

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