- Added constants.SupportedShells for consistent shell list
- Updated 7 usages across start.go, crew_lifecycle.go, crew_helpers.go, tmux.go
- All tests pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enhanced the package-level documentation to explain why all write
operations in the keepalive package silently ignore errors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add PrintWarning helper in internal/style/style.go
- Update 35 warning message outputs across 16 files to use consistent format
- All warnings now display as "⚠ Warning: <message>" in yellow/bold
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extended the unified cycle system to include rig infrastructure sessions:
- Witness ↔ Refinery (per rig) now cycle with C-b n/p
Also moved SetCycleBindings into ConfigureGasTownSession so ALL Gas Town
sessions automatically get the unified cycle bindings. Removed redundant
individual calls from crew, mayor, and deacon startup code.
Cycle groups are now:
- Town: Mayor ↔ Deacon
- Crew (per rig): All crew members in same rig
- Infra (per rig): Witness ↔ Refinery
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fail fast with clear error when run outside ~/gt instead of
hanging while bd tries to start.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reduced runStart from 126 lines to 48 lines by extracting:
- startCoreAgents: Mayor and Deacon session startup (28 lines)
- startRigAgents: Witness/Refinery startup for --all flag (37 lines)
- startConfiguredCrew: Auto-start configured crew members (29 lines)
No behavior change - all existing tests pass.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Return *Model from NewModel() so SetEventChannel works
- Use sync.Once for safe channel close on quit
- Use pointer receivers consistently throughout
- Capture channels in closure to prevent race
- Fix indent panic in renderAgent when indent < 2
- Remove unused filterActive and err fields
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add bubbletea and bubbles dependencies
- Create internal/tui/feed package with:
- model.go: Main bubbletea model with agent tree and event stream
- view.go: Rendering logic with lipgloss styling
- keys.go: Vim-style key bindings (j/k, tab, /, q)
- styles.go: Color palette and component styles
- events.go: Event source from bd activity
- Update gt feed to use TUI by default (--plain for text mode)
- TUI features: agent tree by role, event stream, keyboard nav
Closes gt-be0as, gt-lexye, gt-1uhmj
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The sessionToAgentID function was missing handling for polecat sessions,
causing gt sling to fail to update the agent bead's hook_bead field.
Before: gt-gastown-nux -> gt-gastown-nux (unchanged, no match)
After: gt-gastown-nux -> gastown/polecats/nux (correct format)
This enables updateAgentHookBead to properly convert to the agent bead ID
(gt-polecat-gastown-nux) and update the hook_bead field, which is
required for agents to know they have work on their hook.
Found via E2E test (gt-j0gx2) - nux wasn't picking up slung work because
hook_bead was null despite the task being pinned.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Claude needs ~2 seconds to initialize before it can process nudges.
Without this delay, the initial "Work slung" message would arrive
before Claude was ready, causing the SessionStart hook not to fire.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The loadTasksFromBeads() function was reading 'dependents' from bd show
output, but the actual JSON field is 'dependencies'. This caused swarms
to have empty task lists, requiring manual dispatch.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move duplicated processExists function to shared util package:
- Create internal/util/process.go with ProcessExists function
- Add internal/util/process_test.go with basic tests
- Update witness/manager.go to use util.ProcessExists
- Update refinery/manager.go to use util.ProcessExists
- Remove local processExists functions from both files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create helper functions in internal/session/names.go for consistent
session name construction across Gas Town agents:
- MayorSessionName()
- DeaconSessionName()
- WitnessSessionName(rig)
- RefinerySessionName(rig)
- CrewSessionName(rig, name)
- PolecatSessionName(rig, name)
Includes comprehensive unit tests in names_test.go.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous implementation set separate bindings for crew vs town
sessions, but tmux key bindings are global. This meant whichever
session type was started last would overwrite the other's bindings.
New approach:
- Add unified `gt cycle next/prev` command that auto-detects session type
- Town sessions (gt-mayor, gt-deacon) cycle within town group
- Crew sessions (gt-*-crew-*) cycle within their rig's crew
- Other sessions (polecats, witness, refinery) do nothing on cycle
The old SetCrewCycleBindings and SetTownCycleBindings are now aliases
for the unified SetCycleBindings function.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create gt town next/prev commands for cycling between town-level sessions
- Add SetTownCycleBindings() to tmux package
- Wire up bindings when starting mayor and deacon sessions
Now mayor and deacon have the same C-b n/p cycling behavior as crew workers.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Prevents data loss from concurrent/interrupted state file writes by using
atomic write pattern (write to .tmp, then rename).
Changes:
- Add internal/util package with AtomicWriteJSON/AtomicWriteFile helpers
- Update witness/manager.go saveState to use atomic writes
- Update refinery/manager.go saveState to use atomic writes
- Update crew/manager.go saveState to use atomic writes
- Update daemon/types.go SaveState to use atomic writes
- Update polecat/namepool.go Save to use atomic writes
- Add comprehensive tests for atomic write utilities
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds tests to prevent regression of polecat identity bugs:
1. TestInstallCLAUDETemplate: Verifies template is loaded from
mayor/rig/templates/ (not rig root) with correct variable substitution.
2. TestInstallCLAUDETemplateNotAtRigRoot: Verifies templates at the
old buggy location (rig root) are NOT used.
3. TestPolecatCommandFormat: Documents and verifies that polecat sessions
export GT_ROLE=polecat, GT_RIG, GT_POLECAT, BD_ACTOR inline before
starting Claude (because tmux SetEnvironment only affects new panes).
These tests ensure polecats correctly identify as polecats, not mayor.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Two bugs caused polecats to think they were mayor:
1. Template lookup path (gt-si6am):
- Was looking at rig.Path/templates/ which doesn't exist
- Now correctly looks at mayor/rig/templates/
- Polecats get the polecat CLAUDE.md instead of inheriting mayor's
2. Env var export (gt-y41ep):
- tmux SetEnvironment only affects new panes, not current shell
- Now exports GT_ROLE, GT_RIG, GT_POLECAT, BD_ACTOR inline before Claude
- Matches how crew sessions work
Combined effect (gt-9ar8x): Polecats now correctly identify as polecats
and work from their own directory instead of mayor/rig.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements the nuclear cleanup option for post-merge polecat removal:
- Kills Claude session (force mode)
- Deletes git worktree (bypassing all safety checks)
- Deletes polecat branch
- Closes agent bead
Supports --all for bulk nuke and --dry-run for preview.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements session-preserving polecat recycle:
- Kills Claude session (tmux kill-session)
- Preserves sandbox (worktree and branch intact)
- Updates agent bead state to 'stopped'
- Leaves polecat ready for respawn on next molecule step
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously gt done wrote MRs to .beads/mq/*.json files, but gt mq list
queried beads for issue_type=merge-request. These were two different
storage systems, so MRs created by gt done never showed in gt mq list.
Now gt done creates a proper MR bead with:
- issue_type: merge-request
- Description containing branch, target, source_issue, rig, worker
Also updated mq_submit.go for consistency.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add installCLAUDETemplate() to Manager that:
- Reads templates/polecat-CLAUDE.md from rig root
- Substitutes {{rig}} and {{name}} with actual values
- Writes to polecats/<name>/CLAUDE.md
Called from both Add() and Recreate() after worktree creation.
Non-fatal if template is missing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- doctor/agent_beads_check.go: Check and create agent beads for all crew workers
- New listCrewWorkers() helper finds crew directories in each rig
- Run() checks for missing crew agent beads
- Fix() creates missing crew agent beads with proper fields
- cmd/crew_add.go: Create agent bead when adding a crew worker
- Creates gt-crew-<rig>-<name> agent bead after workspace creation
- Non-fatal if bead creation fails (warns but continues)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Strip (gt-xxx), (bd-xxx) suffixes from code comments. The descriptions
remain meaningful without the ephemeral issue IDs.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 2: Adds dedicated tmux window support:
- gt feed --window creates 'feed' window in current session
- If window exists, switches to it (idempotent)
- Always uses --follow mode in window (persistent stream)
- Error handling for non-tmux environments
Users can now C-b n/p to cycle to/from the activity feed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changes:
1. prime.go: Create agent beads on first prime for all roles including crew
2. done.go: Update agent state to done/stuck/idle when work completes
3. sling.go: Populate hook_bead when work is assigned to agents
4. mol-witness-patrol.formula.toml: Document dead and spawning states
Closes: gt-hymm0, gt-0lop3, gt-59k2x, gt-c4j4j
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Wraps bd activity with Gas Town integration:
- Default follow mode for streaming
- --rig flag to target specific rig beads
- Passthrough of bd activity flags (--since, --mol, --type, --limit)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add HookBead and State fields to AgentRuntime struct
- discoverGlobalAgents and discoverRigAgents now look up agent beads
- Display hook_bead ID and work title in status output
- Show agent_state when not idle
- Fall back to legacy Hooks array for rig agents without agent beads
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changes:
1. Fix reportAgentState in prime.go to use beads API directly instead of
non-existent `bd agent state` command. Agents now properly self-report
their state to their agent beads on startup.
2. Update witness patrol survey-workers step to use agent beads:
- List polecats via `bd list --type=agent --json`
- Filter by role_type: polecat in description
- Check agent_state field (running/idle/stuck/done)
- Trust agent-reported state (ZFC principle)
No more PID/tmux inference for polecat state - agents self-report.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
gt rig add now creates .claude/settings.json with patrol hooks for:
- witness/ directory (SessionStart, PreCompact, UserPromptSubmit hooks)
- refinery/ directory (same hooks)
gt deacon start also creates hooks if not present (idempotent).
These hooks run `gt prime && gt mail check --inject` on session start,
enabling autonomous patrol execution when daemon sends heartbeats.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds witness patrol to daemon heartbeat cycle:
- ensureWitnessesRunning(): Start witness for each rig if not running
- pokeWitnesses(): Send heartbeat messages to all witnesses
- getKnownRigs(): Read rig list from mayor/rigs.json
The daemon now ensures both Deacon and Witnesses are running
and sends periodic heartbeats to trigger their patrol molecules.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added comments explaining that RoleBead establishes a naming convention
for the canonical location of role definitions. The referenced bead may
not exist yet - this enables tooling like gt doctor to check for and
scaffold missing role beads.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Bootstrap now creates agent beads for ZFC compliance:
- Always: <prefix>-witness-<rig>, <prefix>-refinery-<rig>
- First rig only: <prefix>-deacon, <prefix>-mayor
Agent beads are created in the rig's beads database (not town beads)
because the daemon looks up beads by prefix routing.
Changes:
- internal/rig/manager.go: Added initAgentBeads() function
- internal/cmd/install.go: Added comment explaining why beads aren't
created here (no rig exists yet at install time)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add checkStaleAgents() to detect agents reporting "running" but not updating
- Add markAgentDead() to update agent bead state to "dead"
- Integrate stale agent check into heartbeat cycle
- DeadAgentTimeout set to 15 minutes
This is a safety mechanism for agents that crash without updating their state.
The daemon now marks them as dead so they can be restarted.
Also fixes duplicate AgentFields declaration - now uses beads.go version with
ParseAgentFieldsFromDescription alias in fields.go.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add AgentFields and ParseAgentFieldsFromDescription to internal/beads/fields.go
- Update daemon/lifecycle.go to use shared parsing
- Update cmd/molecule_status.go to use shared parsing
- Remove duplicate parsing code and unused isAgentRunningByBead function
This consolidates agent bead field parsing in one place, following the pattern
established for AttachmentFields and MRFields.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create ephemeral agent beads for ZFC-compliant polecat state tracking.
- Add AgentFields struct and helpers to beads package
- CreateAgentBead: Creates agent bead with role_type/rig/agent_state
- UpdateAgentState: Updates agent_state and hook_bead fields
- DeleteAgentBead: Hard-deletes ephemeral agent bead
- GetAgentBead: Retrieves and parses agent bead
- Integrate lifecycle in polecat manager:
- Add(): Creates gt-polecat-<rig>-<name> bead with state=spawning
- Recreate(): Deletes old bead, creates fresh with state=spawning
- RemoveWithOptions(): Deletes agent bead on nuke
This enables Witness to read polecat state from beads instead of
tmux scraping. State updates (spawning→working→done) are done by
polecats via bd agent state (separate beads CLI enhancement).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add getAgentBeadState() and getAgentBeadInfo() to read agent state from beads
- Add identityToAgentBeadID() to map daemon identities to agent bead IDs
- Update ensureDeaconRunning() to check agent bead state first (ZFC compliant)
- Add agent bead state logging in executeLifecycleAction()
This is the first step toward ZFC-compliant state detection. Dependent tasks:
- gt-psuw7: Remove PID/tmux state inference
- gt-2hzl4: Add timeout fallback for dead agents
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This change migrates gt mol status from querying by pinned status + assignee
to reading the hook_bead field from agent beads.
Changes:
- Add AgentBeadFields struct to parse agent bead description fields
- Add buildAgentBeadID function to convert identity to agent bead ID
- Update runMoleculeStatus to:
1. First try to find the agent bead by ID
2. Read hook_bead from agent bead description
3. If hook_bead is set, fetch and display that bead
4. Fall back to legacy pinned-query approach if no agent bead or hook
The implementation is backwards compatible - agents without agent beads
(like polecats before gt-rxa7v is completed) still work via the fallback.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>