Commit Graph

48 Commits

Author SHA1 Message Date
slit
9caf5302d4 fix(tmux): use KillSessionWithProcesses to prevent zombie bash processes
When Claude sessions were terminated using KillSession(), bash subprocesses
spawned by Claude's Bash tool could survive because they ignore SIGHUP.
This caused zombie processes to accumulate over time.

Changed all critical session termination paths to use KillSessionWithProcesses()
which explicitly kills all descendant processes before terminating the session.

Fixes: gt-ew3tk

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 20:45:58 -08:00
gastown/crew/dennis
0db2bda6e6 feat(deacon): add zombie-scan command for tmux-verified process cleanup
Unlike cleanup-orphans (which uses TTY="?" detection), zombie-scan uses
tmux verification: it checks if each Claude process is in an active
tmux session by comparing against actual pane PIDs.

A process is a zombie if:
- It's a Claude/codex process
- It's NOT the pane PID of any active tmux session
- It's NOT a child of any pane PID
- It's older than 60 seconds

Also refactors:
- getChildPIDs() with ps fallback when pgrep unavailable
- State file handling with file locking for concurrent access

Usage:
  gt deacon zombie-scan           # Find and kill zombies
  gt deacon zombie-scan --dry-run # Just list zombies

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 14:19:29 -08:00
dennis
7ff87ff012 docs: improve help text and add nudge documentation
Polish help text across all agent commands to clarify roles:
- crew: persistent workspaces vs ephemeral polecats
- deacon: town-level watchdog receiving heartbeats
- dog: cross-rig infrastructure workers (cats vs dogs)
- mayor: Chief of Staff for cross-rig coordination
- nudge: universal synchronous messaging API
- polecat: ephemeral one-task workers, self-cleaning
- refinery: merge queue serializer per rig
- witness: per-rig polecat health monitor

Add comprehensive gt nudge documentation to crew template explaining
when to use nudge vs mail, common patterns, and target shortcuts.

Add orphan-process-cleanup step to deacon patrol formula to clean up
claude subagent processes that fail to exit (TTY = "?").

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 02:55:39 -08:00
aleiby
22064b0730 feat: Add automatic orphaned claude process cleanup (#588)
* feat: Add automatic orphaned claude process cleanup

Claude Code's Task tool spawns subagent processes that sometimes don't clean up
properly after completion. These accumulate and consume significant memory
(observed: 17 processes using ~6GB RAM).

This change adds automatic cleanup in two places:

1. **Deacon patrol** (primary): New patrol step "orphan-process-cleanup" runs
   `gt deacon cleanup-orphans` early in each cycle. More responsive (~30s).

2. **Daemon heartbeat** (fallback): Runs cleanup every 3 minutes as safety net
   when deacon is down.

Detection uses TTY column - processes with TTY "?" have no controlling terminal.
This is safe because:
- Processes in terminals (user sessions) have a TTY like "pts/0" - untouched
- Only kills processes with no controlling terminal
- Orphaned subagents are children of tmux server with no TTY

New files:
- internal/util/orphan.go: FindOrphanedClaudeProcesses, CleanupOrphanedClaudeProcesses
- internal/util/orphan_test.go: Tests for orphan detection

New command:
- `gt deacon cleanup-orphans`: Manual/patrol-triggered cleanup

Fixes #587

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(orphan): add Windows build tag and minimum age check

Addresses review feedback on PR #588:

1. Add //go:build !windows to orphan.go and orphan_test.go
   - The code uses Unix-specific syscalls (SIGTERM, ESRCH) and
     ps command options that don't exist on Windows

2. Add minimum age check (60 seconds) to prevent false positives
   - Prevents race conditions with newly spawned subagents
   - Addresses reviewer concern about cron/systemd processes
   - Uses portable etime format instead of Linux-only etimes

3. Add parseEtime helper with comprehensive tests
   - Parses [[DD-]HH:]MM:SS format (works on both Linux and macOS)
   - etimes (seconds) is Linux-specific, etime is portable

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(orphan): add proper SIGTERM→SIGKILL escalation with state tracking

Previous approach used process age which doesn't work: a Task subagent
runs without TTY from birth, so a long-running legitimate subagent that
later fails to exit would be immediately SIGKILLed without trying SIGTERM.

New approach uses a state file to track signal history:

1. First encounter → SIGTERM, record PID + timestamp in state file
2. Next cycle (after 60s grace period) → if still alive, SIGKILL
3. Next cycle → if survived SIGKILL, log as unkillable and remove

State file: $XDG_RUNTIME_DIR/gastown-orphan-state (or /tmp/)
Format: "<pid> <signal> <unix_timestamp>" per line

The state file is automatically cleaned up:
- Dead processes removed on load
- Unkillable processes removed after logging

Also updates callers to use new CleanupResult type which includes
the signal sent (SIGTERM, SIGKILL, or UNKILLABLE).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 15:35:48 -08:00
Steve Yegge
42d9890e5c fix(deacon): improve health check reliability and error handling (#499)
Co-authored-by: Dylan <sigfawn@gmail.com>
2026-01-13 22:34:03 -08:00
Julian Knutsen
e7ca4908dc refactor(config): remove BEADS_DIR from agent environment and add doctor check (#455)
* fix(sling_test): update test for cook dir change

The cook command no longer needs database context and runs from cwd,
not the target rig directory. Update test to match this behavior
change from bd2a5ab5.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(tests): skip tests requiring missing binaries, handle --allow-stale

- Add skipIfAgentBinaryMissing helper to skip tests when codex/gemini
  binaries aren't available in the test environment
- Update rig manager test stub to handle --allow-stale flag

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(config): remove BEADS_DIR from agent environment

Stop exporting BEADS_DIR in AgentEnv - agents should use beads redirect
mechanism instead of relying on environment variable. This prevents
prefix mismatches when agents operate across different beads databases.

Changes:
- Remove BeadsDir field from AgentEnvConfig
- Remove BEADS_DIR from env vars set on agent sessions
- Update doctor env_check to not expect BEADS_DIR
- Update all manager Start() calls to not pass BeadsDir

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(doctor): detect BEADS_DIR in tmux session environment

Add a doctor check that warns when BEADS_DIR is set in any Gas Town
tmux session. BEADS_DIR in the environment overrides prefix-based
routing and breaks multi-rig lookups - agents should use the beads
redirect mechanism instead.

The check:
- Iterates over all Gas Town tmux sessions (gt-* and hq-*)
- Checks if BEADS_DIR is set in the session environment
- Returns a warning with fix hint to restart sessions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: julianknutsen <julianknutsen@users.noreply.github>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 22:13:57 -08:00
dementus
87fde4b4fd feat(spawn): migrate to NewSessionWithCommand pattern
Migrate witness, boot, and deacon spawns to use NewSessionWithCommand
instead of NewSession+SendKeys to ensure BD_ACTOR is visible in the
process tree for orphan detection via ps.

Refs: gt-emi5b

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 11:06:21 -08:00
julianknutsen
e999ceb1c1 refactor: consolidate agent env vars into config.AgentEnv
Create centralized AgentEnv function as single source of truth for all
agent environment variables. All agents now consistently receive:
- GT_ROLE, BD_ACTOR, GIT_AUTHOR_NAME (role identity)
- GT_ROOT, BEADS_DIR (workspace paths)
- GT_RIG, GT_POLECAT/GT_CREW (rig-specific identity)
- BEADS_AGENT_NAME, BEADS_NO_DAEMON (beads config)
- CLAUDE_CONFIG_DIR (optional account selection)

Remove RoleEnvVars in favor of AgentEnvSimple wrapper.
Remove IncludeBeadsEnv flag - beads env vars always included.
Update all manager and cmd call sites to use AgentEnv.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 21:52:30 -08:00
Ben Kraus
38adfa4d8b codex 2026-01-08 12:36:54 -05:00
Steve Yegge
c4d956ebe7 feat(deacon): implement bulletproof pause mechanism (gt-bpo2c) (#265)
Add multi-layer pause mechanism to prevent Deacon from causing damage:

Layer 1: File-based pause state
- Location: ~/.runtime/deacon/paused.json
- Stores: paused flag, reason, timestamp, paused_by

Layer 2: Commands
- `gt deacon pause [--reason="..."]` - pause with optional reason
- `gt deacon resume` - remove pause file
- `gt deacon status` - shows pause state prominently

Layer 3: Guards
- `gt prime` for deacon: shows PAUSED message, skips patrol context
- `gt deacon heartbeat`: fails when paused

Helper package:
- internal/deacon/pause.go with IsPaused/Pause/Resume functions

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 21:56:46 -08:00
jv
6afd85df4b feat: add --agent overrides to start/attach 2026-01-06 19:11:58 -08:00
gastown/crew/joe
c2451b85e7 Merge origin/main into fix/205-address-claude-startup-issues
Resolved conflict in internal/witness/manager.go:
- Kept session import (used by PR code)
- Kept PR's more accurate comment for PID check
- Removed duplicate sessionName method introduced by merge
2026-01-06 19:04:29 -08:00
gastown/crew/gus
74409dc32b feat(deacon): add stale hooked bead cleanup (gt-2yls3)
Add `gt deacon stale-hooks` command to find and unhook stale beads.

Problem: Beads can get stuck in 'hooked' status when agents die or
abandon work without properly unhooking.

Solution:
- New command scans for hooked beads older than threshold (default 1h)
- Checks if assignee agent is still alive (tmux session exists)
- Unhooks beads with dead agents (sets status back to 'open')
- Supports --dry-run to preview without making changes

Also adds "stale-hook-check" step to Deacon patrol formula.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 13:20:45 -08:00
mayor
f6f6acdb2d Consolidate Claude settings management
Settings creation was scattered across multiple places (createPatrolHooks,
ensurePatrolHooks, inline code). Now unified via claude.EnsureSettingsForRole().

Changes:
- Add "deacon" to autonomous roles in claude/settings.go
- Remove ensurePatrolHooks() from cmd/deacon.go, use EnsureSettingsForRole
- Remove createPatrolHooks() from rig/manager.go (no longer needed at rig add)
- Add EnsureSettingsForRole call in crew_lifecycle.go
- Add doctor check for stale/missing Claude settings files
- Wire up claude-settings check in cmd/doctor.go

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 01:51:24 -08:00
prime
af95b7b7f4 Remove StateIdle and idle polecat concept
The transient polecat model says: "Polecats exist only while working."
This removes the deprecated StateIdle and updates the codebase:

- Remove StateIdle from polecat/types.go (keep StateActive for legacy data)
- Update manager.go: Get() returns StateDone (not StateIdle) when no work
- Update manager.go: Add/Recreate return StateWorking (not StateIdle)
- Remove zombie scan logic from deacon.go (no idle polecats to scan for)
- Update tests to reflect new behavior

The correct lifecycle is now:
- Spawn: polecat created with work (StateWorking)
- Work: sessions cycle, sandbox persists
- Done: polecat signals completion (StateDone)
- Nuke: Witness destroys sandbox

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 14:41:28 -08:00
imperator
1532a08aeb feat: Update agent bead lookups to use correct tier (gt-eqptl)
Implement two-level beads architecture for agent lookups:

- Town-level agents (Mayor, Deacon) now use hq- prefix and are
  looked up in town beads (~/.beads/)
- Rig-level agents continue using rig prefix (e.g., gt-) and are
  looked up in rig beads

Changes:
- Add MayorBeadIDTown(), DeaconBeadIDTown(), DogBeadIDTown() helpers
- Add GetTownBeadsPath() for town beads path resolution
- Update gt status to pre-fetch town-level agent beads
- Update agentIDToBeadID() to use town-level IDs
- Update agent_beads_check.go to check/fix in correct tier
- Update agentAddressToIDs() in deacon.go

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 21:09:59 -08:00
max
1b69576573 fix: Address golangci-lint errors (errcheck, gosec) (#76)
Apply PR #76 from dannomayernotabot:

- Add golangci exclusions for internal package false positives
- Tighten file permissions (0644 -> 0600) for sensitive files
- Add ReadHeaderTimeout to HTTP server (slowloris prevention)
- Explicit error ignoring with _ = for intentional cases
- Add //nolint comments with justifications
- Spelling: cancelled -> canceled (US locale)

Co-Authored-By: dannomayernotabot <noreply@github.com>

🤖 Generated with Claude Code
2026-01-03 16:11:55 -08:00
joe
4bcf50bf1c Revert to simple gt-mayor/gt-deacon session names
Reverts the session naming changes from PR #70. Multi-town support
on a single machine is not a real use case - rigs provide project
isolation, and true isolation should use containers/VMs.

Changes:
- MayorSessionName() and DeaconSessionName() no longer take townName parameter
- ParseSessionName() handles simple gt-mayor and gt-deacon formats
- Removed Town field from AgentIdentity and AgentSession structs
- Updated all callers and tests

Generated with Claude Code

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 14:33:24 -08:00
markov-kernel
e7145cfd77 fix: Make Mayor/Deacon session names include town name
Session names `gt-mayor` and `gt-deacon` were hardcoded, causing tmux
session name collisions when running multiple towns simultaneously.

Changed to `gt-{town}-mayor` and `gt-{town}-deacon` format (e.g.,
`gt-ai-mayor`) to allow concurrent multi-town operation.

Key changes:
- session.MayorSessionName() and DeaconSessionName() now take townName param
- Added workspace.GetTownName() helper to load town name from config
- Updated all callers in cmd/, daemon/, doctor/, mail/, rig/, templates/
- Updated tests with new session name format
- Bead IDs remain unchanged (already scoped by .beads/ directory)

Fixes #60

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 21:37:05 +01:00
nux
cf53e2852e feat(session): Include session ID in PropulsionNudge for /resume picker
PropulsionNudgeForRole now accepts a workDir parameter and reads
session ID from .runtime/session_id to append [session:xxx] to the
nudge message. This enables Claude Code's /resume picker to discover
Gas Town sessions.

(gt-u49zh)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 11:51:30 -08:00
toast
9683744b53 feat: Add 'spawn' as alias for 'start' subcommand across roles
Added 'spawn' as an alias for 'start' in the following commands:
- gt witness start → also gt witness spawn
- gt refinery start → also gt refinery spawn
- gt deacon start → also gt deacon spawn
- gt crew start → also gt crew spawn

This improves discoverability since agents are guessing 'spawn'
when trying to start roles.

Note: gt polecat does not have a 'start' command - polecat spawning
is handled via 'gt sling'.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 17:30:24 -08:00
valkyrie
65c34efd4e feat(session): Add GUPP to non-polecat roles (Mayor, Deacon, Witness, Refinery)
GUPP (Gas Town Universal Propulsion Principle) is the propulsion nudge sent
after beacon to trigger autonomous work execution. Previously only polecats
received this nudge.

Now all roles get role-specific propulsion nudges on startup:
- Polecat/Crew: "Run `gt hook` to check your hook and begin work."
- Witness: "Run `gt prime` to check patrol status and begin work."
- Refinery: "Run `gt prime` to check MQ status and begin patrol."
- Deacon: "Run `gt prime` to check patrol status and begin heartbeat cycle."
- Mayor: "Run `gt prime` to check mail and begin coordination."

Changes:
- internal/session/names.go: Add PropulsionNudgeForRole() function
- internal/cmd/witness.go: Add GUPP nudge to ensureWitnessSession
- internal/cmd/start.go: Add GUPP nudge to ensureRefinerySession (also
  converted from respawn loop to direct Claude launch like other roles)
- internal/cmd/deacon.go: Add GUPP nudge to startDeaconSession
- internal/cmd/mayor.go: Add GUPP nudge to startMayorSession

Fixes: gt-zzpmt

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 18:52:42 -08:00
rictus
380f36b413 feat(deacon): Add zombie-scan backup check for idle polecats (gt-dpiw3)
Add gt deacon zombie-scan command that provides defense-in-depth
against Witness cleanup failures. The command:

- Scans all rigs for polecats that are idle, have no session running,
  no hooked work, and are stale (>10 min inactive)
- Reports found zombies with details
- Optionally nukes them and notifies the mayor

Flags:
  --dry-run        Preview only
  --threshold      Custom staleness threshold (default 10m)
  --nuke=false     Report only, do not clean up

Also adds zombie-scan step to mol-deacon-patrol formula.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 18:19:54 -08:00
gastown/crew/gus
b7c26d52e1 Migrate startup paths from SessionBeacon to StartupNudge (gt-7pp3l)
All 12 startup paths now use session.StartupNudge instead of the
older SessionBeacon pattern. The key difference is that StartupNudge
includes sender information, enabling better predecessor discovery
via gt seance.

Files updated:
- crew_lifecycle.go: 3 locations (refresh, restart)
- start.go: 2 locations (crew start)
- deacon.go: 1 location (deacon start)
- witness.go: 1 location (witness start)
- up.go: 4 locations (mayor, witness, crew, polecat)
- mayor.go: 1 location (mayor start)
- session/manager.go: 1 location (polecat spawn)

Format change:
Old: [GAS TOWN] address • molID • timestamp
New: [GAS TOWN] recipient <- sender • timestamp • topic[:mol-id]

This completes the Agent Startup Consolidation epic (gt-85whr).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 11:52:46 -08:00
gastown/crew/gus
626a24e013 Refactor startup paths to use RuntimeConfig (gt-j0546)
Replaced all hardcoded 'claude --dangerously-skip-permissions' invocations
with configurable helpers from internal/config:

- GetRuntimeCommand(rigPath) - simple command string
- GetRuntimeCommandWithPrompt(rigPath, prompt) - with initial prompt
- BuildAgentStartupCommand(role, bdActor, rigPath, prompt) - generic agent
- BuildPolecatStartupCommand(rigName, polecatName, rigPath, prompt) - polecat
- BuildCrewStartupCommand(rigName, crewName, rigPath, prompt) - crew
- BuildStartupCommand(envVars, rigPath, prompt) - custom env vars

Files updated:
- internal/cmd/start.go (4 locations)
- internal/cmd/crew_lifecycle.go (2 locations)
- internal/cmd/crew_at.go (2 locations)
- internal/cmd/deacon.go
- internal/cmd/witness.go
- internal/cmd/up.go (2 locations)
- internal/cmd/handoff.go (2 locations)
- internal/daemon/daemon.go (3 locations)
- internal/daemon/lifecycle.go
- internal/session/manager.go
- internal/refinery/manager.go
- internal/boot/boot.go

This enables future support for alternative LLM runtimes (aider, etc.)
via rig/town settings configuration.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 23:48:34 -08:00
gastown/polecats/slit
3dd18a1981 Add Deacon stuck-session detection and force-kill protocol
Implements gt-l6ro3.4: Deacon can now detect and kill genuinely stuck/hung
Claude Code sessions during health rounds.

New commands:
- gt deacon health-check <agent>: Pings agent, waits for response, tracks
  consecutive failures. Returns exit code 2 when force-kill threshold reached.
- gt deacon force-kill <agent>: Kills tmux session, updates agent bead state,
  notifies mayor. Respects cooldown period.
- gt deacon health-state: Shows health check state for all monitored agents.

Detection protocol:
1. Send HEALTH_CHECK nudge to agent
2. Wait for agent bead update (configurable timeout, default 30s)
3. Track consecutive failures (default threshold: 3)
4. Recommend force-kill when threshold exceeded

Force-kill protocol:
1. Log intervention (mail to agent)
2. Kill tmux session
3. Update agent bead state to "killed"
4. Notify mayor (optional)

Configurable parameters:
- --timeout: How long to wait for response (default 30s)
- --failures: Consecutive failures before force-kill (default 3)
- --cooldown: Minimum time between force-kills (default 5m)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 22:14:05 -08:00
gastown/crew/joe
df46e75a51 Fix: Unknown subcommands now error instead of silently showing help
Parent commands (mol, mail, crew, polecat, etc.) previously showed help
and exited 0 for unknown subcommands like "gt mol foobar". This masked
errors in scripts and confused users.

Added requireSubcommand() helper to root.go and applied it to all parent
commands. Now unknown subcommands properly error with exit code 1.

Example before: gt mol unhook → shows help, exits 0
Example after:  gt mol unhook → "Error: unknown command "unhook"", exits 1

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 20:52:23 -08:00
Steve Yegge
66042da18b Add session beacon for predecessor discovery via /resume
Inject an identity beacon as the first message when Gas Town starts Claude
sessions. This beacon becomes the session title in Claude Code '/resume
picker, enabling workers to find their predecessor sessions for debugging.

Beacon format: [GAS TOWN] <address> • <mol-id or "ready"> • <timestamp>

Examples:
- [GAS TOWN] gastown/crew/max • gt-abc12 • 2025-12-30T14:32
- [GAS TOWN] gastown/polecats/Toast • ready • 2025-12-30T09:15
- [GAS TOWN] deacon • patrol • 2025-12-30T08:00

Workers can now press / in /resume picker and search for their address
(e.g., "gastown/crew/max") to see all predecessor sessions.

Note: Respawn-loop agents (deacon/refinery via up.go) skip beacon injection
since Claude restarts multiple times - would need post-restart injection.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 18:01:47 -08:00
Steve Yegge
3099d99424 Set GIT_AUTHOR_NAME per agent session (gt-6r18e.1)
Export GIT_AUTHOR_NAME alongside BD_ACTOR in all agent session startup
locations. This enables git log --author queries for agent work while
keeping GIT_AUTHOR_EMAIL as the workspace owner.

Files updated:
- internal/session/manager.go (polecat sessions)
- internal/daemon/daemon.go (deacon, witness, polecat via daemon)
- internal/daemon/lifecycle.go (polecat lifecycle)
- internal/cmd/*.go (crew, mayor, deacon, witness, refinery, up, handoff)
- internal/session/manager_test.go (updated test expectations)
- docs/federation.md (marked feature as implemented)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 16:14:33 -08:00
Steve Yegge
03775c6fc7 Startup hooks nudge Deacon for GUPP backstop (gt-vdprb.3)
- 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>
2025-12-29 18:05:50 -08:00
Steve Yegge
a4281da60b Merge origin/main 2025-12-28 16:39:26 -08:00
Steve Yegge
5e9ca4c618 Standardize warning output to use style.PrintWarning (gt-g6kor)
- 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>
2025-12-28 16:38:04 -08:00
Steve Yegge
b172fd4787 feat: Add rig infra cycling (witness ↔ refinery)
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>
2025-12-28 16:36:38 -08:00
Steve Yegge
faee888a9f Add town session cycling for mayor/deacon (C-b n/p)
- 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>
2025-12-28 16:00:41 -08:00
Steve Yegge
f90b7d9817 feat: Auto-create patrol hooks for witness/refinery/deacon (gt-qpoxz)
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>
2025-12-28 09:33:17 -08:00
Steve Yegge
34b5a3bb8d Document intentional error suppressions with comments (gt-zn9m)
All 156 instances of _ = error suppression in non-test code now have
explanatory comments documenting why the error is intentionally ignored.

Categories of intentional suppressions:
- non-fatal: session works without these - tmux environment setup
- non-fatal: theming failure does not affect operation - visual styling
- best-effort cleanup - defer cleanup on failure paths
- best-effort notification - mail/notifications that should not block
- best-effort interrupt - graceful shutdown attempts
- crypto/rand.Read only fails on broken system - random ID generation
- output errors non-actionable - fmt.Fprint to io.Writer

This addresses the silent failure and debugging concerns raised in the
issue by making the intentionality explicit in the code.

Generated with Claude Code https://claude.com/claude-code

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 23:14:29 -08:00
Steve Yegge
6f003d85a5 refactor: Remove deprecated gt deacon pending command
The functionality now lives exclusively in gt spawn pending.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 13:55:43 -08:00
Steve Yegge
d3164f72a6 refactor: Move pending spawn tracking to gt spawn pending (hq-466n)
- Moved pending.go from deacon/ to polecat/ package
- Changed storage location from deacon/pending.json to spawn/pending.json
- Added 'gt spawn pending' subcommand for listing/clearing pending spawns
- Deprecated 'gt deacon pending' (still works, shows deprecation notice)

This decouples pending spawn observation from the Deacon role - anyone
can now observe pending polecats (Mayor, humans, debugging, etc.).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 13:50:26 -08:00
Steve Yegge
9afd6c5572 feat: Set BD_ACTOR env var when spawning agents (gt-rhfji)
When gt spawns agents (polecats, crew, patrol roles), it now sets the
BD_ACTOR env var so that bd commands (like `bd hook`) know the agent
identity without coupling to gt.

Updated spawn points:
- gt up (mayor, deacon, witness via ensureSession/ensureWitness)
- gt deacon start
- gt witness start
- gt start refinery
- gt mayor start
- Daemon deacon restart
- Daemon lifecycle restart
- Handoff respawn
- Refinery manager start

BD_ACTOR uses slash format (e.g., gastown/witness, gastown/crew/max)
while GT_ROLE may use dash format internally.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 13:26:38 -08:00
Steve Yegge
4aa58c14da bd sync: 2025-12-25 12:41:08 2025-12-25 12:41:41 -08:00
Steve Yegge
2e8dfcbe75 feat: Add gt deacon trigger-pending command (gt-t5uk)
Implements auto-triggering of polecats after spawn:
- New pending.go in deacon package tracks pending spawns
- CheckInboxForSpawns reads POLECAT_STARTED messages
- TriggerPendingSpawns polls WaitForClaudeReady and nudges when ready
- PruneStalePending removes spawns older than 5 minutes

The Deacon can now call `gt deacon trigger-pending` during patrol to
automatically send "Begin." to newly spawned polecats once Claude is ready.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 12:19:28 -08:00
Steve Yegge
f86a73c2f0 feat: Add gcloud-style command grouping to gt help output
Organize 43 commands into 7 logical groups using cobra's built-in
AddGroup/GroupID feature:

- Work Management: spawn, sling, hook, handoff, done, mol, mq, etc.
- Agent Management: mayor, witness, refinery, deacon, polecat, etc.
- Communication: mail, nudge, broadcast, peek
- Services: daemon, start, stop, up, down, shutdown
- Workspace: rig, crew, init, install, git-init, namepool
- Configuration: account, theme, hooks, issue, completion
- Diagnostics: status, doctor, prime, version, help

Also renamed molecule to mol as the primary command name
(molecule is now an alias).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 02:32:01 -08:00
Steve Yegge
5f2e16f789 refactor: remove shell respawn loops from witness and deacon (gt-zxgu)
Shell loops bypassed the proper lifecycle architecture. Now:

- Witness: Launches Claude directly, daemon/deacon health-scan handles restart
- Deacon: Launches Claude directly, daemon detects exit and restarts
- Daemon: ensureDeaconRunning() now checks if Claude is running (pane cmd)
         and restarts it if session exists but Claude has exited
- gt deacon restart: Now does stop+start instead of Ctrl-C

This enforces proper lifecycle flow through LIFECYCLE mail and daemon
heartbeat rather than bypassing it with shell loops.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 04:02:17 -08:00
Steve Yegge
259d635d67 Fix deacon role detection: start in deacon/ directory
The deacon was being detected as Mayor because it started in ~/gt (town root).
Now starts in ~/gt/deacon/ so gt prime correctly detects RoleDeacon.

Also ensures deacon directory exists on start.
2025-12-22 20:08:28 -08:00
Steve Yegge
e9587bf045 Smart attach: link window when inside tmux
When 'gt X attach' is run from inside a tmux session, link the target
session's window as a new tab instead of switching sessions entirely.
Use C-b n/p to navigate between tabs.

Outside tmux: unchanged behavior (full attach)
Inside tmux: links window as tab for convenient multi-session viewing

- Add tmux.LinkWindow() and tmux.IsInsideTmux()
- Update attachToTmuxSession() with smart detection
- Update mayor, deacon, crew, refinery attach commands
2025-12-22 15:42:37 -08:00
Steve Yegge
1554380228 feat(deacon): improve timing and add heartbeat command
Timing changes for more relaxed poke intervals:
- Daemon heartbeat: 60s → 5 minutes
- Backoff base: 60s → 5 minutes
- Backoff max: 10m → 30 minutes
- Fresh threshold: <2min → <5min
- Stale threshold: 2-5min → 5-15min
- Very stale threshold: >5min → >15min

New command:
- `gt deacon heartbeat [action]` - Touch heartbeat file easily

Template rewrite:
- Clearer wake/sleep model
- Documents wake sources (daemon poke, mail, timer callbacks)
- Simpler rounds with `gt deacon heartbeat` instead of bash echo
- Mentions plugins as optional maintenance tasks
- Explains timer callbacks pattern

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 02:12:21 -08:00
Steve Yegge
348a7d0525 feat(deacon): make deacon the system heartbeat with auto-start
Robustness improvements for the Deacon:

- Add DeaconTheme (purple/silver ecclesiastical theme)
- Apply theme to deacon sessions like mayor/witness
- Daemon now auto-starts deacon if not running
- Daemon pokes deacon instead of directly poking mayor/witnesses
- Deacon is responsible for monitoring mayor and witnesses

The daemon is a "dumb scheduler" that keeps the deacon alive.
The deacon (Claude agent) has the intelligence to understand
context and take remedial action when agents are unhealthy.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 02:00:54 -08:00
Steve Yegge
5102cee9ad feat(cmd): add gt deacon start/stop/status commands (gt-5af.2)
Add CLI commands for managing the Deacon session, following the same
pattern as the Mayor commands:
- gt deacon start: Start the Deacon tmux session
- gt deacon stop: Stop the session with graceful shutdown
- gt deacon status: Check if session is running
- gt deacon attach: Attach to session (auto-starts if needed)
- gt deacon restart: Restart Claude within the session

The Deacon is the hierarchical health-check orchestrator that monitors
Mayor and Witnesses, handles lifecycle requests, and keeps Gas Town running.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 17:25:24 -08:00