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>
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>
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>
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>
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>
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>
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>
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 --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 --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>
- 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.
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 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>
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>
- Update version.go to 0.2.0
- Add comprehensive CHANGELOG.md entry for v0.2.0 (178 commits)
- Add gt info command with --whats-new flag for agent-relevant changes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The bd slot command doesn't route correctly from town root - it only
works when run from the rig directory. This fix changes done.go to
use the rig path (filepath.Join(townRoot, ctx.Rig)) instead of
townRoot when calling slot commands.
Bug: gt polecat nuke was blocked by stale hooks on closed beads
because gt done wasn't actually clearing the hook_bead field.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
gt peek now correctly handles crew worker paths by detecting the crew/
prefix and using the proper crew session name format (gt-{rig}-crew-{name}).
Changes:
- Add CaptureSession method to Manager for raw session ID capture
- Detect crew/ prefix in peek command and use CrewSessionName
- Update help text with crew path examples
Fixes: gt-yud21
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Optimize getWorkersForIssues() from O(N×R) to O(R) subprocess calls:
- Batch sqlite queries per rig using WHERE hook_bead IN (...)
- Parallelize rig lookups with goroutines
Expected improvement: 300-600ms → 50-100ms for moderate convoys
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>