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>
- 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>
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>
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 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>
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 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>
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>
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>
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>
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>
* 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>
* 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>
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>
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.
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>