Add t.Parallel() calls across config and rig test files to enable
concurrent test execution and faster test runs.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add three new flags to gt prime command:
- --state: Output role state as JSON and exit early (for scripting)
- --dry-run: Skip side effects (persistence, locks, events)
- --explain: Show verbose role detection reasoning
The --state flag is mutually exclusive with all other flags and errors
if combined. The other flags (--dry-run, --explain, --hook) can be
combined freely.
Also fixes missing filepath import in beads.go.
Closes: bd-t8ven
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The AGENTS.md file at rig level (e.g., gastown/AGENTS.md) should be a thin
bootstrap pointer (<20 lines), not full context. This adds a check in
checkRigPriming() to flag large AGENTS.md files, similar to how CLAUDE.md
is checked in checkAgentPriming().
Also fixes missing filepath import in beads.go that was breaking the build.
Closes: bd-mfrs6
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
detectSessionState() and checkSlungWork() both contained identical
logic for finding hooked/in_progress beads assigned to an agent.
Extracted this into findHookedBead() helper function.
Also includes priming subsystem improvements from mayor:
- Add --dry-run flag for testing without side effects
- Add --state flag to output detected state only
- Add --explain flag to show why sections are included
- Add missing filepath import to beads.go
Fixes: bd-hvwnb
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 1 of dynamic priming subsystem:
1. PRIME.md provisioning for all workers (hq-5z76w, hq-ukjrr Part A)
- Added ProvisionPrimeMD to beads package with Gas Town context template
- Provision at rig level in AddRig() so all workers inherit it
- Added fallback provisioning in crew and polecat managers
- Created PRIME.md for existing rigs
2. Post-handoff detection to prevent handoff loop bug (hq-ukjrr Part B)
- Added FileHandoffMarker constant (.runtime/handoff_to_successor)
- gt handoff writes marker before respawn
- gt prime detects marker and outputs "HANDOFF COMPLETE" warning
- Marker cleared after detection to prevent duplicate warnings
3. Priming health checks for gt doctor (hq-5scnt)
- New priming_check.go validates priming subsystem configuration
- Checks: SessionStart hook, gt prime command, PRIME.md presence
- Warns if CLAUDE.md is too large (should be bootstrap pointer)
- Fixable: provisions missing PRIME.md files
This ensures crew workers get Gas Town context (GUPP, hooks, propulsion)
even if the gt prime hook fails, via bd prime fallback.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When `gt formula run` fell back to the default "gastown" rig (because no
rig could be detected), it didn't set rigPath, which meant the default
formula lookup would fail. Now rigPath is properly constructed when we
have townRoot but can't detect a current rig.
Also adds tests for GetDefaultFormula helper.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Allow `gt formula run` to be called without a formula name by configuring
a default in the rig's settings/config.json under workflow.default_formula.
Co-authored-by: Brett VanderVeen <brett.vanderveen@gfs.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
When a session starts via handoff, the nudge message now includes
clear instructions to check hook and mail. This prevents agent
confusion when SessionStart hooks haven't loaded CLAUDE.md yet.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Import beads' UX design system into gastown:
- Add internal/ui/ package with Ayu theme colors and semantic styling
- styles.go: AdaptiveColor definitions for light/dark mode
- terminal.go: TTY detection, NO_COLOR/CLICOLOR support
- markdown.go: Glamour rendering with agent mode bypass
- pager.go: Smart paging with GT_PAGER support
- Add colorized help output (internal/cmd/help.go)
- Group headers in accent color
- Command names styled for scannability
- Flag types and defaults muted
- Add gt thanks command (internal/cmd/thanks.go)
- Contributor display with same logic as bd thanks
- Styled with Ayu theme colors
- Update gt doctor to match bd doctor UX
- Category grouping (Core, Infrastructure, Rig, Patrol, etc.)
- Semantic icons (✓ ⚠ ✖) with Ayu colors
- Tree connectors for detail lines
- Summary line with pass/warn/fail counts
- Warnings section at end with numbered issues
- Migrate existing styles to use ui package
- internal/style/style.go uses ui.ColorPass etc.
- internal/tui/feed/styles.go uses ui package colors
Co-Authored-By: SageOx <ox@sageox.ai>
hq-hcil1: Remove deprecated HasConflict/HasAuthFailure/IsNotARepo/HasRebaseConflict
methods that violated ZFC by having Go code decide error types based on stderr parsing.
Changes:
- Remove deprecated helper methods from GitError and SwarmGitError
- Export GetConflictingFiles() which uses git porcelain output (diff --diff-filter=U)
- Update CheckConflicts(), engineer.go, and integration.go to use GetConflictingFiles()
- Update tests to verify raw stderr is available for agent observation
ZFC principle: Go code transports raw output to agents; agents observe and decide.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Apply ZFC (Zero Forge Cache) principle across git error handling and
feed curation. Agents now observe raw git output and make their own
decisions rather than relying on pre-interpreted error types.
- Add GitError type with raw stdout/stderr for observation
- Add SwarmGitError following the same pattern
- Remove in-memory deduplication maps from Curator
- Curator now reads state from feed/events files
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Removed the pending.json file that shadowed observable state. Now
discovers pending spawns directly from POLECAT_STARTED messages in
the Deacon's inbox.
Changes:
- CheckInboxForSpawns: Discovers from mail, no more LoadPending/SavePending
- TriggerPendingSpawns: Archives mail after successful trigger
- PruneStalePending: Archives old messages instead of pruning from JSON
The mail system is now the source of truth for pending spawns.
Closes: hq-i31f7
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
hq-u0ach: done.go - Add --cleanup-status flag so agents can pass cleanup
status directly. Removes computeCleanupStatus() which violated ZFC by
having Go compute cleanup status from git state.
hq-z0zqw: beads.go - Remove strings.Contains parsing for ErrNotARepo and
ErrSyncConflict. Per ZFC, Go should transport errors to agents, not parse
them to make decisions. IsBeadsRepo() now uses file existence check.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a bead is closed externally via bd close, it could remain on
an agent's hook, causing confusion when running gt hook. Now
gt hook detects closed beads and shows a warning message with
instructions to clear the hook using gt unsling.
Closes: gt-8w0r6
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The gt hook command wasn't finding hooked beads for town-level roles
(mayor, deacon) because of an identity format mismatch:
- When hooking a bead, resolveSelfTarget() sets assignee with trailing
slash (e.g., "mayor/")
- When querying, buildAgentIdentity() returned without slash ("mayor")
This caused the assignee filter to miss the hooked bead since bd does
exact matching on the assignee field.
Fix:
- Update buildAgentIdentity() to return "mayor/" and "deacon/" with
trailing slash, matching the format used when setting assignee
- Update isTownLevelRole() to accept both formats for compatibility
Fixes: gt-g6ng2
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Two fixes in this commit:
1. daemon/lifecycle.go: Fix agent bead ID pattern for GUPP/orphaned work checks
- Wrong: gt-polecat-<rig>-<name> (e.g., gt-polecat-gastown-nux)
- Correct: <prefix>-<rig>-polecat-<name> (e.g., gt-gastown-polecat-nux)
- Use config.GetRigPrefix() instead of hardcoding gt prefix
- Use beads.ParseAgentBeadID() in extractRigFromAgentID
2. beads/beads.go: Fix invalid --add-label flag in bd create calls
- bd create uses --labels, not --add-label
- bd update uses --add-label (unchanged, was correct)
- Fixed Create, CreateWithID, CreateAgentBead, CreateRigBead
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Two ZFC fixes:
1. Boot marker file (hq-zee5n): Changed IsRunning() to query
tmux.HasSession() directly instead of checking marker file
freshness with TTL. Removed stale marker check from doctor.
2. Branch pattern matching (hq-zwuh6): Replaced hardcoded "polecat/"
strings with constants.BranchPolecatPrefix for consistency.
Also removed 60-second WaitForCommand blocking from crew Start()
which was causing gt crew start to hang.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Per ZFC principle: 'Let agents decide thresholds. Stuck is a judgment call.'
Changes:
- Add health check threshold fields to RoleConfig (ping_timeout,
consecutive_failures, kill_cooldown, stuck_threshold)
- Add LoadStuckConfig() to read thresholds from hq-deacon-role bead
- Update patrol_check.go to use configurable stuck threshold
- Defaults remain as fallbacks when no role bead config exists
Agents can now configure their stuck detection by adding fields to their
role bead, e.g.:
ping_timeout: 45s
consecutive_failures: 5
kill_cooldown: 10m
stuck_threshold: 2h
Fixes: hq-2355b
Replace ProcessExists() checks in witness and refinery managers with
tmux session detection. Agent liveness should be derived from tmux
session state, not PID probing (per ZFC tracking principles).
- Remove util.ProcessExists() from witness/manager.go and refinery/manager.go
- Delete internal/util/process.go and process_test.go (now unused)
- Foreground mode and Stop() now rely solely on tmux HasSession/KillSession
Closes: hq-yxkdr (recentDeaths already removed)
Closes: hq-1sd4o (ProcessExists removed)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extends the --agent flag with a more general --env flag that allows
setting arbitrary environment variables when starting a witness.
Precedence (highest to lowest):
1. CLI --env overrides
2. Role bead env_vars
3. config.AgentEnv() defaults
Examples:
gt witness start greenplace --env ANTHROPIC_MODEL=claude-3-haiku
gt witness restart greenplace --env DEBUG=1 --env VERBOSE=true
Co-authored-by: joshuavial <git@codewithjv.com>
Introduces config.AgentEnv() as the single source of truth for all agent
environment variables. Previously, different roles received different subsets
of variables depending on their startup path.
Changes:
- All agents now receive GT_ROOT and BEADS_DIR (previously only polecat/refinery)
- Add gt doctor env-vars check to validate tmux session variables
- Fix gt role home witness returning incorrect path
- Fix BEADS_DIR not following redirects for repos with tracked beads
Co-authored-by: julianknutsen <julianknutsen@users.noreply.github.com>
Update docs to reflect the centralized config.AgentEnv() function and
complete environment variable coverage:
reference.md:
- Restructured env vars section with tables by category
- Added GT_ROOT, GT_CREW, BEADS_AGENT_NAME documentation
- Added "Environment by Role" quick reference table
- Added doctor check documentation for env-vars validation
identity.md:
- Updated Environment Setup section with complete examples
- Added crew environment example showing BEADS_NO_DAEMON
- Mentioned centralized config.AgentEnv() function
- Cross-referenced to reference.md for full details
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The env-vars check was using AgentEnvSimple which doesn't know the
actual TownRoot and BeadsDir paths. This could cause false positive
mismatches when comparing expected (empty paths) vs actual (real paths).
- Use config.AgentEnv with proper TownRoot and BeadsDir from CheckContext
- Rig-level roles resolve beads dir from rig path
- Update tests to use expectedEnv helper that generates full env vars
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Complete test coverage for all roles in the centralized AgentEnv
function:
- TestAgentEnv_Deacon: verifies deacon env vars (GT_ROLE, BD_ACTOR,
GIT_AUTHOR_NAME)
- TestAgentEnv_Boot: verifies boot env vars including BD_ACTOR=deacon-boot
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
spawnDegraded was manually constructing env vars, missing GT_ROOT,
BEADS_DIR, and GIT_AUTHOR_NAME that spawnTmux sets via config.AgentEnv().
Now both paths use the same centralized env var generation for
consistency.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The env-vars doctor check was skipping deacon with a stale comment
"it doesn't use standard env vars". After the AgentEnv refactor,
deacon/manager.go now uses config.AgentEnv() like all other roles.
- Remove the skip condition for deacon in env_check.go
- Update test from TestEnvVarsCheck_DeaconSkipped to test deacon is
actually checked (TestEnvVarsCheck_DeaconCorrect/DeaconMissing)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tests for AgentEnv(), ExportPrefix(), BuildStartupCommandWithEnv(),
and helper functions (MergeEnv, FilterEnv, WithoutEnv, EnvToSlice).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Crew workspaces use clones with redirected beads directories, like
polecat and refinery. They should bypass the bd daemon for fresh
data and isolation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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>
Adds a new `gt doctor` check that verifies tmux session environment
variables match expected values from `config.RoleEnvVars()`.
- Checks all Gas Town sessions (gt-*, hq-*)
- Compares actual tmux env vars against expected for each role
- Reports mismatches with guidance to restart sessions
- Treats no sessions as success (valid when Gas Town is down)
- Skips deacon (doesn't use standard env vars)
Also:
- Adds `tmux.GetAllEnvironment()` to retrieve all session env vars
- Removes redundant gtroot_check (env-vars check covers GT_ROOT)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, polecat startup used hardcoded paths for BEADS_DIR that
didn't follow redirects for repos with tracked beads. This meant
polecats working in worktrees (where .beads/redirect points to the
actual beads location) would use the wrong beads directory.
Fixed locations:
- daemon.go: polecat startup now uses ResolveBeadsDir
- polecat/session_manager.go: session startup now uses ResolveBeadsDir
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Consolidates all role startup code to use the shared RoleEnvVars()
function, ensuring consistent env vars across tmux SetEnvironment
and Claude startup command exports.
Updated:
- Mayor manager
- Deacon startup (daemon.go)
- Witness manager
- Refinery manager
- Polecat startup (daemon.go)
- BuildPolecatStartupCommand, BuildCrewStartupCommand helpers
This ensures all agents receive the same identity env vars regardless
of startup path.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Introduces config.RoleEnvVars() as the single source of truth for role
identity environment variables (GT_ROLE, GT_RIG, BD_ACTOR, etc.).
CLI improvements:
- Fix getRoleHome paths (witness has no /rig suffix, polecat/crew do)
- Make gt role env read-only (displays current role from env/cwd)
- Add EnvIncomplete handling: fill missing env vars from cwd with warning
- Add cwd mismatch warnings when not in role home directory
- gt role home now validates --polecat requires --rig
Includes comprehensive e2e tests for all role detection scenarios.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Start crew members concurrently instead of sequentially. Previously,
`gt crew start --all` could hang for minutes because each crew member
was started one at a time, with each waiting up to 60 seconds for
Claude to initialize.
With parallel startup, all crew members start simultaneously and
the total wait time is bounded by the slowest individual startup.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add detection for when the installed gt binary is out of date with the
source repository. This helps catch issues where commands fail mysteriously
because the installed binary doesn't have recent fixes.
Changes:
- Add internal/version package with stale binary detection logic
- Add startup warning in PersistentPreRunE when binary is stale
- Add gt doctor check for stale-binary
- Use prefix matching for commit comparison (handles short vs full hash)
The warning is non-blocking and only shows once per shell session via
the GT_STALE_WARNED environment variable.
Resolves: gt-ud912
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When routing-based verification (verifyBeadExists) fails due to
routes.jsonl configuration issues, gt sling now falls back to pattern
matching via looksLikeBeadID to accept valid bead ID formats.
The fix ensures:
1. verifyBeadExists is tried first (routing-based lookup)
2. verifyFormulaExists is tried second (formula check)
3. looksLikeBeadID pattern match is used as final fallback
Also improved looksLikeBeadID to accept any 1-5 letter lowercase
prefix followed by hyphen and alphanumeric chars.
Fixes: gt sling bd-xxx failing with "not a valid bead or formula"
when the bead exists but routing cannot find it.
Closes: gt-9e8s5
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Deacon patrol formula now uses `gt mol step await-signal` with
exponential backoff instead of vague "sleep 60s" instructions.
How it works:
- Subscribes to `bd activity --follow` (beads activity feed)
- Returns IMMEDIATELY when any gt/bd command triggers activity
- On timeout, waits exponentially longer: 60s → 120s → 240s → max 10m
- Tracks idle:N label on hq-deacon bead across invocations
This connects the designed-but-unintegrated backoff mechanism to the
actual patrol loop. Idle towns let Deacon sleep; active work wakes it.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Coordination section with gt nudge command
- Clarify line 180: routine nudging is Witness job, Mayor can nudge stuck refinery/witness
- Add warning to NEVER use tmux send-keys (drops Enter key)
- Includes liftoff test timestamp in manager.go
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add three layers of protection to prevent accidental branch switches in
the town root (~/gt), which should always stay on main:
1. Doctor check `town-root-branch`: Verifies town root is on main/master.
Fixable via `gt doctor --fix` to switch back to main.
2. Doctor check `pre-checkout-hook`: Verifies git pre-checkout hook is
installed. The hook blocks checkout from main to any other branch.
Fixable via `gt doctor --fix` or `gt git-init`.
3. Runtime warning in all gt commands: Non-blocking warning if town root
is on wrong branch, with fix instructions.
The root cause of this issue was git commands running in the wrong
directory, switching the town root to a polecat branch. This broke gt
commands because rigs.json and other configs were on main, not the
polecat branch.
Closes: hq-1kwuj
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive crash logging improvements to help diagnose mass session death events:
- Add TypeSessionDeath and TypeMassDeath event types for feed visibility
- Log pre-death events before killing sessions (who killed, why)
- Add mass death detection in daemon (3+ deaths in 30s triggers alert)
- Add macOS crash report check in gt doctor
- Support session death events in townlog and feed curator
Closes hq-kt1o6
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use ResolveBeadsDir() to find beads.db in multi-worktree setups
where .beads/redirect points to the canonical beads location
- Add --allow-stale flag to bd sync command to handle cases where
the daemon is actively writing and staleness check would fail
Fixes hq-0cgd3
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This file was added with -f despite .claude/ being in .gitignore.
When the repo is used as a crew workspace, this file shadows the
proper crew-level settings at crew/.claude/settings.json.
Removing it allows Claude Code to find the correct settings by
walking up the directory tree.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add BeadsCustomTypes constant ("agent,role,rig,convoy,slot") to avoid
hardcoded strings scattered across the codebase
- Add CustomTypesCheck to gt doctor that verifies Gas Town custom types
are registered with beads, with --fix support
- Register custom types during gt init (best-effort, skips if no beads)
- Update install.go, rig_check.go, and rig/manager.go to use the constant
This ensures consistent type registration across all code paths and
catches misconfigured beads databases via gt doctor.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Agents were confused when receiving "gt prime" as their first prompt,
interpreting it as a command to investigate rather than understanding
they were starting a Gas Town session.
Changed crew_at.go, start.go, and handoff.go to use FormatStartupNudge()
which produces a proper beacon like:
[GAS TOWN] george/crew/george <- human • 2026-01-09T10:30 • start
The SessionStart hook (gt prime --hook) still injects context - the
prompt just needs to be something agents recognize as a greeting.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Refinery was using rig.Path which found the town's .git with rig-named
remotes (e.g., 'gastown') instead of 'origin'. This caused refinery to
miss polecat branches when fetching.
Now falls back to mayor/rig (which has 'origin' pointing to the project
repo) when refinery/rig doesn't exist.
Fixes: hq-uvrzt
gt shutdown was not stopping the daemon, which caused it to restart
agents (witnesses, refineries) after shutdown completed. The daemon
heartbeats every 3 minutes and calls ensureWitnessesRunning() and
ensureRefineriesRunning(), which would notice the sessions were dead
and restart them.
This adds daemon stop logic to both runGracefulShutdown (as Phase 6)
and runImmediateShutdown (after polecat cleanup), matching the behavior
that gt down already has.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds the missing github-gate-check step that runs `bd gate discover` and
`bd gate check --type=gh` to evaluate GitHub CI gates. Updates
dispatch-gated-molecules to depend on both gate-evaluation and
github-gate-check.
Fixes: gt-sfxpr
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enterprise teams can now customize integration branch names to match
their conventions (e.g., username/TICKET-123/feature-name).
- Add integration_branch_template to MergeQueueConfig
- Add --branch CLI override for gt mq integration create
- Support {epic}, {prefix}, {user} template variables
- Validate branch names for git-safe characters
- Store actual branch name in epic metadata at create time
- Read stored branch name in land/status (fallback for old epics)
Also fixes unrelated build error in polecat/manager.go (polecatPath
variable was undefined).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add --verbose/-v flag to gt costs command that outputs debug information
when silent failures occur during cost tracking operations:
- wisp list failures in querySessionCostWisps and deleteSessionCostWisps
- bd show failures when querying wisp details
- JSON unmarshal failures when parsing wisp/event data
- payload unmarshal failures when parsing session payloads
This makes debugging cost tracking issues much easier as these error
paths previously continued silently without any indication of failure.
Closes: bd-qv8f9
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Sort map keys before iteration in createCostDigestBead for deterministic
output ordering in By Role and By Rig sections (bd-66z6a)
- Batch wisp IDs into single bd show call to fix N+1 query pattern in
querySessionCostWisps (bd-3hqvs)
- Batch wisp deletion into single subprocess call in deleteSessionCostWisps
(bd-i8zab)
Part of: bd-1wmwp
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Agent sessions would fail on startup because send-keys arrived before the
shell was ready, causing 'bad pattern' and 'command not found' errors.
Fix: Create sessions with the command directly using tmux new-session's
command argument. This runs the agent as the pane's initial process,
avoiding shell readiness timing issues entirely.
Updated all agent managers: mayor, deacon, witness, refinery, polecat, crew.
Also fixes pre-existing build error in polecat/manager.go (polecatPath →
clonePath/newClonePath).
Closes#280
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Bare clones don't have remote.origin.fetch set by default, which breaks
worktrees that need to fetch and see origin/* refs. This caused refinery
to fail because origin/main never appeared after fetch.
- Add configureRefspec() to set standard refspec on bare repos
- Call from CloneBare() and CloneBareWithReference()
- Add BareRepoRefspecCheck to doctor for existing rigs
Closes#286
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changes polecat worktree structure from:
polecats/<name>/
to:
polecats/<name>/<rigname>/
This gives Claude Code agents a recognizable directory name (e.g., tidepool/)
in their cwd instead of just the polecat name, preventing confusion about
which repo they are working in.
Key changes:
- Add clonePath() method to manager.go and session_manager.go for the actual
git worktree path, keeping polecatDir() for existence checks
- Update Add(), RepairWorktree(), Remove() to use new structure
- Update daemon lifecycle and restart code for new paths
- Update witness handlers to detect both structures
- Update doctor checks (rig_check, branch_check, config_check,
claude_settings_check) for backward compatibility
- All code includes fallback to old structure for existing polecats
Fixes#283
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds EnableMouseMode() and calls it from ConfigureGasTownSession so all
new GT sessions get mouse support. Users can now click panes, scroll with
mouse wheel, and resize by dragging. Hold Shift for terminal text selection.
Closes#33
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds support for alternative AI runtime backends (Codex, OpenCode) alongside
the default Claude backend through a runtime abstraction layer.
- internal/runtime/runtime.go - Runtime-agnostic helper functions
- Extended RuntimeConfig with provider-specific settings
- internal/opencode/ for OpenCode plugin support
- Updated session managers to use runtime abstraction
- Removed unused ensureXxxSession functions
- Fixed daemon.go indentation, updated terminology to runtime
Backward compatible: Claude remains default runtime.
Co-Authored-By: Ben Kraus <ben@cinematicsoftware.com>
Co-Authored-By: Cameron Palmer <cameronmpalmer@users.noreply.github.com>
* feat(costs): redesign session cost tracking with wisps and daily digests
Implement the wisp-based cost tracking architecture per gt-cm900:
- gt costs record now creates ephemeral wisps (not exported to JSONL)
to avoid log-in-database pollution with O(sessions/day) events
- gt costs digest aggregates yesterday's session wisps into a single
permanent "Cost Report YYYY-MM-DD" bead for audit purposes
- gt costs query updated: --today queries wisps, --week queries
digest beads + today's wisps
- gt costs migrate closes legacy open session.ended beads
- Deacon patrol formula updated with costs-digest step
The new architecture:
Session ends -> Wisp (fast, N/day) -> Patrol digest -> Bead (1/day)
This preserves audit trail while keeping issues.jsonl clean.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: sync canonical formula with embedded copy
Update .beads/formulas/ with the costs-digest step added to
mol-deacon-patrol.formula.toml. The go:generate copies from
.beads/formulas/ to internal/formula/formulas/.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Remove unused ensureRefinerySession function from start.go
- Remove unused ensureSession and ensureWitness functions from up.go
- Remove unused ensureWitnessSession function from witness.go
- Remove orphaned imports (runtime, session, constants, config, rig, filepath, time)
- Fix indentation error in daemon.go triggerPendingSpawns comment
These functions were added as part of the Codex/OpenCode runtime support
but were never wired up. The existing managers (refinery.Manager.Start,
witness.Manager.Start) already handle session creation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Polecats were creating GitHub PRs instead of using gt done to submit
to the Refinery. Added clear conditional language:
- If repo is steveyegge/beads or steveyegge/gastown: NEVER create PRs
- Polecats use gt done → Refinery merges
- Crew workers push directly to main
- PRs are for external contributors only
This fixes a prompting gap that led to PR #292 being created incorrectly.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When upgrading gt on an existing installation without .installed.json,
formulas that exist but don't match embedded were incorrectly marked as
"modified" (implying user customization). Now they're marked "untracked"
and are safe to update since there's no record of user modification.
This improves the upgrade experience:
- "modified" = tracked file user changed (skip update)
- "untracked" = file exists but not tracked (safe to update)
Adds 3 new tests for untracked scenarios.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds infrastructure to automatically update embedded formulas when
the binary is upgraded, while preserving user customizations.
Changes:
- Add CheckFormulaHealth() to detect outdated/modified/missing formulas
- Add UpdateFormulas() to safely update formulas via gt doctor --fix
- Track installed formula checksums in .beads/formulas/.installed.json
- Add FormulaCheck to gt doctor with auto-fix capability
- Compute checksums at runtime from embedded files (no build-time manifest)
Update scenarios:
- Outdated (embedded changed, user unchanged): Update automatically
- Modified (user customized): Skip with warning
- Missing (user deleted): Reinstall with message
- New (never installed): Install
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Two improvements:
1. gt crew start now infers rig from cwd when first arg is not a valid
rig name (gt-czltv). Previously, running `gt crew start bob` from
within a rig directory would fail because "bob" was treated as the
rig name. Now it checks if the arg is a valid rig first.
2. Refactored copyOverlay to shared rig.CopyOverlay utility:
- Eliminates code duplication between crew and polecat managers
- Preserves source file permissions instead of hardcoding 0644
- Follows PR #278 improvements
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds a visible "CRITICAL" warning and pre-submission checklist to the
polecat template. Explicitly notes that polecats should NOT manually
close the root issue - the Refinery handles that after merge.
This addresses the intent of PR #287 while avoiding the conflicting
`bd close` instruction that would break the Refinery workflow.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add new step to mol-deacon-patrol.formula.toml that discovers molecules
blocked on gates that have now closed, and dispatches them to the
appropriate rig's polecat pool.
This completes the async resume cycle without explicit waiter tracking.
The molecule state IS the waiter - patrol discovers reality each cycle.
- Uses bd mol ready --gated to find gate-ready molecules
- Dispatches via gt sling <mol-id> <rig>/polecats
- Runs after gate-evaluation, before health-scan
- Bumps formula version to 6
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When rig/.beads doesn't exist, fall back to mayor/rig/.beads (tracked
beads architecture) with a warning suggesting 'bd doctor' to fix.
This restores behavior that was inadvertently removed in #290, which
simplified SetupRedirect but removed the fallback path.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace the hand-rolled contains() function with the standard library
strings.Contains(). Also removes the redundant len(data) > 0 check
since strings.Contains handles empty strings correctly.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The t.Skipf call had a raw newline inside a double-quoted string,
which is invalid Go syntax. Use \n escape sequence instead.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The SessionHookCheck was incorrectly flagging 'gt prime --hook' as invalid,
only accepting 'session-start.sh' wrapper. The --hook flag properly handles
session_id passthrough via stdin JSON, making it a valid alternative.
Changes:
- Update usesSessionStartScript to accept --hook flag
- Add containsFlag helper to prevent false positives (e.g., --hookup)
- Update error messages and fix hints to suggest both options
- Add comprehensive tests including edge cases
Tests cover:
- Bare gt prime (fails)
- gt prime --hook (passes)
- gt prime --hookup (fails - not a valid flag)
- gt prime --verbose --hook (passes - flag order doesn't matter)
- session-start.sh (passes)
- Mixed valid/invalid hooks in same file
- Town-level and rig-level settings
- Add custom types config after bd init in daemon tests
- Replace fixed sleeps with poll-based waiting in tmux tests
- Skip beads integration test for JSONL-only repos
Fixes flaky test failures in parallel execution.
Adds RigBeadsCheck to gt doctor to verify rig identity beads exist.
These beads track rig metadata (git URL, prefix, state) and are created
by gt rig add. The check scans routes.jsonl and verifies each rig
has an identity bead, with --fix to create missing ones.
Recovered from furiosa's uncommitted work after worker interruption.
Co-Authored-By: furiosa <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add overlay directory support to automatically copy gitignored files
(like .env, config files) from <rig>/.runtime/overlay/ to polecat
and crew worktree roots when they are spawned.
This allows services started by polecats/crew to have their required
configuration files at the root without committing them to git.
Changes:
- Add copyOverlay() function to polecat and crew managers
- Call copyOverlay() after setupSharedBeads() in AddWithOptions/RepairWorktreeWithOptions
- Non-fatal: overlay copy failures only log warnings, don't block spawn
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Claude Code can report its pane command as "node", "claude", or a version
number like "2.0.76". Previously only "node" was detected, causing healthy
sessions to be incorrectly identified as zombies and killed during daemon
heartbeat recovery.
This fix detects all three patterns to prevent witness sessions from being
killed every 3 minutes.
Based on michaellady's work in PR #174.
Co-Authored-By: michaellady <michaellady@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The orphan-processes check previously killed any Claude process without
a tmux ancestor, which incorrectly targeted user's personal Claude
sessions running in regular terminals.
Now the check is informational only:
- Changed from FixableCheck to BaseCheck (no auto-fix)
- Returns StatusOK with details listing processes outside tmux
- Message advises user to verify processes are expected
- Removed Fix method and related helpers
The orphan-sessions check remains fixable since it only targets gt-*
sessions that don't match valid Gas Town patterns.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The heartbeat now explicitly calls ensureDeaconRunning() for basic
"is Deacon alive" checks, while Boot handles intelligent triage
(stuck/nudge/interrupt decisions).
Changed ensureDeaconRunning to use deacon.Manager.Start() instead of
duplicating startup logic. This gives daemon the same benefits:
- WaitForShellReady (fixes race condition)
- Claude settings setup
- Theming
- StartupNudge and PropulsionNudge (GUPP)
Heartbeat order:
1. ensureDeaconRunning - restart if dead (via Manager)
2. ensureBootRunning - intelligent triage for stuck states
3. checkDeaconHeartbeat - belt-and-suspenders fallback
4-11. Other checks (witnesses, refineries, polecats, etc.)
This was inadvertently removed when Boot was introduced, which
delegated all Deacon checks to Boot. But Boot's mol doesn't actually
restart Deacon - it just reports. Now responsibilities are clear:
daemon ensures alive, Boot ensures responsive.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The deacon tmux session is named hq-deacon, not gt-deacon. Fix the
incorrect references in mol-boot-triage and mol-gastown-boot formulas.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The formula parser only supports TOML (uses toml.Decode). The JSON
version of mol-gastown-boot was never used - it was likely created
by mistake or for an abandoned experiment.
Changes:
- Remove .beads/formulas/mol-gastown-boot.formula.json
- Remove internal/formula/formulas/mol-gastown-boot.formula.json
- Simplify go:generate to only copy .formula.toml files
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously GT_ROOT was documented as a formula search path but never
actually set, making $GT_ROOT/.beads/formulas/ unreachable for agents.
Now BuildStartupCommand automatically sets GT_ROOT to the town root,
enabling all agents (witness, refinery, polecat, crew, etc.) to find
town-level formulas without relying on cwd-relative paths.
Also adds a doctor check (gt-root-env) that warns when existing sessions
are missing GT_ROOT, with instructions to restart sessions.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The SetupRedirect function was failing for rigs that use the tracked
beads architecture where the canonical beads location is mayor/rig/.beads
and there is no rig-level .beads directory.
This fix now checks for both locations:
1. rig/.beads (with optional redirect to mayor/rig/.beads)
2. mayor/rig/.beads directly (if no rig/.beads exists)
This ensures crew and polecat workspaces get the correct redirect file
pointing to the shared beads database in all configurations.
Closes: gt-jy77g
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds the ability to switch between Claude Code accounts with a single command:
gt account switch <handle>
The command:
1. Detects current account by checking ~/.claude symlink target
2. If ~/.claude is a real directory, moves it to the current account config_dir
3. Removes existing ~/.claude symlink (if any)
4. Creates symlink from ~/.claude to target account config_dir
5. Updates default account in accounts.json
6. Prints confirmation with restart reminder
Handles edge cases:
- Already on target account (no-op with message)
- Target account does not exist (error with list of valid accounts)
- ~/.claude is real directory (first-time setup scenario)
Closes gt-jd8m1
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add explicit handoff/cycling heuristics for the Witness role:
- Hand off after 15 patrol loops (vs Deacon's 20)
- Immediate handoff after extraordinary actions
- Define extraordinary actions specific to Witness role
- Add Handoff (Wisp-Based) section explaining idempotent patrols
This brings Witness documentation in line with Deacon's level of
detail for context cycling.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The manager refactors (ea8bef2, 72544cc0) conflicted with the agent
override feature, causing regressions:
Deacon (ea8bef2):
- Lost agentOverride parameter
- Re-added respawn loop (removed in 5f2e16f)
- Lost GUPP (startup + propulsion nudges)
Crew (72544cc0):
- Lost agentOverride wiring to StartOptions
- --agent flag had no effect on crew refresh/restart
This fix restores agent override support and GUPP while keeping
improvements from the manager refactors (zombie detection, etc).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: Add rig-level custom agent support
Implement rig-level custom agent configuration support to enable per-rig
agent definitions in <rig>/settings/config.json, following the same pattern as
town-level agents in settings/config.json.
Changes:
- Added RigSettings.Agents field to internal/config/types.go
- Added DefaultRigAgentRegistryPath() and LoadRigAgentRegistry() functions to internal/config/agents.go
- Updated ResolveAgentConfigWithOverride() to accept and pass rigSettings parameter
- Updated GetRuntimeCommandWithAgentOverride() to use rigSettings when available
- Updated GetRuntimeCommandWithPromptAndAgentOverride() to use rigSettings
- Updated all Build*WithOverride functions to pass rigSettings
This fixes the issue where rig-level agent settings were loaded but
ignored by lookupAgentConfig, enabling per-rig custom agents for
polecats and crew members.
* test: Add rig-level custom agent tests
Added comprehensive unit tests for rig agent registry functions:
- TestDefaultRigAgentRegistryPath: verifies path construction
- TestLoadRigAgentRegistry: verifies file loading and JSON parsing
- TestLookupAgentConfigWithRigSettings: verifies agent lookup priority (rig > town > builtin)
Added placeholder integration test for future CI/CD setup.
* initial commit
* fix: resolve compilation errors in rig-level custom agent support
- Add missing RigAgentRegistryPath function (alias for DefaultRigAgentRegistryPath)
- Restore ResolveAgentConfigWithOverride function that was incorrectly removed
- Fix ResolveAgentConfig to return single value (not triple)
- Add initRegistryLocked() call to LoadRigAgentRegistry to prevent nil panic
- Fix DefaultRigAgentRegistryPath to use rigPath directly (not parent dir)
- Fix test file syntax errors (remove EOF artifacts)
- Fix test parameter order for lookupAgentConfig calls
- Fix test expectations to match correct custom agent override behavior
* test: implement rig-level custom agent integration test
- Add stub agent script that simulates AI agent with Q&A capability
- Test ResolveAgentConfig correctly picks up rig-level agents
- Test BuildPolecatStartupCommand includes custom agent command
- Test ResolveAgentConfigWithOverride respects rig agents
- Test rig agents override town agents with same name
- Add tmux integration test that spawns session and verifies output
- Stub agent echoes 'STUB_AGENT_STARTED' and handles ping/pong Q&A
- All tests pass including real tmux session verification
* docs: add OpenCode custom agent example to reference
- Show settings/agents.json format for advanced configs
- Include OpenCode example with session resume flags
- Document OPENCODE_PERMISSION env var for autonomous mode
* fix: improve rig-level agent support with docs and test fixes
- Add rig-level agent documentation to reference.md
- Document agent resolution order (rig → town → built-in)
- Deduplicate LoadAgentRegistry/LoadRigAgentRegistry into shared helper
- Fix test isolation in TestLoadRigAgentRegistry
- Fix nil pointer dereference in test assertions (use t.Fatal not t.Error)
Replaces inline ensureRefinerySession function with refinery.NewManager(r).Start(false) in gt start --all. Gains zombie detection, proper state tracking, and WaitForShellReady fix.
CI failures (lint in beads.go, integration tests) are pre-existing issues unrelated to this PR's changes.
Co-Authored-By: julianknutsen <julianknutsen@users.noreply.github.com>
Key decisions:
- Fixed pool of 5 goroutines (not Claude sessions)
- State file persistence for crash recovery
- Warrant queuing when pool exhausted
- Dogs are lightweight state machine executors
- New internal/shutdown/ package (separate from existing dog package)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Deacon patrol formula's zombie-scan step now:
- Only detects zombies via --dry-run, never kills directly
- Files death warrants for Boot to handle interrogation/execution
- Includes psychological weight language about termination gravity
This prevents accidental destruction of worker context, mid-task
progress, and unsaved state. Kill authority belongs to Boot.
Bumped version to 5.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add WaitForShellReady call before SendKeys in all agent managers
(deacon, mayor, witness, refinery). This prevents intermittent
"can't find pane" errors that occur when the tmux session is
created but the shell isn't ready to receive input yet.
The issue manifests under load (e.g., during `gt up` when multiple
agents start in sequence) where the 200ms delay in SendKeysDelayed
isn't sufficient for the pane to be fully initialized.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* bd sync: 2026-01-05 06:22:43
* bd sync: 2026-01-05 07:08:42
* bd sync: 2026-01-05 07:24:58
* feat: Add code coverage PR comment to GitHub Actions
Adds a step to the CI workflow that:
- Collects code coverage during test runs
- Parses per-package coverage percentages
- Posts a markdown table comment on PRs with:
- Overall coverage percentage
- Per-package breakdown table
- Updates existing comment on subsequent pushes
Closes: ga-tl5
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(ci): handle fork PR permissions for coverage comment
Fork PRs cannot write comments via GITHUB_TOKEN due to security
restrictions. Add condition to skip comment step for external PRs
and upload coverage report as artifact instead.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor(ci): separate coverage into dedicated job
- Test job now uploads coverage.out and test-output.txt as artifacts
- New Coverage Report job runs after tests complete
- Downloads coverage data, generates report, uploads as artifact
- Always uploads coverage-report artifact (for both fork and internal PRs)
- Comments on PR only for internal PRs (fork PRs get notice message)
- Cleaner separation of concerns
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(ci): coverage job waits for both test and integration
Coverage Report job now depends on [test, integration] to ensure
it only runs after all test stages complete successfully.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(ci): restore Coverage Report job after Test and Integration
Coverage Report job now properly:
- Depends on [test, integration] - waits for both to complete
- Downloads coverage data from Test job
- Generates and uploads coverage-report artifact
- Comments on internal PRs only
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* test: add debugging output to TestInstallTownRoleSlots
Add logging for gt install output and bd list to help diagnose
CI failures where agent beads may not be created.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(ci): update beads to @main and fix lint errors
- Change CI to install beads from @main instead of @latest
(latest release doesn't support role/agent issue types)
- Remove error return from cleanBeadsRuntimeFiles since all
errors are intentionally ignored (best-effort cleanup)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(ci): pin beads to v0.44.0 for agent/role types
Beads main recently extracted Gas Town-specific types (agent, role, etc.)
from core. Pin CI to v0.44.0 which still has these types.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(ci): unpin beads version back to @latest
Beads v0.46.0 now supports agent/role types again.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: remove stale gastown/.beads files from PR
These beads files are local runtime state that shouldn't be committed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Defines the state machine that Dogs execute for death warrants:
- 3-attempt interrogation with escalating timeouts (60s, 120s, 240s)
- PARDON path when session responds with ALIVE
- EXECUTE path after all attempts exhausted
- EPITAPH step for audit logging
Key design decisions documented:
- Dogs are goroutines, not Claude sessions
- Timeout gates close on timer OR early response detection
- State persisted to ~/gt/deacon/dogs/active/ for crash recovery
Implements specification for gt-cd404.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When gt doctor --fix detects stale Claude settings at town root, it was
automatically killing ALL Gas Town sessions (gt-* and hq-*). This is too
disruptive because:
1. Deacon runs gt doctor automatically, creating a restart loop
2. Active crew/polecat work could be lost mid-task
3. Settings are only read at startup, so running agents already have
the config loaded in memory
Instead, warn the user and tell them to restart agents manually:
"Town-root settings were moved. Restart agents to pick up new config:
gt up --restart"
Addresses PR #239 feedback.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
TestGetReturnsWorkingWithoutBeads assumes bd is not available and
expects state to default to StateWorking. When bd is installed, it
actually queries beads and returns the real state, causing the test
to fail.
Skip the test when bd is detected to avoid environment-dependent
failures.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add Cursor Agent as compatible agent for Gas Town
Add AgentCursor preset with ProcessNames field for multi-agent detection:
- AgentCursor preset: cursor-agent -p -f (headless + force mode)
- ProcessNames field on AgentPresetInfo for agent detection
- IsAgentRunning(session, processNames) in tmux package
- GetProcessNames(agentName) helper function
Closes: ga-vwr
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: centralize agent preset list in config.go
Replace hardcoded ["claude", "gemini", "codex"] arrays with calls to
config.ListAgentPresets() to dynamically include all registered agents.
This fixes cursor agent not appearing in `gt config agent list` and
ensures new agent presets are automatically included everywhere.
Also updated doc comments to include "cursor" in example lists.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* test: add comprehensive agent client tests
Add tests for agent detection and command generation:
- TestIsAgentRunning: validates process name detection for all agents
(claude/node, gemini, codex, cursor-agent)
- TestIsAgentRunning_NonexistentSession: edge case handling
- TestIsClaudeRunning: backwards compatibility wrapper
- TestListAgentPresetsMatchesConstants: ensures ListAgentPresets()
returns all AgentPreset constants
- TestAgentCommandGeneration: validates full command line generation
for all supported agents
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add Auggie agent, fix Cursor interactive mode
Add Auggie CLI as supported agent:
- Command: auggie
- Args: --allow-indexing
- Supports session resume via --resume flag
Fix Cursor agent configuration:
- Remove -p flag (requires prompt, breaks interactive mode)
- Clear SessionIDEnv (cursor uses --resume with chatId directly)
- Keep -f flag for force/YOLO mode
Updated all test cases for both agents.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(agents): add Sourcegraph AMP as agent preset
Add AgentAmp constant and builtinPresets entry for Sourcegraph AMP CLI.
Configuration:
- Command: amp
- Args: --dangerously-allow-all --no-ide
- ResumeStyle: subcommand (amp threads continue <threadId>)
- ProcessNames: amp
Closes: ga-guq
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: lint error in cleanBeadsRuntimeFiles
Change function to not return error (was always nil).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: beads v0.46.0 compatibility and test fixes
- Add custom types config (agent,role,rig,convoy,event) after bd init calls
- Fix tmux_test.go to use variadic IsAgentRunning signature
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs: update agent documentation for new presets
- README.md: Update agent examples to show cursor/auggie, add built-in presets list
- docs/reference.md: Add cursor, auggie, amp to built-in agents list
- CHANGELOG.md: Add entry for new agent presets under [Unreleased]
Addresses PR #247 review feedback.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
During `gt install`, the beads database is initialized but Gas Town's
custom issue types (agent, role, rig, convoy, slot) were not being
registered. This caused subsequent agent bead creation to fail with
"invalid issue type: agent" errors.
The fix adds `bd config set types.custom "agent,role,rig,convoy,slot"`
after `bd init` completes. This is idempotent and safe to run multiple
times.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Error: Ran 1 stop hook
⎿ Stop hook error: Failed with non-blocking status code: Error: --session flag required (or set GT_SESSION env var, or GT_RIG/GT_ROLE)
Usage:
gt costs record [flags]
deriveSessionName() now falls back to gt-{role} when GT_ROLE is mayor
or deacon but GT_TOWN is not set. Previously this case returned empty
string, causing the Stop hook to fail.
- Show clearer error explaining user needs to specify crew name or cd into crew dir
- When --rig is specified, list available crew members in that rig
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The TMUX environment variable is not inherited when Claude Code runs
bash commands, even though we are inside a tmux session. This caused
the Stop hook's 'gt costs record' to fail with:
Error: --session flag required
Fix: Remove the early return that checked TMUX env var. The
tmux display-message command will naturally fail if we're not
in tmux, so the check was unnecessary and harmful.
Fixes: hq-to0lr
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Rig operational state management, unified agent startup, and extensive
stability fixes. See CHANGELOG.md for full release notes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Logs a warning when checking rig operational state if the wisp
config file doesn't exist. This helps diagnose cases where a
parked rig unexpectedly restarts because its parked state was lost.
- Remove references to non-existent .repo.git bare repo
- Clarify that polecats/refinery are worktrees from mayor/rig
- Clarify that crew/* are full clones for human developers
- Update routes.jsonl examples to match actual format
- Add explanation of why routes point to mayor/rig
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, SetupRedirect used os.RemoveAll() which deleted all files
in .beads/ including tracked files like formulas/, README.md, config.yaml.
Now cleanBeadsRuntimeFiles() selectively removes only gitignored runtime
files (*.db, daemon.*, issues.jsonl, etc.) while preserving tracked content.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously `gt doctor --fix` would automatically kill and restart patrol
sessions when fixing stale settings.json files. This was disruptive as it
interrupted work without explicit consent.
Now session cycling only happens when `--restart-sessions` is explicitly
passed along with `--fix`. Without the flag, settings files are updated
but running sessions are left alone.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The isTownLevelSession() function was checking workspace.FindFromCwd()
which fails when gt cycle is invoked via tmux run-shell, since run-shell
executes from whatever directory the tmux server started in (often / or
home), not from within the Gas Town workspace.
Town-level sessions (hq-mayor, hq-deacon) can be identified by their
fixed names alone - no workspace context needed. This fix removes the
unnecessary workspace dependency, allowing C-b n/p to cycle between
Mayor and Deacon sessions as intended.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
gt doctor --fix was killing all sessions with stale settings, including
crew and polecats that cannot auto-recover. Now only kills patrol roles
(witness, refinery, deacon, mayor) which the daemon will restart.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When checking if a polecat can be nuked, verify that any hooked bead is
still active (not closed). If the hooked bead was closed externally, the
hook is stale and should not block the nuke.
Also shows 'stale' in dry-run output when hook points to a closed bead.
stale_hooks.go was using hardcoded 'gt-deacon' and 'gt-mayor' instead of
session.DeaconSessionName() and session.MayorSessionName() which return
'hq-deacon' and 'hq-mayor'. This caused incorrect session lookups.
Also fixes duplicate WorktreeAddFromRef method from merge conflict.
Merge artifact - two versions of the method existed. Keep the one
with sparse checkout support.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Deacon is a town-level role, so its beads should be at ctx.TownRoot
(~/gt/.beads/) not ctx.WorkDir (~/gt/deacon/). This fixes the issue
where outputDeaconPatrolContext couldn't find patrol molecules because
it was looking in the wrong location.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
verifyBeadExists was setting BEADS_DIR to town root, which overrides
bd's native prefix-based routing via routes.jsonl. This broke resolution
of rig-level beads (e.g., gt-* beads routed via gt- -> gastown/mayor/rig).
Fix:
- Remove BEADS_DIR override in verifyBeadExists
- Set cmd.Dir to town root so bd can find routes.jsonl
- Apply same fix to getBeadInfo for consistency
Now gt sling gt-xxx correctly finds beads using the same routing as
bd show gt-xxx.
(gt-l5qwb)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Regenerate formulas to sync with source templates
- Fix unparam lint warnings in status.go (unused townRoot parameters)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add version check that enforces beads >= 0.44.0 at CLI startup,
required for custom type support (bd-i54l). Commands like version,
help, and completion bypass the check.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Verify that rig add creates settings.json in correct locations:
- witness/.claude/settings.json (outside git repo)
- refinery/.claude/settings.json (outside git repo)
- crew/.claude/settings.json (shared, outside git repos)
- polecats/.claude/settings.json (shared, outside git repos)
Also verify settings are NOT created inside source repos
(witness/rig/.claude, refinery/rig/.claude) which would
pollute the source repos.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
CLAUDE.md moved from town root to mayor/ to prevent inheritance
pollution to child workspaces.
Also verify mayor/.claude/settings.json and deacon/.claude/settings.json
exist at their correct locations (outside source repos).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Daemon's restartPolecatSession was calling BuildPolecatStartupCommand
with empty rigPath, causing polecats to fall back to town-level defaults
instead of honoring rig-specific agent settings.
Now passes rigPath so rig agent settings are honored.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Witness was calling BuildAgentStartupCommand with empty rigPath,
causing it to fall back to town-level defaults instead of honoring
rig-specific agent settings (like RigSettings.Agent).
Now passes m.rig.Path so rig agent settings are honored, consistent
with how refinery already passes the rig path.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tests were creating mayor settings at townRoot/.claude/ but the check
now correctly identifies that location as wrong (should be mayor/.claude/).
Updated tests to use mayor/.claude/settings.json which is the correct
location that doesn't pollute child workspaces via directory traversal.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create mayor.Manager for mayor lifecycle (Start/Stop/IsRunning/Status)
- Create deacon.Manager for deacon lifecycle with respawn loop
- Move session.Manager to polecat.SessionManager (clearer naming)
- Add zombie session detection for mayor/deacon (kills tmux if Claude dead)
- Remove duplicate session startup code from up.go, start.go, mayor.go
- Rename sessMgr -> polecatMgr for consistency
- Make witness/refinery SessionName() public for status display
All agent types now follow the same Manager pattern:
mgr := agent.NewManager(...)
mgr.Start(...)
mgr.Stop()
mgr.IsRunning()
mgr.Status()
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Creates settings.json automatically during initial setup, so Claude
settings are available immediately on launch.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Prevents mayor-specific files (CLAUDE.md, hooks) from polluting child
agent workspaces. Child agents inherit the parent's working directory,
so keeping mayor files in a dedicated subdirectory ensures they don't
interfere with agent operations.
Includes:
- MayorDir constant in templates for consistent path handling
- Updated hooks.go, prime.go, role.go to use mayor/ paths
- Documentation updates
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Refactors all agent startup paths (witness, refinery, crew, polecat) to use
a consistent Manager interface with Start(), Stop(), IsRunning(), and
SessionName() methods.
Includes:
- Witness manager with GUPP propulsion nudge for startup
- Refinery manager for engineer sessions
- Crew manager for worker agents
- Session/polecat manager updates
- claude_settings_check doctor check for settings validation
- Settings management consolidated from rig/manager.go
- Settings location moved outside source repos to prevent conflicts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Excludes all Claude Code context files to prevent source repo instructions
from interfering with Gas Town agent configuration:
- .claude/ : settings, rules, agents, commands
- CLAUDE.md : primary context file
- CLAUDE.local.md: personal context file
- .mcp.json : MCP server configuration
Legacy configurations (only excluding .claude/) are detected and upgraded
by gt doctor --fix.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Complete the "discover, don't track" refactoring:
- checkGUPPViolations: use tmux.IsClaudeRunning() instead of agent_state
- checkOrphanedWork: derive dead agents from tmux, not agent_state=dead
- assessStaleness: rely on HasActiveSession (tmux), not agent_state
Non-observable states (stuck, awaiting-gate) are still respected.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Status line showing operational state (OPERATIONAL/PARKED/DOCKED)
with source indication (local/global - synced/default).
The state is looked up using the property layer system:
1. Wisp layer (local/ephemeral): .beads-wisp/config/<rig>.json
2. Rig bead labels (global/synced): status:parked or status:docked
3. Default: OPERATIONAL
Example output:
gastown
Status: PARKED (local)
Path: /Users/stevey/gt/gastown
...
Closes: gt-5l7h4
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement gt rig dock <rig> and gt rig undock <rig> commands for
global/persistent rig control:
- dock: stops witness/refinery, sets status:docked label on rig bead
- undock: removes docked label, allows daemon to restart agents
This is Level 2 (global/persistent) control:
- Uses rig identity bead labels (synced via git)
- Affects all clones of the rig
- Persists until explicitly undocked
Also includes cherry-picked rig identity bead infrastructure:
- RigFields struct for rig metadata
- CreateRigBead and RigBeadID helpers
- Auto-create rig bead for legacy rigs on first dock
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update daemon to check rig config before auto-starting agents:
- Check wisp config "status" - skip if parked or docked
- Check "auto_restart" config - skip if blocked or false
- Log skip reason for visibility
Affects ensureWitnessRunning, ensureRefineryRunning,
restartPolecatSession, and lifecycle restartSession.
(gt-68c46)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Additional cleanup from the agent_state refactoring:
- Remove dead code: checkStaleAgents(), markAgentDead() in lifecycle.go
- Remove dead code: reportAgentState(), getAgentFields() in prime.go
- Update getAgentBeadState() comment to clarify non-observable states only
- Update mol-witness-patrol.formula.toml to use tmux discovery
- Update mol-polecat-lease.formula.toml to use POLECAT_DONE mail
- Update docs/watchdog-chain.md to reflect new architecture
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement gt rig park <rig> and gt rig unpark <rig> commands:
- park: stops witness/refinery, sets status=parked in wisp layer
- unpark: clears parked status, allows daemon to restart agents
This is Level 1 (local/ephemeral) control - affects only this town
and disappears on wisp cleanup. Exports IsRigParked() for daemon use.
(gt-vxv0u)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements config viewing and manipulation commands for rig configuration
across property layers.
Commands:
- gt rig config show <rig> # Show effective config
- gt rig config show <rig> --layers # Show source of each value
- gt rig config set <rig> <key> <value> # Set in wisp layer
- gt rig config set <rig> <key> <value> --global # Set in bead layer
- gt rig config set <rig> <key> --block # Block inheritance
- gt rig config unset <rig> <key> # Remove from wisp
Includes cherry-picked dependencies:
- Property layer lookup (cb927a73, gt-emh1c)
- Rig identity bead schema for bead layer
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The agent_state field was recording observable state like "running",
"dead", "idle" which violated the "Discover, Don't Track" principle.
This caused stale state bugs where agents were marked "dead" in beads
but actually running in tmux.
Changes:
- Remove daemon's checkStaleAgents() which marked agents "dead"
- Simplify ensureXxxRunning() to use tmux.IsClaudeRunning() directly
- Remove reportAgentState() calls from gt prime and gt handoff
- Add SetHookBead/ClearHookBead helpers that don't update agent_state
- Use ClearHookBead in gt done and gt unsling
- Simplify gt status to derive state from tmux, not bead
Non-observable states (stuck, awaiting-gate, muted, paused) are still
set because they represent intentional agent decisions that can't be
discovered from tmux state.
Fixes: gt-zecmc
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add --verbose/-v flag to show detailed multi-line output (old behavior)
- Compact mode shows: name + status indicator (●/○) + hook + mail count
- MQ info displayed inline with refinery
- Fix Makefile install target to use ~/.local/bin
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When the daemon detects that an agent bead state doesn't match tmux
(e.g., bead says stopped but Claude is running), it now:
1. Logs the divergence clearly with STATE DIVERGENCE prefix
2. Nudges the agent with an actionable command to fix its state
3. Still skips the restart (safety - don't kill healthy sessions)
This prevents silent state drift where bead state diverges from reality.
Applied to: Deacon, Witness, Refinery ensure functions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add watch mode to gt status
- Add --watch/-w flag for continuous status refresh
- Add --interval/-n flag to set refresh interval (default 2s)
- Clears screen and shows timestamp on each refresh
- Graceful Ctrl+C handling to stop watch mode
- Works with existing --fast and --json flags
* fix(status): validate watch interval to prevent panic on zero/negative values
* fix(status): harden watch mode with signal cleanup, TTY detection, and tests
- Add defer signal.Stop() to prevent signal handler leak
- Reject --json + --watch combination (produces invalid output)
- Add TTY detection for ANSI escapes (safe when piped)
- Use style.Dim for header when in TTY mode
- Fix duplicate '(default 2)' in flag help
- Add tests for interval validation and flag conflicts
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
Implement wisp-based config storage at .beads-wisp/config/<rig>.json
for local-only settings that are never synced via git.
API:
- Get(key) - returns value or nil
- Set(key, value) - stores value
- Block(key) - marks key as blocked (NullValue equivalent)
- Unset(key) - removes from values and blocked
- IsBlocked(key) - checks if blocked
(gt-3w685)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The witness manager's Stop() method was only updating runtime JSON state
without killing the tmux session, causing 'gt rig shutdown' to leave
witness sessions running.
Added sessionName() method and tmux kill-session logic to match the
refinery's existing implementation.
Fixes: bd-gxaf
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous commit (a3bccc8) violated ZFC by implementing molecule step logic
in Go handlers. Per PRIMING.md: Agent decides. Go transports.
This commit:
1. Reverts the gt witness process command (Go code should not make decisions)
2. Updates mol-witness-patrol formula with explicit CLI commands
3. Fixes --wisp to --ephemeral (bd create flag correction)
4. Removes --wisp from bd list calls (invalid flag)
The Witness Claude agent now has explicit instructions:
- Parse POLECAT_DONE message for polecat name
- Check cleanup_status via bd show
- Run gt polecat nuke or bd create --ephemeral based on status
- Archive mail after handling
ZFC: Agent decides. Go transports.
Fixed two issues in `gt crew stop <name>`:
1. --dry-run flag now works for individual crew stops (previously only
worked with --all)
2. HasSession errors are now properly handled instead of being ignored,
which could cause "No session found" messages even when sessions exist
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Witness handlers (HandlePolecatDone, HandleMerged, etc.) existed in Go
code but were never called - there was no CLI command to invoke them.
This caused polecats to remain in 'done' state after MR merge because
POLECAT_DONE messages were never processed.
Changes:
- Add `gt witness process <rig>` command to process Witness mail
- Fix --wisp flag to --ephemeral in cleanup wisp creation
- Command processes POLECAT_DONE, MERGED, HELP, SWARM_START messages
- Auto-nukes clean polecats, creates cleanup wisps for dirty ones
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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>
Added steps from discovered cleanup operations:
- clear-hooks: Detach all hooked work from agents
- reset-in-progress: Reset in-progress beads to open status
- burn-wisps: Clean up wisp directories and ephemeral beads
- validate-clean: Verify all cleanup operations succeeded
Updated existing steps with more detailed procedures.
Key principles preserved:
- No forcing, no lost work
- Idempotent (safe to run multiple times)
- Crew workers NOT affected (user-managed)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 2 of Heresy Correction: Local-Only Polecat Branches
Changes:
- Replace FetchBranch("origin", branch) with BranchExists() check
- Use local branch directly for CheckConflicts() and MergeNoFF()
- Remove "origin/" prefix from branch references
The Refinery worktree shares .repo.git with polecat worktrees, so
branches created by polecats are already visible locally without
needing to fetch from origin.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 3 of heresy correction: polecat branches stay local, Refinery
accesses them via shared .repo.git.
Changes:
- templates/polecat-CLAUDE.md: Remove push from completion checklist
- mol-polecat-work.formula.toml: Remove push step from cleanup-workspace
- polecat.md.tmpl: Update landing rule for local branches
- refinery.md.tmpl: Change origin/polecat to local branch references
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 4 of local-only polecat branches: Handle conflict resolution edge case.
Problem: If polecat worktree is nuked before MR merges, the local branch
is gone and conflict resolution can't access it.
Solution: Witness now defers cleanup for polecats with pending MRs:
- HandlePolecatDone creates a cleanup wisp with "merge-requested" state
- Polecat worktree preserved until MERGED signal arrives
- HandleMerged then nukes the polecat (existing behavior)
Also updated mol-polecat-conflict-resolve.formula.toml:
- Removed fetch from origin (branches are local-only now)
- Added instructions to fetch from source polecat's worktree
- Added rig and source_polecat variables
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When the Refinery detects a build error or test failure and refuses
to merge, the polecat was never notified. This fixes the notification
pipeline by:
1. Adding MERGE_FAILED protocol support to Witness:
- PatternMergeFailed regex pattern
- ProtoMergeFailed protocol type constant
- MergeFailedPayload struct with all failure details
- ParseMergeFailed parser function
- ClassifyMessage case for MERGE_FAILED
2. Adding HandleMergeFailed handler to Witness:
- Parses the failure notification
- Sends HIGH priority mail to polecat with fix instructions
- Includes branch, issue, failure type, and error details
3. Adding mail notification in Refinery's handleFailureFromQueue:
- Creates mail.Router for sending protocol messages
- Sends MERGE_FAILED to Witness when merge fails
- Includes failure type (build/tests/conflict) and error
4. Adding comprehensive unit tests:
- TestParseMergeFailed for full body parsing
- TestParseMergeFailed_MinimalBody for minimal body
- TestParseMergeFailed_InvalidSubject for error handling
- ClassifyMessage test cases for MERGE_FAILED
Fixes#114🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
gt sling failed when hooking rig-level beads from town root because
bd update doesn't support cross-database routing like bd show does.
The fix adds a ResolveHookDir helper that:
1. Extracts the prefix from bead ID (e.g., "ap-xxx" → "ap-")
2. Looks up the rig path from routes.jsonl
3. Falls back to townRoot if prefix not found
Also removes the BEADS_DIR environment override which was preventing
routing from working correctly.
Fixes#148
buildRestartCommand() now propagates Claude-related env vars when
respawning sessions via tmux. Fresh shells don't inherit parent env,
so CLAUDE_CODE_USE_BEDROCK, ANTHROPIC_API_KEY, AWS_*, etc. were lost.
This caused any tmux respawn to result in a non-functional claude.
Adds claudeEnvVars list and includes them in the export command when
building the restart command.
* 📝 (README.md): rewrite documentation with comprehensive guides, architecture diagrams, and detailed workflows
The README has been completely overhauled to provide a more structured and detailed explanation of the Gas Town system. It now includes architecture diagrams, in-depth descriptions of core concepts, step-by-step installation and usage guides, and troubleshooting tips to improve the developer onboarding experience.
* 📝 (README.md): improve formatting, alignment, and spacing
The tables are realigned to improve readability in the raw view, and missing newlines are added before code blocks and after section headers to ensure proper rendering and visual separation.
* fix: create mayor/daemon.json during gt start and gt doctor --fix (#5)
- Add DaemonPatrolConfig type with heartbeat and patrol settings
- Add Load/Save/Ensure functions for daemon patrol config
- Create daemon.json in gt start (non-fatal if fails)
- Make PatrolHooksWiredCheck fixable with Fix() method
- Add comprehensive tests for both config and doctor checks
This fixes the issue where gt doctor expects mayor/daemon.json to exist
but it was never created by gt start or any other command.
* refactor: use constants.DirMayor instead of hardcoded string
* feat: Beads redirect architecture for tracked and local beads
This change implements proper redirect handling so that all rig agents
(Witness, Refinery, Crew, Polecats) can work with both:
- Tracked beads: .beads/ checked into git at mayor/rig/.beads
- Local beads: .beads/ created at rig root during gt rig add
Key changes:
1. SetupRedirect now handles tracked beads by skipping redirect chains.
The bd CLI doesn't support chains (A→B→C), so worktrees redirect
directly to the final destination (mayor/rig/.beads for tracked).
2. ResolveBeadsDir is now used consistently in polecat and refinery
managers instead of hardcoded mayor/rig paths.
3. Rig-level agents (witness, refinery) now use rig beads with rig
prefix instead of town beads. This follows the architecture where
town beads are only for Mayor/Deacon.
4. prime.go simplified to always use ../../.beads for crew redirects,
letting rig-level redirect handle tracked vs local routing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(doctor): Add beads-redirect check for tracked beads
When a repo has .beads/ tracked in git (at mayor/rig/.beads), the rig root
needs a redirect file pointing to that location. This check:
- Detects missing rig-level redirect for tracked beads
- Verifies redirect points to correct location (mayor/rig/.beads)
- Auto-fixes with 'gt doctor --fix'
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: Handle fileLock.Unlock error in daemon
Wrap fileLock.Unlock() return value to satisfy errcheck linter.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This prevents .repo.git/ directories from showing up as untracked files
in town git status.
Changes:
- manager.go: Add .repo.git/ to rig .gitignore during setup
When `gt sling` targets an existing polecat session, it now waits for
Claude to be ready before sending the nudge message. This fixes issue #115
where the "Work slung" message would arrive before Claude had fully started.
Changes:
- Add getSessionFromPane() to extract session name from pane target
- Add ensureClaudeReady() to wait for Claude startup using the same
pragmatic approach as session.Start() (poll for node, accept bypass
dialog, then 8-second delay)
- Call ensureClaudeReady() before injectStartPrompt() in runSling()
The fix uses IsClaudeRunning() for a fast path when Claude is already
running, avoiding unnecessary delays for sessions that have been
running for a while.
Fixes#115🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Handle empty repos in ConfigureSparseCheckout (skip read-tree when no HEAD)
- Fix errcheck: wrap fileLock.Unlock() error in defer
- Fix unparam: remove unused *rig.Rig return from getWitnessManager
- Fix unparam: mark unused agentType parameter with blank identifier
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
detectCurrentTmuxSession() was only accepting gt-* prefix sessions,
rejecting town-level sessions like hq-mayor. Now accepts both gt-*
and hq-* prefixes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Witness and Refinery startup was duplicated across cmd/witness.go, cmd/up.go,
cmd/rig.go, and daemon.go. Worse, not all code paths sent the propulsion nudge
(GUPP - Gas Town Universal Propulsion Principle). Now unified in Manager.Start()
which handles everything including nudges.
Changes:
- witness/manager.go: Full rewrite with session creation, env vars, theming,
WaitForClaudeReady, startup nudge, and propulsion nudge (GUPP)
- refinery/manager.go: Add propulsion nudge sequence after Claude startup
- cmd/witness.go: Simplify to just call mgr.Start(), remove ensureWitnessSession
- cmd/rig.go: Use witness.Manager.Start() instead of inline session creation
- cmd/start.go: Use witness.Manager.Start()
- cmd/up.go: Use witness.Manager.Start(), remove ensureWitness(),
add EnsureSettingsForRole in ensureSession()
- daemon.go: Use witness.Manager.Start() and refinery.Manager.Start() for
unified startup with proper nudges
This ensures all agent startup paths (gt witness start, gt rig boot, gt up,
daemon restarts) consistently apply GUPP propulsion nudges.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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>
When cloning or creating worktrees from repos that have their own .claude/
directory, those settings would override Gas Town's agent settings. This adds
sparse checkout configuration to automatically exclude .claude/ from all
clones and worktrees.
Changes:
- Add ConfigureSparseCheckout() to git.go, called from all Clone/WorktreeAdd methods
- Add IsSparseCheckoutConfigured() to detect if sparse checkout is properly set up
- Add doctor check to verify sparse checkout config (checks config, not symptoms)
- Doctor --fix will configure sparse checkout for repos missing it
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace panic calls in generateID() and generateThreadID() with
time-based fallback when crypto/rand.Read fails. This is an extremely
rare error case, but panicking is not the right behavior for ID
generation functions.
🤝 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add a new 'prefix-mismatch' check to gt doctor that detects when the
prefix configured in rigs.json differs from what routes.jsonl actually
uses for a rig's beads.
This can happen when:
- deriveBeadsPrefix() generates a different prefix than what's in the DB
- Someone manually edited rigs.json with the wrong prefix
- Beads were initialized before auto-derive existed with a different prefix
The check is fixable: running 'gt doctor --fix' will update rigs.json
to match the actual prefixes from routes.jsonl.
Includes comprehensive tests for:
- No routes (nothing to check)
- No rigs.json (nothing to check)
- Matching prefixes (OK)
- Mismatched prefixes (Warning)
- Fix functionality
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add AppendRouteToDir helper and use it to add hq-* route during rig
initialization. This allows rig beads to resolve role beads and other
hq-* prefixed beads stored in town beads.
Uses safe append pattern (load, merge, write) instead of overwriting
to avoid clobbering future rig routes.
Supersedes PR #184 with proper implementation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Per docs/architecture.md, Witness and Refinery are rig-level agents that
should use the rig's configured prefix (e.g., pi- for pixelforge) instead
of hardcoded "gt-".
This extends PR #183's creation fix to also fix all lookup paths:
- internal/rig/manager.go: Create agent beads in rig beads with rig prefix
- internal/daemon/daemon.go: Use rig prefix when looking up agent state
- internal/daemon/lifecycle.go: Use rig prefix for identity-to-bead mapping
- internal/cmd/sling.go: Pass townRoot for prefix lookup
- internal/cmd/unsling.go: Pass townRoot for prefix lookup
- internal/cmd/molecule_status.go: Use rig prefix for agent bead lookups
- internal/cmd/molecule_attach.go: Use rig prefix for agent bead lookups
- internal/config/loader.go: Add GetRigPrefix helper
Without this fix, the daemon would:
- Create pi-gastown-witness but look for gt-gastown-witness
- Report agents as missing/dead when they are running
- Fail to manage agent lifecycle correctly
Based on work by Johann Taberlet in PR #183.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Johann Taberlet <johann.taberlet@gmail.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace Unix-only syscall.Flock with gofrs/flock library for
cross-platform file locking. This enables the daemon to run on
Windows in addition to Unix-like systems.
- Add github.com/gofrs/flock v0.13.0 dependency
- Replace syscall.Flock calls with flock.TryLock/Unlock
- Maintain same non-blocking exclusive lock semantics
(gt-5354h)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
In startConfiguredCrew(), only HasSession() was checked, missing the case
where a tmux session exists but Claude has exited. Now checks IsClaudeRunning()
and restarts Claude with BuildCrewStartupCommand if dead, matching the behavior
in runStartCrew(). (gt-ms8s4)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add --purge flag to gt crew remove that:
- Deletes the agent bead (not just closes it)
- Unassigns any beads assigned to the crew member
- Properly handles git worktrees (not just regular clones)
- Add gt doctor crew-worktrees check to detect stale cross-rig worktrees
- Worktrees in crew/ with hyphenated names are now properly cleaned up
using git worktree remove instead of rm -rf
The --purge flag is for accidental/test crew that should leave no trace
in the capability ledger. Normal crew removal closes the agent bead to
preserve CV history per HOP architecture.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Session-ended event beads were accumulating without being processed.
Modified costs.go to auto-close these events immediately after creation
since they are informational audit events. The event data is preserved
in the closed bead and remains queryable.
Also bulk-closed 83 existing stale session-ended events.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When Deacon respawns refinery/witness sessions via LIFECYCLE requests,
the new sessions were starting at the Claude welcome screen without
the propulsion nudge that triggers autonomous execution.
Added StartupNudge and PropulsionNudgeForRole calls to restartSession()
in lifecycle.go, matching the pattern used in ensureRefinerySession()
in start.go. This ensures respawned agents receive the GUPP nudge and
begin autonomous work immediately.
Fixes: gt-01jpg
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
gt crew start beads and gt crew stop beads now default to --all
behavior when no crew names are specified, matching user expectations.
- crew start: accepts 0-1 args (rig only) and starts all crew
- crew stop: detects if single arg is a rig name vs crew name
- Updated help text with new examples
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Global agents like mayor and deacon are town-level agents that should use
the "hq-" prefix, not "gt-". Changed to use AgentBeadIDWithPrefix with
TownBeadsPrefix for consistency with the beads architecture.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add DefaultBranch field to RoleData struct
- Update refinery.md.tmpl to use {{ .DefaultBranch }} template variable
- Populate DefaultBranch from rig config in prime.go and rig/manager.go
- Default to 'main' if not configured
- Add test verifying DefaultBranch rendering in refinery template
Fixes issue where refinery agents merged to master instead of the
configured default branch (e.g., 'develop' or 'develop-cstar').
The test helper createTestGitRepo was using plain `git init` which
creates a branch based on the system's init.defaultBranch config.
When AddRig tries to detect and checkout the default branch, it
falls back to "main" if detection fails, causing "pathspec 'main'
did not match" errors in CI where the system default is "master".
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Town-level services (Mayor, Deacon) now use hq- prefix instead of gt-:
- hq-mayor (was gt-mayor)
- hq-deacon (was gt-deacon)
This distinguishes town-level sessions from rig-level sessions which
continue to use gt- prefix (gt-gastown-witness, gt-gastown-crew-max, etc).
Changes:
- session.MayorSessionName() returns "hq-mayor"
- session.DeaconSessionName() returns "hq-deacon"
- ParseSessionName() handles both hq- and gt- prefixes
- categorizeSession() handles both prefixes
- categorizeSessions() accepts both prefixes
- Updated all tests and documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Audit of test coverage identifying:
- 10 packages with 0 test coverage (2,452 lines)
- Priority list for new tests (internal/lock is P0)
- 1 flaky test candidate (feed/curator_test.go)
- Test quality analysis and recommendations
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes gt-v07fl: Polecat lifecycle cleanup for stale worktrees and git
tracking conflicts.
Changes:
1. Add .claude/ to .gitignore (prevents untracked file accumulation)
2. Add beads runtime state patterns to .gitignore (prevents future tracking)
3. Remove .beads/ runtime state from git tracking (mq/, issues.jsonl, etc.)
- Formulas and config remain tracked (needed for go install)
- Created follow-up gt-mpyuq for formulas refactor
4. Add DetectStalePolecats() to polecat manager for identifying cleanup candidates
5. Add CountCommitsBehind() to git package for staleness detection
6. Add `gt polecat stale <rig>` command for stale polecat detection/cleanup
- Shows polecats without active sessions
- Identifies polecats far behind main (configurable threshold)
- Optional --cleanup flag to auto-nuke stale polecats
The existing `gt polecat gc` command handles branch cleanup.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When slinging rig-level beads (gt-*, bd-*, etc.), the BEADS_DIR was
unconditionally set to town beads, which could bypass the redirect-based
routing needed for these beads. This caused assignee updates to potentially
fail silently or target the wrong database.
Changes:
- sling.go: Only set BEADS_DIR for town-level (hq-*) beads; rig-level
beads now use redirect from polecat worktree for proper routing
- convoy.go: Add --no-daemon to bd show calls to ensure fresh data
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create internal/agent package with shared State type and StateManager
- StateManager uses Go generics for type-safe load/save operations
- Update witness and refinery to use shared State type alias
- Replace loadState/saveState implementations with StateManager delegation
- Maintains backwards compatibility through re-exported constants
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Introduces a typed CleanupStatus with constants:
- CleanupClean, CleanupUncommitted, CleanupStash, CleanupUnpushed, CleanupUnknown
Adds helper methods:
- IsSafe(): true for clean status
- RequiresRecovery(): true for uncommitted/stash/unpushed
- CanForceRemove(): true if force flag can bypass
Updated files to use the new type:
- internal/polecat/types.go: Type definition and methods
- internal/polecat/manager.go: Validation logic
- internal/witness/handlers.go: Nuke safety checks
- internal/cmd/done.go: Status reporting
- internal/cmd/polecat.go: Recovery status checks
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create util.ExecWithOutput and util.ExecRun to consolidate repeated
exec.Command patterns across witness/handlers.go and refinery/manager.go.
Changes:
- Add internal/util/exec.go with ExecWithOutput (returns stdout) and
ExecRun (runs command without output)
- Refactor witness/handlers.go to use utility functions (7 call sites)
- Refactor refinery/manager.go, removing unused gitRun/gitOutput methods
- Add comprehensive tests in exec_test.go
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extracted duplicate bd command execution pattern from mailbox.go and
router.go into a new helper function in bd.go. This reduces code
duplication and provides consistent error handling via the bdError type.
Changes:
- Added internal/mail/bd.go with runBdCommand helper and bdError type
- Refactored 5 functions in mailbox.go to use runBdCommand
- Refactored 5 functions in router.go to use runBdCommand
- Net reduction of 55 lines of code
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- DiscoverRigs() now logs failed rig loads to stderr instead of silently
continuing
- AddRig warnings now output to stderr instead of stdout, matching the
codebase convention for non-fatal warnings
- Added clarifying comment for best-effort git ref update in worktree
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, when gt done was called, it cleared the agent's hook_bead
slot but didn't update the status of the hooked bead itself. This left
handoff beads with status=hooked forever.
Now the hooked bead is closed (status changed from hooked to closed)
before clearing the agent's hook slot.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The TestIntegration test was flaky because it uses the real .beads directory
and the SQLite database could be out of sync with the JSONL file (e.g., after
git pull updates the JSONL but before the database is re-imported).
The fix runs `bd sync --import-only` at the start of the test to ensure
the database is synchronized before running the actual test operations.
Fixes gt-5ww96
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add debugSession helper that logs non-fatal errors when GT_DEBUG_SESSION=1.
Replaced all _ = error patterns with debugSession() calls for better
visibility when diagnosing session startup issues.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, listFromDir silently ignored all query errors and returned an
empty list with no error if all queries failed. This could hide real problems
like a corrupted beads database or missing bd command.
Now the function tracks whether at least one query succeeded. If all queries
fail, it returns the last error wrapped with context. This enables graceful
degradation (partial results if some queries work) while surfacing complete
failures.
(gt-lm41t)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The --molecule flag was defined but never wired up - the slingMolecule
variable was set by the flag parser but never read by any code path.
Users should use --on instead, which is fully implemented:
gt sling <formula> --on <bead> <target>
The --on flag properly instantiates the formula (cook + wisp + bond)
and applies it to the target bead before slinging.
Keeping --on as the canonical way to apply formulas to beads since it's
actually wired up and working. The --molecule flag can be re-added later
if a different argument order is desired.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The --quality flag (basic|shiny|chrome) referenced mol-polecat-* formulas
that were removed in c47a746 ("Remove obsolete polecat formula files") but
the flag code was left behind, causing errors when used.
Rather than restore the formulas, remove the flag entirely since:
- The default `gt sling <bead> <rig>` is now the standard workflow
- Formula-on-bead via `--on` or `--molecule` covers custom workflows
- The quality-level formulas were intentionally deprecated
Removes:
- --quality/-q flag and help text
- qualityToFormula() function
- Quality Levels section from command documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add isValidBeadsPrefix() to validate prefix format before passing to
exec.Command. Prefixes from config files (detectBeadsPrefixFromConfig)
are now validated to contain only alphanumeric and hyphen characters,
start with a letter, and be max 20 chars.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Verifies all clones have core.hooksPath set to .githooks.
Auto-fixable with 'gt doctor --fix'.
This ensures the pre-push hook is active on all clones,
blocking pushes to invalid branches (no internal PRs).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use regexp.QuoteMeta to treat Query and FromFilter as literal strings
instead of raw regex patterns. This prevents ReDoS attacks from malicious
patterns and provides more intuitive literal string matching for users.
Fixes gt-kwa09
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Audit of test coverage identifying:
- 10 packages with 0 test coverage (2,452 lines)
- Priority list for new tests (internal/lock is P0)
- 1 flaky test candidate (feed/curator_test.go)
- Test quality analysis and recommendations
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Avoid template literals with backticks that confuse YAML parsers.
Use array.join() instead.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add --no-daemon to all 17 bd exec calls to bypass daemon socket timing issues
- Set BEADS_DIR in verifyBeadExists() so bd can find beads from any directory
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Gas Town agents must push directly to main, not create PRs.
This adds defense-in-depth:
1. .githooks/pre-push - Blocks pushes to non-main branches locally
2. .github/workflows/block-internal-prs.yml - Auto-closes PRs from
the same repo (forks/contributors can still create PRs)
3. internal/git/git.go - Auto-configures core.hooksPath on clone
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add error suppression for enc.Encode() calls in info.go (errcheck lint)
- Add missing encoding/json import in install_integration_test.go
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes PR #39 to follow the pattern established in PR #54 - all beads
initialization in done.go should use ResolveBeadsDir to support
.beads/redirect files in worktrees.
* fix: Commit embedded formulas for go install @latest
The internal/formula/formulas/ directory was gitignored, causing
`go install github.com/steveyegge/gastown/cmd/gt@latest` to fail with:
pattern formulas/*.formula.json: no matching files found
The go:embed directive requires these files at build time, but
go install @latest doesn't run go:generate. By committing the
generated formulas, users can install directly without cloning.
Maintainers should run `go generate ./...` after modifying
.beads/formulas/ to keep the embedded copy in sync.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* ci: Add check for committed embedded formulas
Adds a new CI job that:
1. Builds without running go:generate (catches missing formulas)
2. Verifies committed formulas match .beads/formulas/ source
Also removes redundant go:generate steps from other jobs since
formulas are now committed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: exclude towers-of-hanoi test formulas from embed
These are durability stress test fixtures (pre-computed move sequences),
not production formulas users need. Excluding them reduces embedded
content by ~10K lines.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: gus <steve.yegge@gmail.com>
Sync with mayor/rig fix: Set hook slot in CreateAgentBead and pass
beadID to UpdateAgentState.
Fixes: mi-619
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Previously, BuildStartupCommand, GetRuntimeCommand, and
GetRuntimeCommandWithPrompt would fall back to DefaultRuntimeConfig()
(hardcoded "claude") when rigPath was empty, instead of reading
the town settings for the default_agent.
This meant that `gt config default-agent` had no effect on town-level
agents like the mayor.
Fix: Added findTownRootFromCwd() to detect town root from cwd,
then call ResolveAgentConfig() to read the town's default_agent
setting and custom agents.
Now `gt mayor attach` (and other town-level agents) correctly use
the agent configured in town settings.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
When no rig argument is provided, now uses GetRole() to detect the
rig from the current directory or GT_ROLE environment variable.
Shows a helpful error message if rig cannot be determined.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The issue: gt crew start --all was not priming crew sessions like
gt crew at does.
Root cause: gt crew at passes "gt prime" as the initial prompt to
BuildCrewStartupCommand(), while gt crew start (via startCrewMember
and runStartCrew) passed an empty string and tried to send gt prime
afterwards via NudgeSession. This created a race condition where the
SessionStart hook would fire and Claude would start responding before
the nudge arrived.
Fix: Pass "gt prime" directly in the startup command for all three
cases: startCrewMember, runStartCrew new session, and runStartCrew
session restart. This makes the behavior consistent with gt crew at.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Wisps now live in main .beads/ directory with type=wisp instead
of a separate .beads-wisp/ directory. Updated documentation to
reflect this architectural change.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Updates README.md and docs/reference.md with the new gt config command usage, including:
- All subcommands (agent list, get, set, remove, default-agent)
- Example of setting up a custom agent (claude-glm)
- Note about overriding built-in agents
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The crew start command now infers the rig name from the current
working directory when using --all without specifying a rig. This
matches the behavior of crew stop and other commands.
Before: gt crew start gastown --all (required)
After: gt crew start --all (infers from cwd)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements GitHub issue #127 - allow custom agent configuration
through a CLI interface instead of command-line aliases.
The gt config command provides:
- gt config agent list [--json] List all agents
- gt config agent get <name> Show agent configuration
- gt config agent set <name> <cmd> Set custom agent command
- gt config agent remove <name> Remove custom agent
- gt config default-agent [name] Get/set default agent
Users can now define custom agents (e.g., claude-glm) and
override built-in presets (claude, gemini, codex) through
town settings instead of shell aliases.
Changes:
- Add SaveTownSettings() to internal/config/loader.go
- Add internal/cmd/config.go with full config command implementation
- Add comprehensive unit tests for both SaveTownSettings and
all config subcommands (17 test cases covering success and
error scenarios)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Extract the cross-rig bead formatting logic into a testable helper
function and add comprehensive unit tests:
- TestFormatTrackBeadID: 8 test cases covering HQ beads, cross-rig
beads, and edge cases (single segment, empty string, many segments)
- TestFormatTrackBeadIDConsumerCompatibility: 3 test cases verifying
the external ref format can be correctly parsed by consumers in
convoy.go, model.go, feed/convoy.go, and web/fetcher.go
The helper function includes godoc with examples showing expected
behavior for different bead ID formats.
When creating auto-convoys for cross-rig beads (e.g., gt-xxx or gu-xxx),
the tracking relation was failing because bd couldn't resolve the bead ID
from HQ context. Now formats non-HQ beads as external:prefix:id for proper
resolution.
Fixes convoy tracking for cross-rig sling operations.
When patrol agents (witness, refinery, deacon) complete their patrol wisp,
they were left idle because the instructions only said "loop back" without
specifying the command to create a new wisp.
Updated:
- Work loop instructions in prime.go now explicitly tell agents:
* If context LOW: run `bd mol wisp mol-<role>-patrol` to create new wisp
* If context HIGH: use `gt handoff` and exit for daemon respawn
- mol-witness-patrol.formula.toml loop-or-exit step now has clear commands
This ensures patrol agents always either create a new wisp or exit cleanly,
preventing the "session alive but idle" state that caused mail to pile up.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The hook query now falls back to checking in_progress beads assigned to the
agent when no hooked beads are found. This ensures work is not lost when
a session is interrupted after claiming work.
Previously, gt hook only looked for status=hooked beads, so work that had
been claimed but not completed appeared lost. The fix extends the query to
also include in_progress beads assigned to the agent.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sync with mayor/rig fix: Set hook slot in CreateAgentBead and pass
beadID to UpdateAgentState.
Fixes: mi-619
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a polecat worker is recycled via RecreateWithOptions, it now starts
from the latest fetched origin/<default-branch> instead of the stale HEAD.
Previously, `WorktreeAdd` created branches from the current HEAD, but after
fetching, HEAD still pointed to old commits. The new `WorktreeAddFromRef`
method allows specifying a start point (e.g., "origin/main").
Fixes#101
Address review comment: the test now explicitly asserts that ResolveBeadsDir
follows exactly one level of redirect, returning intermediate (not canonical).
The implementation intentionally does NOT follow chains transitively - it stops
at the first resolved path and prints a warning about the detected chain.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add tests verifying that done.go correctly uses beads.ResolveBeadsDir()
to follow .beads/redirect files. This is critical for polecat/crew
worktrees that redirect to a shared mayor/rig/.beads directory.
Tests cover:
- Redirect followed from polecat directory
- Both ExitCompleted (line 181) and ExitPhaseComplete (line 277) paths
- Fallback behavior when no redirect exists
- Empty redirect file handling
- Circular redirect protection
- Redirect chain handling
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
gt done was not following .beads/redirect files, causing it to fail
in worktrees where beads are redirected to a shared location.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a crew or other agent dispatches work to a polecat using `gt sling`,
the polecat now tracks who dispatched the work and sends them a completion
notification when running `gt done`.
Changes:
- Add DispatchedBy field to AttachmentFields in beads/fields.go
- Store dispatcher agent ID in bead when slinging (both direct and formula)
- Check for dispatcher in done.go and send WORK_DONE notification to them
This fixes the orchestration issue where crews were left waiting because
polecats only notified the Witness on completion, not the dispatcher.
Fixes: id-c17
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 22:24:48 -05:00
379 changed files with 56183 additions and 13652 deletions
"description":"Mayor bootstraps Gas Town via a verification-gated lifecycle molecule.\n\n## Purpose\nWhen Mayor executes \"boot up gas town\", this proto provides the workflow.\nEach step has action + verification - steps stay open until outcome is confirmed.\n\n## Key Principles\n1. **Verification-gated steps** - Not \"command ran\" but \"outcome confirmed\"\n2. **gt peek for verification** - Capture session output to detect stalls\n3. **gt nudge for recovery** - Reliable message delivery to unstick agents\n4. **Parallel where possible** - Witnesses and refineries can start in parallel\n5. **Ephemeral execution** - Boot is a wisp, squashed to digest after completion\n\n## Execution\n```bash\nbd mol wisp mol-gastown-boot # Create wisp\n```",
"version":1,
"steps":[
{
"id":"ensure-daemon",
"title":"Ensure daemon",
"description":"Verify the Gas Town daemon is running.\n\n## Action\n```bash\ngt daemon status || gt daemon start\n```\n\n## Verify\n1. Daemon PID file exists: `~/.gt/daemon.pid`\n2. Process is alive: `kill -0 $(cat ~/.gt/daemon.pid)`\n3. Daemon responds: `gt daemon status` returns success\n\n## OnFail\nCannot start daemon. Log error and continue - some commands work without daemon."
},
{
"id":"ensure-deacon",
"title":"Ensure deacon",
"needs":["ensure-daemon"],
"description":"Start the Deacon and verify patrol mode is active.\n\n## Action\n```bash\ngt deacon start\n```\n\n## Verify\n1. Session exists: `tmux has-session -t gt-deacon 2>/dev/null`\n2. Not stalled: `gt peek deacon/` does NOT show \"> Try\" prompt\n3. Heartbeat fresh: `deacon/heartbeat.json` modified < 2 min ago\n\n## OnStall\n```bash\ngt nudge deacon/ \"Start patrol.\"\nsleep 30\n# Re-verify\n```"
},
{
"id":"ensure-witnesses",
"title":"Ensure witnesses",
"needs":["ensure-deacon"],
"type":"parallel",
"description":"Parallel container: Start all rig witnesses.\n\nChildren execute in parallel. Container completes when all children complete.",
"children":[
{
"id":"ensure-gastown-witness",
"title":"Ensure gastown witness",
"description":"Start the gastown rig Witness.\n\n## Action\n```bash\ngt witness start gastown\n```\n\n## Verify\n1. Session exists: `tmux has-session -t gastown-witness 2>/dev/null`\n2. Not stalled: `gt peek gastown/witness` does NOT show \"> Try\" prompt\n3. Heartbeat fresh: Last patrol cycle < 5 min ago"
},
{
"id":"ensure-beads-witness",
"title":"Ensure beads witness",
"description":"Start the beads rig Witness.\n\n## Action\n```bash\ngt witness start beads\n```\n\n## Verify\n1. Session exists: `tmux has-session -t beads-witness 2>/dev/null`\n2. Not stalled: `gt peek beads/witness` does NOT show \"> Try\" prompt\n3. Heartbeat fresh: Last patrol cycle < 5 min ago"
}
]
},
{
"id":"ensure-refineries",
"title":"Ensure refineries",
"needs":["ensure-deacon"],
"type":"parallel",
"description":"Parallel container: Start all rig refineries.\n\nChildren execute in parallel. Container completes when all children complete.",
"children":[
{
"id":"ensure-gastown-refinery",
"title":"Ensure gastown refinery",
"description":"Start the gastown rig Refinery.\n\n## Action\n```bash\ngt refinery start gastown\n```\n\n## Verify\n1. Session exists: `tmux has-session -t gastown-refinery 2>/dev/null`\n2. Not stalled: `gt peek gastown/refinery` does NOT show \"> Try\" prompt\n3. Queue processing: Refinery can receive merge requests"
},
{
"id":"ensure-beads-refinery",
"title":"Ensure beads refinery",
"description":"Start the beads rig Refinery.\n\n## Action\n```bash\ngt refinery start beads\n```\n\n## Verify\n1. Session exists: `tmux has-session -t beads-refinery 2>/dev/null`\n2. Not stalled: `gt peek beads/refinery` does NOT show \"> Try\" prompt\n3. Queue processing: Refinery can receive merge requests"
}
]
},
{
"id":"verify-town-health",
"title":"Verify town health",
"needs":["ensure-witnesses","ensure-refineries"],
"description":"Final verification that Gas Town is healthy.\n\n## Action\n```bash\ngt status\n```\n\n## Verify\n1. Daemon running: Shows daemon status OK\n2. Deacon active: Shows deacon in patrol mode\n3. All witnesses: Each rig witness shows active\n4. All refineries: Each rig refinery shows active\n\n## OnFail\nLog degraded state but consider boot complete. Some agents may need manual recovery.\nRun `gt doctor` for detailed diagnostics."
description="End of patrol cycle decision.\n\n**If context LOW**:\n- Sleep briefly to avoid tight loop (30-60 seconds)\n- Return to inbox-check step\n- Continue patrolling\n\n**If context HIGH**:\n- Write handoff mail to self with any notable observations:\n```bash\ngt handoff -s \"Witness patrol handoff\" -m \"<observations>\"\n```\n- Exit cleanly (daemon respawns fresh Witness)\n\nThe daemon ensures Witness is always running."
description="End of patrol cycle decision.\n\n**If context LOW** (can continue patrolling):\n1. Generate a brief summary of this patrol cycle\n2. Squash the current wisp:\n```bash\nbd mol squash <mol-id> --summary \"<patrol-summary>\"\n```\n3. Create a new patrol wisp:\n```bash\nbd mol wisp mol-witness-patrol\n```\n4. Continue executing from the inbox-check step of the new wisp\n\n**If context HIGH** (approaching limit):\n1. Write handoff mail with notable observations:\n```bash\ngt handoff -s \"Witness patrol handoff\" -m \"<observations>\"\n```\n2. Exit cleanly - the daemon will respawn a fresh Witness session\n\n**IMPORTANT**: You must either create a new wisp (context LOW) or exit (context HIGH).\nNever leave the session idle without work on your hook."
- **Warn on closed hooked bead** - Alert when hooked bead already closed (#2f50a59)
- **Correct agent bead ID format** - Fix bd create flags for agent beads (#c4fcdd8)
#### Formula
- **rigPath fallback** - Set rigPath when falling back to gastown default (#afb944f)
#### Doctor
- **Full AgentEnv for env-vars check** - Use complete environment for validation (#ce231a3)
### Changed
- **Refactored beads/mail modules** - Split large files into focused modules for maintainability
## [0.2.3] - 2026-01-09
Worker safety release - prevents accidental termination of active agents.
> **Note**: The Deacon safety improvements are believed to be correct but have not
> yet been extensively tested in production. We recommend running with
> `gt deacon pause` initially and monitoring behavior before enabling full patrol.
> Please report any issues. A 0.3.0 release will follow once these changes are
> battle-tested.
### Critical Safety Improvements
- **Kill authority removed from Deacon** - Deacon patrol now only detects zombies via `--dry-run`, never kills directly. Death warrants are filed for Boot to handle interrogation/execution. This prevents destruction of worker context, mid-task progress, and unsaved state (#gt-vhaej)
- **Bulletproof pause mechanism** - Multi-layer pause for Deacon with file-based state, `gt deacon pause/resume` commands, and guards in `gt prime` and heartbeat (#265)
- **Doctor warns instead of killing** - `gt doctor` now warns about stale town-root settings rather than killing sessions (#243)
- **Orphan process check informational** - Doctor's orphan process detection is now informational only, not actionable (#272)
### Added
- **`gt account switch` command** - Switch between Claude Code accounts with `gt account switch <handle>`. Manages `~/.claude` symlinks and updates default account
- **`gt crew list --all`** - Show all crew members across all rigs (#276)
Multi-agent orchestrator for Claude Code. Track work with convoys; sling to agents.
**Multi-agent orchestration system for Claude Code with persistent work tracking**
## Why Gas Town?
## Overview
| Without | With Gas Town |
|---------|---------------|
| Agents forget work after restart | Work persists on hooks - survives crashes, compaction, restarts |
| Manual coordination | Agents have mailboxes, identities, and structured handoffs |
| 4-10 agents is chaotic | Comfortably scale to 20-30 agents |
| Work state in agent memory | Work state in Beads (git-backed ledger) |
Gas Town is a workspace manager that lets you coordinate multiple Claude Code agents working on different tasks. Instead of losing context when agents restart, Gas Town persists work state in git-backed hooks, enabling reliable multi-agent workflows.
## Prerequisites
### What Problem Does This Solve?
- **Go 1.23+** - [go.dev/dl](https://go.dev/dl/)
- **Git 2.25+** - for worktree support
- **beads (bd)** - [github.com/steveyegge/beads](https://github.com/steveyegge/beads) - required for issue tracking
- **tmux 3.0+** - recommended for the full experience (the Mayor session is the primary interface)
**The Mayor** is your AI coordinator. It's Claude Code with full context about your workspace, projects, and agents. The Mayor session (`gt prime`) is the primary way to interact with Gas Town - just tell it what you want to accomplish.
### The Mayor 🎩
```
Town (~/gt/) Your workspace
├── Mayor Your AI coordinator (start here)
├── Rig (project) Container for a git project + its agents
│ ├── Polecats Workers (ephemeral, spawn → work → disappear)
│ ├── Witness Monitors workers, handles lifecycle
│ └── Refinery Merge queue processor
```
Your primary AI coordinator. The Mayor is a Claude Code instance with full context about your workspace, projects, and agents. **Start here** - just tell the Mayor what you want to accomplish.
**Hook**: Each agent has a hook where work hangs. On wake, run what's on your hook.
### Town 🏘️
**Beads**: Git-backed issue tracker. All work state lives here. [github.com/steveyegge/beads](https://github.com/steveyegge/beads)
Your workspace directory (e.g., `~/gt/`). Contains all projects, agents, and configuration.
## Workflows
### Rigs 🏗️
### Full Stack (Recommended)
Project containers. Each rig wraps a git repository and manages its associated agents.
The primary Gas Town experience. Agents run in tmux sessions with the Mayor as your interface.
### Crew Members 👤
Your personal workspace within a rig. Where you do hands-on work.
### Polecats 🦨
Ephemeral worker agents that spawn, complete a task, and disappear.
### Hooks 🪝
Git worktree-based persistent storage for agent work. Survives crashes and restarts.
### Convoys 🚚
Work tracking units. Bundle multiple issues/tasks that get assigned to agents.
### Beads Integration 📿
Git-backed issue tracking system that stores work state as structured data.
> **New to Gas Town?** See the [Glossary](docs/glossary.md) for a complete guide to terminology and concepts.
## Installation
### Prerequisites
- **Go 1.23+** - [go.dev/dl](https://go.dev/dl/)
- **Git 2.25+** - for worktree support
- **beads (bd) 0.44.0+** - [github.com/steveyegge/beads](https://github.com/steveyegge/beads) (required for custom type support)
| `pour` | Proto → Mol | Instantiate as persistent |
| `wisp` | Proto → Wisp | Instantiate as ephemeral |
| `squash` | Mol/Wisp → Digest | Condense to permanent record |
| `burn` | Wisp → ∅ | Discard without record |
Restart Mayor session:
---
```bash
gt mayor detach
gt mayor attach
```
## License
MIT
MIT License - see LICENSE file for details
---
**Getting Started:** Run `gt install ~/gt --git && cd ~/gt && gt config agent list && gt mayor attach` (or `gt mayor attach --agent codex`) and tell the Mayor what you want to build!
Gas Town is an agentic development environment for managing multiple Claude Code instances simultaneously using the `gt` and `bd` (Beads) binaries, coordinated with tmux in git-managed directories.
## Core Principles
### MEOW (Molecular Expression of Work)
Breaking large goals into detailed instructions for agents. Supported by Beads, Epics, Formulas, and Molecules. MEOW ensures work is decomposed into trackable, atomic units that agents can execute autonomously.
### GUPP (Gas Town Universal Propulsion Principle)
"If there is work on your Hook, YOU MUST RUN IT." This principle ensures agents autonomously proceed with available work without waiting for external input. GUPP is the heartbeat of autonomous operation.
### NDI (Nondeterministic Idempotence)
The overarching goal ensuring useful outcomes through orchestration of potentially unreliable processes. Persistent Beads and oversight agents (Witness, Deacon) guarantee eventual workflow completion even when individual operations may fail or produce varying results.
## Environments
### Town
The management headquarters (e.g., `~/gt/`). The Town coordinates all workers across multiple Rigs and houses town-level agents like Mayor and Deacon.
### Rig
A project-specific Git repository under Gas Town management. Each Rig has its own Polecats, Refinery, Witness, and Crew members. Rigs are where actual development work happens.
## Town-Level Roles
### Mayor
Chief-of-staff agent responsible for initiating Convoys, coordinating work distribution, and notifying users of important events. The Mayor operates from the town level and has visibility across all Rigs.
### Deacon
Daemon beacon running continuous Patrol cycles. The Deacon ensures worker activity, monitors system health, and triggers recovery when agents become unresponsive. Think of the Deacon as the system's watchdog.
### Dogs
The Deacon's crew of maintenance agents handling background tasks like cleanup, health checks, and system maintenance.
### Boot (the Dog)
A special Dog that checks the Deacon every 5 minutes, ensuring the watchdog itself is still watching. This creates a chain of accountability.
## Rig-Level Roles
### Polecat
Ephemeral worker agents that produce Merge Requests. Polecats are spawned for specific tasks, complete their work, and are then cleaned up. They work in isolated git worktrees to avoid conflicts.
### Refinery
Manages the Merge Queue for a Rig. The Refinery intelligently merges changes from Polecats, handling conflicts and ensuring code quality before changes reach the main branch.
### Witness
Patrol agent that oversees Polecats and the Refinery within a Rig. The Witness monitors progress, detects stuck agents, and can trigger recovery actions.
### Crew
Long-lived, named agents for persistent collaboration. Unlike ephemeral Polecats, Crew members maintain context across sessions and are ideal for ongoing work relationships.
## Work Units
### Bead
Git-backed atomic work unit stored in JSONL format. Beads are the fundamental unit of work tracking in Gas Town. They can represent issues, tasks, epics, or any trackable work item.
### Formula
TOML-based workflow source template. Formulas define reusable patterns for common operations like patrol cycles, code review, or deployment.
### Protomolecule
A template class for instantiating Molecules. Protomolecules define the structure and steps of a workflow without being tied to specific work items.
### Molecule
Durable chained Bead workflows. Molecules represent multi-step processes where each step is tracked as a Bead. They survive agent restarts and ensure complex workflows complete.
### Wisp
Ephemeral Beads destroyed after runs. Wisps are lightweight work items used for transient operations that don't need permanent tracking.
### Hook
A special pinned Bead for each agent. The Hook is an agent's primary work queue - when work appears on your Hook, GUPP dictates you must run it.
## Workflow Commands
### Convoy
Primary work-order wrapping related Beads. Convoys group related tasks together and can be assigned to multiple workers. Created with `gt convoy create`.
### Slinging
Assigning work to agents via `gt sling`. When you sling work to a Polecat or Crew member, you're putting it on their Hook for execution.
### Nudging
Real-time messaging between agents with `gt nudge`. Nudges allow immediate communication without going through the mail system.
### Handoff
Agent session refresh via `/handoff`. When context gets full or an agent needs a fresh start, handoff transfers work state to a new session.
### Seance
Communicating with previous sessions via `gt seance`. Allows agents to query their predecessors for context and decisions from earlier work.
### Patrol
Ephemeral loop maintaining system heartbeat. Patrol agents (Deacon, Witness) continuously cycle through health checks and trigger actions as needed.
---
*This glossary was contributed by [Clay Shirky](https://github.com/cshirky) in [Issue #80](https://github.com/steveyegge/gastown/issues/80).*
Reviewed 14 infrastructure packages for dead code, missing abstractions, performance concerns, and error handling consistency. Found significant cleanup opportunities totaling ~44% dead code in constants package and an entire unused package (keepalive).
The keepalive package (5 functions) was removed from the codebase on Dec 30, 2025 as part of the shift to feed-based activation. No imports exist anywhere.
### High Priority: Functions to Remove
| Package | Function | Location | Notes |
|---------|----------|----------|-------|
| `config` | `NewExampleAgentRegistry()` | agents.go:361-381 | Zero usage in codebase |
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.