Commit Graph

61 Commits

Author SHA1 Message Date
morsov
a16b94ffa8 fix(daemon): Reduce heartbeat from 10 min to 3 min for faster stuck detection (gt-6y5o3)
The 10-minute recovery heartbeat was too slow to detect stuck agents promptly.
Reduced to 3 minutes for better balance between detection speed and overhead.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 20:02:12 -08:00
gastown/polecats/furiosa
278abf15d6 fix(hook): Read hook_bead from database column, not description (gt-7m33w)
The hook discovery code was reading hook_bead from the agent bead's
description field (parsed via ParseAgentFieldsFromDescription), but
the slot update code writes to the hook_bead database column via
'bd slot set'. This mismatch caused polecats to see stale hook values
from the description instead of the current value from the database.

Fixed in:
- molecule_status.go: Use agentBead.HookBead instead of parsing description
- status.go: Use issue.HookBead directly
- lifecycle.go: Update all GUPP and orphan detection to read from
  database columns instead of parsing description

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 17:42:31 -08:00
gastown/polecats/nux
6f1b6269b1 Fix Deacon spin indefinitely bug (hq-oosxt)
- Add heartbeat checking to Boot degraded triage: detects stale Deacon
  heartbeat (>15min nudges, >30min restarts)
- Add checkDeaconHeartbeat to daemon heartbeat cycle as fallback
- This ensures the Deacon is monitored continuously, not just at startup

The mol-deacon-patrol formula was also updated separately to use
gt deacon health-check instead of ephemeral context memory tracking.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 11:47:10 -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/crew/jack
d37bd53a90 Dynamically discover rigs in checkStaleAgents
Instead of hardcoding the rig list (gastown, beads), now loads rigs
from mayor/rigs.json using config.LoadRigsConfig. Falls back gracefully
to just checking global agents if the config cannot be loaded.

(gt-mmp0q)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 23:23:05 -08:00
Steve Yegge
b241a353f3 Clean up stale issue references in comments (gt-z5bri)
- daemon.go: Update gt-2hzl4 comment to past tense (timeout fallback is implemented)
- lifecycle.go: Remove "to be removed" promise for gt-psuw7 (code stays)
- keepalive_test.go: Remove tombstoned gt-gaxo epic reference
- doctor.go: Remove tombstoned gt-gaxo epic reference
- daemon_test.go: Remove tombstoned gt-gaxo epic reference

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 22:29:23 -08:00
gastown/polecats/furiosa
108afdbc52 Remove keepalive file infrastructure for feed-based wake model (gt-vdprb.2)
- Remove TouchTownActivity() calls from root.go PersistentPreRun hook
- Remove ReadTownActivity() and activity-based backoff from daemon.go
- Delete TouchTownActivity/ReadTownActivity functions from keepalive.go
- Replace dynamic backoff with fixed 10-min recovery heartbeat

Normal wake is now handled by feed subscription (bd activity --follow).
The daemon is a safety net for dead sessions, GUPP violations, and orphaned work.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 22:13:14 -08:00
Steve Yegge
2112804aba Implement Boot: daemon entry point dog for Deacon triage (gt-rwd5j)
Boot is a watchdog that the daemon pokes instead of Deacon directly,
centralizing the 'when to wake Deacon' decision in an agent that can
reason about context.

Key changes:
- Add internal/boot package with marker file and status tracking
- Add gt boot commands: status, spawn, triage
- Add mol-boot-triage formula for Boot's triage cycle
- Modify daemon to call ensureBootRunning instead of ensureDeaconRunning
- Add tmux.IsAvailable() for degraded mode detection
- Add boot.md.tmpl role template

Boot lifecycle:
1. Daemon tick spawns Boot (fresh each time)
2. Boot runs triage: observe, decide, act
3. Boot cleans stale handoffs from Deacon inbox
4. Boot exits (or handoffs in non-degraded mode)

In degraded mode (no tmux), Boot runs mechanical triage directly.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 16:20:00 -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
437d42c7fa ZFC #4: Replace daemon identity parsing with agent self-registration
Implements role-based lifecycle configuration where agent types self-register
via role beads instead of hardcoded identity string parsing in the daemon.

Changes:
- Add RoleConfig struct with lifecycle fields (session_pattern, work_dir_pattern,
  needs_pre_sync, start_command, env_vars)
- Add ParseRoleConfig/FormatRoleConfig/ExpandRolePattern to beads package
- Add role bead ID helpers (RoleBeadID, MayorRoleBeadID, etc.)
- Refactor daemon to use single parseIdentity function as ONLY place where
  identity strings are parsed
- Daemon now looks up role beads to get lifecycle config, with fallback to
  defaults when role bead is missing or has no config
- Updated all role beads (mayor, deacon, witness, refinery, crew, polecat)
  with structured lifecycle configuration fields
- Add comprehensive unit tests for RoleConfig parsing and expansion

This makes the daemon ZFC-compliant by trusting what agents self-report in
their role beads rather than encoding agent-specific knowledge in Go code.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 02:13:14 -08:00
Steve Yegge
e72882cdcb Add feed curator to daemon for activity feed curation (gt-38doh)
Implements the feed daemon goroutine that:
- Tails ~/gt/.events.jsonl for raw events
- Filters by visibility tag (keeps feed/both, drops audit)
- Deduplicates repeated done events from same actor
- Aggregates sling events when multiple occur in window
- Writes curated events to ~/gt/.feed.jsonl with summaries

The curator runs as a goroutine in the gt daemon, starting when
the daemon starts and stopping gracefully on shutdown.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 02:12:01 -08:00
Steve Yegge
85ec39c487 fix: Add session health monitoring and auto-restart for crashed polecats (gt-i7wcn)
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>
2025-12-29 22:13:24 -08:00
Steve Yegge
553e29626a Daemon heartbeat becomes recovery-focused (gt-vdprb.4)
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>
2025-12-29 18:10:20 -08:00
Steve Yegge
c92b11d1bd feat: Standardize agent bead naming to prefix-rig-role-name (gt-zvte2)
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>
2025-12-29 14:54:37 -08:00
Steve Yegge
40cb3eb9fc Extract timing constants to constants package (gt-795e8)
Added 6 timing constants:
- ShutdownNotifyDelay (500ms)
- ClaudeStartTimeout (15s)
- ShellReadyTimeout (5s)
- DefaultDebounceMs (100)
- DefaultDisplayMs (5000)
- PollInterval (100ms)

Updated 7 files to use these constants instead of magic numbers.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 17:18:03 -08:00
Steve Yegge
213b3bab20 feat: Add atomic write pattern for state files (gt-wled7)
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>
2025-12-28 15:57:53 -08:00
Steve Yegge
2655a85124 chore: remove issue ID references from comments
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>
2025-12-28 10:05:16 -08:00
Steve Yegge
34f5ef0e93 feat: Wire witness patrol formula to daemon cron (gt-qpoxz)
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>
2025-12-28 02:44:37 -08:00
Steve Yegge
2d6b93f26b fix: Remove PID/tmux state inference (gt-psuw7)
ZFC compliance: daemon becomes pure transport layer, trusting agent beads.

Changes:
- refinery Status(): Simply returns loaded state, no PID/tmux reconciliation
- witness Status(): Simply returns loaded state, no PID inference
- daemon ensureDeaconRunning(): Trusts agent bead state, no tmux fallback
- daemon pokeDeacon(): Trusts agent bead state, no HasSession check

Removed:
- 78 lines of state inference code (PID checks, tmux session parsing)
- "Reconciliation" logic that overwrote agent-reported state

Note: Timeout fallback for dead agents is gt-2hzl4 (separate issue).

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

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 01:56:42 -08:00
Steve Yegge
597c6b8071 Add timeout fallback for dead agents (gt-2hzl4)
- 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>
2025-12-28 01:55:52 -08:00
Steve Yegge
a1715fa91f refactor: Move agent field parsing to shared beads package
- 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>
2025-12-28 01:43:43 -08:00
Steve Yegge
9c47f99767 Daemon reads agent bead state (gt-39ttg)
- 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>
2025-12-28 01:35:29 -08:00
Steve Yegge
fa0dfc324e feat: Add crew session cycling fix and daemon exponential backoff (gt-ws8ol)
- Fix crew next/prev: Pass session name via key binding to avoid run-shell context issue
- Add TouchTownActivity() for town-level activity signaling
- Implement daemon exponential backoff based on activity.json:
  - 0-5 min idle → 5 min heartbeat
  - 5-15 min idle → 10 min heartbeat
  - 15-45 min idle → 30 min heartbeat
  - 45+ min idle → 60 min heartbeat (max)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-26 21:15:08 -08:00
Steve Yegge
a68e5bf95b fix: ignore lifecycle requests older than 6 hours (gt-a41um)
Defense in depth: Even if message deletion fails, stale lifecycle
requests (>6 hours old) are now ignored and deleted without execution.

This prevents ancient LIFECYCLE messages from killing sessions if
they somehow survive in the inbox.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-26 17:52:48 -08:00
Steve Yegge
96ce991bb7 fix: delete LIFECYCLE messages before executing action (gt-a41um)
P0 bug: Crew workers were being killed every 5 minutes due to stale
LIFECYCLE messages from days ago being reprocessed on each heartbeat.

Root cause: closeMessage() was only called after successful action
execution. Failed actions left messages in inbox to be reprocessed.

Fix: "Claim then execute" pattern - delete message FIRST, before
attempting the action. This guarantees stale messages are cleaned up
regardless of action outcome. If a lifecycle action is needed, the
sender must re-request.

Also improved closeMessage() to capture and log actual error output.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-26 17:44:21 -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
39faf79322 Fix polecat auto-start by triggering pending spawns in daemon heartbeat (gt-iu23)
The daemon now calls triggerPendingSpawns() on each heartbeat, which:
- Checks for POLECAT_STARTED messages in Deacon inbox
- Polls pending spawns with WaitForClaudeReady (2s timeout)
- Nudges ready polecats with Begin message
- Prunes stale pending spawns (>5 min old)

This ensures polecats get triggered even when Deacon is not in an
active patrol cycle. Uses bootstrap mode regex detection which
is acceptable for daemon operations.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 22:13:31 -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
b6817899b4 refactor: ZFC cleanup - move Go heuristics to Deacon molecule (gt-gaxo)
Remove Go code that makes workflow decisions. All health checking,
staleness detection, nudging, and escalation belongs in the Deacon
molecule where Claude executes it.

Removed:
- internal/daemon/backoff.go (190 lines) - exponential backoff decisions
- internal/doctor/stale_check.go (284 lines) - staleness detection
- IsFresh/IsStale/IsVeryStale from keepalive.go
- pokeMayor, pokeWitnesses, pokeWitness from daemon.go
- Heartbeat staleness classification from pokeDeacon

Changed:
- Lifecycle parsing now uses structured body (JSON or simple text)
  instead of keyword matching on subject line
- Daemon now only ensures Deacon is running and sends simple heartbeats
- No backoff, no staleness classification, no decision-making

Total: ~800 lines removed from Go code

The Deacon molecule will handle all health checking, nudging, and
escalation. Go is now just a message router.

See gt-gaxo epic for full rationale.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-24 00:11:15 -08:00
Steve Yegge
8d47911623 Fix deacon startup: use ~/gt/deacon dir and export GT_ROLE
The daemon was creating the deacon session in ~/gt (town root) which loaded
the Mayor CLAUDE.md instead of the Deacon CLAUDE.md. Also, tmux SetEnvironment
does not export variables to spawned processes.

Changes:
- Create deacon session in ~/gt/deacon (correct CLAUDE.md)
- Export GT_ROLE=deacon in launch command (process inherits env)
- Apply to both initial launch and restart paths

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 12:39:04 -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
a5a37f5d63 Fix: /handoff regression - use respawn-pane with direct claude command
Three related fixes:

1. lifecycle.go: Use gt mail delete instead of gt mail read to prevent
   lifecycle requests from accumulating.

2. handoff.go: Return exec claude command for respawn-pane instead of
   gt crew at which tries to attach to existing session.

3. handoff.md skill: Work without --cycle and -m flags, send mail separately.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 00:23:40 -08:00
Steve Yegge
c9dcaf0c51 bd sync: 2025-12-22 22:04:04 2025-12-22 22:04:11 -08:00
Steve Yegge
ae513a5db4 Deacon uses wisp-based patrol (gt-3x0z.9)
Daemon changes:
- Remove checkDeaconAttachment() - Deacon self-spawns wisps
- Remove findDeaconPatrolMolecule() - unused
- Remove nudgeDeaconForPatrol() - unused
- Remove DeaconPatrolMolecule const - unused
- Remove beads import - no longer needed

Deacon template changes:
- Update to wisp-based patrol model
- Replace bd mol run with bd mol spawn (wisps by default)
- Remove pinned molecule concept for patrol
- Add Why Wisps section explaining ephemeral design
- Update startup/handoff protocols for wisp-based cycles

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 02:13:24 -08:00
Steve Yegge
5d7291962a Rename ephemeral -> wisp terminology throughout Gas Town
- .beads-ephemeral/ -> .beads-wisp/
- Rename doctor checks: EphemeralCheck -> WispCheck
- Update all docs to use 'transient' for polecats, 'wisp' for molecules
- Preserve 'ephemeral' only as descriptive adjective for wisps
- Steam engine metaphor: wisps are steam vapors that dissipate

Part of Christmas launch wisp terminology unification.
2025-12-22 00:55:31 -08:00
Steve Yegge
8cf15ded35 Add rotating MOTD messages to deacon heartbeat
The deacon patrol role is thankless - it gets a nudge every minute.
This adds rotating motivational and educational tips to make it more fun.
Messages include gratitude, encouragement, and tips about Gas Town.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 00:18:00 -08:00
Steve Yegge
db3fee8088 refactor: add constants package for magic strings
Create internal/constants/constants.go with centralized definitions for:
- Directory names (mayor, polecats, crew, etc.)
- File names (rigs.json, town.json, state.json)
- Git branch names (main, beads-sync)
- Tmux session names (gt-mayor, gt-deacon)
- Agent role names

Add helper functions for common path construction:
- MayorRigsPath(), MayorTownPath(), MayorStatePath()
- RigMayorPath(), RigBeadsPath(), RigPolecatsPath()

Update key files to use the new constants:
- internal/cmd/rig_helpers.go
- internal/cmd/status.go
- internal/daemon/daemon.go

Closes: gt-xnql

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 22:13:21 -08:00
Steve Yegge
107b6bf16b feat(daemon): add attachment detection for Deacon patrol system
Implements gt-rana.2: Daemon attachment detection

- Add Labels field to beads.Issue struct to parse label arrays
- Add attachment APIs: AttachMolecule, DetachMolecule, GetAttachment
- Add helper methods: HasAttachment, IsNaked for checking attachment state
- Add checkDeaconAttachment to daemon heartbeat cycle
- When Deacon's pinned bead is naked (no attached molecule):
  - Find or create mol-deacon-patrol template
  - Instantiate patrol molecule with steps as child issues
  - Attach molecule to Deacon's pinned bead
  - Nudge Deacon to start patrol loop
- Add comprehensive tests for attachment functionality

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 16:15:46 -08:00
Steve Yegge
f4379944a3 Merge polecat/furiosa: fix lifecycle parser order (gt-rixa)
Check restart/shutdown before cycle to avoid matching 'lifecycle:' prefix.
Use ' cycle' (with leading space) for word boundary matching.

Resolved conflict: fixed variable name (title → subject).
2025-12-21 14:14:53 -08:00
Steve Yegge
36d6fc28f3 fix: check restart/shutdown before cycle in lifecycle parser
The parseLifecycleRequest function was checking for "cycle" first,
but since the title already contains "lifecycle:" (which includes
"cycle"), all lifecycle messages matched as cycle actions, making
restart and shutdown unreachable.

Fixed by:
1. Checking restart/shutdown before cycle
2. Using " cycle" (with leading space) to match the word, not prefix

Closes gt-rixa

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 14:08:49 -08:00
Steve Yegge
5ee9bb13c8 fix: replace stale 'bd mail' references with 'gt mail'
- docs/architecture.md: update mail routing explanation
- internal/witness/manager.go: fix actual bd mail calls to gt mail
- internal/cmd/mail.go: remove stale compatibility note
- internal/daemon/lifecycle.go: update comment
2025-12-21 10:44:20 -08:00
Steve Yegge
dbecfe1d38 feat(handoff): route crew lifecycle requests to deacon
Crew workers now use deacon for lifecycle management instead of
requiring manual session termination. When a crew worker runs
'gt handoff', it sends a lifecycle request to the deacon which
handles session kill/restart like it does for Mayor and Witness.

Changes:
- Route crew manager to deacon/ instead of "human"
- Add getCrewIdentity() to extract <rig>-crew-<name> from session
- Include full crew identity in LIFECYCLE subject for daemon parsing
- Remove special case that skipped lifecycle flow for crew

Also fixes pre-existing test failures in daemon/lifecycle_test.go
where BeadsMessage field names were out of sync with the struct.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 01:17:32 -08:00
Steve Yegge
bdbba025f5 fix(daemon): clear requesting_cycle after successful restart
Bug: When daemon cycled a session, it verified requesting_cycle=true
but never cleared the flag after restart. This caused infinite
cycle loops on each heartbeat.

Also removed redundant SendKeysDelayed("gt prime") that injected
rogue text into terminal (SessionStart hook already handles priming).

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 01:14:20 -08:00
Steve Yegge
c4892938d0 fix(daemon): use gt mail instead of bd mail for lifecycle requests
The handoff command sends lifecycle requests via 'gt mail send' to
town-level beads, but the daemon was reading with 'bd mail inbox'
which reads from the local beads database. This fixes the mismatch.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 00:47:05 -08:00
Steve Yegge
e5c88ae9d4 feat(lifecycle): immediate daemon notification via SIGUSR1
- daemon.go: Add SIGUSR1 handler to process lifecycle requests immediately
- handoff.go: Signal daemon after sending lifecycle mail to deacon/
- mail.go: Show message IDs in hook output for direct reading

Previously, gt handoff would wait up to 5 min for daemon heartbeat poll.
Now lifecycle requests are processed within milliseconds.

Closes gt-zut3

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 20:28:36 -08:00
Steve Yegge
a9d204aa22 feat(daemon): add lifecycle support for refinery and crew
- Add refinery and crew patterns to identityToSession()
- Add refinery and crew handling to restartSession() with pre-sync
- Add refinery and crew to identityToStateFile()
- Fix gt refinery start to send gt prime after Claude starts
- New syncWorkspace() helper for agents with persistent clones
2025-12-20 17:42:21 -08:00
Steve Yegge
d2fccd580c feat(daemon): Add slot-based notification deduplication (gt-wpg)
Implement replaceable notifications to prevent heartbeat stacking when
agents are busy. Only the latest notification per slot is delivered.

Changes:
- Add NotificationManager for tracking pending notifications
- Add SendKeysReplace() that clears input line before sending
- Integrate slot tracking into daemon heartbeat pokes
- Mark notifications consumed when agent shows activity

The system tracks pending notifications in state files and skips
sending if a notification for the same slot is still pending.
When agent activity is detected (keepalive), slots are marked
consumed allowing new notifications to be sent.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:19:40 -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
23cf29df9c Merge remote-tracking branch 'origin/polecat/Slit'
# Conflicts:
#	internal/daemon/lifecycle_test.go
#	internal/refinery/engineer.go
2025-12-19 18:27:12 -08:00