Evaluate pending async gates

Evaluate pending async gates.

Gates are async coordination primitives that block until conditions are met.
The Deacon is responsible for monitoring gates and closing them when ready.

**Timer gates** (await_type: timer):
Check if elapsed time since creation exceeds the timeout duration.

```bash
# List all open gates
bd gate list --json

# For each timer gate, check if elapsed:
# - CreatedAt + Timeout < Now → gate is ready to close
# - Close with: bd gate close <id> --reason "Timer elapsed"
```

**GitHub gates** (await_type: gh:run, gh:pr) - handled in separate step.

**Human/Mail gates** - require external input, skip here.

After closing a gate, the Waiters field contains mail addresses to notify.
Send a brief notification to each waiter that the gate has cleared.


Merge: gt-3x1

branch: polecat/Slit
target: main
source_issue: gt-3x1
rig: gastown


Retry logic: exponential backoff for transient failures

Implement retry logic for transient failures.

Retryable failures:
- Push failed (network, auth transient)
- Test flaky (config: retry_flaky_tests)
- Fetch failed (network)

Retry strategy:
- Max retries: 3 (configurable)
- Backoff: 1s, 2s, 4s (exponential)
- On final failure: treat as permanent, assign back

Non-retryable failures:
- Merge conflict
- Test consistently fails
- Build error

Track retry count in MR metadata for debugging.

Reference: docs/merge-queue-design.md#failure-recovery


Control flow: loop, gate, branch

Implement control flow operators for the molecule algebra.

## Core Operators

| Operator | Syntax | Purpose |
|----------|--------|---------|
| loop (fixed) | loop: { count: N, body: [steps] } | Fixed iteration |
| loop (conditional) | loop: { until: COND, max: N, body: [steps] } | Bounded conditional iteration |
| gate | gate: { before: step, condition: COND } | Wait for condition before proceeding |
| branch | branch: { from: step, steps: [a,b,c], join: step } | Parallel paths that rejoin |

Conditions evaluated mechanically (step status, output fields) per gt-8tmz.7.

## Design Review (2025-12-25)

Analyzed patrol patterns (witness, deacon, refinery) to verify these constructs
can express real Gas Town workflows. Key findings:

### Insight: Patrol Loop is OUTSIDE the Algebra

The daemon respawns patrols. Each formula describes ONE cycle. This means:
- Formulas don't need "infinite loop with burn-and-respawn"
- loop is only for **inner loops** (refinery's per-branch processing)
- "burn-or-loop" = complete cycle; daemon decides next action
- Context cycling is external, not algebraic

This significantly simplifies the algebra.

### Gap: for-each is Missing

The current proposal doesn't include for-each, but it's essential for patrol patterns:

| Pattern | Use Case |
|---------|----------|
| Witness survey-workers | For each polecat, bond an arm (parallel) |
| Refinery process-branch | For each branch in queue, run merge pipeline (sequential) |
| Deacon plugin-run | For each plugin where gate open, execute |

Proposed syntax:

    for-each:
      collection: "survey-workers.output.polecats"
      bond: mol-polecat-arm
      vars:
        polecat_name: "{item.name}"
      parallel: true

This overlaps with gt-8tmz.8 (runtime dynamic expansion). Decision needed:
- Include for-each here as control flow, OR
- Ensure gt-8tmz.8 covers these patterns adequately

### Gap: waits-for Gate Variant

The "fanout gate" pattern (aggregate waits for all dynamically-bonded children)
needs formalization:

    step: aggregate
    waits-for: children-of(survey-workers)

Currently exists in formulas as waits_for: "all-children" but not in the algebra spec.

### What This Covers

With these operators (plus for-each), patrols become fully expressible:

**Witness Patrol:**
- for-each polecat -> bond mol-polecat-arm (parallel)
- gate with waits-for: all-children for aggregation

**Refinery Patrol:**
- for-each branch -> process pipeline (sequential)
- gate for test verification before merge

**Deacon Patrol:**
- for-each plugin -> execute if gate open
- Simple sequence otherwise

### Scope Decision

**Option A**: Implement loop, gate, branch now. Track for-each and waits-for separately.

**Option B**: Expand scope to include for-each and waits-for formalization.

Recommendation: Option A - implement core constructs, create child issues for gaps.


Digest: mol-deacon-patrol

Patrol 5: routine


Add gt deacon start/stop/status commands

Add CLI commands: gt deacon start (spawn gt-deacon session), gt deacon stop (kill session), gt deacon status (show health state). Similar to gt mayor commands.


Polecat Arm (arm-toast)

Single polecat inspection and action cycle.

This molecule is bonded dynamically by mol-witness-patrol's survey-workers step.
Each polecat being monitored gets one arm that runs in parallel with other arms.

## Variables

| Variable | Required | Description |
|----------|----------|-------------|
| polecat_name | Yes | Name of the polecat to inspect |
| rig | Yes | Rig containing the polecat |

## Step: capture
Capture recent tmux output for toast.

```bash
tmux capture-pane -t gt-gastown-toast -p | tail -50
```

Record:
- Last activity timestamp (when was last tool call?)
- Visible errors or stack traces
- Completion indicators ("Done", "Finished", etc.)

## Step: assess
Categorize polecat state based on captured output.

States:
- **working**: Recent tool calls, active processing
- **idle**: At prompt, no recent activity
- **error**: Showing errors or stack traces
- **requesting_shutdown**: Sent LIFECYCLE/Shutdown mail
- **done**: Showing completion indicators

Calculate: minutes since last activity.
Needs: capture

## Step: load-history
Read nudge history for toast from patrol state.

```
nudge_count = state.nudges[toast].count
last_nudge_time = state.nudges[toast].timestamp
```

This data was loaded by the parent patrol's load-state step and passed
to the arm via the bonding context.
Needs: assess

## Step: decide
Apply the nudge matrix to determine action for toast.

| State | Idle Time | Nudge Count | Action |
|-------|-----------|-------------|--------|
| working | any | any | none |
| idle | <10min | any | none |
| idle | 10-15min | 0 | nudge-1 (gentle) |
| idle | 15-20min | 1 | nudge-2 (direct) |
| idle | 20+min | 2 | nudge-3 (final) |
| idle | any | 3 | escalate |
| error | any | any | assess-severity |
| requesting_shutdown | any | any | pre-kill-verify |
| done | any | any | pre-kill-verify |

Nudge text:
1. "How's progress? Need any help?"
2. "Please wrap up soon. What's blocking you?"
3. "Final check. Will escalate in 5 min if no response."

Record decision and rationale.
Needs: load-history

## Step: execute
Take the decided action for toast.

**nudge-N**:
```bash
tmux send-keys -t gt-gastown-toast "{{nudge_text}}" Enter
```

**pre-kill-verify**:
```bash
cd polecats/toast
git status                    # Must be clean
git log origin/main..HEAD     # Check for unpushed
bd show <assigned-issue>      # Verify closed/deferred
```
If clean: kill session, remove worktree, delete branch
If dirty: record failure, retry next cycle

**escalate**:
```bash
gt mail send mayor/ -s "Escalation: toast stuck" -m "..."
```

**none**: No action needed.

Record: action taken, result, updated nudge count.
Needs: decide

## Output

The arm completes with:
- action_taken: none | nudge-1 | nudge-2 | nudge-3 | killed | escalated
- result: success | failed | pending
- updated_state: New nudge count and timestamp for toast

This data feeds back to the parent patrol's aggregate step.
---
bonded_from: mol-polecat-arm
bonded_to: gt-md2rg
bonded_ref: arm-toast
bonded_at: 2025-12-23T10:00:00Z


Digest: mol-deacon-patrol

Patrol cycle 8: all nominal


Request shutdown

Send shutdown request to Witness.
Wait for termination.

The polecat is now ready to be cleaned up.
Do not exit directly - wait for Witness to kill the session.


Check Witness and Refinery health

Check Witness and Refinery health for each rig.

**ZFC Principle**: You (Claude) make the judgment call about what is "stuck" or "unresponsive" - there are no hardcoded thresholds in Go. Read the signals, consider context, and decide.

For each rig, run:
```bash
gt witness status <rig>
gt refinery status <rig>
```

**Signals to assess:**

| Component | Healthy Signals | Concerning Signals |
|-----------|-----------------|-------------------|
| Witness | State: running, recent activity | State: not running, no heartbeat |
| Refinery | State: running, queue processing | Queue stuck, merge failures |

**Tracking unresponsive cycles:**

Maintain in your patrol state (persisted across cycles):
```
health_state:
  <rig>:
    witness:
      unresponsive_cycles: 0
      last_seen_healthy: <timestamp>
    refinery:
      unresponsive_cycles: 0
      last_seen_healthy: <timestamp>
```

**Decision matrix** (you decide the thresholds based on context):

| Cycles Unresponsive | Suggested Action |
|---------------------|------------------|
| 1-2 | Note it, check again next cycle |
| 3-4 | Attempt restart: gt witness restart <rig> |
| 5+ | Escalate to Mayor with context |

**Restart commands:**
```bash
gt witness restart <rig>
gt refinery restart <rig>
```

**Escalation:**
```bash
gt mail send mayor/ -s "Health: <rig> <component> unresponsive" \
  -m "Component has been unresponsive for N cycles. Restart attempts failed.
      Last healthy: <timestamp>
      Error signals: <details>"
```

Reset unresponsive_cycles to 0 when component responds normally.


Clean dead sessions

Clean dead sessions and orphaned state.

Run `gt doctor --fix` to handle all cleanup:

```bash
# Preview what needs cleaning
gt doctor -v

# Fix everything
gt doctor --fix
```

This handles:
- **orphan-sessions**: Kill orphaned tmux sessions (gt-* not matching valid patterns)
- **orphan-processes**: Kill orphaned Claude processes (no tmux parent)
- **wisp-gc**: Garbage collect abandoned wisps (>1h old)

All cleanup is handled by doctor checks - no need to run separate commands.


Adaptive backoff for daemon heartbeat

Track agent responsiveness and adjust heartbeat frequency.

## Per-Agent State

```go
type AgentBackoff struct {
    BaseInterval    time.Duration  // 60s default
    CurrentInterval time.Duration  // grows when busy
    MaxInterval     time.Duration  // 10min cap
    ConsecutiveMiss int            // pokes with no response
}
```

## Strategy Options

- **Fixed**: Always 60s (current, simple)
- **Geometric**: 60s → 90s → 135s → 202s (factor 1.5)
- **Exponential**: 60s → 120s → 240s (factor 2, aggressive)

## Recovery

When agent responds (runs a command):
- Reset ConsecutiveMiss to 0
- Return to BaseInterval immediately

## Benefits

- Reduces noise for busy agents
- Saves resources during quiet periods
- Still catches stuck agents (max interval cap)


Polecat auto-start: Claude doesn't process initial nudge

After gt sling spawns a polecat, the 'Work slung' message is sent to tmux but Claude sits idle at the prompt. The SessionStart hook doesn't fire because no user input was received.

Observed:
- gt sling successfully spawns polecat, creates worktree, starts Claude
- Sends 'Work slung: gt-xxx. Start working on it now...' to the pane
- Claude shows idle prompt 'Try refactor...' and doesn't process the message

Expected:
- Polecat should auto-start working on the slung issue

Root cause hypothesis:
- The nudge is sent as tmux send-keys which goes to the input line
- Claude needs Enter to be pressed to submit the prompt
- SessionStart hook only fires after first user message

Workaround:
- Send extra Enter after the nudge message
- Or use daemon's triggerPendingSpawns to send Enter after Claude is ready


GGT Command Parity: Complete gt command coverage

Complete gt command set to match/exceed PGT town commands.

Covers: uninstall, rig info, refinery attach, witness, session mgmt, mail UX, daemon.


Digest: mol-deacon-patrol

Patrol 4: Quiet


Merge: morsov-1766966180179

branch: polecat/morsov-1766966180179
target: main
source_issue: morsov-1766966180179
rig: gastown


Add tests for critical untested packages

Several packages have no tests:

High priority (critical functionality):
- internal/lock/ - file locking
- internal/mail/router.go, mailbox.go - agent communication
- internal/mrqueue/ - merge request queue
- internal/refinery/ (manager_test.go missing for complex merge logic)

Medium priority:
- internal/claude/ - settings management
- internal/wisp/ - ephemeral workflow
- internal/constants/ - constant values

Low priority:
- internal/style/ - terminal styling

The refinery package is especially concerning - it has complex merge, conflict, and retry logic with no tests.


Agent scanner utility for filesystem

Filesystem scanner to discover agent directories in a rig or town.

## Deliverables

1. Function: ScanRigAgents(rigPath) -> []AgentAddr
   - Finds: witness/, refinery/, crew/*, polecats/*
   - Returns normalized addresses (e.g., "gastown/witness")

2. Function: ScanTownAgents(townPath) -> []AgentAddr
   - Iterates all rigs, calls ScanRigAgents for each
   - Returns all agent addresses in town

3. Alias resolution:
   - @rig/gastown → ScanRigAgents("gastown")
   - @town → ScanTownAgents()
   - @witnesses → filter for */witness across all rigs
   - @crew/gastown → filter crew/* in gastown

## Location
internal/discovery/scanner.go (new package)

## Acceptance
- Scanner finds all agent types
- Alias patterns resolve correctly
- Unit tests pass


Phase 2: Awareness and real-time channels (announce:, #channel)

## Scope

Extensions for awareness broadcasting and ephemeral real-time communication.

### Deliverables

1. **announce:name** - Shared single-copy bulletin board
   - Informational, not work-creating
   - Recipients check when convenient, missing is OK
   - Use case: 'Bob is refactoring logging, be aware'
2. **#channel resolution** - Dynamic tmux scan for running agents
   - #rig/gastown → tmux sessions matching gastown/*
   - #town → all Gas Town sessions
3. **gt channel publish** - Ephemeral nudge broadcast to channel

### Key semantics
- announce: shared copy (1 message, N readers) vs list: (N copies, N obligations)
- #channel ephemeral - no storage, real-time only
- Channels resolve against running sessions, not filesystem


Digest: mol-deacon-patrol

Patrol 13: All agents healthy


Day 2.6: Define bd agent state command

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

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

Implementation:
1. Lookup agent bead by ID
2. Update state field
3. Update last_activity timestamp
4. Trigger bd sync if configured

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

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

Delegated to beads repo: bd-uxlb. Assign to beads/crew/dave.


Design mol-ready-work patrol for crew workers

## Summary

Design and implement a protomolecule (mol-ready-work) that enables crew workers to autonomously work through backlogs when the overseer is away. This replaces the normal "await instructions" patrol step with productive backlog processing.

## Context

Crew workers like dave/joe are persistent, user-managed agents. Currently their patrol loop has an "await instructions" step that idles. We want an alternative: sling mol-ready-work at them and they crank through backlogs until:
- The overseer interrupts with new instructions
- Context fills up (request handoff)
- Backlogs are empty

## Backlogs (Priority Order)

1. **Open PRs** - Review/merge pending pull requests
2. **Untriaged GH issues** - New issues needing triage
3. **Open beads work** - bd ready items (unblocked issues)
4. **Triaged GH issues** - Bugs/features to implement

## Key Features

### ROI-Based Selection
Instead of strict priority, agent applies ROI heuristic:
- Size estimate (fits in remaining context?)
- Achievability (has all needed info?)
- Impact (priority + type weight)
- Pick highest-value achievable item

### Context Management
- Check token usage after each work item
- Request handoff before running out
- Leave clear handoff notes (mail to self)
- Next session picks up the patrol

### Patrol Loop Structure
```
orient → scan-backlogs → select-work → execute-work → check-context → (loop or handoff)
```

## Design Questions

1. How does gt sling work? Does it exist?
2. How does this interact with the normal crew patrol?
3. Should the molecule go in Gas Town catalog or per-rig?
4. How does bonding work for discovered work during execution?
5. Should this be a wisp (ephemeral) or mol (persistent)?

## Acceptance Criteria

- [ ] mol-ready-work protomolecule defined in catalog
- [ ] gt sling command implemented (or existing mechanism documented)
- [ ] Context-checking step works with agent token awareness
- [ ] Handoff mechanism integrates with gt mail
- [ ] Documentation for crew workers on using the patrol


Digest: mol-deacon-patrol

Patrol 5: All clear


Swarm cleanup: delete merged polecat branches and reset state

After a swarm completes and branches are merged, leftover state remains:

## Current Problem

1. **Remote branches not deleted** - polecat/* branches stay on origin after merge
2. **Polecat clones not reset** - still on old branch with completed work
3. **No cleanup command** - manual cleanup required

## Observed After Swarm

Remote branches still present:
- origin/polecat/Morsov
- origin/polecat/Nux
- origin/polecat/Rictus
- origin/polecat/Slit
- origin/polecat/Toast

## Proposed Solution

Add cleanup commands:

1. gt swarm cleanup <swarm-id> - Clean up after swarm completion
   - Delete remote polecat branches that were merged
   - Reset polecat clones to main
   - Clear issue assignments

2. gt polecat reset <rig>/<polecat> - Reset single polecat
   - git checkout main && git pull
   - Delete local polecat branch
   - Clear current issue assignment

3. Auto-cleanup option on gt session stop --cleanup

## Manual Cleanup For Now

git push origin --delete polecat/Nux polecat/Toast ...
cd polecats/Nux && git checkout main && git pull


Digest: mol-deacon-patrol

Patrol 13: all healthy


stderr suppression hides critical errors

Multiple files set cmd.Stderr = nil:
- prime.go
- up.go
- orphans.go
- daemon.go

This hides git errors and command failures.

Should capture stderr for debugging and log when errors occur,
rather than suppressing entirely.


Add accounts.yaml config parsing to gt

Parse ~/gt/mayor/accounts.yaml with structure: accounts map (handle -> email, config_dir) and default field. This is the foundational config that other account features depend on. Location follows existing town-level config pattern in mayor/.


Execute registered plugins

Execute registered plugins.

Scan ~/gt/plugins/ for plugin directories. Each plugin has a plugin.md with YAML frontmatter defining its gate (when to run) and instructions (what to do).

See docs/deacon-plugins.md for full documentation.

Gate types:
- cooldown: Time since last run (e.g., 24h)
- cron: Schedule-based (e.g., "0 9 * * *")
- condition: Metric threshold (e.g., wisp count > 50)
- event: Trigger-based (e.g., startup, heartbeat)

For each plugin:
1. Read plugin.md frontmatter to check gate
2. Compare against state.json (last run, etc.)
3. If gate is open, execute the plugin

Plugins marked parallel: true can run concurrently using Task tool subagents. Sequential plugins run one at a time in directory order.

Skip this step if ~/gt/plugins/ does not exist or is empty.


Day 4.1: Implement gt polecat recycle command

Add gt polecat recycle <name> command:
- Kill the Claude session (tmux kill-session)
- Preserve the sandbox (branch/worktree)
- Update agent bead state to 'stopped'
- Leave for respawn on next step

This enables session-per-step.

Parent: gt-4a2qt


Digest: mol-deacon-patrol

Patrol 9: All healthy


ZFC Cleanup: Move Go heuristics to Deacon molecule

Remove Go code that makes workflow decisions. All health checking, staleness
detection, nudging, and escalation belongs in the Deacon molecule where Claude
executes it once per minute.

## The Problem

Go code currently implements polling-based health inference:
- Daemon watches heartbeats with hardcoded thresholds
- Decides if agents are "stuck" based on timestamps
- Sends nudges, triggers restarts
- Parses mail subjects with regex to extract intent

This is a ZFC violation. Go should be message transport, not decision-maker.

## The Fix

Move all health/oversight logic to Deacon patrol molecule:
- Deacon runs once per minute
- Claude reads molecule steps, executes them
- Claude decides if agents are stuck (by checking mail, activity, etc.)
- Claude sends nudges/escalations via mail
- Go just routes messages

## Scope

1. daemon/daemon.go - heartbeat staleness logic
2. daemon/backoff.go - exponential backoff decisions
3. daemon/lifecycle.go - regex parsing of lifecycle intent
4. keepalive/keepalive.go - staleness thresholds
5. deacon/heartbeat.go - heartbeat age classification
6. doctor/stale_check.go - staleness detection
7. polecat/manager.go - state derivation from issues

## Success Criteria

- Go code has no hardcoded time.Duration for health decisions
- No regex parsing of mail subjects for intent
- No switch statements deciding agent state
- Deacon molecule has all oversight logic
- Go daemon is just a message router


Go scaffolding: cmd/gt, go.mod, Cobra setup

Set up Go project structure with CLI framework.

**Stack:**
- Cobra for command/flag handling
- Lipgloss for styled terminal output

**Deliverables:**
- cmd/gt/main.go with Cobra root command
- Basic subcommands: version, help
- Lipgloss styles for status output (success, warning, error)
- go.mod with dependencies


gt mq submit: create MR from current branch

Implement 'gt mq submit' command that creates a merge-request bead.

Auto-detection logic:
1. Branch: current git branch
2. Issue: parse from branch name (polecat/Nux/gt-xyz → gt-xyz)
3. Target: main (or integration branch if --epic specified)
4. Worker: parse from branch name
5. Rig: current rig

Options:
- --branch BRANCH: explicit source branch
- --issue ISSUE: explicit source issue
- --epic EPIC: target integration/EPIC instead of main
- --priority P: override priority (default: inherit from source issue)

Creates merge-request bead and prints MR ID.

Reference: docs/merge-queue-design.md#creating-merge-requests


Clean dead sessions

Clean dead sessions.

Garbage collect terminated sessions:
- Remove stale polecat directories
- Clean up wisp session artifacts
- Prune old logs and temp files
- Archive completed molecule state

```bash
gt gc --sessions
gt gc --wisps --age=1h
```

Preserve audit trail. Only clean sessions confirmed dead.


Phase 1.1: gt rig init creates .beads-ephemeral/

Add ephemeral beads repo creation to rig initialization.

## Implementation

In `gt rig init` (or equivalent setup):
1. Create `<rig>/.beads-ephemeral/` directory
2. Initialize as git repo
3. Create minimal beads config (no sync-branch needed)
4. Add to .gitignore if not already

## Config

```yaml
# .beads-ephemeral/config.yaml
ephemeral: true
# No sync-branch - ephemeral is local only
```

## Verification

```bash
gt rig init gastown
ls gastown/.beads-ephemeral/  # Should exist
```


Add event-triggered lifecycle wisps

Commands like `gt town start` should auto-trigger lifecycle wisps.

## Event → Wisp Mapping

| Command | Triggers Wisp |
|---------|---------------|
| gt town start | mol-gastown-boot |
| gt rig add <name> | mol-rig-spinup (param: rig=<name>) |
| gt rig remove <name> | mol-rig-spindown (param: rig=<name>) |
| gt daemon restart | mol-gastown-boot |

## Implementation

1. Command implementation checks for lifecycle proto
2. Auto-slings wisp to Mayor with --wisp flag
3. Mayor picks up via molecule attachment

## Alternative: Explicit Sling

Keep commands simple, require explicit:

```bash
gt town start        # Just starts sessions
gt sling gastown-boot mayor/ --wisp   # Bootstrap with verification
```

This is more transparent - user sees the sling happen.

## Recommendation

Start with explicit sling. Add auto-trigger later once pattern proven.
`gt town start --verified` could trigger the wisp.


Merge: gt-rana.2

branch: polecat/nux
target: main
source_issue: gt-rana.2
rig: gastown


gt-gastown-polecat-cheedo

gt-gastown-polecat-cheedo

role_type: polecat
rig: gastown
agent_state: done
hook_bead: null
role_bead: gt-polecat-role
cleanup_status: has_stash


Digest: mol-deacon-patrol

Patrol 3: all healthy


gt mail: Cross-level routing is broken

When Mayor sends mail to rig worker, message lands in wrong beads database. Sender's beads vs recipient's.


Digest: mol-deacon-patrol

Patrol 18: all healthy


Digest: mol-deacon-patrol

Patrol 7: Mayor OK, 11 sessions


Digest: mol-deacon-patrol

Patrol 20: all clear


Use Beads issue status as spawn source of truth

Currently witness tracks spawned issues in .gastown/witness.json to prevent re-spawning:

{"spawned_issues": ["gt-abc1", "gt-def2", ...]}

This is redundant with Beads issue status (in_progress). The witness could query:
  bd list --status=in_progress

The local list serves as a performance cache to avoid querying beads every cycle. Consider:
1. Use Beads as source of truth
2. Keep local cache with TTL
3. Sync cache on witness start

This simplifies state management and ensures consistency.


Day 1.1: Add type=agent to bead schema

Add agent as a valid bead type in the schema. This is the foundation for agent-as-bead.

Parent: gt-d0jqp

Re-opened: Close reason referenced non-existent commit 927e8374. Type=agent not yet implemented in bd CLI.


gt-gastown-polecat-keeper

gt-gastown-polecat-keeper

role_type: polecat
rig: gastown
agent_state: done
hook_bead: null
role_bead: gt-polecat-role
cleanup_status: has_stash


Merge: gt-t9u7

branch: polecat/furiosa
target: main
source_issue: gt-t9u7
rig: gastown


gt convoy create/status/list commands

CLI for convoy management in Gas Town.

Commands:
- gt convoy create <name> <issues...> [--molecule <mol>] [--notify <addr>]
- gt convoy status [id]
- gt convoy list

Creates convoy beads in town-level beads (hq-* prefix).
Convoys track issues across project chains.

Depends on: bd-3roq (tracks relation), bd-hj0s (convoy type)
Related: hq-7h8jx (Convoy System epic in town beads)


Digest: mol-deacon-patrol

Patrol #19


gt done: Missing command referenced in polecat docs


Digest: mol-deacon-patrol

Patrol 5: 11 sessions, all healthy


Digest: mol-deacon-patrol

Patrol cycle 4: All healthy


Digest: mol-deacon-patrol

Patrol 2: Quick scan, no changes


Digest: mol-deacon-patrol

Patrol 16: All healthy.


Digest: mol-deacon-patrol

Patrol 18: all healthy, handled 1 handoff msg


Digest: mol-deacon-patrol

Patrol 3: 14 sessions healthy, no changes


gt session start --issue doesn't pin work to hook

When starting a polecat with --issue, the work isn't pinned to the hook:
  gt session start beads/Toast --issue bd-oxgi

After session starts, 'gt mol status' shows empty hook.

The polecat had to manually discover the work via bd ready. The --issue flag should call 'gt hook attach' or equivalent to pin the work.


Compile-time vs runtime cooking

Distinguish two cooking modes: 1) Compile-time: produces proto with variable placeholders, for modeling/estimation/contractor handoff. 2) Runtime: produces mol with real issue IDs. Compile-time lets you pre-decompose work for untrusted executors or planning purposes.


burn-or-loop

Squash wisp and decide: loop or cycle session.

If context low: spawn new wisp and loop
If context high: handoff and request cycle

Needs: generate-summary


Deacon health pings clear agent backoff

Deacon's periodic health checks also clear patrol agent backoff.

## Current Flow (mol-deacon-patrol)

Deacon already pings witnesses/refineries for health checks. These pings should:
1. Verify agent is alive
2. Clear their backoff as side effect

## Implementation

In mol-deacon-patrol health-scan step:
- gt nudge <rig>/witness 'HEALTH_CHECK from deacon'
- gt nudge <rig>/refinery 'HEALTH_CHECK from deacon'

Receiving agent:
- Responds to prove liveness
- Resets backoff to base interval

## Ping Interval

Deacon patrols every ~1-2 minutes. This ensures:
- Maximum backoff is bounded by deacon ping interval
- Even if daemon misses activity, deacon catches up


Map expansion should match nested child steps


Digest: mol-deacon-patrol

Patrol 1: All healthy, no lifecycle requests, 8 active sessions


Digest: mol-deacon-patrol

Patrol 2: Quiet cycle, all healthy, orphan gt-mol-aux persists


Digest: mol-deacon-patrol

Patrol #18


Digest: mol-deacon-patrol

Patrol 3: All agents healthy, routine


Digest: mol-deacon-patrol

Patrol 19: all clear


Update rig init to create refinery as worktree

Modify rig initialization to create refinery as a git worktree instead of a separate clone.

## Changes
- internal/rig/init.go or similar - change refinery setup
- Create worktree at <rig>/refinery/ with branch 'refinery'
- Remove clone logic for refinery
- Update any path assumptions

## Considerations
- Refinery worktree should track main (or its own branch?)
- May need to handle existing rigs (migration path)


Mail system: JSONL inbox, delivery, tmux injection

Refactor mail system to wrap bd mail commands.

## Status

Current implementation uses JSONL files directly. Now that Beads mail is available (gt-r01 closed), refactor to use bd mail as the backend.

## Implementation

Replace internal/mail/* with thin wrappers around bd CLI:

```go
// Send wraps: bd mail send <to> -s <subject> -m <body>
func (r *Router) Send(msg *Message) error

// List wraps: bd mail inbox --json
func (m *Mailbox) List() ([]*Message, error)

// Get wraps: bd mail read <id> --json
func (m *Mailbox) Get(id string) (*Message, error)

// MarkRead wraps: bd mail ack <id>
func (m *Mailbox) MarkRead(id string) error
```

## Address Translation

GGT addresses → Beads recipients:
- `mayor/` → `mayor`
- `<rig>/refinery` → `<rig>-refinery`
- `<rig>/<polecat>` → `<rig>-<polecat>`

## Tmux Notification

Keep the tmux injection for --notify flag. After bd mail send, optionally inject notification into tmux session.

## Migration

No migration needed - bd mail creates messages as beads issues with type=message. Old JSONL inboxes can be ignored or cleaned up.

## Dependencies

- gt-r01: CLOSED (Beads mail available)
- gt-u1j.4: Tmux wrapper (for notifications)


Implement gt mol status command

Show what's on an agent's hook.

```bash
gt mol status [target]
```

Output:
- What's slung (molecule name, associated issue)
- Current phase and progress
- Whether it's a wisp
- Next action hint

If no target, shows current agent's status.

Acceptance:
- [ ] Read pinned bead attachment
- [ ] Display molecule/issue info
- [ ] Show phase progress
- [ ] Indicate wisp vs durable


Digest: mol-deacon-patrol

Patrol 15: routine


gt mail send: --priority flag should work like bd mail send

UX inconsistency: gt mail send passes flags that bd mail send doesn't support.

## Root Cause

router.go line 42 passes `--priority` to bd:
```go
args = append(args, "--priority", fmt.Sprintf("%d", beadsPriority))
```

But `bd mail send` only has `--urgent` (boolean), not `--priority`.

## Fix Options

1. Add `--priority` flag to `bd mail send` (preferred - more expressive)
2. Change router to only use `--urgent` when priority=0

## Also Affected

- `--type` flag (line 46) - bd mail send doesn't have this
- `--thread-id` flag (line 51) - bd mail send doesn't have this
- `--reply-to` flag (line 56) - bd mail send doesn't have this

The router assumes bd mail send has features it doesn't have.


Convert formula files from YAML to JSON

Formulas currently use .formula.yaml but the project avoids YAML. Convert to .formula.json for consistency with the rest of the codebase. This blocks implementing compose operators (advice, expand, etc.) since the schema needs to be right first.


sling pin test 2


Patrol agents subscribe to bd activity --follow

Each patrol agent (Deacon, Witness, Refinery) should run bd activity --follow as a background process. Any output line is a wake signal. This is the primary wake mechanism.

Implementation:
1. Add feed subscription to await-signal step logic
2. Agent starts bd activity --follow on entering await-signal
3. Any line of output breaks the wait immediately
4. Timeout still applies as safety net

See patrol-system-design.md for full specification.


MR: gt-test (main)

branch: main
target: main
source_issue: gt-test


decide-actions

Apply nudge matrix and queue actions.

Progressive nudge levels:
- Level 1: Gentle reminder
- Level 2: Stronger nudge
- Level 3: Final warning
- Level 4: Escalate to Mayor

Needs: inspect-workers


Fanout gate runtime evaluation

Aggregate step uses waits-for: all-children. Deacon must evaluate this gate by checking if all dynamically-bonded arm children are complete. If no children bonded, gate passes immediately.


Digest: mol-deacon-patrol

Patrol 13: nominal


Fix out-of-sync molecule test expectations

Tests in builtin_molecules_test.go have hardcoded expectations that no longer match actual molecules:
- TestBuiltinMolecules: expects 9 molecules, got 11
- TestPolecatWorkMolecule: step refs out of sync
- TestDeaconPatrolMolecule: step count and refs out of sync

This is pre-existing on main, not introduced by any polecat work.


Digest: mol-deacon-patrol

Patrol 15: healthy


Polecat health check loop

Implement the Witness health check loop:

Every 60 seconds:
1. List active polecats (gt polecats <rig>)
2. For each polecat, check:
   - Is tmux session still alive?
   - Is there a state.json with recent update?
   - Has there been git activity recently?
3. If stuck (no activity for configurable threshold):
   - First: nudge (send message asking for status)
   - Second: escalate to Mayor
   - Third: force kill after human confirmation

This is the 'health monitor' part of Witness.


Cook patrol formulas into proto beads

Use bd cook to transform formula YAML into proto beads with proper child beads for each step.

Verify with bd mol show that protos have all children.


Delete hook types from internal/wisp

Delete from internal/wisp/types.go:
- WispType type
- TypeSlungWork constant
- HookPrefix, HookSuffix constants
- Wisp struct
- SlungWork struct
- NewSlungWork function
- HookFilename function
- AgentFromHookFilename function

The entire file may become empty or minimal.


gt spawn pins mol-polecat-work

Enhance gt spawn to automatically pin mol-polecat-work to new polecats.

## Current Behavior

gt spawn --issue gt-xxx creates polecat with issue in mail but no molecule.

## New Behavior

gt spawn should:
1. Create fresh worktree (existing)
2. Initialize polecat beads (existing)
3. Bond mol-polecat-work with issue as variable
4. Pin the molecule to polecat hook
5. Create polecat session

## Molecule Bonding

```bash
bd mol bond mol-polecat-work --var issue_id=gt-xxx --var rig=gastown
```

Creates .beads/molecules/mol-polecat-work-<hash>.state.yaml

## Hook Pinning

```bash
bd pin mol-polecat-work-<hash> --for polecat/<name>
```

Creates .beads-wisp/hook-polecat-<name>.wisp.yaml pointing to molecule

## Files

- internal/spawn/spawn.go - Add mol-polecat-work bonding
- Or: internal/cmd/spawn.go depending on structure


Deacon patrol banners: visual feedback on atom transitions

Print large ASCII banners when transitioning between patrol atoms.

## Problem

When the deacon progresses through patrol atoms (steps), there is no visual feedback.
The operator cannot easily see what the deacon is doing without reading the full output.

## Desired Behavior

Print banners on step start and completion:

  INBOX-CHECK - Checking for lifecycle requests, escalations, timers
  INBOX-CHECK COMPLETE - Processed 3 messages, 0 lifecycle requests

## Benefits

1. Scanability: Operator can glance at tmux and see what is happening
2. Progress tracking: Easy to see where in the patrol loop we are
3. Debugging: Clear demarcation between steps for troubleshooting

## Implementation Options

1. In deacon CLAUDE.md: Instruct agent to print banners
2. gt patrol step start/end: Commands that print banners
3. bd mol step hooks: Automatically on step transitions

## Related

- gt-id36: Deacon Kernel
- gt-rana: Patrol System


Test message

Testing GGT mail via beads


Digest: mol-deacon-patrol

Patrol 13: quiet


Success handling: close MR, close source issue, cleanup

Handle successful merge completion.

Steps:
1. Update MR with merge_commit SHA:
   bd update <id> --body='...\nmerge_commit: <sha>'
2. Close MR with reason:
   bd close <id> --reason='merged'
3. Close source issue (the work item):
   bd close <source_issue> --reason='Merged in <mr_id>'
4. Delete source branch (if configured):
   git push origin --delete <mr.branch>
5. Log success

Configuration:
- delete_merged_branches: bool (default true)

Reference: docs/merge-queue-design.md#process-merge-steps


CLI: spawn command

High-level command to spawn a polecat with work assignment.

## Command

```
gt spawn <rig>/<polecat> --issue <id>
gt spawn <rig> --issue <id>  # auto-select available polecat
gt spawn <rig>/<polecat> -m "Work on X"  # free-form task
```

## What It Does

1. Select or create polecat
2. Ensure polecat is in idle/active state
3. Assign the issue (update beads, set polecat state)
4. Start session (gt session start)
5. Inject initial context

## Options

- `--issue <id>`: Beads issue to assign
- `-m "message"`: Free-form work description
- `--create`: Create polecat if it does not exist
- `--no-start`: Assign work but do not start session

## Auto-Select Logic

If polecat not specified:
1. Look for idle polecats in rig
2. Prefer ones that worked on similar issues before
3. If none available, fail (or create if --create)

## Initial Context

Injects into session:
```
[SPAWN] You have been assigned: <issue-title>
Issue: <id>
Priority: <priority>

<description>

Work on this issue. Signal DONE when complete.
```

## Implementation

Orchestrates PolecatManager + SessionManager + Beads:
```go
func Spawn(rig, polecat, issue string, opts SpawnOptions) error
```


Digest: mol-deacon-patrol

Patrol 15: OK


Digest: mol-deacon-patrol @ 2025-12-24 19:21

Patrol 3: all healthy, no work


Test Patrol Parent

[RESURRECTED] This issue was deleted but recreated as a tombstone to preserve hierarchical structure.

Original description:
[RESURRECTED] This issue was deleted but recreated as a tombstone to preserve hierarchical structure.

Original description:
Test parent for Christmas Ornament pattern


Merge: gt-h6eq.6

branch: polecat/keeper
target: main
source_issue: gt-h6eq.6
rig: gastown


ZFC #7: Make message age filtering configurable

**ZFC Violation:** internal/daemon/lifecycle.go:64-75

Go hardcodes 6-hour max message age:
```go
const MaxLifecycleMessageAge = 6 * time.Hour
```

**ZFC-compliant solution:**
- Make this configurable per message type
- Or let agents decide message relevance
- Low priority - not blocking liftoff

Reference: ~/gt/docs/zfc-violations-audit.md #7


Digest: mol-deacon-patrol

Patrol cycle 2: all healthy, no action required


Deacon primes pending workers instead of spawn nudge

## Problem

When gt spawn starts a polecat, it tries to send a nudge message immediately:
1. Starts tmux session with Claude Code
2. Waits 3 seconds (hardcoded)
3. Sends nudge via NudgeSession

But Claude Code takes 10-20+ seconds to be ready. The message arrives before
the prompt is ready, so it appears as part of the prompt string instead of
being executed.

## Solution

Move priming responsibility to the Deacon patrol cycle:

1. gt spawn: Mark polecat as pending_prime=true in state, return immediately
2. Deacon patrol: New step prime-pending-workers that:
   - Scans all rigs for workers with pending_prime=true
   - Uses WaitForClaudeReady() to poll for "> " prompt (already exists in tmux.go)
   - Once ready, sends gt prime + assignment nudge
   - Clears pending_prime flag

## Implementation

### spawn.go changes
- Remove the 3-second sleep (line 368)
- Remove the NudgeSession call (lines 375-383)
- Instead: Update polecat state with pending_prime=true

### Polecat state addition
status: assigned, pending_prime: true, issue: gt-xxx

### Deacon patrol addition
Add step between inbox-check and plugin-run:
prime-pending-workers: Check all rigs for workers marked pending_prime.
For each pending worker: WaitForClaudeReady(60s), then gt prime + nudge

### Benefits
- No race condition - we poll until actually ready
- Deacon already does health checks - priming is natural fit
- Works for polecats, witnesses, refineries, crew (unified approach)
- Timeout handling built in

## Depends on
- Existing WaitForClaudeReady() in tmux.go (lines 384-403)


gt polecat remove --all: bulk polecat teardown

Currently gt polecat remove only accepts one polecat at a time. Need bulk operations:

## Requested
- `gt polecat remove gastown --all` - remove all polecats from a rig
- `gt polecat remove gastown/A gastown/B ...` - remove multiple by name

## Context
After a swarm completes, tearing down 20 polecats one at a time is tedious.
Ephemeral workers should be easy to create and destroy in bulk.

## Related
- gt-c92: CLI: all command for batch polecat operations


Remove pinned field workaround after beads fix

## Summary

Once bd-phtv is fixed in beads, we can remove the workaround documentation and potentially simplify the pinToHook() implementation.

## Current Workaround

The handoff bead attachment mechanism (AttachMolecule) is used as the primary work assignment mechanism instead of the pinned field. This works correctly but adds complexity.

## Changes After Beads Fix

1. Remove the NOTE comment in internal/beads/beads.go:Pin() explaining the bug
2. Consider simplifying pinToHook() if the pinned field becomes reliable
3. Update gt-o3is to reference the fix

## Blocked By

This issue is blocked by external:beads:pinned-field-fix (bd-phtv).
When that capability is shipped, this issue becomes ready.

## Related

- gt-o3is: Original investigation that found this bug
- bd-phtv: The beads fix (in ~/gt/beads)

BLOCKED: Can't add external:beads:pinned-field-fix dependency due to bd-ucgz (migration invariants bug). Once that's fixed, add: bd dep add gt-hj9e external:beads:pinned-field-fix


Refinery patrol: Add sibling-check step

Refinery should check on Witness health as part of patrol (village sibling watch).

## Implementation

1. Add `sibling-check` step to mol-refinery-patrol (early in cycle)
2. Use `gt peek <rig>/witness 20` to check Witness output
3. Look for signs of health:
   - Recent activity (tool calls, log messages)
   - No error stack traces
   - Responsive to pings
4. If Witness seems stuck:
   - Send status request mail
   - Note for potential escalation
   - Don't block Refinery work

## Acceptance
- Refinery checks Witness each patrol cycle
- Anomalies logged
- Non-blocking (Refinery continues even if Witness is down)


Merge: gt-7923

branch: polecat/rictus
target: main
source_issue: gt-7923
rig: gastown


Digest: mol-deacon-patrol

Patrol 2: inbox clear, all agents healthy


execute-actions

Send nudges, process shutdowns, escalate as decided.

Needs: decide-actions


Digest: mol-deacon-patrol

Patrol 4: Routine


Digest: mol-deacon-patrol

Patrol 1: All clear - inbox empty, agents healthy, no orphans


Digest: mol-deacon-patrol

Patrol 12


Add tmux hotkey (C-b f) for gt feed window

## Goal

Add a tmux hotkey (e.g., C-b f) that jumps to the activity feed window, creating it if it doesn't exist.

## Behavior

1. If 'feed' window exists in current session → switch to it
2. If 'feed' window doesn't exist → create it with `bd activity --follow`, then switch

## Implementation

Add to gt's tmux session configuration (similar to SetCrewCycleBindings):

```go
// C-b f → jump to feed window
tmux bind-key -T prefix f run-shell "gt feed --window"
```

The `gt feed --window` command already handles:
- Creating the window if missing
- Switching to it if exists
- Running `bd activity --follow` in the window

## Where to add

- `internal/tmux/tmux.go` - add SetFeedBinding() method
- Call it from session configuration (ConfigureGasTownSession or similar)

## Testing

1. In tmux: C-b f should open/switch to feed window
2. Feed window should show streaming activity
3. C-b n/p should still work to cycle back to other windows


MR state transitions: validate open→in_progress→closed

Enforce valid state transitions for merge-requests:

Valid transitions:
- open → in_progress (Engineer claims MR)
- in_progress → closed (merge success or rejection)
- in_progress → open (failure, reassign to worker)
- open → closed (manual rejection)

Invalid:
- closed → anything (immutable once closed)

Implement validation in MR update operations.

Reference: docs/merge-queue-design.md#state-machine


Digest: mol-deacon-patrol

Patrol 15: All agents healthy


Digest: mol-deacon-patrol

Patrol 8: all clear, handing off for fresh context


HTTP work client: CloudRun dispatch client

## Overview

HTTP client for dispatching work to Cloud Run and streaming results back.

## Implementation

```go
type WorkClient struct {
    serviceURL string
    httpClient *http.Client  // HTTP/2 enabled
}

func NewWorkClient(serviceURL string) *WorkClient {
    return &WorkClient{
        serviceURL: serviceURL,
        httpClient: &http.Client{
            Transport: &http2.Transport{},
            Timeout:   0,  // No timeout for streaming
        },
    }
}

func (c *WorkClient) DispatchWork(ctx context.Context, req WorkRequest) (<-chan WorkEvent, error) {
    // 1. POST to /work
    // 2. Return channel that streams WorkEvents
    // 3. Close channel when done/error
}
```

## Streaming Reader

```go
func (c *WorkClient) streamEvents(body io.Reader, events chan<- WorkEvent) {
    defer close(events)
    decoder := json.NewDecoder(body)
    for {
        var event WorkEvent
        if err := decoder.Decode(&event); err != nil {
            return
        }
        events <- event
    }
}
```

## Files

- `internal/cloudrun/client.go`

## Dependencies

Depends on: gt-9a2.7 (protocol types)
Used by: gt-9a2.8 (CloudRunOutpost)


gt mail send should tmux-notify recipient

## Problem

When mail is sent via gt mail send, the recipient session does not get a tmux notification. In Python Gas Town (PGT), mail delivery triggers a tmux display-message or similar notification so the agent knows mail arrived.

## Expected Behavior

When gt mail send <addr> is called:
1. Mail is delivered to recipient inbox
2. If recipient has an active tmux session, send notification
3. Notification should be visible (display-message or bell)

## Current Behavior

Mail is delivered but no notification. Agent has to poll inbox to discover new mail.

## Impact

- Agents miss time-sensitive messages
- Heartbeat pokes from daemon will not wake agents
- Coordination is slower (polling vs push)

## Implementation Notes

After successful mail delivery, check if recipient has active session:
- gt session list can identify active sessions
- tmux display-message or send-keys can notify
- Could inject a visible prompt like "[MAIL] New message from <sender>"

## Reference

Check PGT implementation for how it handles this.


Unify gt sling and gt spawn with --args support

## Summary

Complete the unification: `gt sling` becomes THE way to assign work. Remove top-level `gt spawn`.

## Current State (Partially Done)

- `gt sling` auto-spawns polecats when target is a rig
- `gt sling --args` stores args in bead (no-tmux mode, gt-vc3l4)
- `gt spawn` still exists with flags not yet in sling

## Remaining Work

### 1. Move spawn-only flags to sling

| Flag | Current | Action |
|------|---------|--------|
| `--naked` | spawn only | Move to sling |
| `--create` | spawn only | Move to sling |
| `--molecule` | spawn only | Move to sling |
| `--force` | spawn only | Move to sling |
| `--account` | spawn only | Move to sling |
| `--no-start` | spawn only | Evaluate if needed |

### 2. Remove top-level gt spawn

- Keep `gt spawn pending` as subcommand if still needed
- Remove `gt spawn` from root commands
- Update all docs and CLAUDE.md references

### 3. Unified UX Design

Target resolution (smart defaults):
```bash
gt sling gt-abc                    # Self (current agent)
gt sling gt-abc crew               # Crew worker in current rig
gt sling gt-abc gastown            # Auto-spawn polecat in rig
gt sling gt-abc gastown/Toast      # Specific polecat
gt sling gt-abc mayor              # Mayor
```

Key flags:
```bash
gt sling gt-abc --args "patch release"   # Natural language context
gt sling gt-abc --naked                  # No-tmux mode (manual start)
gt sling gt-abc --create                 # Create polecat if missing
gt sling gt-abc --molecule mol-review    # Use specific workflow
```

### 4. Update Witness/Refinery/Deacon

These agents currently use `gt spawn`. Update to use `gt sling`:
- Witness: spawning polecats for work
- Refinery: spawning merge workers
- Deacon: any spawn logic

## Acceptance Criteria

- [ ] All spawn flags available in sling
- [ ] `gt spawn` removed (or hidden/deprecated)
- [ ] Witness uses `gt sling <rig>` for polecat work
- [ ] Docs updated
- [ ] Both human and agent UX is clean


Move mol run semantics from bd into gt spawn

Currently gt spawn shells out to bd mol run for the pour+assign+pin combo. This blurs the architectural boundary between bd (data layer) and gt (orchestration layer).

## Current State
- bd mol run = bd pour + bd update --status=in_progress + bd pin --for me
- gt spawn calls: exec.Command("bd", "mol", "run", ...)

## Proposed Change
Move the combo logic into gt spawn directly:
1. gt spawn calls bd pour (create issues from template)
2. gt spawn calls bd update --status=in_progress (claim work)
3. gt spawn calls bd pin (set pinned flag)
4. gt spawn does session/tmux orchestration

This keeps bd as pure data operations and gt as the orchestration layer.

## Why
- Cleaner separation of concerns
- bd mol run feels like orchestration but it's in the data layer
- gt should own the "start a workflow" semantics

## Coordination
beads side will deprecate bd mol run once gt no longer depends on it.


Digest: mol-deacon-patrol

Patrol 17


Digest: mol-deacon-patrol

Patrol 17: All healthy.


Digest: mol-deacon-patrol

Patrol: 4 msgs (2 blocked on bd mol current, 2 handoffs). 11 polecats, 18 sessions. Swarm in progress.


Integration test: simple file creation

Test task for polecat integration test (gt-7psb8).

Simple task: Create a file ~/gt/gastown/test-polecat-integration.txt with content 'Polecat integration test successful'.

This is an intentionally trivial task to verify the polecat → witness → refinery → merged flow works end-to-end.


Merge execution: merge, test, push

Implement the actual merge execution.

Steps:
1. git checkout <mr.target>
2. git merge <mr.branch> --no-ff -m 'Merge <branch>: <title>'
3. If config.run_tests:
   - Run test_command (from config)
   - If failed: git reset --hard HEAD~1, return Failure(tests_failed)
4. git push origin <mr.target>
5. Return Success(merge_commit=HEAD)

Configuration:
- run_tests: bool (default true)
- test_command: string (default 'go test ./...')

Handle push failures with retry logic.

Reference: docs/merge-queue-design.md#process-merge-steps


Witness: active polecat monitoring and nudging

## Problem
Witness runs but doesn't actively monitor polecats during patrol.

## ZFC-Compliant Solution
Add step to `mol-witness-patrol.formula.toml`:

```toml
[[step]]
id = "survey-polecats"
title = "Survey polecat health"
description = """
For each polecat in this rig:
1. Run: gt peek <rig>/<polecat> 20
2. Check if work is pinned: gt mol status --rig <rig>/<polecat>
3. If pinned but idle (no recent output), nudge: gt nudge <rig>/<polecat> "You have work on hook"
4. If stuck >15min with no progress, escalate to Mayor via mail
"""
depends_on = ["inbox-check"]
```

## Why This Works
- Witness Claude agent reads formula step
- Agent decides what "stuck" means (uses judgment)
- Agent runs gt commands (CLI can exist)
- No Go code makes decisions

## Files
- formulas/mol-witness-patrol.formula.toml


gt sling command implementation

Implement the gt sling command for handoff with attached work.

## Command Signature

```bash
gt sling <bead-id> [-s subject] [-m message]
```

## Behavior

1. Validate the bead exists: bd show <bead-id>
2. Create wisp on agents hook:
   - File: .beads-wisp/hook-<agent>.wisp.yaml
   - Content: bead_id, slung_at, optional context
3. Optionally send handoff mail with subject/message
4. Exit cleanly (or signal restart)

## Wisp Format

```yaml
type: slung-work
bead_id: gt-xxx
slung_at: 2025-12-24T...
slung_by: crew/joe
context: "Optional message"
```

## Files to Create/Modify

- cmd/gt/sling.go (new)
- internal/wisp/wisp.go (may need creation)
- internal/wisp/hook.go (hook reading)

## Notes

- Keep it simple - this is connector code
- The wisp is burned after pickup
- Sling should work for any role (crew, polecat, deacon)


Add bulk session stop command (gt session stop --all)

When decommissioning a rig, need to stop multiple sessions one at a time. A --all or --rig flag would allow: gt session stop --rig gastown


Test Patrol for Bonding

Parent issue for mol bond CLI test


CRITICAL: gt doctor orphan-processes kills active crew sessions

## Problem

The deacon's patrol runs `gt doctor --fix` which includes an orphan-processes check. This check is incorrectly identifying ACTIVE crew sessions as orphaned and killing them.

## Impact

- Crew workers are being killed mid-session
- Work is lost
- The deacon is currently disabled until this is fixed

## Root Cause

The orphan-processes detection logic in `internal/doctor/` doesn't properly identify crew workers. It likely:
1. Doesn't recognize the `gt-<rig>-<name>` session pattern for crew
2. Or misidentifies the Claude process as orphaned when it has a valid tmux parent

## Workaround

The patrol formula was updated to instruct deacon not to run `--fix` if orphan-processes reports any PIDs. But this workaround failed - the deacon still killed crew.

## Fix Required

1. Update `internal/doctor/identity_check.go` or `branch_check.go` to properly detect crew sessions
2. Add crew session patterns to the valid session detection
3. Add test coverage for crew worker scenarios

## Files

- internal/doctor/identity_check.go
- internal/doctor/branch_check.go
- internal/cmd/doctor.go

## Related

- Commit 3452b041 attempted to fix via formula instructions but failed
- The digest hq-yedg claimed to file gt-vj5zc but never did


OSS Launch Readiness

Track all issues blocking or affecting OSS launch quality.

P0 Blocker:
- gt-ofl2: ProcessMRFromQueue not implemented

P1 Must Fix:
- gt-vzic: README missing prerequisites (tmux)
- gt-xbfw: Missing OSS files (CONTRIBUTING, etc.)
- gt-wexr: Polecat role swarm terminology
- gt-6n13: Competing molecule mechanisms
- gt-3abj: go install may fail

P2 Should Fix:
- gt-qj12: Obsolete beads cleanup
- gt-zn9m: Error suppression patterns
- gt-9uxr: Test coverage gaps
- gt-fm75: os.Exit in library code
- gt-yewf: Mismatched startup protocols
- gt-1z4m: Undocumented gt swarm
- gt-bho9: stderr suppression
- gt-rxsh: Merge model confusion
- gt-5ipl: Witness role commands

P3 Nice to Have:
- gt-t5mz: Hardcoded values


Phase 1.3: gt doctor checks for ephemeral health

Add doctor checks for ephemeral beads repo.

## Checks

1. **ephemeral-exists**: .beads-ephemeral/ directory exists for each rig
2. **ephemeral-git**: It's a valid git repo
3. **ephemeral-orphans**: Molecules started but never squashed (>24h old)
4. **ephemeral-size**: Warn if ephemeral repo is >100MB (should be cleaned)
5. **ephemeral-stale**: Molecules with no activity in last hour

## Auto-fix

--fix can:
- Create missing ephemeral repo
- Clean up old completed molecules (already squashed)
- NOT auto-squash incomplete molecules (needs AI summary)


Test Patrol Parent

[RESURRECTED] This issue was deleted but recreated as a tombstone to preserve hierarchical structure.

Original description:
Test parent for Christmas Ornament pattern


Activity feed from wisp state: gt patrol status

Enable mayor and gt tool to quickly see what patrol agents are doing.

## Problem

The mayor and gt tool cannot quickly see what the deacon (or other patrol agents) are doing.
Need a way to extract an activity feed from the current wisp state.

## Desired Commands

- gt patrol status: Show current patrol state (step, timing, cycle count)
- gt patrol history: Show recent patrol cycles (from digests)
- gt patrol feed: Live tail of patrol activity

## Data Sources

- .beads-wisp/issues.jsonl: Current wisp with step progress
- .beads/issues.jsonl: Digests from squashed patrols
- heartbeat.json: Last activity timestamp

## Use Cases

1. Mayor checking deacon: Is the deacon doing anything?
2. Debugging hangs: What step is it stuck on?
3. Operator monitoring: Dashboard of patrol health
4. Summaries for handoffs: Auto-generate patrol digest

## Related

- gt-id36: Deacon Kernel
- gt-3x0z: Wisp Molecule Integration


Daemon: integration test with real lifecycle

Need an end-to-end test that:
1. Starts daemon
2. Starts a test agent session
3. Sends lifecycle request to daemon
4. Verifies session was killed and restarted
5. Cleans up

Could use a mock 'agent' that's just a shell script.


Polecats go off-task instead of working pinned bead

During swarm execution, polecats frequently stop working on their assigned task (pinned bead) and start doing other things like:
- Asking about other polecats
- Checking mail
- Monitoring swarm status
- Working on unrelated issues

Expected: Polecat receives task via gt sling, works on it until completion, signals done.
Actual: Polecat gets distracted and stops working on assigned task.

Root cause hypothesis: CLAUDE.md instructions don't strongly enforce 'work your hook' behavior. Need clearer polecat template that emphasizes single-task focus.


Digest: mol-deacon-patrol

Patrol 14: routine


Merge: gt-8v8

branch: polecat/nux
target: main
source_issue: gt-8v8
rig: gastown


Guardrail: Verify commits exist before closing polecat issues

## Updated Approach (ZFC)

The original proposal was for mechanical guardrails in bd close. This contradicts the ZFC principle: all decisions go to models, not code.

## Correct Solution

The verification should happen in **mol-polecat-arm** execute step, not bd close:

In the pre-kill-verify action:
```bash
# Current steps
git status                    # Must be clean
git log origin/main..HEAD     # Check for unpushed
bd show <assigned-issue>      # Verify closed/deferred

# ADD: Verify productive work
git log --oneline --grep='<issue-id>' | head -1
# If no commits AND issue being closed as 'done' → flag for review
```

The agent (Witness) makes the decision. The mol gives it the verification step.

## Why Not Code Guardrails

Polecats have legitimate reasons to close issues without commits:
- Already done (someone else fixed it)
- Deferred (out of scope)
- Escalated (needs human decision)
- Duplicate (merged with another issue)

A code guardrail would block all these. The mol step lets the agent verify AND make the judgment call.

## Implementation

Update mol-polecat-arm execute step to include commit verification for 'done' closures.


Molecule execution support for polecats and crew

Enable agents to run bonded molecules through the full lifecycle.

## The Model
1. BOND - bd mol bond <template> --assignee <identity>
   Creates concrete issues, assigns root to agent

2. DISCOVER - Agent finds assigned molecules via bd ready
   DAG structure shows unblocked steps

3. WORK - Agent works through DAG, closing steps as done
   Can delegate children to lower-tier agents (haiku)

4. SURVIVE - Agent dies → beads persist
   Any agent resumes from DAG state

5. SUPERVISE - Witness monitors for stalled molecules
   Nudges owner or reassigns if dead

## Questions to Resolve
- Seed node terminology: seed vs root vs pole vs nucleus
- Assignee inheritance: single owner vs delegation model
- Stall detection: heartbeat vs activity timeout vs session monitoring

## Implementation
- Polecat startup: check for assigned molecules
- Polecat work loop: follow molecule DAG
- Witness: monitor molecule progress, detect stalls
- Mayor: can assign molecules, handle escalations

## Depends On
- beads: bd mol bond command (bd-usro in beads repo)


Digest: mol-deacon-patrol

Patrol 19: Routine


Digest: mol-deacon-patrol

Patrol cycle 6: All healthy


gt crew refresh: Context cycling with handoff

Implement 'gt crew refresh <name>' command:
- Send handoff mail to self (context summary)
- Kill current session cleanly
- Start new session
- New session reads handoff mail and resumes
- Support --message to add custom handoff notes


Merge: gt-i4kq

branch: polecat/slit
target: main
source_issue: gt-i4kq
rig: gastown


Digest: mol-deacon-patrol

Patrol cycle 20: All healthy


Session cycling: Auto-spawn successor when context full

Enable automatic session succession for crew workers.

When a crew worker's context fills up (>80%), they should:
1. Write handoff mail to themselves
2. Signal session end
3. System auto-spawns successor session
4. Successor reads handoff, finds attached work, auto-continues

This completes the autonomous overnight work pattern from gt-9g82.

Depends on:
- Detecting context fullness (Claude Code API?)
- Session spawning mechanism (tmux/daemon)
- Handoff protocol already implemented


Find abandoned work

Find abandoned work.

Scan for orphaned state:
- Issues marked in_progress with no active polecat
- Polecats that stopped responding mid-work
- Merge queue entries with no polecat owner
- Wisp sessions that outlived their spawner

```bash
bd list --status=in_progress
gt polecats --all --orphan
```

For each orphan:
- Check if polecat session still exists
- If not, mark issue for reassignment or retry
- File incident beads if data loss occurred


Refinery needs branch visibility: Convert to worktree or push branches

The refinery cannot see polecat branches because it is a separate clone, not a worktree.

## Problem
- Polecats are worktrees of mayor/rig (correct, per gt-4u5z)
- Refinery is still a separate clone at refinery/rig (not converted)
- Polecat branches are local to mayor/rig, invisible to refinery

## Decision (2025-12-25)
**Use a shared bare repo as the single git source of truth.**

```
gastown/
├── .repo.git/           ← Bare repo (no working tree, invisible base)
├── mayor/rig/           ← Worktree (human workspace)
├── polecats/
│   └── Toast/           ← Worktree on polecat/Toast
├── refinery/rig/        ← Worktree on main (can see all branches!)
└── crew/max/            ← Worktree or separate clone (TBD)
```

**Why bare repo:**
- No working directory to accidentally work in
- Standard git pattern (how servers work)
- All worktrees share branch visibility
- Refinery on main can merge polecat branches directly

## Implementation
1. Create `.repo.git` as bare clone
2. Convert refinery to worktree of .repo.git on main
3. Convert polecats to worktrees of .repo.git
4. Optionally convert mayor/rig (or keep as worktree)
5. Update gt rig init for new rigs
6. Write migration for existing rigs

## Evidence
Tracer bullet 2025-12-23: Refinery could not see polecat/tracer until pushed to origin.


gt spawn: polecats report success but no work actually happens

## Problem

gt spawn polecats have multiple silent failure modes:

### Failure Mode 1: No gt prime
- Claude starts at prompt and waits for input
- SessionStart hook doesn't auto-run 'gt prime'
- Without gt prime, polecats don't pick up work

### Failure Mode 2: No git push (CRITICAL)
- Polecat commits code locally
- Polecat closes the beads issue
- Polecat sends POLECAT_DONE
- **But code is never pushed to remote branch**
- When worktree is cleaned up, commits are lost forever
- Issue appears closed but no code exists

## Evidence

testcat on bd-d28c:
- Reported 'Work Complete' with commits 7d3447b9, cd87e541
- Closed bd-d28c
- Submitted MR bd-yx22
- But: `grep -r 'TestCreateTombstone' cmd/bd/*.go` returns nothing
- No polecat/testcat branch on remote

## Required Fixes

1. Polecats MUST push their branch before closing issues
2. Witness MUST verify branch exists on remote before cleanup
3. gt spawn should auto-nudge 'gt prime'
4. Consider: Polecat handoff should fail if unpushed commits exist

## Verification Protocol for Witness

Before accepting POLECAT_DONE:
```bash
# 1. Verify branch pushed
git branch -r | grep polecat/<name>

# 2. Verify code exists
grep -r '<expected_function>' path/to/files

# 3. Only then cleanup
```


Merge: gt-3x0z.3

branch: polecat/slit
target: main
source_issue: gt-3x0z.3
rig: gastown


Digest: mol-deacon-patrol

Patrol complete: 0 messages, agents healthy, no cleanup needed


Merge: gt-h1n5

branch: polecat/rictus
target: main
source_issue: gt-h1n5
rig: gastown


Update Deacon template to emphasize staying in ~/gt/deacon directory

The Deacon template should instruct the agent to stay in ~/gt/deacon/ as much as possible, and always return there after any excursion. This prevents issues with identity detection (mail, mol status) which depend on cwd.


Merge: slit-1767073379145

attached_args: Code review

branch: polecat/slit-1767073379145
target: main
source_issue: slit-1767073379145
rig: gastown


Implement shared beads architecture for rig

Implement redirect-based shared beads to eliminate git sync overhead within a rig.

## Background
Each polecat currently has its own .beads/ directory synced via git. This burns tokens on sync operations.

## Solution
Use bd's redirect feature:
1. Create single shared .beads/ at rig root
2. Polecats get redirect files pointing to shared location
3. All agents connect to same daemon
4. SQLite WAL + daemon serialization handles concurrency

## Implementation
1. Create shared .beads/ at rig root (e.g., ~/gt/gastown/.beads/)
2. Update gt spawn to create redirect files:
   mkdir -p polecats/nux/.beads
   echo ../../.beads > polecats/nux/.beads/redirect
3. Test that all polecats connect to same daemon
4. Remove git sync from intra-rig workflow
5. Keep JSONL export for backup/cross-rig only

## Reference
beads/polecats/rictus/internal/beads/beads.go:45 - followRedirect()


gt mq submit: creates task type instead of merge-request type

## Problem

`gt mq submit` creates an issue with `type: task` but should be `type: merge-request`.

## Evidence

```
$ bd show gt-n508
gt-n508: Merge: gt-70b3
Status: open
Priority: P1
Type: task      <-- WRONG, should be merge-request
...
Description:
type: merge-request   <-- Correct type is in description, not in actual type field
```

## Impact

`gt mq list` shows empty queue because it queries for `type: merge-request`

## Fix

`gt mq submit` should set `--type merge-request` when creating the bead.


bd doctor: detect clone divergence emergencies

Add doctor check to detect:
1. Crew/Mayor on feature branches (should always be on main)
2. Significant divergence between clones that should be in sync
3. Distinguish from normal beads-sync vs main divergence (expected)

Context: bd sync --status shows all divergence as equal, but some is emergency (clones drifted) vs normal (sync branch mechanics).


Digest: mol-deacon-patrol

Patrol 1: All agents healthy, no lifecycle requests, no orphans


Polecat didn't commit before gt done

Integration test gt-7psb8: Polecat furiosa ran gt done before committing changes.

The polecat:
1. Created a test file
2. Closed the bead with bd close --force
3. Ran bd sync
4. Ran gt done

But it NEVER ran:
- git add <file>
- git commit

Result: Branch pushed with no new commits. Refinery detected branch at same commit as main.

The polecat CLAUDE.md or session close protocol should enforce commit before gt done.


Digest: mol-deacon-patrol

Patrol #14: Stable


Digest: mol-deacon-patrol

Patrol 4: quiet, health OK


Digest: mol-deacon-patrol

Patrol 10


Polecat mood command and status line display

CLI and status line support for polecat mood.

## CLI Command
```
gt polecat mood <name> <emoji>   # Set mood
gt polecat mood <name>           # Get mood
```

Sets GT_MOOD environment variable in the polecat's tmux session.

## Status Line Integration
Update runWorkerStatusLine() to read mood:
```go
mood, _ := t.GetEnvironment(session, "GT_MOOD")
if mood != "" {
    icon = mood  // Use mood emoji instead of default
} else {
    icon = AgentTypeIcons[AgentPolecat]  // Fallback to 😺
}
```

## Storage
Mood stored in tmux session environment (ephemeral, per-session).
No persistence needed - mood is reassessed each patrol cycle.

Depends on: gt-u818 (plugin system)


Polecats must not create GitHub PRs

Polecats should never use 'gh pr create' or create GitHub pull requests.

## Correct Workflow
1. Polecat works on polecat/<name> branch
2. Commits and pushes to origin
3. Creates beads MR issue (type: merge-request)
4. Refinery processes the MR and merges to main

## Wrong Workflow
- Using gh pr create
- Creating GitHub pull requests directly

## Why
- Refinery is our merge queue processor
- GitHub PRs bypass our workflow
- Beads MRs are the coordination mechanism


Daemon sending heartbeat to Mayor - should not

Daemon appears to be sending heartbeat messages to Mayor, but Mayor should not receive heartbeats. Observed at least once or twice - needs investigation to confirm and fix.


Digest: mol-deacon-patrol

Patrol 3: Routine


Digest: mol-deacon-patrol

Patrol 2: Quick scan, all healthy, no work


Implement mol bond command for dynamic child molecules

Add 'gt mol bond' command that creates child molecules at runtime with variable substitution.

Usage from mol-witness-patrol survey-workers step:
```bash
bd mol bond mol-polecat-arm $PATROL_WISP_ID \
  --ref arm-$polecat \
  --var polecat_name=$polecat \
  --var rig=<rig>
```

This creates child wisps like patrol-x7k.arm-ace with variables expanded.

Implementation:
1. Add 'bond' subcommand to mol command
2. Accept: proto ID, parent ID, --ref for child suffix, --var key=value pairs
3. Call InstantiateMolecule with Context map populated from --var flags
4. Return created child ID

Critical for Christmas Ornament pattern - without this, Witness cannot spawn per-polecat inspection arms.


Digest: mol-deacon-patrol

Patrol 7: all healthy


Test message

Testing GGT mail system


mol-witness-patrol

Per-rig worker monitor patrol loop using the Christmas Ornament pattern.

The Witness is the Pit Boss for your rig. You watch polecats, nudge them toward
completion, verify clean git state before kills, and escalate stuck workers.

**You do NOT do implementation work.** Your job is oversight, not coding.

## The Christmas Ornament Shape

This molecule uses dynamic bonding to create inspection arms per-polecat:

```
                    ★ mol-witness-patrol (trunk)
                   /|\
            ┌─────┘ │ └─────┐
         PREFLIGHT DISCOVERY CLEANUP
            │       │        │
        ┌───┴───┐ ┌─┴─┐  ┌───┴───┐
        │inbox  │ │sur│  │aggreg │
        │refnry │ │vey│  │save   │
        │load   │ └─┬─┘  │summary│
        └───────┘   │    │contxt │
                    │    │loop   │
          ┌─────────┼─────────┐ └───────┘
          │         │         │
          ●         ●         ●     mol-polecat-arm (dynamic)
         ace       nux      toast
          │         │         │
       ┌──┴──┐   ┌──┴──┐   ┌──┴──┐
       │cap  │   │cap  │   │cap  │
       │ass  │   │ass  │   │ass  │
       │dec  │   │dec  │   │dec  │
       │exec │   │exec │   │exec │
       └──┬──┘   └──┬──┘   └──┬──┘
          │         │         │
          └─────────┴─────────┘
                    │
                 ⬣ base (cleanup)
```

## Phases

### PREFLIGHT (fixed steps)
1. inbox-check - Process lifecycle requests, help messages
2. check-refinery - Ensure MQ is alive and processing
3. load-state - Read persistent state (nudge counts, etc.)

### DISCOVERY (spawns dynamic arms)
4. survey-workers - List polecats, bond mol-polecat-arm per polecat
5. run-plugins - Bond mol-plugin-runner for each witness plugin

### CLEANUP (gate + fixed steps)
6. aggregate - GATE: WaitsFor all arms + plugins to complete
7. save-state - Persist nudge counts, action log
8. generate-summary - Create digest content
9. context-check - Check if context is high
10. burn-or-loop - Squash/burn wisp, then loop or exit

## Dynamic Arms

Each polecat gets mol-polecat-arm bonded as a wisp child:
- capture - Capture tmux output
- assess - Categorize state (working/idle/error/done)
- load-history - Get nudge counts for this polecat
- decide - Apply nudge matrix
- execute - Take action (nudge/kill/escalate/none)

Arms run in PARALLEL. The aggregate step waits for all to complete.

## Activity Feed

This design enables real-time visibility:

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

## Storage

- Wisp storage: .beads-wisp/ (ephemeral, gitignored)
- Persistent state: witness handoff bead (nudge counts, etc.)
- Digests: Squashed summaries in permanent beads

## Dependencies

- bd-xo1o: Dynamic Molecule Bonding epic (in beads rig)
  - bd mol bond with variable substitution
  - WaitsFor directive for fanout gates
  - Activity feed query

Labels: [template, christmas-ornament]


Swarm: E2E Swarm Test Epic

Swarm molecule orchestrating epic gt-1tpts.

Epic: gt-1tpts
Coordinator:


gt spawn should verify daemon is running for polecat triggering

gt spawn notifies the Deacon (via mail) that a polecat was started, expecting the Deacon to trigger it once Claude is ready. But if the daemon isn't running, the mail sits unread and the polecat never gets triggered.

## Current Behavior
1. gt spawn starts polecat session
2. gt spawn sends POLECAT_STARTED to deacon/
3. (assumes daemon will trigger polecat)

## Problem
If gt daemon isn't running, step 3 never happens and polecat sits at prompt.

## Solution
In gt spawn, after session start:
1. Check if daemon is running (gt daemon status)
2. If not running, either:
   a. Start daemon: gt daemon start
   b. Or warn user: 'Daemon not running, polecat may not auto-start'

## Alternative
The user can manually trigger with gt nudge, but automated flow should work.


Define constants for magic strings

Several magic strings are hardcoded throughout the codebase:
- "mayor" appears in 20+ places as a path component
- "main" branch name appears in 20+ places
- "beads-sync" branch name in multiple files
- "rigs.json" filename

These should be constants in a central location for maintainability.


Digest: mol-deacon-patrol

Patrol 18: Mayor OK, 11 sessions


Digest: mol-deacon-patrol

Patrol 7: All healthy


Digest: mol-deacon-patrol

Patrol 10: Quiet, 8 sessions healthy


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.


Draft mol-ready-work protomolecule definition

Draft the actual protomolecule definition in markdown format.

## Molecule Structure

```markdown
## Molecule: ready-work
Autonomous backlog processing patrol for crew workers.

Phase: vapor (wisp) - ephemeral patrol cycles
Squash: after each work item or context threshold

## Step: orient
Load context and check for interrupts:
- Read mail for overseer instructions
- Check for predecessor handoff
- Load current context state

## Step: scan-backlogs
Survey all backlogs in priority order:
1. gh pr list --state open
2. gh issue list --state open --label untriaged (or no label)
3. bd ready
4. gh issue list --state open --label triaged

Capture counts and candidates.

Needs: orient

## Step: select-work
Apply ROI heuristic to select best work item:
- Estimate size (tokens needed)
- Check remaining context capacity
- Weight by impact (priority, type)
- Select highest ROI achievable item
- If empty: exit patrol

Needs: scan-backlogs

## Step: execute-work
Work the selected item:
- For PRs: review, request changes, or merge
- For untriaged: triage and label
- For beads: implement and close
- For triaged GH: implement fix

Commit, push, close/update as appropriate.

Needs: select-work

## Step: check-context
Assess context state:
- Estimate remaining capacity
- If < 20%: goto handoff
- If ok: loop to scan-backlogs

Needs: execute-work

## Step: handoff
Prepare for session transition:
- Summarize work completed this cycle
- Note any in-progress items
- Send handoff mail to self
- Squash wisp to digest
- Exit for fresh session

Needs: check-context
```

## Variables

- `backlog_priority`: Override backlog scan order
- `context_threshold`: Percentage at which to handoff (default: 20)
- `max_items`: Maximum items to process per session

## Notes

- This is a vapor-phase molecule (wisp)
- Each work item should squash to a digest
- The patrol itself squashes at handoff


Digest: mol-deacon-patrol

Patrol 18: All healthy


Polecat template: fix 'git clone' to 'git worktree'

Template says 'You're in a project git clone' but polecats use worktrees, not clones. Fix terminology.


Add tmux crash detection hooks

Use tmux hooks to detect when agent panes die unexpectedly.

## tmux Hooks to Use
- pane-died: fires when a pane exits
- session-closed: fires when session ends

## Implementation
```bash
set-hook -g pane-died 'run-shell "gt log pane-died #{pane_id} #{pane_dead_status}"'
set-hook -g session-closed 'run-shell "gt log session-closed #{session_name}"'
```

## Integration
- gt spawn should set these hooks on agent sessions
- Distinguish expected exits (handoff, done) from crashes
- Capture last N lines of output on crash
- Record exit code/signal for forensics

## gt log crash command
- Parse pane-died events
- Show crash history
- Filter by agent, time range


Integration test: Christmas Ornament with live polecats

Test the dynamic bonding pattern with actual polecats.

Test scenarios:
1. Patrol with 0 polecats (empty arms)
2. Patrol with 3 polecats (parallel arms)
3. Polecat appears mid-patrol (picked up next cycle)
4. Nudge progression (idle -> nudge-1 -> nudge-2 -> nudge-3)
5. Pre-kill verification flow
6. Activity feed output verification


Implement context-checking for agent sessions

Implement the context-checking step that allows agents to assess their remaining context capacity.

## Challenge

Agents don't have direct access to token counts. Need heuristics:

### Approach 1: Message count heuristic
- Count messages in conversation
- Estimate tokens per message
- Compare to model's context window

### Approach 2: External tool
- Claude Code could expose a /context command
- Returns estimated usage percentage
- Agent queries before each work item

### Approach 3: Conservative fixed limits
- After N work items, always handoff
- Simple but may waste context or handoff too early

### Approach 4: Hook-based injection
- SessionStart hook injects context estimate
- Updated periodically via tool call

## Recommendation

Start with Approach 3 (fixed limits) as MVP:
- Default: 3-5 work items per session
- Agent can override via variable
- Upgrade to smarter heuristics later

## Integration

- Add check-context step to mol-ready-work
- Implement handoff trigger logic
- Test with various context states


Digest: mol-deacon-patrol

Patrol 4: all healthy


Digest: mol-deacon-patrol

Patrol 11: quiet


Digest: mol-deacon-patrol @ 2025-12-24 19:22

Patrol 5: all healthy, 2 crews (dave, max) active


gt-gastown-polecat-nux

gt-gastown-polecat-nux

role_type: polecat
rig: gastown
agent_state: running
hook_bead: gt-5o2l0
role_bead: gt-polecat-role
cleanup_status: clean


Digest: mol-deacon-patrol

Patrol 20: all healthy - handoff


Digest: mol-deacon-patrol

Patrol 20: OK - Handoff threshold reached


Digest: mol-deacon-patrol

Patrol 14: quiet


Digest: mol-deacon-patrol

Patrol 7: Routine


gt-polecat-gastown-rictus

gt-polecat-gastown-rictus

role_type: polecat
rig: gastown
agent_state: running
hook_bead: gt-dsqxw
role_bead: null


Persist patrol state

Update handoff bead with new states.

Persist state to the witness handoff bead:
- Updated worker statuses from all arms
- Current nudge counts per worker
- Nudge timestamps
- Actions taken this cycle
- Pending items for next cycle

```bash
bd update <handoff-bead-id> --description="<serialized state>"
```

This state survives wisp burns and session cycles.


Digest: mol-deacon-patrol

Patrol #3: Routine - 6 agents healthy


Remove redundant gt prime SendKeys from crew commands

The crew commands (gt crew at, gt crew restart) still send 'gt prime' via SendKeys after session creation:
- internal/cmd/crew_at.go:97, 121
- internal/cmd/crew_lifecycle.go:202

This is now redundant because SessionStart hook handles priming automatically.

**Low priority** - these aren't causing bugs (just duplicate work), unlike the spawn race condition that was fixed. Can be cleaned up when convenient.


Digest: mol-deacon-patrol @ 2025-12-24 19:26

Patrol 12: quiet


Digest: mol-deacon-patrol

Patrol 16: All healthy, mayor handoff observed (not for deacon)


Add multi-lang-shiny example and tests

Create example meta-formula and test suite.

## Example

Create .beads/formulas/multi-lang-shiny.meta.yaml:
- Generates shiny-go, shiny-python, shiny-typescript
- Each extends base-shiny with language-specific vars

## Tests

1. Test basic expansion (3 languages -> 3 formulas)
2. Test variable substitution in names and content
3. Test error on duplicate generated names
4. Test empty values list
5. Integration: cook a generated formula


Work on ga-y6b: Implement Refinery as Claude agent. Conve...

Work on ga-y6b: Implement Refinery as Claude agent. Convert from shell to Claude agent that processes MRs in merge queue, runs tests, merges to integration branch. When done, submit MR (not PR) to integration branch for Refinery.


Add molecule phase lifecycle diagram to architecture.md

Create a clear lifecycle diagram showing molecule phases:

```
                    ┌─────────────┐
                    │   Proto     │
                    │  (crystal)  │
                    └──────┬──────┘
                           │
                      bd mol bond
                           │
              ┌────────────┴────────────┐
              │                         │
              ▼                         ▼
      ┌───────────────┐        ┌───────────────┐
      │     Mol       │        │    Wisp       │
      │   (liquid)    │        │    (gas)      │
      │   durable     │        │  ephemeral    │
      │  main beads   │        │ .beads-eph/   │
      └───────┬───────┘        └───────┬───────┘
              │                        │
         bd mol squash            bd mol squash
              │                        │
              ▼                        ▼
      ┌───────────────┐        ┌───────────────┐
      │    Digest     │        │   (nothing)   │
      │ (distillate)  │        │  evaporates   │
      │  in git hist  │        └───────────────┘
      └───────────────┘
```

Also document:
- When to use Mol vs Wisp
- Mol: code review waves, epic implementation, feature work
- Wisp: orchestration, polecat work sessions, patrol loops


Digest: mol-deacon-patrol

Patrol cycle 2: all quiet, agents healthy


Digest: mol-deacon-patrol

Patrol 3: quiet, health OK


Digest: mol-deacon-patrol

Patrol 17: routine


Digest: mol-deacon-patrol

Patrol 8: OK


Polecats should not push branches to remote

## Current Behavior

Polecats push their branches to origin (e.g., `polecat/furiosa`), which pollutes the remote with many short-lived branches.

## Desired Behavior

Polecats should only commit locally. The Refinery handles all remote pushes:
1. Polecat works on local `polecat/<name>` branch
2. Polecat signals done (state → idle)
3. Refinery pulls from local polecat branch
4. Refinery runs tests, merges to main
5. Refinery pushes main to remote
6. If PR review needed, Refinery creates the PR

## Benefits

- Clean remote (no branch pollution)
- Clear responsibility (Refinery is the quality gate)
- Simpler cleanup (local branches deleted with worktree)
- Less noise in GitHub UI

## Trade-offs

- If polecat crashes before Refinery merges, code is lost locally
- But beads issue remains open, another polecat can redo the work
- This is acceptable for ephemeral workers

## Implementation

In polecat CLAUDE.md or landing protocol:
- Remove `git push origin HEAD` from workflow
- Replace with just `git commit` + signal done
- Refinery handles the rest


Polecat beads not synced with rig beads

When gt spawn assigns an issue to a polecat, the polecat cannot find the issue because:

1. Rig beads at /gt/gastown/.beads contains gt-th7
2. Polecat beads at /gt/gastown/polecats/dementus/.beads does NOT have gt-th7
3. bd sync in polecat dir pulls from beads-sync branch which doesn't have the new issue
4. Rig bd sync uses 'main' branch, causing a branch mismatch

The polecat gets a work assignment for an issue it literally cannot see.

## Root Cause

- Rig beads and polecat beads are separate git-tracked copies
- No mechanism to propagate newly created issues from rig to polecats before assignment
- Sync branch configuration mismatch between rig and polecats

## Fix Options

1. gt spawn should sync rig beads before assigning work
2. gt spawn should sync polecat beads after assignment
3. Use shared beads (symlink or same DB) instead of copies
4. Push new issues immediately on create

Note: This sync mismatch is resolved by gt-9nf (fresh polecats). Rather than fixing sync between stale clones, we'll always create fresh worktrees. This issue documents the root cause for posterity.


Digest: mol-deacon-patrol

Patrol 16: all healthy


Max expansion depth limit (default 5)

Add maxExpansionDepth config (default 5) to prevent runaway nested expansions. This still allows massive work generation but with a safety bound. Note: distinguish compile-time cooking (produces proto with placeholders) vs runtime cooking (produces mol with real issue IDs). Compile-time is for modeling/estimation/contractor handoff.


bd update --claim for work queue semantics

Atomic claim operation for work queue messages.

## Deliverables

1. Add --claim flag to bd update
2. Atomic operation:
   - Sets assignee to claimer
   - Sets status to in_progress
   - Fails if already claimed
3. Conflict detection:
   - If already claimed, return error: "already claimed by X"
4. Integration with gt mail for queue messages

## Example
```bash
gt mail queue cleanup/gastown  # See available work
bd update msg-xxx --claim       # Claim it atomically
# Returns error if someone else claimed first
```

## Dependencies
- queue: shared storage (gt-???)

## Acceptance
- --claim sets assignee + status atomically
- Double-claim returns clear error
- Works with queue messages


Fetch remote and identify polecat branches waiting.

```bash
git fetch origin
git branch -r | grep polecat
gt refinery queue <rig>
```

If queue empty, skip to context-check step.
Track branch list for this cycle.

instantiated_from: mol-refinery-patrol
step: queue-scan


gt crew add: CLAUDE.md customization leaves git dirty

When gt crew add generates a customized CLAUDE.md for crew workers, it differs from the repo version (Crew Worker Context vs Polecat Context, personalized footer). This leaves the git state 'dirty'.

Options:
1. Add CLAUDE.md to .gitignore in crew workspaces
2. Auto-commit the customized CLAUDE.md locally
3. Store crew CLAUDE.md content elsewhere (e.g., .claude/CLAUDE.md)

Current behavior is functional but 'gt crew list' shows 'Git: dirty' for new crew.

Found during: adding crew workers grip, fang, wolf


Digest: mol-deacon-patrol

Patrol cycle 7: routine, healthy


Pinned Beads: Ongoing concerns and anchors

Pinned beads represent persistent concerns that do not close traditionally. Stay out of bd ready. Examples: Monitor production, Weekly syncs. Implementation: pinned: true field on bead.


Digest: mol-deacon-patrol

Patrol 13: all healthy


Merge: gt-xw7b

branch: polecat/morsov
target: main
source_issue: gt-xw7b
rig: gastown


Messaging infrastructure: lists, queues, channels

Multi-recipient and broadcast messaging for Gas Town.

## Phases

**Phase 1 - Foundation**: Config directory (gt-i6jvc)
**Phase 1 - Core**: list:, queue:, @group (requires agent-as-bead for @group)
**Phase 2 - Channels**: announce:, #channel, gt channel publish

## Addressing Syntax

| Prefix | Resolution | Storage | Claim? |
|--------|------------|---------|--------|
| `@group` | Dynamic (bead queries) | Fan-out (N copies) | No |
| `list:name` | Static config | Fan-out (N copies) | No |
| `queue:name` | Static config | Shared (1 copy) | Yes |
| `announce:name` | Static config | Shared (1 copy) | No |
| `#channel` | Dynamic (tmux) | None (ephemeral) | No |

## Alignment with Agent-as-Bead

@group resolution now uses agent bead queries:
- @rig/gastown → bd list --type=agent --rig=gastown
- @witnesses → bd list --type=agent --role_type=witness

This replaces the originally planned filesystem scanner (gt-xo05b, now closed).

## Independent Work

Config-based features (list:, queue:, announce:) can proceed without agent identity.
Only @group requires the agent schema from Pillar 1.


gt-gastown-polecat-charlie

gt-gastown-polecat-charlie

role_type: polecat
rig: gastown
agent_state: spawning
hook_bead: null
role_bead: gt-polecat-role
cleanup_status: null


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

## Moved from beads
Originally bd-rl5t. Tests Deacon patrol which is in gastown.


Merge: gt-h6eq.5

branch: polecat/keeper
target: main
source_issue: gt-h6eq.5
rig: gastown


Digest: mol-deacon-patrol

Patrol 4: All healthy


Molecule converge: iterate until AI says done

Work isn't 'done' until AI is confident it's done. Fixes the 85% problem.

**From VC**: internal/iterative/converge.go - 3-7 iterations with AI convergence detection. ~600 lines.
Target: 20%+ more issues discovered. Observed: ~25% average improvement.

**Gas Town implementation**: Molecule converge config:
```yaml
converge:
  strategy: ai
  min_iterations: 3
  max_iterations: 7
  confidence: 0.85
```

Polecat iterates, AI checks convergence. Stop when AI is confident or max reached.

**Value**: Raw agents get to ~85% and stop. Iteration catches the remaining 15%.

**VC metrics**: Convergence rate >70%, mean 4-5 iterations for complex work.


Merge: gt-4ev4

branch: polecat/furiosa
target: main
source_issue: gt-4ev4
rig: gastown


Digest: mol-deacon-patrol

Patrol 7: all healthy


Digest: mol-deacon-patrol

Patrol 17: All healthy


Digest: mol-deacon-patrol

Patrol 20: all healthy, doctor pass, handoff cycle


gt crew remove: Remove crew workspace

Implement 'gt crew remove <name> [--force]' command:
- Check for uncommitted changes, unpushed commits
- Warn and require --force if dirty
- Kill any running session
- Remove directory
- Unregister from mail


Digest: mol-deacon-patrol

Patrol cycle 8: thorough check, all healthy


Add keyboard navigation and filtering

Keyboard navigation: j/k or arrows to move, enter to expand/collapse, q to quit. Filtering: by rig name, worker name, event type. Search within activity stream.


bd ready --type: missing type filter for MQ integration

bd ready lacks --type flag that engineer.go expects.

## Code (internal/refinery/engineer.go)
readyMRs, err := e.beads.ReadyWithType("merge-request")

## Actual bd ready
No --type flag - only supports assignee, label, priority filters.

## Impact
Refinery can't find merge-requests in queue, so MQ doesn't process anything.

## Fix Options
1. Add --type flag to bd ready
2. Use bd list --type=merge-request --status=open instead
3. Both (ready filters for unblocked, list for all)

This is blocking the entire MQ pipeline.


Agent Communication Protocol

Structured mail between agents for coordination.

## Problem
Agents communicate via freeform mail. This works but lacks parseable structure for automated handling.

## Protocols

### Witness to Refinery
- POLECAT_READY: worker X completed, branch ready for merge
- REWORK_COMPLETE: worker Y finished requested rework

### Refinery to Witness
- MERGE_SUCCESS: worker X merged, can be cleaned up
- MERGE_FAILED: worker X needs rework (reason attached)
- REWORK_REQUEST: please have worker X rebase on current main

### Polecat to Witness
- WORK_COMPLETE: done with assigned issue
- NEED_HELP: stuck, requesting intervention

### Any to Deacon
- ESCALATION: problem requiring Mayor attention

## Mail Format
Subject: [PROTOCOL_TYPE] brief description
Body: Structured YAML or JSON payload

## Success Criteria
- Patrol steps parse protocol messages automatically
- Handlers exist for each protocol type
- Integration test: polecat completes -> witness notifies -> refinery merges -> witness cleans up

Consolidates gt-0qki.


Digest: mol-deacon-patrol

Patrol 14: OK


Digest: mol-deacon-patrol

Patrol #18: Stable


Digest: mol-deacon-patrol

Patrol 7: Nominal


Complete gt crew commands (list, attach, remove, refresh, status)

Add remaining crew subcommands to internal/cmd/crew.go:

1. gt crew list - List crew workspaces with status
2. gt crew at/attach - Start tmux session in crew workspace
3. gt crew remove - Remove crew workspace (with safety checks)
4. gt crew refresh - Context cycling with mail-to-self handoff
5. gt crew status - Show detailed workspace status

Build on existing crew add implementation in internal/cmd/crew.go.
Reference closed issues gt-cik.3-7 for original requirements.


Digest: mol-deacon-patrol

Patrol cycle 13: routine


Digest: mol-deacon-patrol

Patrol cycle 14: nominal


Bubbletea TUI dashboard

Interactive TUI using Charm Bubbletea. Root model, view routing, Lipgloss theme. Includes: dashboard, rig explorer, polecat detail with live tail, mail view, beads view, spawn wizard.


Polecat spawn: CLAUDE.md template lookup path is wrong

Template lookup uses rig.Path/templates/ but templates are in mayor/rig/templates/

In internal/polecat/manager.go installCLAUDETemplate():
  templatePath := filepath.Join(m.rig.Path, "templates", "polecat-CLAUDE.md")
  // Looks for: /Users/stevey/gt/gastown/templates/polecat-CLAUDE.md
  // But templates are at: /Users/stevey/gt/gastown/mayor/rig/templates/

This causes silent failure (template not found is OK) and polecats inherit the wrong CLAUDE.md from the git worktree.

Fix options:
1. Copy templates to rig root during rig init
2. Change lookup to use mayor/rig/templates/
3. Embed templates in binary


Digest: mol-deacon-patrol

Patrol #9


Digest: mol-deacon-patrol

Patrol 10: full check, all healthy


orphan-check

Find abandoned work. Check for in_progress issues with no active agent.


Digest: mol-deacon-patrol

Cycle 3: quiet patrol


gt crew add: role_bead field references non-existent bead

## Problem

When `gt crew add` creates an agent bead (e.g., `gt-crew-gastown-grip`), it sets:
```
role_bead: gt-crew-gastown-grip-role
```

This is WRONG. It creates per-instance role bead references that don't exist.

## Correct Pattern

Role beads are SHARED templates defining what a role IS. Agent beads reference them:

| Role Type | Role Bead (shared) | Agent Bead (per-instance) |
|-----------|-------------------|---------------------------|
| Mayor | gt-mayor-role | gt-mayor |
| Deacon | gt-deacon-role | gt-deacon |
| Witness | gt-witness-role | gt-witness-<rig> |
| Refinery | gt-refinery-role | gt-refinery-<rig> |
| Crew | gt-crew-role | gt-crew-<rig>-<name> |
| Polecat | gt-polecat-role | gt-polecat-<rig>-<name> |

## Current State

Working correctly:
- gt-mayor → gt-mayor-role ✅
- gt-witness-gastown → gt-witness-role ✅
- gt-refinery-gastown → gt-refinery-role ✅

Broken:
- gt-deacon → gt-deacon-role (bead doesn't exist)
- gt-crew-* → gt-crew-<rig>-<name>-role (wrong pattern, beads don't exist)
- gt-polecat-* → (not set at all)

## Code Locations

1. `internal/cmd/crew_add.go:91` - sets `RoleBead: crewID + "-role"`
   Should be: `RoleBead: "gt-crew-role"`

2. `internal/polecat/manager.go:220,426` - doesn't set RoleBead
   Should set: `RoleBead: "gt-polecat-role"`

## Fix Required

1. Create missing role beads: gt-crew-role, gt-polecat-role, gt-deacon-role
2. Fix crew_add.go to use shared gt-crew-role
3. Fix polecat/manager.go to use shared gt-polecat-role
4. Update existing crew agent beads to point to gt-crew-role


Simplify and reorganize molecular chemistry docs

The Gas Town molecular chemistry docs (molecules.md, molecular-chemistry.md, molecule-algebra.md) are too dramatic and verbose. They need a simplification pass to be more reference-manual style.

**Current problems:**
1. Too much metaphor and philosophy, not enough practical reference
2. Start with the chemistry abstraction instead of what users care about (patrols, workflows)
3. Layer cake is presented top-down (formulas → protos → molecules) instead of bottom-up (issues → dependencies → execution)

**Proposed structure (inverted pyramid):**

1. **Start with execution semantics:**
   - Work = issues with dependencies
   - Dependencies control execution (blocks = sequential, no dep = parallel)
   - Agents traverse dependency graphs until blocked
   - Multi-day workflows via compound bonding

2. **Move to molecules:**
   - Molecules are just epics with workflow intent
   - Bonding = creating dependencies between work graphs
   - No protos required for ad-hoc workflows

3. **Then templates (protos/wisps):**
   - Phase metaphor for storage locations
   - pour/wisp/squash/burn operations
   - When to use each phase

4. **Finally formulas (for advanced users):**
   - YAML compile-time composition
   - extends, compose, aspects
   - Only needed for complex reusable patterns

**Style guidelines:**
- Reference manual with quick examples
- Written like agent priming (context they need to execute)
- Less dramatic, more straightforward
- TL;DR at top of each doc

**See also:**
- beads/docs/MOLECULES.md has a simplified version to use as template
- The execution model section explains multi-day traversal clearly


Digest: mol-deacon-patrol

Patrol 3: All agents healthy.


Digest: mol-deacon-patrol

Patrol 1: All agents healthy, no lifecycle requests, cleaned 3 abandoned wisps