Add merge queue activity events to the refinery:
- merge_started: When refinery begins processing an MR
- merged: When MR successfully merged to main
- merge_failed: When merge fails (conflict, tests, push, etc.)
- merge_skipped: When MR skipped (superseded)
Events include MR ID, worker, branch, and reason (for failures).
Implemented in both Manager.ProcessMR and Engineer.ProcessMRFromQueue.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The swarm status was stale because bd commands were running from the rig
root path instead of the mayor/rig clone which has proper beads sync config.
Changes:
- Add Rig.BeadsPath() method to return mayor/rig path when available
- Update all bd commands in swarm.go to use BeadsPath()
- Update swarm manager to use separate beadsDir and gitDir paths
- beadsDir for bd commands (git-synced location)
- gitDir for git operations and mail (rig root)
This ensures swarm status reflects the latest beads data from the
git-synced beads-sync branch instead of stale local daemon data.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, UpdateAgentState embedded hook_bead in the description
text field, while bd slot commands read/write from the SQLite
hook_bead column. This caused gt sling to report hooks as occupied
when bd slot show showed them empty.
Fix: Change UpdateAgentState to use proper bd commands:
- `bd agent state` for agent_state (updates column directly)
- `bd slot set/clear` for hook_bead (updates column directly)
This ensures consistency between gastown and beads commands.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements `gt callbacks process` for Mayor/Deacon patrol to handle
callbacks from agents:
- POLECAT_DONE: Log polecat completion
- MERGE_COMPLETED: Close source issue, log merge
- MERGE_REJECTED: Log rejection reason
- HELP/ESCALATION: Forward to overseer
- SLING_REQUEST: Log sling request for spawn
- WITNESS_REPORT: Log rig health status
- REFINERY_REPORT: Log queue status
Also adds EventCallback to townlog for callback processing events.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Agent session molecules (gt-gastown-crew-joe, gt-gastown-witness, etc.)
update frequently for status tracking, creating noisy entries in the
activity feed. This change:
- Adds IsAgentSessionBead() to identify agent session beads
- Filters out "update" events for agent sessions from the event feed
- Still updates the agent tree so status is visible there
- Still shows create/complete/fail/delete events for agents
The filtering happens in addEvent() in the TUI feed model. Agent session
updates are identified by parsing the bead ID pattern and checking for
known agent roles (mayor, deacon, witness, refinery, crew, polecat).
Resolves: gt-sb6m4
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 1 of activity feed improvements: gt commands now log events to
~/gt/.events.jsonl. This is the raw audit log that the feed daemon
(phase 2) will curate into the user-facing feed.
Instrumented commands:
- gt sling: logs sling events with bead and target
- gt hook: logs hook events with bead
- gt handoff: logs handoff events with subject
- gt done: logs done events with bead and branch
- gt mail send: logs mail events with to and subject
Event format follows the specification:
```json
{"ts":"2025-12-30T07:36:28Z","source":"gt","type":"mail",
"actor":"gastown/crew/joe","payload":{...},"visibility":"feed"}
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When using `gt sling <formula> --on <bead>`, the command now properly
instantiates the formula as a molecule and bonds it to the target bead:
1. Cook the formula (ensures proto exists)
2. Create wisp with feature variable from bead title
3. Bond wisp to original bead (creates compound)
4. Hook the compound root (not bare bead) to target agent
This enables the "shiny" workflow (design→implement→review→test→submit)
to be applied to existing bugs/features, ensuring polecats complete all
phases including the code review step.
Example:
gt sling shiny --on gt-abc gastown
# Creates shiny molecule, bonds to gt-abc, slings compound to polecat
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This fix addresses the issue where polecat sessions terminate unexpectedly
during work without recovery:
Changes:
- Add `checkPolecatSessionHealth()` to daemon heartbeat loop
- Proactively validates tmux sessions are alive for polecats
- Detects crashed polecats that have work-on-hook
- Auto-restarts crashed polecats with proper environment setup
- Notifies Witness if restart fails as fallback
- Add polecat support to lifecycle identity mapping
- `identityToSession()` now handles polecat identities
- `restartSession()` can restart crashed polecat sessions
- `identityToStateFile()` handles polecat state files
- `identityToAgentBeadID()` handles polecat agent beads
- `identityToBDActor()` handles polecat BD_ACTOR conversion
- Add `gt session check` command for manual health checking
- Validates tmux sessions exist for all polecats
- Shows summary of healthy vs not-running sessions
- Useful for debugging session issues
This provides faster recovery (within heartbeat interval) compared to
waiting for GUPP violation timeout (30 min) or Witness detection.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When slinging to an existing polecat with --naked flag, the code was still
attempting to look up the tmux pane, which fails for terminated polecats.
Now resolveTargetAgent accepts a skipPane parameter that bypasses the tmux
pane and working directory lookup when true.
This allows work to be slung to terminated polecats that will be restarted
manually later.
Also updated unsling to skip pane lookup since it only needs the agent ID.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The main polecat spawn fix was already in place (ec29ca07), but the naked
mode help text was telling users to run `claude` without the flag. Updated
to show the correct command with --dangerously-skip-permissions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements the primary wake mechanism for patrol agents:
- Subscribes to bd activity --follow as a background process
- Returns immediately when any line of output is received
- Timeout with optional exponential backoff as safety net
- JSON output mode for scripting
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Before: gt crew at only looked for tmux sessions with the specific naming
convention gt-<rig>-crew-<name>. If the user started Claude manually or
via a different mechanism, it would create a duplicate session.
After: Before creating a new session, check if any existing tmux session
has Claude running in the crews directory. If found, attach to that
session instead of creating a new one.
Changes:
- Add FindSessionByWorkDir() to internal/tmux/tmux.go to search sessions
by working directory, optionally filtering for Claude (node) running
- Update runCrewAt() to check for existing sessions before creating new
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When starting a polecat session with --issue flag, the issue is now
properly hooked to the polecat via bd update --status=hooked. This
ensures 'gt mol status' shows the assigned work when the session starts.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Two bugs fixed in loadTasksFromBeads():
1. JSON field name mismatch: code parsed dependencies but bd show
returns dependents - meant worker discovery always failed
2. Missing Assignee field: even if field name was correct, assignees
were not being extracted from the bd show output
Also added hooked status to TaskInProgress mapping since workers
with hooked beads are actively working.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds a new 'gt commit' command that wraps git commit and automatically
injects agent identity trailers into commit messages:
- Executed-By: agent identity (e.g., beads/crew/dave)
- Rig: the rig name
- Role: crew, polecat, witness, etc.
- Molecule: pinned molecule ID if any
This enables forensic analysis and audit trails for agent-mediated commits.
Supports common git commit flags: -a, --amend, --no-edit, --allow-empty.
Use --no-trailers to skip adding identity trailers.
- Add LoadSwarm method for loading swarms from beads
- Rewrite tests to use LoadSwarm, GetSwarm, GetReadyTasks, IsComplete
- Remove tests for deprecated Create, Start, UpdateState methods
- Keep E2E lifecycle documentation test
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change daemon from wake-focused to recovery-focused:
Before: Daemon pokes agents every 5-60min as primary wake
After: Daemon only checks for edge cases that feed-wake cannot handle
Recovery checks:
- Dead sessions that need restart (ensureDeaconRunning, ensureWitnessesRunning)
- Stale agents that crashed without updating state (checkStaleAgents)
- GUPP violations: agents with work-on-hook not progressing (checkGUPPViolations)
- Orphaned work: work assigned to dead agents (checkOrphanedWork)
Removed:
- pokeDeacon() - no longer sending HEARTBEAT messages
- pokeWitness()/pokeWitnesses() - no longer sending HEARTBEAT messages
- MOTD message arrays - only used by poke functions
Normal agent wake is now handled by feed subscription (bd activity --follow).
The daemon is the safety net for edge cases, not the primary propulsion.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds Type and Backoff fields to MoleculeStep for patrol agents to implement
cost-saving await-signal patterns:
- Type field: "task" (default), "wait" (await-signal), etc.
- BackoffConfig: base interval, multiplier, max cap
- Parsing for "Type:" and "Backoff:" lines in step definitions
- Comprehensive tests for new parsing functionality
Step definition format:
## Step: await-signal
Type: wait
Backoff: base=30s, multiplier=2, max=10m
Agents interpret these declaratively, implementing backoff behavior at runtime.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add special handling for 'deacon' target in gt nudge command
- Maps 'deacon' to gt-deacon session, gracefully handles if not running
- Add gt nudge deacon session-started to SessionStart hooks
- Updated settings-autonomous.json, settings-interactive.json, and
ensurePatrolHooks() template
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds first-class support for the human overseer in Gas Town mail:
- New OverseerConfig in internal/config/overseer.go with identity
detection (git config, gh cli, environment)
- Overseer detected/saved on town install (mayor/overseer.json)
- Simplified detectSender(): GT_ROLE set = agent, else = overseer
- New overseer address alongside mayor/ and deacon/
- Added --cc flag to mail send for CC recipients
- Inbox now includes CC'd messages via label query
- gt status shows overseer identity and unread mail count
- New gt whoami command shows current mail identity
Generated with Claude Code
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The swarm Manager was maintaining an in-memory map of swarms that was
never persisted and duplicated state from beads. This caused stale state
after restarts and confusion about source of truth.
Changes:
- Remove swarms map from Manager (now stateless)
- Add LoadSwarm() that queries beads for swarm state
- Refactor all methods to use LoadSwarm() instead of in-memory lookup
- Discover workers from assigned tasks in beads
- Remove obsolete unit tests that tested in-memory behavior
- Keep type/state tests that do not need beads
The E2E test (gt-kc7yj.4) now covers the beads integration.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Changed icon from 📌 to 🪝 for hooked beads
- Changed label from "Pinned" to "Hooked"
- Added 🚀 AUTONOMOUS MODE banner when work is on hook
- Clarified that hooked bead triggers autonomous work even without molecule
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add "The Capability Ledger" section to all 6 role templates explaining:
- Work visibility and reputation
- Redemption through consistent quality
- Every completion as evidence of autonomous execution at scale
- Work history as growing portfolio/CV
Also fix hooked vs pinned terminology confusion:
- "Hooked" = work assigned to you (triggers autonomous mode)
- "Pinned" = permanent reference beads
- Add clarifying note to all startup behavior sections
- Update code examples to use --status=hooked
Update prime.go AUTONOMOUS MODE output with ledger framing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When gt crew remove runs, it now closes the associated agent bead
(gt-<rig>-crew-<name>) with reason "Crew workspace removed".
This prevents orphaned agent beads in the system after crew removal.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- checkSlungWork now queries for status=hooked instead of status=pinned
- This makes AUTONOMOUS WORK MODE fire correctly when work is slung via gt hook
- Added "physics not politeness" language to AUTONOMOUS MODE output
- Added full Theory of Operation section to refinery.md.tmpl for consistency
The bug was: gt hook sets status=hooked but gt prime was querying for
status=pinned, so AUTONOMOUS MODE never triggered for hooked work.
(gt-kc7yj.3)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The hook mechanism was broken because gt hook sets status=hooked
but gt mol status was querying for status=pinned.
Adds StatusHooked constant and updates queries accordingly.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements canonical naming convention for agent bead IDs:
- Town-level: gt-mayor, gt-deacon (unchanged)
- Rig-level: gt-<rig>-witness, gt-<rig>-refinery (was gt-witness-<rig>)
- Named: gt-<rig>-crew-<name>, gt-<rig>-polecat-<name> (was gt-crew-<rig>-<name>)
Changes:
- Added AgentBeadID helper functions to internal/beads/beads.go
- Updated all ID generation call sites to use helpers
- Fixed session parsing in theme.go, statusline.go, agents.go
- Updated doctor check and fix to use canonical format
- Updated tests for new format
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When run from inside a crew directory like gastown/crew/joe, the command
now auto-detects the crew workspace name instead of requiring it as an
argument. This matches the existing behavior of 'gt crew at'.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add HookBead and RoleBead fields to Issue struct for JSON unmarshal
- CreateAgentBead now calls bd slot set to set role slot properly
- This ensures role_bead is stored as a first-class field, not just
embedded in description text
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
All agent bead creation now uses shared role beads:
- gt-mayor-role, gt-deacon-role
- gt-witness-role, gt-refinery-role
- gt-crew-role, gt-polecat-role
Previous code created per-instance role bead references like
gt-witness-gastown-role which is wrong. Role beads are shared
class definitions, not per-instance.
Files fixed:
- internal/rig/manager.go
- internal/doctor/agent_beads_check.go
- internal/cmd/prime.go
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
crew_add.go: Use gt-crew-role instead of per-instance role bead
polecat/manager.go: Add RoleBead field pointing to gt-polecat-role
Per agent-as-bead design, role beads are shared class definitions.
Each agent bead references its role via the role_bead field/slot.
Fixes gt-ne9he
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace .runtime/swarms.json with beads-backed swarm tracking:
- gt swarm create: calls bd create --type=epic --mol-type=swarm
- gt swarm status: calls bd swarm status
- gt swarm list: calls bd list --mol-type=swarm --type=epic
- gt swarm start: uses bd swarm status to find ready tasks
- gt swarm land: checks completion via bd, closes epic
- gt swarm cancel: closes epic with cancelled reason
Removed:
- SwarmStore type and LoadSwarmStore/Save functions
- Old spawnSwarmWorkers (replaced with spawnSwarmWorkersFromBeads)
- Unused helper functions (stateStyle, taskStateIcon, matchesStatus)
This implements "discovery over tracking" principle from swarm-architecture.md:
swarm state is now derived from beads epic/issue statuses rather than
maintaining separate state in .runtime/swarms.json.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Show unread mail count and first message subject for each agent
- Display format: "mail: 📬 N unread → Subject..."
- Only shows mail line when agent has unread messages
- Fix agent bead ID generation for global agents (mayor/, deacon/)
Example output:
🏭 Refinery
gt-refinery-gastown running
hook: refinery Handoff
mail: 📬 8 unread → MERGE_READY morsov
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Show full agent bead ID for each agent (e.g., gt-crew-gastown-joe)
- Display hook/pinned work with bead ID and title
- Use role icons and section separators for clarity
- Fall back to hooks array when agent bead lacks hook_bead field
Example output:
🎩 Mayor
gt-mayor running
hook: (none)
─── gastown/ ───────────────────────
🏭 Refinery
gt-refinery-gastown running
hook: refinery Handoff
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use tree characters (├── └── │) for hierarchical display
- Group agents by role type (Witness, Refinery, Crew, Polecats)
- Add role icons (🎩 Mayor, 🔔 Deacon, 👁 Witness, 🏭 Refinery, 👷 Crew, 😺 Polecats)
- Show pinned work inline with truncation
- Fix unused import in polecat/manager.go
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Inverse of 'gt rig shutdown'. Starts rig patrol agents:
- Checks tmux sessions to avoid duplicates
- Starts witness if not running
- Starts refinery if not running
- Reports what was started vs skipped
Also adds ProcessExists util function needed by witness/refinery managers.
- polecat.go: Remove unreachable first loop in splitLines (was using filepath.SplitList incorrectly)
- townlog/logger.go: Remove unused Event.JSON() method and json import
- lock/lock.go: Remove unused ErrStaleLock error variable
- refinery/manager.go: Remove unused getTestCommand() method
Note: witness.StatePaused is actually used by cmd/witness.go, not dead code.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>