Migrate config.yaml to config.json

The beads config file uses YAML format (config.yaml) but should use JSON (config.json) for consistency with the rest of the system. gastown has a fallback in internal/rig/manager.go:initBeads that writes YAML format - this needs to be updated once beads supports JSON config.


Wait for CI to pass

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


Run bump-version.sh

Update all component versions atomically.

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

This updates:
- cmd/bd/version.go
- .claude-plugin/*.json
- integrations/beads-mcp/pyproject.toml
- integrations/beads-mcp/src/beads_mcp/__init__.py
- npm-package/package.json
- Hook templates
- README.md
- CHANGELOG.md (adds date)


bd update --parent: allow reparenting issues

**Request:** Add `--parent` flag to `bd update` command.

**Use case:** When renaming/migrating an epic (e.g., gt-oki8p → gt-liftoff), need to reparent child issues to the new epic.

**Current workaround:** None clean - must delete and recreate children, or manually edit JSONL.

**Proposed:**
```bash
bd update gt-j0gx2 --parent=gt-liftoff
```

**Note:** `bd create` already has `--parent` flag, so the semantics are established.


Add pre-sync validation hook

Future: Hook integration to run bd lint before sync, respecting config settings.


Respond to GitHub issue #479 with solution

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

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

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

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

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

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


Merge: bd-d28c

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


Add comments to 30+ silently ignored errors or fix them

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

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

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

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


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


Preflight: Check git status

Ensure working tree is clean before starting release.

```bash
git status
```

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


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

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


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`


Merge: ruby-1767138542815

branch: polecat/ruby-1767138542815
target: main
source_issue: ruby-1767138542815
rig: beads


bd activity: Real-time molecule state feed

Implement activity feed command for watching molecule state transitions.

## Commands
```bash
bd activity --follow              # Real-time streaming
bd activity --mol <id>            # Activity for specific molecule
bd activity --since 5m            # Last 5 minutes
bd activity --type step           # Only step transitions
```

## Output Format
```
[14:32:01] ✓ patrol-x7k.inbox-check completed
[14:32:03] ✓ patrol-x7k.check-refinery completed
[14:32:08] + patrol-x7k.arm-ace bonded (5 steps)
[14:32:09] → patrol-x7k.arm-ace.capture in_progress
[14:32:10] ✓ patrol-x7k.arm-ace.capture completed
[14:32:14] ✓ patrol-x7k.arm-ace.decide completed (action: nudge-1)
[14:32:17] ✓ patrol-x7k.arm-ace COMPLETE
[14:32:23] ✓ patrol-x7k SQUASHED → digest-x7k
```

## Event Types
- `+` bonded - New molecule/step created
- `→` in_progress - Step started
- `✓` completed - Step/molecule finished
- `✗` failed - Step failed
- `⊘` burned - Wisp discarded
- `◉` squashed - Wisp condensed to digest

## Implementation
- Could use SQLite triggers or polling
- --follow uses OS file watching or polling
- Filter by mol ID, type, time range


Merge: bd-n386

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


Test actor direct


Test agent bead

Testing new agent type


Compound visualization in bd mol show

Enhance bd mol show to display compound structure.

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

EXAMPLE OUTPUT:

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

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

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


Introduce slog for structured daemon logging.

## Current State
Daemon uses fmt.Fprintf for logging:
```go
fmt.Fprintf(os.Stderr, "Warning: failed to detect user role: %v\n", err)
fmt.Fprintf(logFile, "[%s] %s\n", time.Now().Format(time.RFC3339), msg)
```

This produces unstructured, hard-to-parse logs.

## Target State
Use Go 1.21+ slog for structured logging:
```go
slog.Warn("failed to detect user role", "error", err)
slog.Info("sync completed", "created", 5, "updated", 3, "duration_ms", 150)
```

## Implementation

### 1. Create logger setup (internal/daemon/logger.go)

```go
package daemon

import (
    "io"
    "log/slog"
    "os"
)

// SetupLogger configures the daemon logger.
// Returns a cleanup function to close the log file.
func SetupLogger(logPath string, jsonFormat bool, level slog.Level) (func(), error) {
    var w io.Writer = os.Stderr
    var cleanup func()

    if logPath \!= "" {
        f, err := os.OpenFile(logPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
        if err \!= nil {
            return nil, err
        }
        w = io.MultiWriter(os.Stderr, f)
        cleanup = func() { f.Close() }
    }

    var handler slog.Handler
    opts := &slog.HandlerOptions{Level: level}

    if jsonFormat {
        handler = slog.NewJSONHandler(w, opts)
    } else {
        handler = slog.NewTextHandler(w, opts)
    }

    slog.SetDefault(slog.New(handler))

    return cleanup, nil
}
```

### 2. Add log level flag

In cmd/bd/daemon.go:
```go
daemonCmd.Flags().String("log-level", "info", "Log level (debug, info, warn, error)")
daemonCmd.Flags().Bool("log-json", false, "Output logs in JSON format")
```

### 3. Replace fmt.Fprintf with slog calls

**Pattern 1: Simple messages**
```go
// Before
fmt.Fprintf(os.Stderr, "Starting daemon on %s\n", socketPath)

// After
slog.Info("starting daemon", "socket", socketPath)
```

**Pattern 2: Errors**
```go
// Before
fmt.Fprintf(os.Stderr, "Error: failed to connect: %v\n", err)

// After
slog.Error("failed to connect", "error", err)
```

**Pattern 3: Debug info**
```go
// Before
if debug {
    fmt.Fprintf(os.Stderr, "Received request: %s\n", method)
}

// After
slog.Debug("received request", "method", method)
```

**Pattern 4: Structured data**
```go
// Before
fmt.Fprintf(logFile, "Import: %d created, %d updated\n", created, updated)

// After
slog.Info("import completed",
    "created", created,
    "updated", updated,
    "unchanged", unchanged,
    "duration_ms", duration.Milliseconds())
```

### 4. Files to Update

| File | Changes |
|------|---------|
| cmd/bd/daemon.go | Add log flags, call SetupLogger |
| internal/daemon/server.go | Replace fmt with slog |
| internal/daemon/rpc_handler.go | Replace fmt with slog |
| internal/daemon/sync.go | Replace fmt with slog |
| internal/daemon/autoflush.go | Replace fmt with slog |
| internal/daemon/logger.go | New file |

### 5. Log output examples

**Text format (default):**
```
time=2025-12-23T12:30:00Z level=INFO msg="daemon started" socket=/tmp/bd.sock pid=12345
time=2025-12-23T12:30:01Z level=INFO msg="import completed" created=5 updated=3 duration_ms=150
time=2025-12-23T12:30:05Z level=WARN msg="sync branch diverged" local_ahead=2 remote_ahead=1
```

**JSON format (--log-json):**
```json
{"time":"2025-12-23T12:30:00Z","level":"INFO","msg":"daemon started","socket":"/tmp/bd.sock","pid":12345}
{"time":"2025-12-23T12:30:01Z","level":"INFO","msg":"import completed","created":5,"updated":3,"duration_ms":150}
```

## Migration Strategy

1. **Add logger.go** with SetupLogger
2. **Update daemon startup** to initialize slog
3. **Convert one file at a time** (start with server.go)
4. **Test after each file**
5. **Remove old logging code** once all converted

## Testing

```bash
# Start daemon with debug logging
bd daemon start --log-level debug

# Check logs
bd daemons logs . | head -20

# Test JSON output
bd daemon start --log-json --log-level debug
bd daemons logs . | jq .
```

## Success Criteria
- All daemon logging uses slog
- --log-level controls verbosity
- --log-json produces machine-parseable output
- Log entries have consistent structure
- No fmt.Fprintf to stderr in daemon code


Add bd update --parent flag to change issue parent

Allow changing an issue's parent with bd update --parent <new-parent-id>. Useful for reorganizing tasks under different epics or moving issues between hierarchies. Should update the parent-child dependency relationship.


Add ValidateTemplate() function

Add internal/validation package with ValidateTemplate(issueType, description) that checks for missing sections and returns actionable errors.


Crew worker emma in beads - human-managed persistent workspace.

role_type: crew
rig: beads
agent_state: idle
hook_bead: null
role_bead: gt-crew-role
cleanup_status: null


Review changes since last release

Understand what's being released.

```bash
git log $(git describe --tags --abbrev=0)..HEAD --oneline
```

Categorize changes:
- Features (feat:)
- Fixes (fix:)
- Breaking changes
- Documentation


Commit the release changes.

Commit the release changes.

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

instantiated_from: bd-mol-xga
step: commit-release


beads-release

Beads release workflow - from version bump to verified release.

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

## Usage

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

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


Release v{{version}}

SUPERSEDED by bd-7bs4. Use the new proto for releases.


Verify npm package

Confirm npm package published.

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

Should show 0.99.0-test.

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


Exclude pinned issues from bd blocked

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


Verify PyPI package

Confirm PyPI package published.

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

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

Should show 0.41.0.


Merge: bd-g4b4

branch: polecat/Hooker
target: main
source_issue: bd-g4b4
rig: beads


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


Document sync.branch 'always dirty' working tree behavior

## Context

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

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

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

## Documentation Needed

Update README.md sync.branch section with:

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

## Related

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


bd activity --town: Aggregated town feed

Add --town flag to bd activity for aggregated cross-rig feed.

Behavior:
- Uses routes.jsonl to discover all rigs
- Aggregates activity from all rig beads
- Essential for Deacon's convoy tracking and cross-rig dep resolution

Usage:
  bd activity --follow --town   # Stream all rig activity

Related: hq-7h8jx (Convoy System epic in town beads)


Design auto-squash behavior for wisps

Explore the design space for automatic wisp squashing.

**Context:**
Wisps are ephemeral molecules that should be squashed (digest) or burned (no trace)
when complete. Currently this is manual. Should it be automatic?

**Questions to answer:**
1. When should auto-squash trigger?
   - On molecule completion?
   - On session end/handoff?
   - On patrol detection?

2. What's the default summary for auto-squash?
   - Generic: 'Auto-squashed on completion'
   - Step-based: List closed steps
   - AI-generated: Require agent to provide

3. Should this be configurable?
   - Per-molecule setting in formula?
   - Global config: auto_squash: true/false
   - Per-wisp flag at creation time?

4. Who decides - Beads or Gas Town?
   - Beads: Provides operators (squash, burn)
   - Gas Town: Makes policy decisions
   - Proposal: GT patrol molecules call bd mol squash

**Constraints:**
- Don't lose important context (summary matters)
- Don't create noise in digest history
- Respect agent's intent (some wisps should burn, not squash)

**Recommendation:**
Gas Town patrol molecules should have explicit squash/burn steps.
Beads provides primitives, GT makes policy decisions.
Auto-squash at Beads level is probably wrong layer.


Code smell: Issue struct still has ~100 fields - consider composition

internal/types/types.go Issue struct (lines 14-100) still has approximately 100 fields across many categories despite prior cleanup:

- Core identification (ID, ContentHash)
- Content (Title, Description, Design)
- Status & Workflow
- Assignment, Timestamps
- External integration
- Compaction metadata
- Relational data (Labels, Dependencies, Comments)
- Tombstone, Messaging, Context markers
- Bonding, HOP, Gate, Source tracing, Agent identity fields

**Problem:**
- Very large struct is difficult to understand
- Hard to identify required vs optional fields
- High change risk

**Acceptance Criteria:**
- [ ] Group related fields into embedded structs (IssueMetadata, IssueCompaction, IssueAgent, etc.)
- [ ] Use composition instead of single flat struct
- [ ] Maintain backward compatibility for serialization
- [ ] Tests pass


Code smell: show.go is 1592 lines - needs splitting

cmd/bd/show.go is 1592 lines mixing data fetching, transformation, output formatting, and thread reconstruction.

**Problem:**
- Too large to understand and maintain
- Poor separation of concerns
- Hard to test individual components

**Acceptance Criteria:**
- [ ] Extract formatting into show_formatter.go
- [ ] Extract thread reconstruction into show_threads.go
- [ ] Each file under 500 lines
- [ ] No functionality changes
- [ ] Tests pass


Merge: jasper-1767083473604

branch: polecat/jasper-1767083473604
target: main
source_issue: jasper-1767083473604
rig: beads


Wait for CI

Monitor GitHub Actions for release completion.

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

Expected time: 5-10 minutes

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


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

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


Commit release

git add -A && git commit -m 'release: v{{version}}'


Merge: onyx-1767106262992

branch: polecat/onyx-1767106262992
target: main
source_issue: onyx-1767106262992
rig: beads


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


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


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)


Merge: topaz-1767083484329

branch: polecat/topaz-1767083484329
target: main
source_issue: topaz-1767083484329
rig: beads


Update CHANGELOG.md with release notes

Add meaningful release notes to CHANGELOG.md describing what changed in test-squash


Code smell: Incomplete TODOs in formula/types.go

internal/formula/types.go has multiple TODO items for features that are defined in the schema but not implemented:

- Line 170: Expand field not implemented in bd cook
- Line 174: ExpandVars field not implemented
- Line 179: Gate integration pending (bd-udsi gates)
- Line 186: Condition evaluation not implemented
- Line 210: Additional expansion features

**Problem:**
- Schema defines features that aren't implemented
- Can confuse users who try to use these fields
- Creates maintenance burden of unused code paths

**Acceptance Criteria:**
- [ ] Either implement the features OR
- [ ] Remove unimplemented fields from schema OR
- [ ] Document clearly which fields are future-only
- [ ] Update related beads issues if they exist


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#519: bd sync fails when sync.branch is currently checked-out branch


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.


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

attached_args: Refactor Issue struct God Object

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

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

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

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


Graph Link: duplicates for deduplication

Implement duplicates link type for marking issues as duplicates.

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

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

Storage:
- duplicates column pointing to canonical issue ID

Essential for large issue databases with many similar reports.


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

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

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

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

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

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


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


Release complete

Release v0.99.0-test is complete!

Summary:
- All version files updated
- Git tag pushed
- CI artifacts built
- npm and PyPI packages published
- Local installation updated
- Daemons restarted

Optional next steps:
- Announce on social media
- Update documentation site
- Close related milestone


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.


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.


wish: list & ready show issues as hierarchy tree

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


Rename 'wisp' back to 'ephemeral' in beads API

The beads API uses 'wisp' terminology (Wisp field, bd wisp command) but the underlying SQLite column is 'ephemeral'.

This creates cognitive overhead since wisp is a Gas Town concept.

Rename to use 'ephemeral' consistently:
- types.Issue.Wisp → types.Issue.Ephemeral
- JSON field: wisp → ephemeral
- CLI: bd wisp → bd ephemeral (or just use flags on existing commands)

The SQLite column already uses 'ephemeral' so no schema migration needed.


Default bd list to non-closed issues

Change bd list default from showing all issues to showing only actionable issues (open, in_progress, blocked, deferred). This addresses GH#788 where agents get context blown out by closed issues.

Current: bd list shows everything including closed
Proposed: bd list shows non-closed by default

This is the core fix - other enhancements depend on this change.

## Implementation Plan

### Code Changes (cmd/bd/list.go)

1. **Add new filter logic in Run function** (~line 393-399):
```go
// Default to non-closed if no status filter specified
if status == "" && \!cmd.Flags().Changed("all") {
    // Show actionable issues by default (GH#788)
    filter.ExcludeStatus = []types.Status{"closed"}
}
```

2. **Need to add ExcludeStatus to IssueFilter** (internal/types/types.go):
```go
type IssueFilter struct {
    // ... existing fields ...
    ExcludeStatus []Status // Exclude these statuses
}
```

3. **Update SearchIssues query** (internal/storage/sqlite/issues.go):
```go
if len(filter.ExcludeStatus) > 0 {
    placeholders := make([]string, len(filter.ExcludeStatus))
    for i, s := range filter.ExcludeStatus {
        placeholders[i] = "?"
        args = append(args, string(s))
    }
    conditions = append(conditions,
        fmt.Sprintf("status NOT IN (%s)", strings.Join(placeholders, ",")))
}
```

### Testing
- Verify `bd list` shows open, in_progress, blocked, deferred (not closed)
- Verify `bd list --status=closed` still works
- Verify `bd list --all` shows everything (requires bd-34q1)

### Backwards Compatibility
- Scripts using `bd list | grep` may get fewer results
- Document in changelog: "bd list now defaults to non-closed issues"


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


Polymorphic bond command: bd mol bond A B

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

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

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

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

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

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


Performance Validation

Confirm no performance regression from cache removal


Technical debt: Scattered TODOs should be tracked as issues

Multiple TODO comments exist in the codebase that should be tracked as proper issues:

1. cmd/bd/migrate_hash_ids.go:24 - 'Consider integrating into bd doctor migration detection'
2. cmd/bd/migrate_tombstones.go:72 - Same
3. cmd/bd/migrate_sync.go:16 - Same
4. cmd/bd/migrate_issues.go:15 - Same
5. cmd/bd/create.go:164 - 'Switch to target repo for multi-repo support'
6. cmd/bd/create.go:208 - 'Add RPC method to get config in daemon mode'
7. cmd/bd/daemon_logger.go:131 - 'Remove this once all callers are updated'
8. cmd/bd/mol_stale.go:67 - 'Add RPC endpoint for stale check'
9. cmd/bd/sync_test.go:444 - 'Refactor to use direct import logic'
10. cmd/bd/jira.go:633 - 'In a full implementation, fetch Jira issue and compare timestamps'
11. internal/formula/types.go:170,174,179,186,210 - Multiple 'Not yet implemented' TODOs
12. internal/importer/importer_test.go:1010 - 'Test hangs due to database deadlock'

Consider:
1. Running 'grep -r TODO' periodically to find new ones
2. Adding a lint rule to discourage inline TODOs
3. Converting each to a bd issue with proper tracking

Location: Various files across codebase


Implement formula features: Step.Condition and Step.Gate

Multiple formula features in internal/formula/types.go are marked as "Not yet implemented":

IMPLEMENTED (TODOs removed):
- Step.Expand: Inline expansion - implemented in ApplyInlineExpansions (expand.go)
- Step.ExpandVars: Variable overrides for expansion - implemented alongside Expand

STILL NOT IMPLEMENTED (TODOs remain):
- Step.Condition: Make step optional based on variable (types.go:177-180)
- Step.Gate: Async wait condition for step (types.go:185-187)
- Gate struct: Schema defined but not processed in bd cook (types.go:209-210)

File: internal/formula/types.go


GH#517: Claude sets priority wrong on new install

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


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


Opt-in template validation for issues

## Summary

Add optional validation that issues include required sections based on type, without making it mandatory by default.

## Background

GH#821 proposed mandatory template validation, but that's too draconian for quick capture workflows. Instead, provide opt-in validation through multiple mechanisms.

## Design

### 1. `bd lint` command

Check issues for missing recommended sections:

```bash
bd lint              # Lint all open issues
bd lint bd-xxx       # Lint specific issue
bd lint --fix        # Interactive: prompt to add missing sections
```

Output:
```
bd-abc [bug]: Missing "## Steps to Reproduce"
bd-def [task]: Missing "## Acceptance Criteria"

2 issues with warnings
```

### 2. `--validate` flag on `bd create`

Opt-in strict mode at creation time:

```bash
bd create -t bug --validate -d "..."  # Fails if missing required sections
bd create -t bug -d "..."             # Succeeds (current behavior)
```

### 3. Section requirements by type

| Type | Recommended Sections |
|------|---------------------|
| Bug | Steps to Reproduce, Acceptance Criteria |
| Task/Feature | Acceptance Criteria |
| Epic | Success Criteria |
| Chore/Message | None |

Note: "Workaround" dropped from GH#821 - not always applicable.

### 4. Config option (future)

```json
// .beads/config.json
{
  "validation": {
    "on_create": "warn" | "error" | "none",
    "on_sync": "warn" | "error" | "none"
  }
}
```

### 5. Hook integration (future)

Pre-sync hook could run `bd lint` and warn/block based on config.

## Implementation Order

1. Add `RequiredSections()` to IssueType (internal/types)
2. Add `ValidateTemplate()` function (internal/validation)
3. Implement `bd lint` command
4. Add `--validate` flag to `bd create`
5. (Future) Config file support
6. (Future) Hook integration

## Acceptance Criteria

- [ ] `bd lint` reports missing sections without blocking
- [ ] `bd lint <id>` works on single issue
- [ ] `bd create --validate` enforces sections
- [ ] `bd create` without flag works as today
- [ ] Clear, actionable error messages

## References

- GH#821: Original proposal (will close referencing this epic)


bd repair: Check comments and events tables for orphans

bd repair currently checks dependencies and labels tables, but the schema also has comments and events tables with issue_id foreign keys that could be orphaned.

Add orphan detection and cleanup for:
- comments table (issue_id not in issues)
- events table (issue_id not in issues)


bd prime should mention when beads is redirected

## Problem

Agents running in a redirected clone don't know they're sharing beads with other clones. This can cause confusion when molecules or issues seem to 'appear' or 'disappear'.

## Proposed Solution

When `bd prime` runs and detects a redirect, include it in the output:

```
Beads: /Users/stevey/gt/beads/mayor/rig/.beads
       (redirected from crew/dave - you share issues with other clones)
```

## Why

Visibility over magic. If agents can see the redirect, they can reason about it.

## Related

- bd where command (shows this on demand)
- gt redirect following (ensures gt matches bd behavior)


Merge: bd-ao0s

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


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

Add new entry at the TOP of versionChanges array in cmd/bd/info.go:

```go
{
    Version: "{{version}}",
    Date:    "{{date}}",
    Changes: []string{
        // Add notable changes here
    },
},
```

Copy changes from CHANGELOG.md [Unreleased] section.


Push release tag

Push the version tag to trigger CI release.

```bash
git push origin v0.99.0-test
```

This triggers GitHub Actions to build artifacts and publish.


Release v0.34.0

Minor version release for beads v0.34.0. This bead serves as my persistent work assignment; the actual release steps are tracked in an attached wisp.


Implement --check flag with test runner

## Summary
Implement the `--check` flag to run `go test -short ./...` and report results.

## Implementation Details

### Location
File: `cmd/bd/preflight.go`

### Changes Required

1. **Add check execution logic** in `runPreflight()`:
```go
if check {
    runChecks(cmd)  // New function
    return
}
```

2. **Implement test runner**:
```go
func runTestCheck() CheckResult {
    cmd := exec.Command("go", "test", "-short", "./...")
    output, err := cmd.CombinedOutput()
    return CheckResult{
        Name:    "tests",
        Passed:  err == nil,
        Output:  string(output),
        Command: "go test -short ./...",
    }
}
```

3. **Define CheckResult struct**:
```go
type CheckResult struct {
    Name    string
    Passed  bool
    Output  string
    Command string
}
```

4. **Output format**:
```
$ bd preflight --check
✓ Tests pass
  Command: go test -short ./...

# On failure:
✗ Tests fail
  Command: go test -short ./...
  Output: [truncated test output]
```

### Testing
- Add tests in `cmd/bd/preflight_test.go`
- Test with passing tests (this repo)
- Test with intentionally failing test (mock or temp file)

### Acceptance Criteria
- [x] `--check` flag runs tests (not just prints message)
- [x] Clear pass/fail output with ✓/✗ symbols
- [x] Shows command being run
- [x] Shows output on failure (truncated if long)
- [x] Exits with non-zero code if tests fail
- [x] Works with `--json` flag for programmatic use


Review PR #512: clarify bd ready docs

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


Thread Test

Testing the thread feature


Implement subgraph cloning with variable substitution

Core implementation of template instantiation:

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

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


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

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

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

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

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

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


Ephemeral patrol molecules leaking into beads

## Problem

Ephemeral patrol orchestration molecules (e.g., mol-deacon-patrol, wisp step issues) keep appearing in `bd ready` output in gastown beads.

These are ephemeral/wisp issues that should:
1. Never be synced to the beads-sync branch
2. Live only in .beads-wisp/ (ephemeral storage)
3. Be squashed to digests, not persisted as regular beads

## Examples found

- gt-wisp-6ue: mol-deacon-patrol
- gt-pacdm: mol-deacon-patrol
- gt-wisp-mpm: Check own context limit
- gt-wisp-lkc: Clean dead sessions

## Investigation needed

1. Where are these being created? (gt mol bond? manual bd create?)
2. Why are they using the gt- prefix instead of staying ephemeral?
3. Is the wisp storage (.beads-wisp/) being used correctly?
4. Is bd sync accidentally picking up ephemeral issues?

## Expected behavior

Patrol molecules and their steps should be ephemeral and never appear in `bd ready` or `bd list`.


Commit release

Stage and commit all version changes.

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

Review the commit to ensure all expected files are included.


Push to main

Push the release commit to origin.

```bash
git push origin main
```

If rejected, someone else pushed. Pull, rebase, try again.


Enhance bd doctor to suggest reset for broken states

Update bd doctor to detect severely broken states and suggest reset.

## Detection Criteria
Suggest reset when:
- Multiple unfixable errors detected
- Corrupted JSONL that can't be repaired
- Schema version mismatch that can't be migrated
- Daemon state inconsistent and unkillable

## Implementation
Add to doctor's check/fix flow:
```go
if unfixableErrors > threshold {
    suggest('State may be too broken to fix. Consider: bd reset')
}
```

## Output Example
```
✗ Found 5 unfixable errors

  Your beads state may be too corrupted to repair.
  Consider running 'bd reset' to start fresh.
  (Use 'bd reset --backup' to save current state first)
```

## Notes
- Don't auto-run reset, just suggest
- This is lower priority, can be done in parallel with main work


Implement transaction retry logic for SQLITE_BUSY

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

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

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

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

Impact: Spurious failures under concurrent write load

Effort: 3 hours


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 cmd/bd/info.go with release notes for 0.37.0.

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

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

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


Remove/relocate pin command (covered by mol commands)

## Task
Review and potentially remove `bd pin` as it overlaps with mol commands.

## Analysis needed
- `bd pin` sets the pinned flag on issues for agent work assignment
- `bd hook` shows what's pinned to an agent
- `bd unpin` removes the pinned flag
- `bd mol` commands deal with molecules/templates

## Options
1. **Keep as-is**: pin/unpin are about work assignment, mol is about templates
2. **Move under mol**: `bd mol pin`, `bd mol unpin`
3. **Deprecate**: If mol commands fully cover the use case

## Decision criteria
- Are pin/unpin used independently of mol workflows?
- Does Gas Town (gt) use these commands?

## Recommendation
Check gt codebase for usage patterns before deciding. If pin/unpin are primarily used with mol workflows, consolidate under mol. If used independently, keep as-is.

## Files potentially affected
- cmd/bd/pin.go
- cmd/bd/unpin.go
- cmd/bd/hook.go
- cmd/bd/mol.go (if moving)


bd init should stop running daemon to avoid stale cache

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

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

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


Integration test: agent waits for CI via gate

End-to-end test of the gate workflow.

## Test Scenario
1. Agent creates gate: bd gate create --await gh:run:123 --timeout 5m --notify beads/dave
2. Agent writes handoff and exits
3. Deacon patrol checks gate condition
4. (Mock) GitHub run completes
5. Deacon notifies waiter and closes gate
6. New agent session reads mail and resumes

## Test Requirements
- Mock GitHub API responses
- Test timeout path
- Test multiple waiters
- Verify mail notifications sent


Witness Patrol

Per-rig worker monitor patrol loop with progressive nudging.


Install 0.30.4 MCP server locally

Upgrade the MCP server (after PyPI publish):
```bash
pip install --upgrade beads-mcp
# OR if using uv:
uv tool upgrade beads-mcp
```

Verify:
```bash
pip show beads-mcp | grep Version
```

```verify
pip show beads-mcp 2>/dev/null | grep -q 'Version: 0.30.4'
```


Refactor: Extract shared getEpicChildren helper for swarm commands

## Context
`getSwarmStatus` and `analyzeEpicForSwarm` in cmd/bd/swarm.go have nearly identical code for:
- Getting epic dependents via GetDependents
- Filtering to parent-child relationships
- Building childIDSet map
- Building dependency maps

## Implementation
1. Extract `getEpicChildren(ctx, store, epicID)` that returns:
   - `[]*types.Issue` - child issues
   - `map[string]bool` - child ID set
   - `map[string][]string` - dependency map (within children)
   - `error`

2. Refactor both `analyzeEpicForSwarm` and `getSwarmStatus` to use it

3. Consider defining a named interface for the store methods:
   ```go
   type SwarmStore interface {
       GetIssue(context.Context, string) (*types.Issue, error)
       GetDependents(context.Context, string) ([]*types.Issue, error)
       GetDependencyRecords(context.Context, string) ([]*types.Dependency, error)
   }
   ```

## Files
- cmd/bd/swarm.go (lines 150-248, 616-682)

## Acceptance
- No duplicated code for fetching epic children
- Both commands produce identical results as before


Test comment display


Reduce global state in cmd/bd/main.go (25+ variables)

Code health review found main.go has 25+ global variables (lines 57-112):

- dbPath, actor, store, jsonOutput, daemonClient, noDaemon
- rootCtx, rootCancel, autoFlushEnabled
- isDirty (marked 'USED BY LEGACY CODE')
- needsFullExport (marked 'USED BY LEGACY CODE')
- flushTimer (marked 'DEPRECATED')
- flushMutex, storeMutex, storeActive
- flushFailureCount, lastFlushError, flushManager
- skipFinalFlush, autoImportEnabled
- versionUpgradeDetected, previousVersion, upgradeAcknowledged

Impact:
- Hard to test individual commands
- Race conditions possible
- State leakage between commands

Fix: Move toward dependency injection. Remove deprecated variables. Consider cmd/bd/internal package.

COMPLETED: Migration of legacy flush state to FlushManager. The main work (isDirty, needsFullExport, flushTimer) moved to local vars in FlushManager.run() lines 170-173. This fixes the race conditions. Remaining globals are: Cobra flag bindings (standard), runtime state (store, daemonClient - structural), store coordination (storeActive/storeMutex). Future: move error tracking to FlushManager, create cmd/bd/internal for encapsulation.


rpc: Rich mutation events not emitted

The activity command (activity.go) references rich mutation event types (MutationBonded, MutationSquashed, MutationBurned, MutationStatus) that include metadata like OldStatus, NewStatus, ParentID, and StepCount.

However, the emitMutation() function in server_core.go:141 only accepts (eventType, issueID) and only populates Type, IssueID, and Timestamp. The additional metadata fields are never set.

Need to either:
1. Add an emitRichMutation() function that accepts the additional metadata
2. Update call sites (close, bond, squash, burn operations) to emit rich events

Without this fix, the activity feed will never show:
- Status transitions (in_progress -> closed)
- Bonded events with step counts
- Parent molecule relationships

Discovered during code review of bd-xo1o implementation.


Run tests and verify build

Run the test suite to verify nothing is broken:

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

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

Fix any failures before proceeding.


Add daemon-side delete operation tests

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

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

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


Add type: event for state transitions

Events capture operational state changes as immutable records.

Fields needed:
- event_type: string (namespaced category like patrol.muted, agent.started)
- actor: string (entity URI who caused this)
- target: string (entity URI or bead ID affected)
- payload: object (event-specific JSON data)

Example:
  id: evt-x7k2
  type: event
  event_type: patrol.muted
  actor: human:overseer
  target: agent:deacon
  payload: {reason: fixing deadlock, until: gt-abc1}

This enables:
- bd activity --follow showing events
- bd list --type=event --target=agent:deacon
- Full audit trail for operational state
- HOP-compatible transaction records


Bump version in all files

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


Merge: ruby-1767142029451

branch: polecat/ruby-1767142029451
target: main
source_issue: ruby-1767142029451
rig: beads


Create git tag v{{version}}

Create the release tag:

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

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


Deacon Patrol

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


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


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

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

Current coverage: 47.5%
Target coverage: 60%


Stale daemon.lock files cause 5+ second delays

## Problem
When a bd daemon crashes or is killed without cleanup, it leaves a stale daemon.lock file. Subsequent bd commands try to connect to the dead daemon, causing 5+ second timeouts before falling back to direct mode.

Found during gt status optimization (gt-zdtpw) - one stale wyvern daemon was causing 10+ second delays.

## Evidence
```
# Lock files with stale PIDs:
$ find ~/gt -name "daemon.lock" -exec cat {} \;
{"pid": 11045, ...}  # Not running (from Dec 27)
{"pid": 15986, ...}  # Not running (from Dec 27)
{"pid": 98055, ...}  # Just restarted

# But running daemons have different PIDs:
$ ps aux | grep "bd.*daemon"
11847, 11683, 11624  # None match the lock files!
```

## Proposed fixes

### 1. Validate lock on startup (quick fix)
Before trusting daemon.lock, check if the PID is still running:
```python
def is_daemon_alive(lock_path):
    lock = json.load(open(lock_path))
    try:
        os.kill(lock["pid"], 0)  # Signal 0 = check if alive
        return True
    except OSError:
        return False
```

### 2. Heartbeat mechanism (robust fix)
Daemon writes periodic heartbeat to lock file or separate file.
Clients check heartbeat age before attempting IPC.

### 3. Lock cleanup in daemon startup
When starting a new daemon, always check for and clean stale locks.

### 4. Graceful shutdown handling
Register signal handlers (SIGTERM, SIGINT) to clean up lock on exit.

## Workaround
For now, gastown uses `--no-daemon` for all read operations to avoid this issue.


Add tests for daemon functionality

Critical daemon functions have 0% test coverage including daemon lifecycle, health checks, and RPC server functionality. These are essential for system reliability and need comprehensive test coverage.


Support session_id field on issue close/update mutations

## Context

Per Gas Town decision 009-session-events-architecture.md, work attribution for
entity CV building requires capturing which Claude Code session performed work.

## Implementation

Add session_id support to issue mutations:

### Schema
Add optional field to issue close:
- closed_by_session: string (Claude Code session UUID)

### CLI
```bash
bd close gt-abc --session "abc123-session-id"
# Or via env var:
CLAUDE_SESSION_ID=abc123 bd close gt-abc
```

### Storage
Store in issues.jsonl:
```json
{"id": "gt-abc", "status": "closed", "closed_by_session": "abc123", ...}
```

## Acceptance Criteria

- [ ] bd close accepts --session flag or reads CLAUDE_SESSION_ID env
- [ ] session_id stored in issue close record
- [ ] bd show displays closed_by_session if present
- [ ] Works for bd update --status=closed as well

## Future

- Query by session: bd list --closed-by-session=X
- Entity chain: aggregate session activity for CV

## Related

- Gas Town docs/hop/decisions/009-session-events-architecture.md
- gt-nvz8b: gt done captures session_id


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

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


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

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

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

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

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

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


Merge: bd-401h

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


Monitor PyPI publish

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

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

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

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


Restart daemons

Restart bd daemons to pick up new version.

```bash
bd daemons killall
```

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

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


Update npm-package/package.json to 0.30.4

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

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


Installation tracking: .beads/installed.json

Track installed formulas for update checking and provenance.

## File Format
```json
{
  "mol-code-review": {
    "source": "github.com/anthropics/mol-code-review",
    "version": "v1.2.0",
    "installed_at": "2025-12-25T12:00:00Z",
    "formula_hash": "abc123..."
  },
  "mol-polecat-work": {
    "source": "local",
    "version": "1",
    "installed_at": "2025-12-24T10:00:00Z"
  }
}
```

## Commands That Update This
- `bd mol install` - Adds entry
- `bd mol update` - Updates version/timestamp
- `bd cook` - Adds entry with source:local
- `bd mol uninstall` - Removes entry (new command)

## Usage
```bash
bd mol list --installed    # Shows installed with source/version
bd mol outdated            # Shows formulas with available updates
```

## Sync Behavior
- installed.json is gitignored (local state)
- Only formulas/ directory is synced
- Each clone tracks its own installations


Implement bd lint command

New command to check issues for missing sections. Supports: bd lint (all open), bd lint <id> (single), bd lint --fix (interactive).


Sling reports 'already pinned' but mol status shows empty hook

During swarm operations, gt sling reported beads were 'already pinned' but gt mol status showed nothing on the hook.

**Observed:**
```
$ gt sling bd-9btu beads/Nux
Error: bead bd-9btu is already pinned to gt-beads-nux

$ gt mol status beads/Nux
Nothing on hook - no work slung
```

**Expected:**
If a bead is pinned, mol status should show it. If mol status shows empty, sling should work.

**Workaround:**
Used --force flag to re-sling, which worked.

**Root cause hypothesis:**
Agent bead state may be stored in town beads but polecat's local view doesn't see it, or the pin record exists but session state is stale.


Remove molecule.go (simple instantiation)

molecule.go uses is_template field for simple single-issue cloning. This is too simple for what molecules should be - full DAG orchestration. The use case is covered by bd mol bond with a single-issue molecule. Delete molecule.go and its commands.


bd cook: waits_for field not preserved in cooked protos

The `waits_for` field in formula steps is not preserved in the cooked proto.

## Formula

```yaml
- id: aggregate
  title: Aggregate arm results
  needs: [survey-workers]
  waits_for: all-children
  description: |
    This is a **fanout gate**...
```

## Expected

The cooked proto step should have metadata indicating it's a gate:
- Label: `gate:all-children` or
- Field in issue metadata indicating wait behavior

## Actual

The `waits_for` field is silently ignored. Only the description mentions 'fanout gate'.

## Impact

The execution engine cannot determine which steps are gates that need to wait
for dynamically-bonded children. This breaks the Christmas Ornament pattern
where aggregate steps must wait for all polecat-arm wisps to complete.

## Related

bd-hr39: needs field not converted to step dependencies


Test issue for pin --for

Testing the pin --for flag


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.


Add --body-file flag to bd create for reading descriptions from files

## Problem

Creating issues with long/complex descriptions via CLI requires shell escaping gymnastics:

```bash
# Current workaround - awkward heredoc quoting
bd create --title="..." --description="$(cat <<'EOF'
...markdown...
EOF
)"

# Often fails with quote escaping errors in eval context
# Agents resort to writing temp files then reading them
```

## Proposed Solution

Add `--body-file` and `--description-file` flags to read description from a file, matching `gh` CLI pattern.

```bash
# Natural pattern that aligns with training data
cat > /tmp/desc.md << 'EOF'
...markdown content...
EOF

bd create --title="..." --body-file=/tmp/desc.md
```

## Implementation

### 1. Add new flags to `bd create`

```go
createCmd.Flags().String("body-file", "", "Read description from file (use - for stdin)")
createCmd.Flags().String("description-file", "", "Alias for --body-file")
```

### 2. Flag precedence

- If `--body-file` or `--description-file` is provided, read from file
- If value is `-`, read from stdin
- Otherwise fall back to `--body` or `--description` flag
- If neither provided, description is empty (current behavior)

### 3. Error handling

- File doesn't exist → clear error message
- File not readable → clear error message
- stdin specified but not available → clear error message

## Benefits

✅ **Matches training data**: `gh issue create --body-file file.txt` is a common pattern
✅ **No shell escaping issues**: File content is read directly
✅ **Works with any content**: Markdown, special characters, quotes, etc.
✅ **Agent-friendly**: Agents already write complex content to temp files
✅ **User-friendly**: Easier for humans too when pasting long descriptions

## Related Commands

Consider adding similar support to:
- `bd update --body-file` (for updating descriptions)
- `bd comment --body-file` (if/when we add comments)

## Examples

```bash
# From file
bd create --title="Add new feature" --body-file=feature.md

# From stdin
echo "Quick description" | bd create --title="Bug fix" --body-file=-

# With other flags
bd create \
  --title="Security issue" \
  --type=bug \
  --priority=0 \
  --body-file=security-report.md \
  --label=security
```

## Testing

- Test with normal files
- Test with stdin (`-`)
- Test with non-existent files (error handling)
- Test with binary files (should handle gracefully)
- Test with empty files (valid - empty description)
- Test that `--description-file` and `--body-file` are equivalent aliases


Add prefix-based routing with routes.jsonl

## Summary

When running `bd show gt-xyz` from a location where that bead doesn't exist locally,
bd should check a `routes.jsonl` file to find where beads with that prefix live.

## Problem

From ~/gt (town root):
- `bd show hq-xxx` works (hq-* beads are local)
- `bd show gt-xxx` fails (gt-* beads live in gastown/mayor/rig)

This breaks `gt hook`, `gt handoff`, and `gt prime` which need to verify beads exist.

## Solution

Add `.beads/routes.jsonl` for prefix-based routing:

\`\`\`json
{"prefix": "gt-", "path": "gastown/mayor/rig"}
{"prefix": "hq-", "path": "."}
{"prefix": "bd-", "path": "beads/crew/dave"}
\`\`\`

### Lookup Algorithm

1. Try local .beads/ first (current behavior)
2. If not found, check for routes.jsonl in current .beads/
3. Match ID prefix against routes
4. If match found, resolve path relative to routes file location and retry
5. If still not found, error as usual

### Affected Commands

Read operations that take a bead ID:
- bd show <id>
- bd update <id>
- bd close <id>
- bd dep add <id> <dep> (both IDs)

Write operations (bd create) still go to local .beads/ - no change needed.

## Implementation Notes

1. New file: routes.jsonl in .beads/ directory
2. New function: resolveBeadsPath(id string) (string, error)
3. Update: beads.Show(), beads.Update(), beads.Close(), etc. to use resolver
4. Caching: Can cache routes in memory since file rarely changes

## Context

This unblocks the gt handoff flow for Mayor. Currently gt handoff gt-xyz fails
because it can't verify the bead exists when running from town root.


mol-beads-release

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

Release checklist for beads version 0.38.0.

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

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

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

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

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

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

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

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

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

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

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

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

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

Needs: update-changelog

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

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

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

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

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

Needs: run-tests

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

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

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

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

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

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

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

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

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

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

# Check npm
npm view @beads/bd version

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

Needs: wait-for-ci

## Step: update-local
Update local installations.

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

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

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

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

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

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

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

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

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

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


Thread Test 2

Testing direct mode


Update local installation

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


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

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

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

Expected: The sender field should use BEADS_AGENT_NAME when set.

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

Related: gt mail routing integration with Gas Town


bd mol run: Only creates partial children from proto

When running `bd mol run gt-lwuu --var issue=gt-xxx`, only 2 of 4 proto children are created.

## Expected
Proto gt-lwuu has 4 children:
- gt-lwuu.1: load-context
- gt-lwuu.2: implement
- gt-lwuu.3: self-review
- gt-lwuu.8: request-shutdown

All 4 should be instantiated.

## Actual
Only 2 children created:
- load-context
- implement

self-review and request-shutdown are missing.

## Repro
```bash
bd --no-daemon mol run gt-lwuu --var issue=gt-xxx --json
bd list --parent=<created-id>  # Only shows 2 children
```

## Impact
Polecats spawned with mol-polecat-work get incomplete workflow.


Merge: bd-d28c

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


Dead code: fetchAndRebaseInWorktree() marked DEPRECATED but still exists

attached_args: Remove dead code fetchAndRebaseInWorktree

The function fetchAndRebaseInWorktree() in internal/syncbranch/worktree.go (lines 811-830) is marked as DEPRECATED with a comment:

```go
// fetchAndRebaseInWorktree is DEPRECATED - kept for reference only.
// Use contentMergeRecovery instead to avoid tombstone resurrection.
```

Since contentMergeRecovery() is the replacement and is being used, this dead code should be removed to reduce maintenance burden.

Location: internal/syncbranch/worktree.go:811-830


Merge: bd-tvu3

branch: polecat/Beader
target: main
source_issue: bd-tvu3
rig: beads


CLI cleanup: Rename bd mol catalog to bd formula list

## Problem
`bd mol catalog` shows formulas, not molecules. This is confusing.

Current state:
- `bd formula list` - lists formulas
- `bd mol catalog` - ALSO lists formulas (duplicate!)

The "mol" namespace should be for molecules (instantiated work), not formulas (templates).

## Proposed Change
- Remove `bd mol catalog`
- Keep `bd formula list` as the canonical command
- Update docs to use `bd formula list`

## Alternative
If we want a "catalog" concept separate from "list", make it `bd formula catalog`.


Fix update-homebrew.sh awk script corrupts formula

The awk script in scripts/update-homebrew.sh incorrectly removes platform conditionals (on_macos do, on_linux do, if Hardware::CPU.arm?, etc.) when updating SHA256 hashes. This corrupts the Homebrew formula.

The issue is the awk script uses 'next' to skip lines containing platform conditionals but never reconstructs them, resulting in a syntax-invalid formula.

Found during v0.34.0 release - had to manually fix the formula.

Fix options:
1. Rewrite awk script to properly preserve structure while updating sha256 lines only
2. Use sed instead with targeted sha256 replacements
3. Template approach - store formula template and fill in version/hashes


GH#518: Document bd setup command

bd setup is undiscoverable. Add to README/docs. Currently only findable by grepping source. See GitHub issue #518.


Give --all flag actual meaning in bd list

The --all flag exists but is currently a no-op ('flag provided for CLI familiarity'). Once we change the default to non-closed, --all should override to show all issues including closed.

This provides backwards compatibility for scripts that depend on seeing all issues.

## Implementation Plan

### Code Changes (cmd/bd/list.go)

1. **Update --all flag handling** (~line 889):
```go
// Currently: listCmd.Flags().Bool("all", false, "Show all issues (default behavior; flag provided for CLI familiarity)")
// Change to:
listCmd.Flags().Bool("all", false, "Show all issues including closed (overrides default filter)")
```

2. **Check for --all in Run function** (before applying default filter):
```go
allFlag, _ := cmd.Flags().GetBool("all")
if status == "" && !allFlag {
    // Apply default non-closed filter
    filter.ExcludeStatus = []types.Status{"closed"}
}
// If --all is set, no ExcludeStatus applied = show everything
```

### Testing
- `bd list --all` shows all issues including closed
- `bd list` shows non-closed (from bd-mypl)
- `bd list --all --status=open` - --all is ignored when explicit status given

### Documentation
- Update --help text
- Add to migration guide: "Use --all for previous default behavior"


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

Work on gt-8tmz.36: Validate expanded step IDs are unique. In internal/formula/, add validation during cooking that checks for duplicate step IDs after expansion. When done: 1) bd close gt-8tmz.36, 2) bd sync, 3) git push, 4) gt mq submit


Molecule execution state management

Implement molecule execution state tracking.

## State Location

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

## State Schema

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

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

# Loop tracking
reset_count: 0
last_reset_at: null

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

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

## Operations

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

## Files

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


Test work item


Create release tag

Create annotated git tag.

```bash
git tag -a v0.99.0-test -m "Release v0.99.0-test"
```

Verify: `git tag -l | tail -5`


Merge: topaz-1767138533986

branch: polecat/topaz-1767138533986
target: main
source_issue: topaz-1767138533986
rig: beads


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


Run tests and verify lint passes.

Run tests and verify lint passes.

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

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

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


mol-christmas-launch: 3-day execution plan

Christmas Launch Molecule - execute phases in order, survive restarts.

PIN THIS BEAD. Check progress each session start.

## Step: phase0-beads-foundation
Fix blocking issues before swarming:
1. Verify gastown beads schema works: bd list --status=open
2. Ensure bd mol bond exists (check bd-usro)
3. Verify bd-2vh3 (squash) is filed

## Step: phase1-polecat-loop
Serial work on polecat execution:
1. gt-9nf: Fresh polecats only
2. gt-975: Molecule execution support
3. gt-8v8: Refuse uncommitted work
Then swarm: gt-e1y, gt-f8v, gt-eu9
Needs: phase0-beads-foundation

## Step: phase2-refinery
Serial work on refinery autonomy:
1. gt-5gkd: Refinery CLAUDE.md
2. gt-bj6f: Refinery context in gt prime
3. gt-0qki: Refinery-Witness protocol
Needs: phase1-polecat-loop

## Step: phase3-deacon
Health monitoring infrastructure:
1. gt-5af.4: Simplify daemon
2. gt-5af.7: Crew session patterns
3. gt-976: Crew lifecycle
Needs: phase2-refinery

## Step: phase4-code-review
Self-improvement flywheel:
1. Define mol-code-review (gt-fjvo)
2. Test on open MRs
3. Integrate with Refinery
Needs: phase3-deacon

## Step: phase5-polish
Demo readiness:
1. gt-b2hj: Find orphaned work
2. Doctor checks
3. Clean up open MRs
Needs: phase4-code-review

## Step: verify-flywheel
Success criteria:
- gt spawn works with molecules
- Refinery processes MRs autonomously
- mol-code-review runs on a PR
- bd cleanup --ephemeral works
Needs: phase5-polish


Deferred HOP schema additions (P2/P3)

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

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

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


Verify the release is complete.

Verify the release is complete.

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

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

# Check npm
npm view @beads/bd version

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

instantiated_from: bd-mol-xga
step: verify-release


Mega-molecule progress support for Hanoi demo

Beads-side work for million-step molecule monitoring.

## Context
Towers of Hanoi with 20 disks = 1,048,575 steps.
Need efficient progress queries and display guards.

## Requirements
1. bd mol progress command (summary without listing all steps)
2. Display guards in bd mol current (detect large molecules)
3. Efficient child count queries (already indexed)


Update info.go versionChanges

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


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)


Restart running daemons

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


Remove dead test code in info_test.go

Code health review found cmd/bd/info_test.go has two tests permanently skipped:

- TestInfoCommand
- TestInfoCommandNoDaemon

Both skip with: 'Manual test - bd info command is working, see manual testing'

These are essentially dead code. Either automate them or remove them entirely.


Beads Messaging & Knowledge Graph (v0.30.2)

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

## Motivation

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

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

## New Issue Type

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

## New Graph Links

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

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

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

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

## New Fields (optional, any issue type)

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

## New Commands

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

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

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

## Identity Configuration

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

## Hooks (for GGT integration)

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

GGT registers hooks to notify daemons of new messages.

## Schema Changes (Migration Required)

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

Migration adds fields as optional - existing beads unchanged.

## Success Criteria

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


Run bump-version.sh

Update all component versions atomically.

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

This updates:
- cmd/bd/version.go
- .claude-plugin/*.json
- integrations/beads-mcp/pyproject.toml
- integrations/beads-mcp/src/beads_mcp/__init__.py
- npm-package/package.json
- Hook templates
- README.md
- CHANGELOG.md (adds date)


Create release tag

Create annotated git tag.

```bash
git tag -a v0.39.0 -m "Release v0.39.0"
```

Verify: `git tag -l | tail -5`


Merge: garnet-1767142025508

branch: polecat/garnet-1767142025508
target: main
source_issue: garnet-1767142025508
rig: beads


Remove unreachable RPC methods

Several RPC server and client methods are unreachable and should be removed:

Server methods (internal/rpc/server.go):
- `Server.GetLastImportTime` (line 2116)
- `Server.SetLastImportTime` (line 2123)
- `Server.findJSONLPath` (line 2255)

Client methods (internal/rpc/client.go):
- `Client.Import` (line 311) - RPC import not used (daemon uses autoimport)

Evidence:
```bash
go run golang.org/x/tools/cmd/deadcode@latest -test ./...
```

Impact: Removes ~80 LOC of unused RPC code


Add integration tests for RPC server and event loops

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

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

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

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


Distinct prefixes for protos, molecules, wisps

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

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

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

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

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


bd repair: Handle .beads/redirect files

The bd repair command hardcodes .beads/beads.db path but doesn't follow .beads/redirect files like other commands do. This means repair won't work on clones that use redirected beads directories.

Fix: Check for .beads/redirect file and follow it to find the actual database location.


Update Homebrew formula

Update the Homebrew tap with new version:

```bash
./scripts/update-homebrew.sh 0.33.2
```

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


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

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


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.


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