239 Commits

Author SHA1 Message Date
max
7ae08ed219 chore: Bump version to 0.2.1
Some checks failed
Release / goreleaser (push) Failing after 4m18s
Release / publish-npm (push) Has been skipped
Release / update-homebrew (push) Has been skipped
2026-01-05 00:51:00 -08:00
max
25a49f80c3 docs: Add CHANGELOG entry for v0.2.1 2026-01-05 00:50:34 -08:00
gastown/crew/jack
6b8c897e37 feat: use hq- prefix for Mayor and Deacon session names
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>
2026-01-05 00:42:24 -08:00
blackfinger
a459cd9fd6 docs: Add test coverage and quality review (gt-a02fj.9)
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>
2026-01-05 00:36:21 -08:00
nux
ca71f9b8de fix: Polecat lifecycle cleanup - stale worktrees and git tracking
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>
2026-01-05 00:23:34 -08:00
wretched
2141be7672 fix: Sync database before beads integration test to prevent flaky failures
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>
2026-01-05 00:13:34 -08:00
gastown/crew/joe
18578b3030 fix(security): validate beads prefix to prevent command injection (gt-l1xsa)
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>
2026-01-05 00:02:43 -08:00
george
b50d2a6fdb fix: validate crew names to prevent path traversal (gt-wzxwm)
Add validateCrewName() that rejects:
- Path separators (/, \)
- Parent directory references (..)
- Characters that break agent ID parsing (-, ., space)

Applied to all public entry points: Add, Remove, Get, Pristine.
2026-01-05 00:01:39 -08:00
Steve Yegge
d9962c54d6 Merge pull request #138 from greghughespdx/fix/sling-no-daemon
fix(sling): Add --no-daemon and BEADS_DIR for reliable bd calls
2026-01-05 00:01:17 -08:00
gus
7a7d558116 feat(doctor): Add hooks-path-configured check
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>
2026-01-05 00:01:07 -08:00
Steve Yegge
325f818e11 Merge pull request #131 from greghughespdx/polecat/furiosa-mk0rmk9b
fix(sling): Set hook slot when creating agent beads
2026-01-04 23:59:33 -08:00
george
117e6a1852 fix: handle crypto/rand.Read error in ID generation (gt-qysj9)
Panic if crypto/rand.Read fails rather than silently returning
zero IDs which could cause message collisions.
2026-01-04 23:58:37 -08:00
Steve Yegge
820ff17f9a Merge pull request #129 from dlukt/main
feat: Add gt config command for managing agent settings
2026-01-04 23:53:43 -08:00
gastown/crew/joe
2c6654b5b2 fix(mail): prevent ReDoS in Search by escaping user input
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>
2026-01-04 23:53:36 -08:00
gus
254288800d fix: Fix YAML syntax in block-internal-prs workflow
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>
2026-01-04 23:38:31 -08:00
gus
e0e6473556 fix: Allow polecat/* branches, remove hanoi test formulas
- Update pre-push hook to allow polecat/* branches (Refinery merges these)
- Remove towers-of-hanoi formulas (test fixtures, not production)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 23:31:40 -08:00
Greg Hughes
afe5cab0ad fix(sling): Add --no-daemon and BEADS_DIR for reliable bd calls
- 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>
2026-01-04 23:28:13 -08:00
gus
ff670c5bd4 feat: Block internal PRs via pre-push hook and GitHub Action
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>
2026-01-04 23:28:11 -08:00
mayor
e0ba057821 Merge remote-tracking branch 'origin/polecat/prime-mk0rmco7' 2026-01-04 23:18:08 -08:00
mayor
dd815e80d1 Merge remote-tracking branch 'origin/polecat/dinki-mk0rlxqc' 2026-01-04 23:18:06 -08:00
mayor
252dcc41f8 Merge remote-tracking branch 'origin/polecat/rockryder-mk0frt3g' 2026-01-04 23:17:58 -08:00
mayor
7507cd85c4 fix: Sync embedded formulas with .beads/formulas
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 23:13:44 -08:00
mayor
32cc3e42bc fix: Resolve CI lint and build errors
- 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>
2026-01-04 23:13:03 -08:00
jack
fd3cb6133e fix(done): use ResolveBeadsDir in getDispatcherFromBead
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.
2026-01-04 23:10:11 -08:00
Steve Yegge
b207d2976b Merge pull request #39 from cvsloane/fix/polecat-dispatcher-notification
feat: notify dispatcher when polecat work completes
2026-01-04 23:09:23 -08:00
Raymond Weitekamp
1e76bfd7ce fix: Commit embedded formulas for go install @latest (#117)
* 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>
2026-01-04 23:08:55 -08:00
Steve Yegge
4ffdc4fe40 Merge pull request #54 from michaellady/polecat/fixer-mjy8jxh1
Clean 2-line fix with comprehensive tests. All tests pass locally.
2026-01-04 23:06:01 -08:00
Steve Yegge
97e06be2b4 Merge pull request #123 from akatz-ai/fix/convoy-cross-rig-tracking
fix(sling): Format cross-rig beads as external refs in convoy tracking
2026-01-04 23:05:44 -08:00
greghughespdx
92c9f544fe fix(sling): Set hook slot when creating agent beads (#124)
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>
2026-01-04 23:05:21 -08:00
Darko Luketic
c1897f5843 fix: Honor town default_agent for town-level agents (mayor, deacon)
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>
2026-01-05 07:41:03 +01:00
dave
a455016361 fix(rig): infer rig name from cwd for 'gt rig status'
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>
2026-01-04 22:26:49 -08:00
george
cfdce55770 fix: pass gt prime as initial prompt in crew start commands
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>
2026-01-04 22:18:24 -08:00
prime
7a0143cedf docs: Update wisp architecture to reflect beads storage
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>
2026-01-04 22:18:00 -08:00
dinki
7404eb6b94 Fix PR→MR terminology in workflow docs (gt-xmy0y)
- docs/reference.md: "review PRs" → "review MRs"
- docs/INSTALLING.md: "PR review" → "MR review"

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 22:15:08 -08:00
Darko Luketic
b6dd6f005a Merge branch 'steveyegge:main' into main 2026-01-05 07:14:19 +01:00
Darko Luketic
4cef25c4cb docs: Add gt config command documentation
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>
2026-01-05 07:12:14 +01:00
Steve Yegge
1508177d9a fix(crew): infer rig from cwd for 'gt crew start --all'
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>
2026-01-04 22:10:47 -08:00
Darko Luketic
5787a16067 feat: Add gt config command for managing agent settings
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>
2026-01-05 06:58:46 +01:00
slit
2d56b6c02b test: Add E2E integration tests for hook slot verification (mi-3zc)
Add comprehensive integration tests covering hook slot operations:
- BasicHook: Verify bead can be hooked to an agent
- Singleton: Document that bd allows multiple hooks (gt enforces singleton)
- Unhook: Verify hook removal via status change
- DifferentAgents: Verify independent hooks per agent
- HookPersistence: Verify hooks survive beads instance recreation
- StatusTransitions: Test open -> hooked -> open -> hooked -> closed

Also fix missing 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>
2026-01-04 19:46:27 -08:00
alice
8f03b44771 test: Add unit tests for formatTrackBeadID helper
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.
2026-01-04 20:53:17 -05:00
gastown/witness
e11bcb931e fix(sling): Format cross-rig beads as external refs in convoy tracking
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.
2026-01-04 20:28:28 -05:00
vuvalini
f0c94db99e fix: Add explicit wisp respawn instructions for patrol agents
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>
2026-01-04 16:55:56 -08:00
rockryder
8592098036 fix: Hook persists across session interruption via in_progress lookup (gt-ttn3h)
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>
2026-01-04 16:52:42 -08:00
nux
3b9d1a113c fix(sling): Set hook slot when creating agent beads
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>
2026-01-04 16:28:57 -08:00
gastown/crew/gus
86c4ea2fa6 release: bump version to v0.2.0
Some checks failed
Release / goreleaser (push) Failing after 2m48s
Release / publish-npm (push) Has been skipped
Release / update-homebrew (push) Has been skipped
- 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>
2026-01-04 15:20:25 -08:00
corpus
095a426ebf fix: Clear polecat hook on completion by using rig path (gt-2wc1n)
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>
2026-01-04 15:18:39 -08:00
nux
ae9741ad7f fix(peek): Support cross-rig crew paths like beads/crew/dave
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>
2026-01-04 15:16:56 -08:00
chumbucket
507402dfca fix: Witness checks all remotes for merge verification (gt-ncq26)
In multi-remote setups, the code may live on a remote other than
"origin" (e.g., "gastown" for gastown.git). The verifyCommitOnMain
function now iterates through all configured remotes to find the
one containing the default branch with the merged commit.

Changes:
- Add git.Remotes() method to list all configured remote names
- Update verifyCommitOnMain to check all remotes/<defaultBranch>
  instead of only origin/<defaultBranch>

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 15:12:44 -08:00
vuvalini
00d73b8f8c perf: Batch and parallelize convoy worker lookups (gt-a40d8)
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>
2026-01-04 14:49:38 -08:00
gastown/crew/george
bef5a10250 fix: repair worktree starts from origin/<default-branch>
When repairing a stale polecat worktree, start from origin/<default-branch>
instead of the bare repo's HEAD. This ensures repaired polecats have the
latest fetched commits rather than potentially stale code.

- Add WorktreeAddFromRef to git package for creating worktrees from a ref
- RepairWorktreeWithOptions now uses origin/<default-branch> as start point
- Respects rig's configured default branch (main, master, etc.)

Based on PR #112 by markov-kernel. Test changes from that PR can be
submitted separately.

Closes #101

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

Co-Authored-By: markov-kernel <markov-kernel@users.noreply.github.com>
2026-01-04 14:46:36 -08:00
prime
af95b7b7f4 Remove StateIdle and idle polecat concept
The transient polecat model says: "Polecats exist only while working."
This removes the deprecated StateIdle and updates the codebase:

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

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

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 14:41:28 -08:00
dinki
871410f157 refactor: Rename RecreateWithOptions to RepairWorktreeWithOptions
Clarify that this operation is for stale state recovery, not normal recycling:

- Recreate → RepairWorktree
- RecreateWithOptions → RepairWorktreeWithOptions
- Updated comments to explain this handles reconciliation when AllocateName
  returns a name that already exists (stale state needing repair)
- Updated polecat_spawn.go output: Recreating → Repairing stale
- Updated gc command help text for consistency

The function is useful for atomic hook_bead setting during repair, so kept
rather than replacing with Remove + Add.

Fixes gt-l0lok

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 14:28:40 -08:00
corpus
b732eb075b Remove gt polecat done/reset/finish/sleep commands (idle producers)
These commands transitioned polecats to idle state, violating the transient
model. From PRIMING.md: "Polecats exist only while working. One task, then nuked."

Removed:
- gt polecat done - marked polecat as done and returned to idle
- gt polecat reset - force reset polecat to idle state
- gt polecat finish - alias for done
- gt polecat sleep - deprecated transition to done state
- gt polecat wake - deprecated transition to working state
- Manager.Finish() method
- Manager.Reset() method
- Manager.Wake() method
- Manager.Sleep() method

The correct model is: polecats use 'gt done' which signals Witness for nuke.
There is no "return to idle" - only death.

(gt-32d4a)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 14:27:54 -08:00
chumbucket
4b8b444133 docs: document polecat lifecycle (session/sandbox/slot layers)
Clarifies the three distinct lifecycle layers to prevent confusion:
- Session (Claude context): ephemeral, cycles per step
- Sandbox (worktree): persistent until nuke
- Slot (name from pool): persistent until nuke

Addresses anti-patterns like "idle polecats" and misunderstanding
what recycling means. (gt-bc6gm)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 14:27:09 -08:00
gastown/crew/jack
eea4435269 feat(rig): Add --branch flag for custom default branch
Add --branch flag to `gt rig add` to specify a custom default branch
instead of auto-detecting from remote. This supports repositories that
use non-standard default branches like `develop` or `release`.

Changes:
- Add --branch flag to `gt rig add` command
- Store default_branch in rig config.json
- Propagate default branch to refinery, witness, daemon, and all commands
- Rename ensureMainBranch to ensureDefaultBranch for clarity
- Add Rig.DefaultBranch() method for consistent access
- Update crew/manager.go and swarm/manager.go to use rig config

Based on PR #49 by @kustrun - rebased and extended with additional fixes.

Co-authored-by: kustrun <kustrun@users.noreply.github.com>

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 14:01:02 -08:00
mayor
31df1bb2c1 Merge remote-tracking branch 'origin/polecat/scrotus-mk083pw5' 2026-01-04 13:53:59 -08:00
Steve Yegge
6bad3e3900 Merge pull request #109 from kiwiupover/update-readme
docs: Add Go PATH setup to README
2026-01-04 13:50:33 -08:00
Steve Yegge
2fd2bdf62a Merge pull request #71 from michaellady/feature/convoy-dashboard
Add lint fixes and E2E tests for convoy dashboard
2026-01-04 13:45:54 -08:00
Steve Yegge
87a43a1d07 Merge pull request #83 from jsamuel1/update-dependencies
Update dependencies
2026-01-04 13:45:49 -08:00
scrotus
4de5a96400 refactor: use hq- prefix for role bead references
Migrate all role bead references from gt-*-role to hq-*-role using
beads.RoleBeadIDTown() function. Role beads are stored in town beads
(~/gt/.beads/) with the hq- prefix.

Changes:
- internal/cmd/prime.go: Use RoleBeadIDTown() for all roles
- internal/doctor/agent_beads_check.go: Use RoleBeadIDTown() for rig agents
- internal/polecat/manager.go: Use RoleBeadIDTown("polecat")
- internal/cmd/crew_add.go: Use RoleBeadIDTown("crew")
- internal/beads/beads.go: Update comments to document hq- convention
- Templates: Update bd show gt-deacon to bd show hq-deacon

Note: Tmux session names remain as gt-* (runtime identifiers).
Bead IDs use hq-* for town-level agents (persistent storage).

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 13:17:39 -08:00
gastown/crew/george
47bc11ccee fix(agents): add thread-safety and session resume support
- Add mutex protection for global registry state
- Cache loaded config paths to avoid redundant file reads
- Add ResetRegistryForTesting() for test isolation
- Add BuildResumeCommand() for agent-specific session resume
- Add SupportsSessionResume() and GetSessionIDEnvVar() helpers

Fixes: gt-sn610, gt-otgn3, gt-r2eg1

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 13:12:45 -08:00
Steve Yegge
8c3872e64f Merge pull request #87 from dannomayernotabot/main
fix(sling): add --no-daemon flag to mol bond command
2026-01-04 13:12:22 -08:00
glory
a0e5831f69 fix(witness): explicitly kill tmux session in NukePolecat
The Witness lifecycle was not reliably killing polecat tmux sessions after
POLECAT_DONE. Sessions were piling up because gt polecat nuke may fail to
kill the session due to rig loading issues or race conditions with
IsRunning checks.

Fix: Kill the tmux session FIRST and unconditionally in NukePolecat,
before calling gt polecat nuke. This ensures the session is always killed
regardless of what happens in the downstream nuke command.

The session name pattern is deterministic (gt-<rig>-<polecat>), so we can
construct it directly from the rigName and polecatName parameters.

Fixes: gt-g9ft5

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 13:10:44 -08:00
Steve Yegge
15e9c210b9 Merge pull request #93 from markov-kernel/fix/mayor-session-hooks
fix: deploy SessionStart hooks in gt install for Mayor role
2026-01-04 13:09:24 -08:00
Steve Yegge
dfa0a758e7 Merge pull request #107 from rawwerks/pr/multi-agent-support
feat(config): Add multi-agent support with pluggable registry
2026-01-04 13:05:09 -08:00
Steve Yegge
251d3825ac Merge pull request #95 from markov-kernel/fix/daemon-init-recommendation
CI failures unrelated to this PR (formula embed issue)
2026-01-04 13:01:39 -08:00
Steve Yegge
ea13c269ae Merge pull request #108 from jakehemmerle/fix/daemon-orphan-race-condition
fix(daemon): prevent orphan daemons via file locking
2026-01-04 13:01:12 -08:00
Chris Sloane
1733c6dbae fix: use mayor/rig path for beads to prevent prefix mismatch (#38)
When creating agent beads for polecats or crew workers, the code was
using the rig root path (e.g., ~/gt/infra-dashboard/) instead of the
mayor/rig path where the actual beads database lives.

The rig root .beads/ directory only contains config.yaml with no
database. When bd runs from there, it walks up the directory tree
and finds the town-level beads database (with 'gm' prefix) instead
of the rig's database (with the rig's prefix like 'id'). This causes
prefix mismatch errors:

  Error: prefix mismatch: database uses 'gm' but you specified 'id'

The routes.jsonl file maps rig prefixes to <rig>/mayor/rig, so the
code should always use that path for beads operations.

Changes:
- polecat/manager.go: Always use mayor/rig path, remove fallback logic
- cmd/crew_add.go: Use mayor/rig path instead of rig root

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

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 12:58:53 -08:00
Steve Yegge
257bfbcbd8 Merge pull request #106 from danshapiro/fix/install-role-slots-pr
CI failures unrelated to this PR (formula embed issue)
2026-01-04 12:56:33 -08:00
gus
5c8565534f fix: improve rig name validation error message
- Use underscores instead of stripping invalid characters
- Convert suggestion to lowercase for consistency
- Explicitly state that underscores are allowed

Before: "MyProject.jl" → "MyProjectjl"
After:  "MyProject.jl" → "myproject_jl"

Closes #97

Co-Authored-By: Olivier Debeuf De Rijcker <markov-kernel@users.noreply.github.com>

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 12:33:15 -08:00
gastown/crew/george
c2034ceea3 fix(costs): auto-detect tmux session in Stop hook
gt costs record now auto-detects the current tmux session when
running inside tmux, so the Stop hook no longer requires --session
flag or GT_SESSION env var.

Detection order:
1. --session flag
2. GT_SESSION env var
3. GT_RIG/GT_ROLE derivation
4. Current tmux session (new)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 12:31:16 -08:00
jakehemmerle
c25ff34b5b fix(daemon): prevent orphan daemons via file locking
Add syscall.Flock() exclusive lock in daemon.Run() to prevent TOCTOU
race condition where concurrent 'gt daemon start' commands could spawn
multiple daemons. Only the first to acquire the lock succeeds; others
exit cleanly. Lock is per-town (in townRoot/daemon/daemon.lock) so
multiple GT instances from different directories work independently.

Also detect race losers in runDaemonStart() by comparing spawned PID
with PID file, reporting 'already running' instead of false success.
2026-01-04 15:30:57 -05:00
Steve Yegge
1f90882a0d Merge pull request #91 from vessenes/refactor/town-session-helper
CI failures unrelated to this PR (formula embed issue)
2026-01-04 12:29:54 -08:00
Dave Laird
274d671bd6 Updated the README.md to include the step to add Go binaries to the PATH.
For a non GO user it took a while to figure out what I needed to add
To get gastown up and running. This should help future users.
2026-01-04 12:12:22 -08:00
mayor
ea1a41f1f5 feat(config): Add multi-agent support with pluggable registry
Implements agent abstraction layer to support multiple AI coding agents.

Built-in presets (E2E tested):
- Claude Code (default)
- Gemini CLI
- OpenAI Codex

Key changes:
- Add AgentRegistry with built-in presets and custom agent support
- Add TownSettings with default_agent and custom agents map
- Add Agent field to RigSettings for per-rig agent selection
- Update ResolveAgentConfig for hierarchical config resolution
- Update spawn paths to use configured agent instead of hardcoded claude

Configuration hierarchy (first match wins):
1. Rig's Runtime config (backwards compat)
2. Rig's Agent -> custom agents -> built-in presets
3. Town's default_agent setting
4. Fallback to Claude

Additional agents (aider, opencode, etc.) can be added via config file:
settings/agents.json

Addresses Issue #10: Agent Agnostic Engine with Multi-provider support

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 14:56:14 -05:00
toecutter
8dea4acf8c refactor: add TownBeadsPrefix constant for hq- prefix (gt-3jnnu)
Add TownBeadsPrefix constant to agent_ids.go to centralize the "hq"
prefix string used for town-level agent beads. This makes prefix
changes easier and reduces string duplication.

Also update agent_beads_check.go to use the helper functions instead
of hardcoded strings for consistency.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 10:45:53 -08:00
bullet
cd429fe873 feat(beads): Add TownBeadsPrefix constant for hq- prefix
Introduces a const TownBeadsPrefix = "hq" to centralize the town-level
beads prefix. Updates all hq- string literals in agent_ids.go to use
the constant, making prefix changes easier and reducing duplication.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 10:43:14 -08:00
max
44e9f81d50 docs: document asymmetric error handling in initTownAgentBeads (gt-m39yd)
Explain why agent bead creation failures are hard errors while role bead
creation failures are soft errors (log and continue).

Agent beads are identity beads that form the CV/reputation ledger foundation.
Role beads are documentation templates not required for agent operation.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 10:42:04 -08:00
immortan
4d24f79492 refactor: remove unused isFirstRig param from initAgentBeads (gt-fugmy)
The isFirstRig parameter was no longer used - it was being assigned
to a blank identifier. Since initAgentBeads is an internal function
with only 2 callers in this repo, remove the parameter entirely.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 10:41:08 -08:00
angharad
b7d82c7243 feat(install): Add hq-dog-role to initTownAgentBeads (gt-2jjry)
Add Dog role bead creation to the roleDefs slice, ensuring Dog
agents have their role definition created during gt install.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 10:40:07 -08:00
splendid
acd2565a5b fix: remove vestigial state.json files from agent directories
Agent directories (witness/, refinery/, mayor/) contained state.json files
with last_active timestamps that were never updated, making them stale and
misleading. This change removes:

- initAgentStates function that created vestigial state.json files
- AgentState type and related Load/Save functions from config package
- MayorStateValidCheck from doctor checks
- requesting_* lifecycle verification (dead code - flags were never set)
- FileStateJSON constant and MayorStatePath function

Kept intact:
- daemon/state.json (actively used for daemon runtime state)
- crew/<name>/state.json (operational CrewWorker metadata)
- Agent state tracking via beads (the ZFC-compliant approach)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 10:36:23 -08:00
Dan Shapiro
e98ad32d7f fix: list existing town agent beads
Install now detects existing town-level agents via bd list to avoid relying on
bd show prefix matching, and the role slot test reads JSON from stdout only to
ignore stderr warnings.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 08:49:32 -08:00
Dan Shapiro
87bdd6c63e fix: create town role beads before agents
Install now creates town role beads before agents and only skips agent creation
when the exact agent bead exists, so role slots get set reliably. Add an
integration test that asserts role slots are populated after install.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 08:49:32 -08:00
Olivier Debeuf De Rijcker
26d696cdc3 fix: recommend 'gt daemon start' instead of invalid 'gt daemon init'
The gt doctor patrol-hooks-wired check was recommending 'gt daemon init'
which doesn't exist. The daemon is auto-initialized when running
'gt daemon start', so that's the correct command to recommend.

Fixes #94

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 12:14:49 +01:00
Olivier Debeuf De Rijcker
266259c92d fix: scope integration.yml to ./internal/cmd/... only
The integration.yml was running ./... which includes beads tests that
require database initialization. Changed to match ci.yml's scope of
./internal/cmd/... which contains the actual integration tests.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 12:02:44 +01:00
Olivier Debeuf De Rijcker
b8d1726d7b fix: add beads (bd) install to integration.yml
The integration.yml workflow was missing the beads CLI installation
that the main ci.yml has. This caused integration tests to fail with
"beads dependency check failed".

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 11:54:42 +01:00
Olivier Debeuf De Rijcker
170e81d548 fix: deploy SessionStart hooks in gt install for Mayor role
Adds CI fix to run go generate before build steps.

- Adds claude.EnsureSettingsForRole() call in gt install after CLAUDE.md
- Adds go generate ./internal/formula/... to ci.yml (test, lint, integration jobs)
- Adds go generate ./internal/formula/... to integration.yml

The go generate step creates the embedded formula JSON files that are
gitignored but required for the go:embed directive in embed.go.

Fixes #84

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 11:52:03 +01:00
markov-kernel
fb6ffa92e5 fix: deploy SessionStart hooks in gt install for Mayor role
When users run `claude` directly at the town root instead of
`gt mayor start`, Claude wasn't receiving the Mayor delegation
protocol because `gt prime` never ran.

Root cause: `gt install` created CLAUDE.md but not the
.claude/settings.json with SessionStart hooks that run `gt prime`.

This adds `claude.EnsureSettingsForRole(absPath, "mayor")` to
`gt install` to ensure the Mayor always gets proper Claude settings
with hooks that enforce the delegation protocol.

Fixes #84

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 11:35:14 +01:00
PV
c299f44aea refactor(session): extract town session helpers for DRY shutdown
Previously, town-level session stopping (Mayor, Boot, Deacon) was
implemented inline in gt down with separate code blocks for each
session. The shutdown order (Boot must stop before Deacon to prevent
the watchdog from restarting Deacon) was implicit in the code ordering.

Add session.TownSessions() and session.StopTownSession() to centralize
town-level session management. This provides a single source of truth
for the session list, shutdown order, and graceful/force logic.

Refactor gt down to use these helpers instead of inline logic.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 00:17:37 -08:00
gastown/crew/george
60ecf1ff76 refactor: migrate callers from deprecated MayorBeadID/DeaconBeadID to Town variants (gt-gbw0a)
Update all callers of deprecated MayorBeadID()/DeaconBeadID() to use
MayorBeadIDTown()/DeaconBeadIDTown() which return hq- prefix IDs for
town-level beads storage.

Changes:
- internal/daemon/lifecycle.go: identityToAgentBeadID and checkStaleAgents
- internal/cmd/prime.go: getAgentBeadID
- internal/cmd/molecule_status.go: buildAgentBeadID
- internal/cmd/prime_test.go: update expected values to hq-*
- Comments updated to reflect hq- prefix for town-level agents

The deprecated functions remain for backward compatibility and are used
by the migration tool (migrate_agents.go).

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 21:53:30 -08:00
Steve Yegge
a5907685cd Merge pull request #86 from vessenes/fix/install-copy-formulas
fix(install): Copy embedded formulas to new installations
2026-01-03 21:27:25 -08:00
coma
3e39f25064 docs: add architecture.md and update manager.go comments (gt-5st7b)
Phase 5 of epic gt-4r1ph (align agent/role beads with two-level architecture):

- Create docs/architecture.md with agent bead storage table documenting
  the correct two-level architecture:
  - Town beads (~/gt/.beads/): hq-mayor, hq-deacon, hq-*-role
  - Rig beads (<rig>/.beads/): <prefix>-<rig>-witness, <prefix>-<rig>-refinery

- Update internal/rig/manager.go initAgentBeads() comments with MIGRATION
  NOTEs explaining current state vs target architecture (gt-4r1ph)

- Close PR #50 with explanation that the fix direction was wrong

CLAUDE.md templates already correctly document hq-* for town beads and
project prefix for rig beads.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 21:15:49 -08:00
warboy
36301adf20 feat(beads): Add hq- prefix helpers for town-level beads (gt-y24km, gt-qgmyz)
Phase 1: Create agent_ids.go with town-level bead ID helpers
- MayorBeadIDTown(), DeaconBeadIDTown(), DogBeadIDTown()
- RoleBeadIDTown() and role-specific helpers (hq-*-role)
- Add deprecation notices to old gt-* prefix functions

Phase 2: Create town-level agent beads during gt install
- initTownAgentBeads() creates hq-mayor, hq-deacon agent beads
- Creates role beads: hq-mayor-role, hq-deacon-role, etc.
- Update rig/manager.go to use rig beads for Witness/Refinery

This aligns with the two-level beads architecture:
- Town beads (~/gt/.beads/): hq-* prefix for Mayor, Deacon, roles
- Rig beads (<rig>/.beads/): <prefix>-* for Witness, Refinery, Polecats

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

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

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

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

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 21:09:59 -08:00
ace
b8250e139f Add hq- prefix agent bead ID helpers
Add new helper functions for town-level agent bead IDs:
- MayorBeadIDTown() → "hq-mayor"
- DeaconBeadIDTown() → "hq-deacon"
- DogBeadIDTown(name) → "hq-dog-<name>"
- RoleBeadIDTown(role) → "hq-<role>-role"

These use the hq- prefix for town-level beads storage, distinct from
the gt- prefix used for rig-level beads.

Mark MayorBeadID() and DeaconBeadID() as deprecated in favor of the
new *Town() variants.

(gt-y24km)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 21:07:39 -08:00
organic
0b88dc204b feat(migration): Add gt migrate-agents command for two-level architecture (gt-nnub1)
Implements Phase 4 of the two-level beads architecture migration:
- Add hq- prefix helper functions for town-level agent beads
- Add CreateWithID method for deterministic bead creation
- Create gt migrate-agents command with dry-run/execute modes
- Migrate gt-mayor/gt-deacon to hq-mayor/hq-deacon in town beads
- Migrate role beads (gt-*-role) to town beads (hq-*-role)
- Add migration labels to old beads for tracking
- Idempotent: skips already-migrated beads

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 21:00:00 -08:00
Danno Mayer
ee49b7ab42 fix(sling): add --no-daemon flag to mol bond command
When using gt sling with --quality=shiny, the mol bond command was
failing with "mol bond requires direct database access" error. This
was because bd daemon can be slow to start or unavailable, and mol
bond requires direct database access.

Fix: Added --no-daemon flag to the bd mol bond invocation in sling.go
at line 407. This bypasses the daemon and uses direct database access
for molecule bonding operations.

Fixes gt--4hz

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

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-03 20:15:48 -08:00
PV
4c9bc36d61 fix(install): Copy embedded formulas to new installations
When `gt install` creates a new HQ, formulas were not being provisioned
to `.beads/formulas/`. This embeds the formula library into the gt binary
and copies them during installation.

- Add go:generate directive to copy formulas from .beads/formulas/
- Add internal/formula/embed.go with ProvisionFormulas() function
- Call ProvisionFormulas() from runInstall() after beads init
- Add generate target to Makefile (build depends on it)
- Add TestInstallFormulasProvisioned integration test
- Log warning if formula stat fails with unexpected error

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 18:54:26 -08:00
Mike Lady
c9b601c429 test(dashboard): Add E2E tests with httptest.Server
Comprehensive end-to-end tests for convoy dashboard:
- TestE2E_Server_FullDashboard: Full dashboard with all sections
- TestE2E_Server_ActivityColors: Activity color rendering (green/yellow/red)
- TestE2E_Server_MergeQueueEmpty: Always-visible section with empty state
- TestE2E_Server_MergeQueueStatuses: All PR status combinations
- TestE2E_Server_HTMLStructure: HTML document structure validation
- TestE2E_Server_RefineryInPolecats: Refinery appears in workers section

Tests use httptest.NewServer for real HTTP server testing.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 18:25:37 -08:00
Mike Lady
f30f46192f test(dashboard): Add unit tests for convoy dashboard fetcher
Add table-driven tests for:
- calculateWorkStatus: complete, active, stale, stuck, waiting states
- determineCIStatus: pass, fail, pending with various check combinations
- determineMergeableStatus: ready, conflict, pending states
- determineColorClass: mq-green, mq-yellow, mq-red combinations
- getRefineryStatusHint: idle, singular, multiple PR messages
- truncateStatusHint: line truncation to 60 chars with ellipsis
- parsePolecatSessionName: gt-<rig>-<polecat> parsing
- isWorkerSession: worker vs non-worker session detection
- parseActivityTimestamp: Unix timestamp parsing from tmux

Also refactors inline logic into testable helper functions.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 18:23:45 -08:00
Mike Lady
d967b33c00 test(dashboard): Add comprehensive integration tests for ConvoyHandler
Added 11 new integration tests covering:
- Error handling: FetchConvoys error returns 500
- Merge queue rendering: PR numbers, repos, CI status badges
- Empty merge queue state
- Polecat workers rendering: names, rigs, activity colors, status hints
- Work status rendering: complete/active/stale/stuck/waiting states
- Progress bar rendering with percentage calculation
- HTMX auto-refresh attributes (hx-get, hx-trigger, every 10s)
- Full dashboard integration with all sections
- Non-fatal errors: merge queue/polecat failures don't break convoys

Tests use MockConvoyFetcher interface to simulate various data scenarios.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 18:23:06 -08:00
Mike Lady
d0bdbc4499 feat(dashboard): Always show Refinery Merge Queue section
The Refinery Merge Queue section now displays always, even when idle:
- Shows 'No PRs in queue' message when merge queue is empty
- Displays PR table with number, title, CI status, and mergeable when PRs exist
- Added empty-state-inline CSS for consistent styling

Previously the section was hidden entirely when no PRs existed.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 18:18:49 -08:00
Mike Lady
1c66b61ad5 docs: Add Dashboard section to README
Document the web dashboard for monitoring Gas Town:
- Run command: gt dashboard --port 8080
- Features: convoy tracking, polecat workers, refinery status
- Auto-refresh every 10 seconds
- Work status indicator reference table

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 18:14:45 -08:00
Mike Lady
8ec7bbd8ab fix(dashboard): Use window_activity for more accurate polecat timing
session_activity only updates on session-level events. window_activity
tracks actual window activity (keypresses, output) for more accurate
last activity times in the Polecat Workers section.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 18:14:31 -08:00
Mike Lady
fe72bd4ddc feat(dashboard): Add dynamic work status column for convoys
The status column now shows computed work status based on progress and activity:
- "complete" (green) - all tracked items are done
- "active" (green) - recent polecat activity (within 1 min)
- "stale" (yellow) - older activity (1-5 min)
- "stuck" (red) - stale activity (5+ min)
- "waiting" (gray) - no assignee/activity

Previously the status column always showed "open" since we only fetch
open convoys, making it static and uninformative.

Changes:
- templates.go: Add WorkStatus field to ConvoyRow, add workStatusClass func
- fetcher.go: Add calculateWorkStatus() to compute status from progress/activity
- convoy.html: Add work status badge styling, use WorkStatus in table

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 18:03:51 -08:00
Mike Lady
6e8c43fc0f fix(lint): Add nolint directive for GitHub API spelling
The misspell linter flags "cancelled" but this is the actual value
returned by GitHub's Check Runs API (British spelling). Added nolint
directive with explanation.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 17:57:20 -08:00
Mike Lady
9a02d18101 Merge fix/convoy-last-activity into feature/convoy-dashboard
Merges PR #85 (fix/convoy-last-activity) into PR #71 (feature/convoy-dashboard).
Resolved conflict in fetcher.go by taking the simplified tmux-based activity tracking.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 17:39:22 -08:00
Mike Lady
565b2a0d52 feat(dashboard): Add Polecat Workers section with activity monitoring
- Add FetchPolecats() to fetch tmux session data for active polecats
- Display polecat name, rig, activity status (green/yellow/red)
- Show status hint from last line of pane output
- Add FetchMergeQueue stub for interface compliance
- Update handler to pass polecats data to template
- Add Polecat Workers table section to convoy.html

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 17:34:22 -08:00
Mike Lady
6d4f2c40d1 fix(test): Update htmx refresh test to expect 10s interval
The template was updated to refresh every 10s (2bb1f1e) but the test
still expected 30s. Update test to match the new intended behavior.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 17:22:39 -08:00
Mike Lady
2bb1f1e726 feat(dashboard): Increase auto-refresh rate to every 10 seconds
Changed htmx trigger from 30s to 10s for faster convoy status updates.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 17:17:35 -08:00
Mike Lady
f512598783 fix(dashboard): Handle unassigned convoys and show fallback activity
Improvements to convoy dashboard last_activity column:

1. When issues have no assignee:
   - Fall back to issue's updated_at timestamp
   - Show age with "(unassigned)" suffix, e.g., "2m (unassigned)"

2. When issues have assignee but no active tmux session:
   - Show "idle" instead of "no activity"

3. Added UpdatedAt field to track issue timestamps

This provides better context for convoys that haven't been assigned yet.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 17:12:26 -08:00
Mike Lady
d7b035dc66 fix(dashboard): Use tmux session activity for convoy last_activity
The convoy dashboard last_activity column was showing "no activity" because
the old code looked for agent records in beads databases at wrong paths.

Changed approach:
- Use the issue's assignee field (e.g., "roxas/polecats/dag")
- Parse assignee to get rig and polecat name
- Query tmux for session activity directly (#{session_activity})

This is more reliable since it uses actual tmux session state instead of
trying to find agent records in beads databases.

Fixes hq-kdhf

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 17:00:06 -08:00
nux
f972c69f3a fix: increase SendKeys debounce to 500ms for reliable Enter key
The tmux send-keys Enter key was unreliable because SendKeys used only
100ms debounce while NudgeSession (known to work) uses 500ms.

Root cause: When agents start other agents or inject startup commands,
they use SendKeys() which had only 100ms debounce. This is insufficient
for Claude Code to process the paste before Enter arrives.

The fix increases DefaultDebounceMs from 100ms to 500ms, making all
SendKeys calls as reliable as NudgeSession calls.

Fixes: hq-y9id

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 16:23:44 -08:00
dag
fc805595bb Add Convoy Tracking Web UI Dashboard (hq-vr35)
Complete convoy dashboard feature with real-time status tracking:

- Activity package: LastActivity calculation with color thresholds
  (green <2min, yellow 2-5min, red >5min)
- Web package: Template, handler, fetcher for convoy list
- CLI: `gt dashboard [--port=8080] [--open]` command
- Browser E2E tests with rod (headless Chrome)

Features:
- Real-time convoy status with htmx auto-refresh (30s)
- Progress tracking for each convoy
- Last activity indicator with color coding
- Empty state handling

Supersedes: PRs #55, #57, #58, #65, #66

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 16:23:44 -08:00
gastown/crew/joe
5186cd90be fix(install): remove vestigial rigs/ directory creation
The rigs/ directory was created by gt install but never used by
gt rig add, which puts rigs at the town root. Rather than restructure
the entire codebase to use rigs/, we remove the unused directory.

Flat structure is fine - similar to Android top-level layout with
100+ subprojects. Rigs at root works well and avoids a breaking change.

Closes #74

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

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

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

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

🤖 Generated with Claude Code
2026-01-03 16:11:55 -08:00
Subhrajit Makur
62848065e3 fix: preserve symlink paths in workspace detection (#3) (#75)
Fixes nested workspace detection and symlink path issues in workspace.Find()

- Remove filepath.EvalSymlinks() for consistency with os.Getwd()
- Add isInWorktreePath() to detect polecats/crew directories
- Continue walking up to outermost workspace when in worktree paths
- Add integration tests for symlink and nested workspace scenarios
2026-01-03 16:10:53 -08:00
Joshua Samuel
14085db392 Update dependencies and add dependency management docs
- Upgrade charmbracelet/x/ansi v0.10.1 -> v0.11.3
- Upgrade spf13/cobra v1.8.1 -> v1.10.2
- Upgrade golang.org/x/text v0.3.8 -> v0.32.0
- Add dependency management section to AGENTS.md
2026-01-04 10:59:47 +11:00
jack
29058f321c refactor(commands): provision slash commands at town-level only (gt-7x274)
- gt install now creates ~/gt/.claude/commands/ with all commands
- Removed per-workspace provisioning from crew/polecat managers
- Updated bd doctor to check town-level instead of per-workspace
- All agents inherit via Claude directory traversal

This eliminates duplicate /handoff skills in the picker.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 15:49:53 -08:00
Steve Yegge
4ca430d628 feat(mail): Accept multiple message IDs in gt mail archive (#82)
Update the archive command to accept variadic arguments like bd close,
allowing users to archive multiple messages in a single command.

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

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 15:47:30 -08:00
Steve Yegge
0cdfff879e feat(witness): Implement ephemeral polecat model for immediate recycling (#81)
Updates HandlePolecatDone to auto-nuke polecats immediately after MR submission
when cleanup_status=clean. This separates polecat lifecycle from MR lifecycle:

- Polecat lifecycle: spawning → working → mr_submitted → nuked
- MR lifecycle: created → queued → processed → merged (handled by Refinery)

Key changes:
- Try auto-nuke for ALL POLECAT_DONE messages regardless of MR status
- If cleanup_status=clean (branch pushed), nuke immediately
- If dirty state, create cleanup wisp for manual intervention
- Cleanup wisps are now exception handling, not the normal flow

Conflict resolution is handled by the Refinery, which creates NEW tasks
for NEW polecats when merge conflicts are detected.

(gt-si8rq.9)

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

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 15:46:32 -08:00
joe
696573e644 Bump version to 0.1.2 2026-01-03 15:10:20 -08:00
joe
4bcf50bf1c Revert to simple gt-mayor/gt-deacon session names
Reverts the session naming changes from PR #70. Multi-town support
on a single machine is not a real use case - rigs provide project
isolation, and true isolation should use containers/VMs.

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

Generated with Claude Code

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 14:33:24 -08:00
jack
d3e47221ac fix(rig): improve UX for rig creation (#7)
- Add progress feedback during slow clone operations (30+ seconds)
- Fix README Quick Start to match actual workflow (--git flag, crew add)
- Update install output to use 'gt mayor attach' consistently
- Clarify "Next steps" wording in rig add output

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 13:54:02 -08:00
mayor
ae6eddbbe7 Merge: ace-mjyshvac (gt-htlmp.5) - Add CI workflow for integration tests 2026-01-03 13:53:03 -08:00
mayor
fc7d570d78 Merge: warboy-mjysi94x (gt-rapj1) - Harden bd daemon startup 2026-01-03 13:52:53 -08:00
rictus
40b8dec2a0 feat(daemon): Add circuit breaker for stuck agents (gt-72cqu)
- Add Refinery monitoring to daemon heartbeat (ensureRefineriesRunning)
- Add circuit breaker: agents marked dead by checkStaleAgents() are
  now force-killed and restarted, even if Claude process is alive
- Fixes zombie Claude sessions that werent updating their bead state

The circuit breaker flow:
1. Agent gets stuck (stops updating bead state)
2. After 15 minutes: checkStaleAgents() marks bead as dead
3. On next heartbeat: ensure*Running() sees state=dead
4. Force-kill session and restart fresh

Generated with Claude Code

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 13:12:39 -08:00
nux
bf6b8b8c92 docs(witness): Update patrol formula for ephemeral polecat model
Updates mol-witness-patrol.formula.toml to document the new ephemeral model:

- Added Ephemeral Polecat Model section explaining lifecycle separation
- Updated POLECAT_DONE handling to describe immediate auto-nuke
- Updated process-cleanups to focus on exception handling (dirty polecats)
- Updated survey-workers Step 4a for ephemeral done polecat handling
- Updated patrol-cleanup for ephemeral model expectations

Key principle: Polecat lifecycle is separate from MR lifecycle.
Polecats are recyclable immediately after MR submission.

(gt-si8rq.9)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 13:11:37 -08:00
warboy
6671f050d8 close(epic): Harden bd daemon startup for reliable gt status (gt-rapj1)
All 4 sub-tasks implemented and merged:
- gt-2f0p3: gt status daemon health check
- gt-faven: Better error messages
- gt-fm3nq: gt install/bd init daemon start
- gt-nrgm5: gt doctor daemon check

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 13:05:32 -08:00
ace
7804a0cebd feat(ci): Add GitHub Actions workflow for integration tests (gt-htlmp.5)
Runs integration tests on PRs that touch install, rig, config, or routing code.
Uses -tags=integration build tag with 5-minute timeout and Go module caching.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 13:04:48 -08:00
nux
8d61c043cd feat(witness): Implement ephemeral polecat model for immediate recycling
Updates HandlePolecatDone to auto-nuke polecats immediately after MR submission
when cleanup_status=clean. This separates polecat lifecycle from MR lifecycle:

- Polecat lifecycle: spawning → working → mr_submitted → nuked
- MR lifecycle: created → queued → processed → merged (handled by Refinery)

Key changes:
- Try auto-nuke for ALL POLECAT_DONE messages regardless of MR status
- If cleanup_status=clean (branch pushed), nuke immediately
- If dirty state, create cleanup wisp for manual intervention
- Cleanup wisps are now exception handling, not the normal flow

Conflict resolution is handled by the Refinery, which creates NEW tasks
for NEW polecats when merge conflicts are detected.

(gt-si8rq.9)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 13:03:55 -08:00
max
915f77ea03 feat(ci): Add integration test job; refactor crew startup to use beacon prompt
CI: Add integration test job that runs go test -tags=integration for
install, rig, and beads routing tests.

Crew lifecycle: Pass startup beacon as Claude's initial prompt instead
of nudging after startup. Removes timing-dependent sleep/nudge sequence.
Also removes redundant SetEnvironment calls (env vars already exported
in BuildCrewStartupCommand).

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 12:58:27 -08:00
Steve Yegge
314e87bf07 Merge pull request #70 from markov-kernel/fix/enter-key-retry
fix: Make Mayor/Deacon session names include town name
2026-01-03 12:48:19 -08:00
markov-kernel
e7145cfd77 fix: Make Mayor/Deacon session names include town name
Session names `gt-mayor` and `gt-deacon` were hardcoded, causing tmux
session name collisions when running multiple towns simultaneously.

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

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

Fixes #60

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 21:37:05 +01:00
Olivier Debeuf De Rijcker
7f9795f630 fix: Close MR beads after successful merge from queue (#52)
The handleSuccessFromQueue function was missing critical steps that
exist in the legacy handleSuccess function:

1. Fetch and update the MR bead with merge_commit SHA and close_reason
2. Close the MR bead with CloseWithReason("merged", mr.ID)

Without these steps, the MR bead stayed "open" in beads even after the
queue file was deleted. This caused Mayor (which queries beads for open
merge-requests) to think there were pending MRs while Refinery (which
uses the queue) reported completion.

Fixes #46
2026-01-03 11:54:14 -08:00
Olivier Debeuf De Rijcker
047585866a fix: Add retry logic for Enter key send in NudgeSession/NudgePane (#53)
When sending messages to Claude sessions via tmux, the Enter key send
could fail silently. This caused polecats to receive their initial
prompt but never submit it - the message appeared in Claude's input
area but Enter was never pressed.

Add retry logic (up to 3 attempts with 200ms delays) for the Enter
send step in both NudgeSession() and NudgePane(). This ensures message
submission is more reliable even if tmux has transient issues.

Fixes #41
2026-01-03 11:53:49 -08:00
medley
eabb1c5aa6 fix(done): detect default branch instead of hardcoding 'main' (#42)
Adds RemoteDefaultBranch() to git.go that detects the repo's actual
default branch by checking origin/HEAD, then falling back to checking
for origin/master or origin/main.

Updates done.go to use this detection instead of hardcoded "main":
- Line 168: CommitsAhead now uses detected default branch
- Line 173: Error message uses detected branch name
- Line 187: Target branch defaults to detected branch

Fixes repos using 'master' as default branch (pre-2020 repos).

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

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Steve Yegge <steve.yegge@gmail.com>
2026-01-03 11:53:38 -08:00
Steve Yegge
cfd24b6831 Merge pull request #44 from austeane/fix-readme-quickstart
docs: Fix Quick Start to use gt mayor attach
2026-01-03 11:53:20 -08:00
mayor
aaa356aeb6 Merge: toast-mjxpchjl - Rename session gt-deacon-boot to fix prefix collision 2026-01-03 11:52:16 -08:00
nux
cf53e2852e feat(session): Include session ID in PropulsionNudge for /resume picker
PropulsionNudgeForRole now accepts a workDir parameter and reads
session ID from .runtime/session_id to append [session:xxx] to the
nudge message. This enables Claude Code's /resume picker to discover
Gas Town sessions.

(gt-u49zh)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 11:51:30 -08:00
Mike Lady
3488933cc2 Add 'gt dashboard' CLI command (hq-s1bg) (#65)
* Add LastActivity calculation for convoy dashboard (hq-x2xy)

Adds internal/activity package with color-coded activity tracking:
- Green: <2 minutes (active)
- Yellow: 2-5 minutes (stale)
- Red: >5 minutes (stuck)

Features:
- Calculate() function returns Info with formatted age and color class
- Helper methods: IsActive(), IsStale(), IsStuck()
- Handles edge cases: zero time, future time (clock skew)

Tests: 8 test functions with 25 sub-tests covering all thresholds.

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

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

* Add convoy dashboard HTML template with Last Activity (hq-fq1g)

Adds internal/web package with convoy dashboard template:
- convoy.html with Last Activity column and color coding
- Green (<2min), Yellow (2-5min), Red (>5min) activity indicators
- htmx auto-refresh every 30 seconds
- Progress bars for convoy completion
- Status indicators for open/closed convoys
- Empty state when no convoys

Also includes internal/activity package (dependency from hq-x2xy):
- Calculate() returns Info with formatted age and color class
- Helper methods: IsActive(), IsStale(), IsStuck()

Tests: 6 template tests + 8 activity tests, all passing.

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

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

* Add convoy list handler with activity data (hq-3edt)

Adds HTTP handler that wires convoy dashboard template to real data:
- ConvoyHandler: HTTP handler for GET / rendering convoy dashboard
- LiveConvoyFetcher: Fetches convoys from beads with activity data
- ConvoyFetcher interface: Enables mocking for tests

Features:
- Fetches open convoys from town beads
- Calculates progress (completed/total) from tracked issues
- Gets Last Activity from worker agent beads
- Color codes activity: Green (<2min), Yellow (2-5min), Red (>5min)

Includes dependencies (not yet merged):
- internal/activity: Activity calculation (hq-x2xy)
- internal/web/templates: HTML template (hq-fq1g)

Tests: 5 handler tests + 6 template tests + 8 activity tests = 19 total

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

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

* Add 'gt dashboard' CLI command (hq-s1bg)

Add dashboard command to start the convoy tracking web server.

Usage: gt dashboard [--port=8080] [--open]

Features:
- --port: Configurable HTTP port (default 8080)
- --open: Auto-open browser on start
- Cross-platform browser launch (darwin/linux/windows)
- Graceful workspace detection

🤖 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>
2026-01-03 11:49:42 -08:00
Steve Yegge
7afcea935b Merge pull request #61 from danshapiro/fix/rig-beads-dir
feat: allow local repo reference clones to save disk
2026-01-03 11:48:58 -08:00
Steve Yegge
2dd0f1e6e3 Merge pull request #64 from dannomayernotabot/fix/daemon-witness-race-condition
fix: Add tmux health check fallback to prevent killing healthy sessions
2026-01-03 11:48:44 -08:00
gus
8bb981c7cf fix(tmux): Use exact matching for HasSession to prevent prefix matches
tmux has-session -t does prefix matching by default, so "gt-deacon-boot"
would match when checking for "gt-deacon". This caused gt start to think
the Deacon was running when only a stale gt-deacon-boot session existed.

Using "=" prefix forces exact matching in tmux.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 11:39:51 -08:00
mayor
e7994d98f7 feat(prime): Add --hook flag for LLM runtime session handling
Enables gt prime to receive session metadata from LLM runtime hooks.
When called with --hook, reads JSON from stdin containing session_id
and persists it to .runtime/session_id for use by PropulsionNudge.

- Add --hook flag for hook mode
- Parse Claude Code session JSON from stdin
- Support GT_SESSION_ID environment variable fallback
- Persist session ID to .runtime/session_id

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 11:30:28 -08:00
rictus
12236f24e3 Make TestDoneRedirectChain assertion deterministic
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>
2026-01-03 10:33:27 -08:00
Dan Shapiro
4727f5079f feat: allow local repo reference clones to save disk
Use git --reference-if-able when a local repo is provided so rigs and crew share objects without changing remotes.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 09:27:58 -08:00
mayor
a83d5c6e0b fix: Add tmux health check fallback to prevent killing healthy sessions
When the daemon checks if Deacon/Witness is running, it first checks the
agent bead state. If this check fails (bead not found, JSON parse error,
or stale state), it would previously attempt to restart the session -
even if the tmux session was perfectly healthy.

This caused "session already exists" errors when:
1. Agent bead state couldn't be read (prefix mismatch, missing bead)
2. But the tmux session was actually running with Claude active

Fix: Add a tmux session health check as fallback before attempting restart.
If the session exists AND Claude is running in it, skip the restart and
log that we're preserving the healthy session despite stale bead state.

This maintains ZFC compliance (still trusts agent bead as primary source)
while adding a defensive check to prevent unnecessary session kills.

Fixes #63

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

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-03 09:01:34 -08:00
Mike Lady
717a82753c test(done): add tests for beads redirect support
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>
2026-01-03 04:12:19 -08:00
Mike Lady
c3269ec841 fix(done): use ResolveBeadsDir for redirect file support
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>
2026-01-03 04:01:44 -08:00
Austin Wallace
739681c883 docs: Fix Quick Start to use gt mayor attach
The Quick Start section incorrectly showed `cd ~/gt && gt prime` as the
way to enter the Mayor's office. However, `gt prime` only outputs role
context to stdout (for use in Claude Code prompt hooks) - it doesn't
start or attach to any session.

Changed to `gt mayor attach` which properly attaches to the Mayor tmux
session (and auto-starts it if not running).

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 20:59:04 -08:00
nux
b8eca6c04a feat: notify dispatcher when polecat work completes
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
mayor
386dbf85fb Merge: nux-mjxn8p5t (gt-30i7v) - Add conflict resolution workflow for polecats 2026-01-02 18:57:45 -08:00
nux
e663928564 feat(formulas): Add conflict resolution workflow for polecats (gt-si8rq.5)
New molecule formula mol-polecat-conflict-resolve defines the workflow for
polecats handling merge conflict resolution tasks:

1. Load task and extract metadata from conflict-resolution bead
2. Acquire merge slot (prevents racing via "Monkey Knife Fight" prevention)
3. Checkout the conflicting branch
4. Rebase onto main and resolve conflicts
5. Run tests to verify resolution
6. Push resolved changes directly to main (bypasses queue)
7. Close original MR bead and source issue
8. Release merge slot for next waiter
9. Clean up and close the conflict-resolution task

This completes the polecat side of the ephemeral merge workflow architecture.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:57:34 -08:00
mayor
6400f94fdb Merge: rictus-mjxofiub (gt-2o3vq) - Add integration tests for beads routing 2026-01-02 18:56:59 -08:00
rictus
175c4d3996 test: Add integration tests for beads routing and redirects (gt-htlmp.4)
Validates:
- bd show routes to correct rig based on issue ID prefix
- bd show hq-* routes to town beads
- Redirect chains (.beads/redirect) resolve correctly
- bd list works from polecat/crew directories with redirects
- Prefix conflicts are detected in routes.jsonl
- Routes loading, appending, and removal work correctly
- GetPrefixForRig returns correct prefix for rig name

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:56:45 -08:00
toast
9dcbdf8106 fix(boot): Rename session gt-deacon-boot → gt-boot to fix prefix collision
The tmux session name "gt-deacon-boot" was causing HasSession("gt-deacon")
to return true due to tmux prefix matching behavior. This made the daemon
think the Deacon was running when only Boot was active, and caused commands
targeting "gt-deacon" to be sent to Boot session instead.

The fix renames Boot session from "gt-deacon-boot" to "gt-boot", which
has no prefix overlap with "gt-deacon".

Fixes: gt-sgzsb

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:56:40 -08:00
mayor
7f49d1ad96 Merge: morsov-mjxpeg1a (gt-zanca) - Add watchdog chain documentation 2026-01-02 18:56:20 -08:00
morsov
ea7f434e81 docs: Add watchdog chain documentation for Boot/Deacon lifecycle (gt-1847v)
Creates docs/watchdog-chain.md explaining the Daemon/Boot/Deacon architecture:
- Why two agents (Boot is ephemeral triage, Deacon is persistent patrol)
- Session ownership (gt-deacon-boot vs gt-deacon)
- Heartbeat mechanics and freshness thresholds
- Boot decision matrix (start/wake/nudge/nothing)
- Design decision: keep separation, fix implementation bugs

Cross-references added to operational-state.md and understanding-gas-town.md.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:56:09 -08:00
mayor
27618e5c2e Merge: valkyrie-mjxpdngw (gt-i9pl9) - Reconcile tmux session state with bead state 2026-01-02 18:55:28 -08:00
valkyrie
63d5502b4b fix(status): Reconcile tmux session state with bead state
The gt status command now properly reconciles the tmux session
existence with the agent bead state to surface mismatches:

- If session exists AND bead says running/idle → "running"
- If session exists BUT bead says stopped/dead → "running [bead: <state>]"
- If session gone BUT bead says running/idle → "running [dead]"
- If session gone AND bead says stopped → "stopped"

This surfaces the key mismatch case where a tmux session is actually
running but the bead state incorrectly says "stopped" or "dead".

Fixes: gt-doih4

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:55:13 -08:00
mayor
92106afd6a Merge: dag-mjxpcv5v (gt-vve6k) - Kill zombie tmux sessions before recreating 2026-01-02 18:54:56 -08:00
dag
9ad826cd8c fix(daemon): Kill zombie tmux sessions before recreating
The daemon was failing to restart agents when zombie tmux sessions existed
(session alive but Claude dead). Added EnsureSessionFresh() helper to
tmux package that:
- Checks if session exists
- If exists but Claude not running (zombie), kills the session
- Creates fresh session

Updated all daemon session creation points to use EnsureSessionFresh:
- ensureDeaconRunning()
- ensureWitnessRunning()
- restartPolecatSession()
- restartSession() in lifecycle.go

Added tests for the new helper function. (gt-j1i0r)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:54:39 -08:00
mayor
883997e044 Merge: keeper-mjxpe1ku - Add ensure semantics to witness/refinery start 2026-01-02 18:54:07 -08:00
keeper
354219033a feat: Add 'ensure' semantics to witness/refinery start commands
gt witness start and gt refinery start now detect zombie sessions
(tmux alive but Claude dead) and automatically kill and recreate them.

This makes the start commands idempotent:
- If no session exists → create new session
- If session exists and healthy → do nothing (already running)
- If session exists but zombie → kill and recreate

Previously users had to manually run stop then start, or use restart.

Closes: gt-ekc5u

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:53:52 -08:00
mayor
dd870bb3e4 Merge: cheedo-mjxpd9go (gt-42whv) - Add binary age detection to status command 2026-01-02 18:53:27 -08:00
cheedo
49116f2deb feat(daemon): Add binary age detection to status command
Shows binary modification time in gt daemon status and warns when
the binary is newer than the running process, suggesting a restart.
This helps detect when bug fixes or new features aren't active because
the daemon is running old code.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:53:13 -08:00
gastown/crew/joe
c31ae2cbfe docs: clarify crew workers never create PRs 2026-01-02 18:41:43 -08:00
mayor
05f4ed95db Merge PR #32: fix(beads): fix agent bead creation during rig add
Merged with conflict resolution after PR #34. Key fixes:

- Remove invalid --no-agents flag from bd init
- Agent beads now created in town beads (gt-* prefix) using NewWithBeadsDir
- Use canonical WitnessBeadID/RefineryBeadID functions
- Update test to verify town beads usage

Original PR by @PepijnSenders, conflict resolution applied.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:41:21 -08:00
capable
fa26265b32 test: Add integration tests for gt rig add command
Add comprehensive integration tests that validate gt rig add:
- TestRigAddCreatesCorrectStructure: Verify directory structure
- TestRigAddInitializesBeads: Verify beads prefix initialization
- TestRigAddUpdatesRoutes: Verify routes.jsonl is updated
- TestRigAddUpdatesRigsJson: Verify rigs.json is updated
- TestRigAddDerivesPrefix: Verify prefix derivation from name
- TestRigAddCreatesRigConfig: Verify config.json content
- TestRigAddCreatesAgentDirs: Verify agent state files
- TestRigAddRejectsInvalidNames: Verify name validation

Uses //go:build integration tag per design doc.
Run with: go test -tags=integration ./internal/cmd -run TestRigAdd

(gt-htlmp.3)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:31:15 -08:00
dementus
8f6e2d2174 test: Add integration tests for gt install command
- TestInstallCreatesCorrectStructure: validates directory structure
  (mayor/, rigs/, CLAUDE.md) and config files (town.json, rigs.json)
- TestInstallBeadsHasCorrectPrefix: verifies beads uses hq- prefix
- TestInstallIdempotent: tests --force flag behavior
- TestInstallNoBeadsFlag: tests --no-beads option

Run with: go test -tags=integration ./internal/cmd/ -run TestInstall

(gt-htlmp.2)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:30:30 -08:00
slit
89785378bf feat(costs): Wire up gt costs record to Stop hook
Add Claude Code Stop hook that automatically records session costs when
sessions end. The hook calls `gt costs record` which now can derive the
session name from GT_* environment variables (GT_RIG, GT_POLECAT, GT_CREW,
GT_ROLE).

Changes:
- Add deriveSessionName() to infer tmux session name from environment
- Add Stop hook to settings-autonomous.json and settings-interactive.json
- Add unit tests for deriveSessionName function

When a Gas Town session ends, the Stop hook fires and records the session
cost as a bead event. Costs then appear in `gt costs --today` output.

Closes: gt-ntzhc

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:29:25 -08:00
rictus
270be9b65c feat: Migrate handoff from commands to skills format (gt-nqtqp)
Claude Code v2.0+ deprecated .claude/commands/ in favor of .claude/skills/.
This migrates the handoff skill to the new format with proper YAML frontmatter.

Changes:
- Create .claude/skills/handoff/SKILL.md with frontmatter
- Remove deprecated .claude/commands/handoff.md

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:27:49 -08:00
furiosa
efd9434ee1 feat(refinery): Integrate merge-slot gate for conflict resolution
Adds merge-slot integration to the Refinery's Engineer for serializing
conflict resolution. When a conflict is detected:
- Acquire the merge slot before creating a conflict resolution task
- If slot is held, defer task creation (MR stays in queue)
- Release slot after successful merge

This prevents cascading conflicts from multiple polecats racing to
resolve conflicts simultaneously.

Adds MergeSlot wrapper functions to beads package for slot operations.

(gt-4u49x)

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:26:45 -08:00
nux
f7839c2724 feat(refinery): Non-blocking delegation via bead-gates (gt-hibbj)
When merge conflicts occur, the Refinery now creates a conflict resolution
task and blocks the MR on that task, allowing the queue to continue to the
next MR without waiting.

Changes:
- Add BlockedBy field to mrqueue.MR for tracking blocking tasks
- Update handleFailureFromQueue to set BlockedBy after creating conflict task
- Add ListReady method to mrqueue that filters out blocked MRs
- Add ListBlocked method for monitoring blocked MRs
- Add IsBeadOpen, ListReadyMRs, ListBlockedMRs helpers to Engineer
- Add 'gt refinery ready' command (unclaimed AND unblocked MRs)
- Add 'gt refinery blocked' command (shows blocked MRs)

When the conflict resolution task closes, the MR unblocks and re-enters
the ready queue for processing.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:25:15 -08:00
Jacob
aaee7fed40 fix(doctor): use route path directly for agent beads check (#36)
The agent-beads-exist check was hardcoding '/mayor/rig' suffix when
constructing the beads path, but routes.jsonl can contain paths like
'my-saas' without this suffix.

This caused the check to look for beads in the wrong location:
- Expected: <town>/<route-path>/.beads (e.g., ~/gt/my-saas/.beads)
- Actual: <town>/<rig>/mayor/rig/.beads (e.g., ~/gt/my-saas/mayor/rig/.beads)

The fix stores the full route path and uses it directly when creating
the beads client, instead of reconstructing an assumed path structure.

Fixes agent beads not being found when routes use simple rig names.
2026-01-02 18:19:58 -08:00
joe
c3e83a3d09 Fix remaining worker startups for gt seance metadata
- startCrewMember: now uses BuildCrewStartupCommand (was GetRuntimeCommand)
- refinery/manager.go: now uses BuildAgentStartupCommand (was GetRuntimeCommand)

Both now properly inject BD_ACTOR and GT_ROLE so seance can identify
sessions correctly. This completes the seance metadata fix started in
the previous commit.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:09:42 -08:00
gastown/witness
cadf09d98c bd sync: 2026-01-02 18:08:14 2026-01-02 18:08:14 -08:00
joe
49be394eef Fix crew startup to inject metadata for gt seance
gt crew start was using GetRuntimeCommand which doesn't set BD_ACTOR,
GT_RIG, GT_CREW, etc. This caused seance to misidentify crew sessions
(showing as "mayor" instead of their actual identity).

Now uses BuildCrewStartupCommand like gt crew restart does, ensuring
proper env var injection for session identification. (gt-jwxgb)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 17:42:27 -08:00
mayor
1805d5b011 Merge: toast-mjxm0mmo (gt-cikbu) - Add spawn as alias for start subcommand across roles 2026-01-02 17:30:33 -08:00
toast
9683744b53 feat: Add 'spawn' as alias for 'start' subcommand across roles
Added 'spawn' as an alias for 'start' in the following commands:
- gt witness start → also gt witness spawn
- gt refinery start → also gt refinery spawn
- gt deacon start → also gt deacon spawn
- gt crew start → also gt crew spawn

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

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

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 17:30:24 -08:00
mayor
8273622806 Merge: rictus-mjxlzc5r (gt-l9toz) - Support batch slinging multiple beads to a rig 2026-01-02 17:30:00 -08:00
rictus
45265f779d feat(sling): Support batch slinging multiple beads to a rig
Allows slinging multiple beads in a single command:
  gt sling gt-abc gt-def gt-ghi gastown

Each bead gets its own freshly spawned polecat. This parallelizes
work dispatch without running gt sling N times manually.

Changes:
- Updated Args from RangeArgs(1,2) to MinimumNArgs(1)
- Added batch mode detection when len(args)>2 and last arg is a rig
- Added runBatchSling() to handle multiple beads with progress tracking

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 17:29:52 -08:00
mayor
a15f4bb753 Merge: dag-mjxm10sv (gt-j8kxo) - Add gt rig restart for multi-rig restart support 2026-01-02 17:29:28 -08:00
dag
7919129ff4 feat(rig): Add 'gt rig restart' for multi-rig restart support
Adds 'gt rig restart <rig>...' command that stops then starts witness
and refinery for one or more rigs. Supports --force and --nuclear flags
like the existing start/stop commands. (gt-s7t1h)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 17:29:21 -08:00
mayor
f4a823370e Merge: slit-mjxlyyte (gt-jhr85) - Provision .claude/commands for crew and polecat workspaces 2026-01-02 17:28:52 -08:00
slit
d4eed2dcf2 feat(crew): Provision .claude/commands/ for crew and polecat workspaces (gt-jhr85)
When adding a crew member with 'gt crew add' or spawning a polecat,
provision the .claude/commands/ directory with standard slash commands
like /handoff. This ensures all agents have Gas Town utilities even if
the source repo does not have them tracked.

Changes:
- Add embedded commands templates (internal/templates/commands/)
- Add ProvisionCommands() to templates package
- Call ProvisionCommands from crew and polecat managers
- Add gt doctor commands-provisioned check with --fix support
2026-01-02 17:28:40 -08:00
capable
a62b35a85c feat(convoy): Add stranded convoy detection and feeding (gt-8otmd)
Add `gt convoy stranded` command to detect convoys with ready work but
no workers processing them. A convoy is stranded when it has open,
unblocked issues with no live assignee.

- New command outputs stranded convoy IDs with ready issue counts
- Supports --json for automation by Deacon patrol
- Checks blocked status via bd blocked
- Verifies assignee session liveness via tmux

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 17:27:53 -08:00
max
37ae702427 docs: Clarify formula vs molecule semantics - formulas are NOT instructions
PROBLEM: Agents were reading formula files directly and manually creating beads
for each step, rather than using the cook→pour→molecule pipeline.

FIXES:
- polecat-CLAUDE.md: Changed "following the formula" to "work through your
  pinned molecule" and added explicit anti-pattern warning
- mol-polecat-work.formula.toml: Added note that formula defines template,
  use bd ready to find step beads
- docs/molecules.md: Added "Common Mistake" section with WRONG/RIGHT examples
- mol-*.formula.toml (5 files): Changed "execute this formula" to "work
  through molecules (poured from this formula)"

The key insight: Formulas are source templates (like source code). You never
read them directly. The cook → pour pipeline creates step beads for you.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 17:26:08 -08:00
dementus
0bcd8acecb feat(convoy): Add --tree flag to show convoy + child status tree
Shows convoys with their tracked issues in a tree format:
🚚 hq-cv-abc: Convoy Name (3/5)
├── ✓ gt-123: Closed issue
├── ▶ gt-456: In progress issue
└── ○ gt-789: Pending issue

Makes convoy progress visible at a glance without running 'gt convoy status' on each one.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 17:19:26 -08:00
nux
8517ff0650 feat(mq): Add priority-ordered queue display and processing (gt-si8rq.6)
Implements priority scoring for merge queue ordering:

## Changes to gt mq list
- Add SCORE column showing priority score (higher = process first)
- Sort MRs by score descending instead of simple priority
- Add CONVOY column showing convoy ID if tracked

## New gt mq next command
- Returns highest-score MR ready for processing
- Supports --strategy=fifo for FIFO ordering fallback
- Supports --quiet for just printing MR ID
- Supports --json for programmatic access

## Changes to Refinery
- Queue() now sorts by priority score instead of simple priority
- Uses ScoreMR from mrqueue package for consistent scoring

## MR Fields Extended
- Added retry_count, last_conflict_sha, conflict_task_id
- Added convoy_id, convoy_created_at for convoy tracking
- These fields feed into priority scoring function

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 17:18:27 -08:00
max
1e1221883b docs: Add shell completion installation instructions (gt-pdrh0)
Document bash/zsh/fish completion setup in README.
Cobra provides `gt completion <shell>` out of the box.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 17:15:04 -08:00
furiosa
8feb27d44c fix(nuke): Check content on main, not just commit SHAs
After squash merge, polecat branches have different commit SHAs than main
even though the content is identical. This was causing false "unpushed
commits" warnings during nuke safety checks.

Now uses `git diff` to verify if content differs from main, rather than
just counting commits ahead. If diff is empty, content is on main
(via squash merge) and nuke is safe. (gt-fo9iz)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 17:11:11 -08:00
nux
2ad83421c5 feat(done): Add conflict resolution tracking fields to MR beads (gt-si8rq.7)
Add retry_count, last_conflict_sha, and conflict_task_id fields to MR bead
descriptions when created via `gt done`. These are initialized at creation
time and will be updated by the Refinery when handling merge conflicts.

- retry_count: 0 (number of conflict-resolution cycles)
- last_conflict_sha: null (SHA of main when conflict occurred)
- conflict_task_id: null (link to conflict-resolution task if any)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 16:46:10 -08:00
furiosa
f8b650cf82 feat(done): Add --phase-complete flag for gate-based phase handoffs
Add support for signaling phase completion when a polecat needs to wait
on a gate before continuing. The --phase-complete flag with --gate ID
allows polecats to hand off control while awaiting external conditions.

Changes:
- done.go: Add --phase-complete and --gate flags, PHASE_COMPLETE exit type
- protocol.go: Add Gate field to PolecatDonePayload
- handlers.go: Handle PHASE_COMPLETE by recycling session (keep worktree)
- beads.go: Add AddGateWaiter method for gate registration

This enables multi-phase molecule workflows with async coordination (bd-gxb4)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 16:43:50 -08:00
Steve Yegge
535bb8e4c2 Merge pull request #34 from kustrun/fix/init-bugs
Fix init bugs when setting first gastown
2026-01-02 16:02:39 -08:00
mayor
c9d6c70e03 fix(sling): Add trailing slash to town-level agent IDs
Town-level agents (mayor/, deacon/) need trailing slash to match
addressToIdentity() normalization.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 14:03:56 -08:00
PepijnSenders
ca487a8fed fix(beads): fix agent bead creation during rig add
Three issues were causing errors when running `gt rig add`:

1. **bd init flag**: Removed non-existent `--no-agents` flag from bd init
   command that was causing silent failures.

2. **BEADS_DIR for init**: Added explicit BEADS_DIR to bd init and migrate
   commands to prevent bd from finding parent directory databases.

3. **Agent beads location**: Agent beads now go in town beads (gt-* prefix)
   instead of rig beads. This is necessary because:
   - Agent IDs use canonical gt-* prefix (e.g., gt-tribal-witness)
   - Rig beads use rig-specific prefixes (e.g., tr-*)
   - bd strictly validates ID prefix against database prefix
   - Town beads must be initialized with `gt` prefix

4. **beads.run() BEADS_DIR**: Modified to explicitly pass BEADS_DIR in child
   process environment to ensure bd uses the correct database.

5. **Agent ID prefix**: Use WitnessBeadID/RefineryBeadID (canonical gt-*)
   instead of WithPrefix variants.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-02 23:03:31 +01:00
slit
31d6f6acf1 feat(convoy): Add gt convoy check for cross-rig auto-close (gt-00qjk)
Convoys in town beads track issues in rig beads via external:rig:id
references. When bd close runs in a rig, the convoy auto-close logic
only checks the local database, missing convoys in town beads.

This adds `gt convoy check` to bridge that gap:
- Finds all open convoys in town beads
- Checks if all tracked issues (across rigs) are closed
- Auto-closes completed convoys
- Sends notification if convoy has notify address

Can be called manually or by deacon patrol.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 14:02:45 -08:00
kustrun
a0a47676f9 fix(sling): Set BEADS_DIR for accessing hq-* beads from polecat worktree
When running bd update commands for hq-* beads from a polecat worktree,
the redirect mechanism only exposes gt-* beads. This fix sets BEADS_DIR
to the town-level .beads directory so hq-* beads are accessible.

Also adds NewWithBeadsDir() constructor to beads package for explicit
cross-database access when needed.
2026-01-02 23:02:42 +01:00
capable
579c11379a fix(polecat): Require rig/polecat format for nuke and remove commands
Previously, when running `gt polecat nuke <name> <rig>`, the parseAddress
function would infer the rig from cwd for each argument, causing a plain
rig name to be misinterpreted as a polecat name. For example, running from
a gastown directory:

  gt polecat nuke angharad gastown --force

Would try to nuke both gastown/angharad AND gastown/gastown.

Now both runPolecatNuke and runPolecatRemove validate that each address
argument contains "/" before parsing, enforcing the documented
`<rig>/<polecat>` format and preventing this misinterpretation.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 14:01:58 -08:00
rictus
2199bdffea fix(convoy): Auto-detect issue IDs in convoy create first arg
When first arg to `gt convoy create` looks like a beads issue ID
(e.g., gt-abc, bd-xyz), treat all args as issues and auto-generate
the convoy name from the first issue title.

This prevents the bug where `gt convoy create gt-abc` would use
"gt-abc" as the convoy name instead of recognizing it as an issue
to track.

(gt-7qyfh)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 14:00:51 -08:00
furiosa
c2dee85617 docs(polecat): Update template to use gt done --exit (gt-x4ad3)
Update polecat template to reflect the new --exit flag behavior:
- Completion checklist now uses `gt done --exit` instead of waiting
- Remove "Wait for Witness" step - polecats now self-terminate
- Update Polecat Contract to reflect new exit flow
- Remove outdated "Don't exit yourself" guidance

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 13:48:14 -08:00
nux
a440a7ff93 feat(mail): Add --all flag to gt mail clear for agent ergonomics (gt-105q3)
The command already clears all messages by default, but agents naturally
try --all when they want to clear everything. Adding it as a no-op flag
improves discoverability and natural usage patterns.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 13:47:34 -08:00
kustrun
58e7c96936 fix(sling): Use target's working directory for bd update commands
When slinging to an existing polecat, the bd update command was running
from town root which doesn't support prefix-based routing for writes.

Fix: Capture the target agent's working directory from resolveTargetAgent
and use it as hookWorkDir. This ensures bd update runs from the polecat's
worktree where the .beads/redirect file enables routing to the correct
database.

Also fixed the self-sling case to capture and use selfWorkDir.
2026-01-02 22:44:59 +01:00
kustrun
b380ded2cc fix(beads): Initialize bd database when cloning repo with tracked .beads/
When cloning a repo that has .beads/ tracked in git, the beads.db file
is missing (gitignored) but issues.jsonl exists. The bd commands fail
with "prefix mismatch" because:
1. No beads.db means no prefix config stored
2. bd falls back to walking up to find a database
3. Finds town-level database with 'hq-' prefix

Fix: After detecting the source repo's prefix from config.yaml or issues,
run 'bd init --prefix <prefix>' to create the database and auto-import
from issues.jsonl. Also updated initAgentBeads to use the correct beads
location (mayor/rig/.beads for repos with tracked beads).
2026-01-02 22:44:59 +01:00
kustrun
94857fc913 fix(session): Auto-accept Claude bypass permissions warning dialog
When Claude starts with --dangerously-skip-permissions, it shows a warning
dialog requiring Down+Enter to accept. This blocked automated polecat and
agent startup.

Added AcceptBypassPermissionsWarning() to tmux package that:
- Checks if the warning dialog is present by capturing pane content
- Only sends Down+Enter if "Bypass Permissions mode" text is found
- Avoids interfering with sessions that don't show the warning

Updated all Claude startup locations:
- session/manager.go (polecat sessions)
- cmd/up.go (mayor, witness, crew, polecat cold starts)
- daemon/daemon.go (crashed polecat restarts)
- daemon/lifecycle.go (role session starts)
2026-01-02 22:44:58 +01:00
kustrun
3c4190597f fix(session): Set BEADS_DIR to town-level beads for polecat hooks
Polecats need access to town-level beads (hq- prefix) for hooks and
convoys. Update session manager to set BEADS_DIR to town root .beads/
instead of rig-level .beads/.

Also update mail.go's findLocalBeadsDir() to respect the BEADS_DIR
environment variable, which is necessary for polecats using
redirect-based beads access.
2026-01-02 22:44:58 +01:00
kustrun
8133cc36b7 fix(sling): Run bd commands from polecat worktree for proper routing
When slinging work to a polecat, run bd commands from the polecat's
worktree directory instead of town root. This enables redirect-based
routing to work correctly since the polecat's .beads/redirect file
points to the canonical database location.

Adds hookWorkDir variable to track the polecat's clone path and passes
it to updateAgentHookBead for proper beads access.
2026-01-02 22:44:58 +01:00
kustrun
b4a6f599ac fix(beads): Use conditional routing based on source repo beads location
Route to the correct beads location based on whether the source repo
has .beads/ tracked in git:
- If source has .beads/ tracked: route to mayor/rig/.beads
- Otherwise: route to rig root .beads/ (created by initBeads)

Updates both route registration in rig.go and polecat manager's
NewManager/setupSharedBeads to use consistent conditional logic.
2026-01-02 22:44:58 +01:00
kustrun
ae90b08f46 fix(beads): Detect and use existing prefix from source repo
When adding a rig from a source repo that has .beads/ tracked in git,
detect and use the project's existing prefix instead of generating a
new one. This prevents prefix mismatch errors when accessing existing
issues via bd commands.

Adds detectBeadsPrefixFromConfig() which reads the prefix from either
config.yaml or by parsing the first issue ID from issues.jsonl.
2026-01-02 22:44:57 +01:00
mayor
598e02408c bd sync: 2026-01-02 13:49 2026-01-02 13:43:56 -08:00
furiosa
ff37d2213a feat(done): Add --exit flag for session self-termination (gt-lynar)
Add --exit flag to `gt done` that terminates the Claude session
immediately after submitting the MR to the merge queue. This prevents
polecats from sitting idle (and wasting money) while waiting for the
Witness to kill them.

Changes:
- Rename existing --exit flag to --status (for exit type)
- Add new --exit boolean flag for session self-termination
- Update docs and help text to reflect new flag names

Usage: gt done --exit

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 13:43:32 -08:00
capable
aafc717113 feat(costs): Use beads for session cost tracking instead of JSONL (gt-f7jxr)
- Updated `gt costs record` to create session.ended events in beads
- Updated `gt costs --today/--week` queries to use bd instead of JSONL
- Removed JSONL ledger support (getLedgerPath, readLedger, WriteLedgerEntry)
- Session costs now stored with event_kind, actor, target, and payload fields
- Filed bd-xwvo for beads bug where --rig flag loses event fields

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 13:38:38 -08:00
mayor
c0d597f092 witness: Stop routine reports to mayor (costs tokens) 2026-01-02 13:11:46 -08:00
rictus
8ce52f166c feat(crew): Add gt crew stop command for stopping crew sessions
Implements gt crew stop with the following features:
- Stop individual crew members: gt crew stop dave
- Stop multiple: gt crew stop beads/emma beads/grip
- Stop all: gt crew stop --all
- Filter by rig: gt crew stop --all --rig beads
- Dry-run mode: gt crew stop --all --dry-run
- Force mode (skip output capture): gt crew stop dave --force

Uses same semantics as gt shutdown: captures output before stopping,
logs kill events to town log, provides clear status reporting.

(gt-q2am4)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 13:11:08 -08:00
slit
db316b0c3f feat(crew): Update gt crew start to use rig-first positional arg (gt-okk2z)
Changed command signature from `gt crew start [name...]` to
`gt crew start <rig> [name]` with --all flag support:

- Takes rig as first required positional argument
- Optional crew member name(s) as subsequent arguments
- --all flag to start all crew members in the rig
- Validates that either name or --all must be provided

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:55:08 -08:00
rictus
c327ea2ca2 feat(doctor): Add session-hooks check for settings.json consistency
Adds a new doctor check that verifies all settings.json files in the
town use session-start.sh wrapper for SessionStart and PreCompact hooks.

Without this wrapper, session_id passthrough fails, which breaks
gt seance discovery of sessions.

The check:
- Scans all settings.json files across town, rigs, crew, and polecats
- Warns if any file uses bare 'gt prime' without session-start.sh
- Provides fix hint pointing to the correct wrapper configuration

(gt-77fhi)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:54:34 -08:00
nux
90e9a2dbcd feat(rig): Add gt rig stop command for multi-rig shutdown
Add new `gt rig stop <rig>...` command that supports stopping multiple rigs
with the same shutdown semantics as `gt rig shutdown`:
- Stops all polecat sessions
- Stops the refinery (if running)
- Stops the witness (if running)
- Checks for uncommitted work before shutdown (unless --nuclear)

Includes --force flag for immediate shutdown and --nuclear flag to bypass
safety checks. (gt-lhitf)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:54:05 -08:00
mayor
28602f3b0f feat(formula): Add check-timer-gates step to Witness patrol
Cross-rig change from beads Timer Gates feature (bd-kbfn).
Adds timer gate expiration check to patrol loop.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:52:22 -08:00
furiosa
2c1e8e2220 feat(rig): Add gt rig start command for multi-rig startup (gt-11z8l)
Add new 'gt rig start <rig>...' command that starts witness and refinery
on patrol for one or more rigs. Similar to 'gt rig boot' but supports
multiple rigs in a single invocation.

- Iterates over all provided rig names
- Skips already-running agents with clear output
- Reports success/failure per-rig with summary

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:50:34 -08:00
dementus
52a610b01b feat(rig): Add gt rig status <rig> command (gt-vcecr)
Shows detailed status for a specific rig including all workers:
- Rig info (name, path, beads prefix)
- Witness status (running/stopped, uptime)
- Refinery status (running/stopped, uptime, queue size)
- Polecats (name, state, assigned issue, session status)
- Crew members (name, branch, session status, git status)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:49:23 -08:00
mayor
25c04a915c fix: Only count registered rigs in status line
The status line was counting rigs based on tmux session names without
validating they were actually registered in mayor/rigs.json. This could
cause incorrect rig counts when session names matched the pattern but
were not real rigs.

Now loads registered rigs from rigs.json and only counts:
- Rigs that are actually registered
- Polecats belonging to registered rigs

Fixes #17

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:40:54 -08:00
nux
33abd769de feat(install): ensure db fingerprint during gt install/rig init (GH #25)
Add repo fingerprint migration after bd init to ensure daemon can start.
Legacy databases (pre-0.17.5) lack fingerprint, causing slow gt status.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:31:20 -08:00
slit
50d9643db1 feat(doctor): Add repo-fingerprint check for beads database (gt-nrgm5)
Add repo-fingerprint check to gt doctor that verifies beads databases have
valid repository fingerprints. Missing or empty fingerprints can cause daemon
startup failures and sync issues.

The check:
- Uses bd doctor --json to check fingerprint status
- Runs on town-level and rig-level beads directories
- Can fix by running bd migrate --update-repo-id
- Restarts daemon after migration if it was running

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:30:49 -08:00
capable
1f72285a76 fix(rig): Reject rig names with hyphens, dots, or spaces (GHI #23)
Add validation in Manager.AddRig() to reject rig names containing
characters that break agent ID parsing. Agent IDs use format
<prefix>-<rig>-<role>[-<name>] with hyphens as delimiters, so
hyphenated rig names like op-baby cause parsing failures.

The validation rejects hyphens, dots, and spaces, and suggests a
sanitized alternative in the error message.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:30:16 -08:00
dementus
c5ee18c6ab feat(doctor): Add bd daemon health check with actionable error messages
Add a new doctor check that verifies the bd (beads) daemon is running
and healthy. When the daemon fails to start, the check:

- Surfaces specific error messages (legacy database, repo mismatch)
- Provides one-liner fix commands
- Auto-fixes by running bd migrate --update-repo-id when appropriate

This addresses GH #25: gt status slow when bd daemon not running.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:29:50 -08:00
rictus
e2b872af11 feat(formula): Update mol-polecat-work for ephemeral polecat model (gt-si8rq.4)
- Change polecat contract from wait-for-termination to ephemeral
- Rename close-issue → prepare-for-review (Refinery closes after merge)
- Rename signal-complete → submit-and-exit (polecat recyclable after gt done)
- Bump formula version to 4

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:29:19 -08:00
furiosa
b81c4760fe feat(status): Check bd daemon health and attempt restart (gt-2f0p3)
Add bd daemon health check at the start of gt status:
- Check daemon health via bd daemon health --json
- Attempt restart if daemons are unhealthy (version mismatch, stale, unresponsive)
- Show warning at end of status output if daemons could not be started
- Non-blocking: status display continues regardless of daemon state

This prevents the 39+ second slowdown when bd daemons are not running
properly, as each bd command falls back to slow direct mode.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:28:42 -08:00
toast
c92cc955dd feat(costs): Add gt costs command for session cost tracking
Implements cost tracking v1 for Gas Town agents:
- `gt costs` shows live costs scraped from running tmux sessions
- `gt costs --today/--week` shows historical costs from ledger
- `gt costs --by-role/--by-rig` shows cost breakdowns
- `gt costs record` for Stop hook integration to record final costs

Cost ledger stored at ~/.gt/costs.jsonl with JSONL entries per session.

Ref: gt-nrpiq

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:28:02 -08:00
mayor
6081847bde fix: Use 'hq' prefix for town beads instead of 'gm'
Town beads should use 'hq-' prefix to match documented architecture:
- Town beads (~/gt/.beads/): hq-* prefix for mayor mail, coordination
- Rig beads: project-specific prefix

The 'gm' prefix was causing convoy creation failures due to prefix
mismatch.

Fixes #19

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:24:49 -08:00
mayor
f3b7640563 feat(deps): Auto-install beads (bd) when missing (GHI #22)
- Add internal/deps package for dependency management
- Check for bd before gt install and gt rig add
- Auto-install bd via go install if missing
- Version check warns if bd is too old (min: 0.43.0)

Closes #22

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:23:55 -08:00
mayor
3093bf40ac docs: Guide users to Mayor session in quickstart
- Change tmux from "optional" to "recommended for the full experience"
- Add "Enter the Mayor's office" step after gt rig add
- Explain Mayor role upfront in Core Concepts
- Reorder workflows to put Full Stack (Recommended) first
- Add example of conversational interaction with Mayor
- Document gt agents for session navigation

Closes #21

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:17:40 -08:00
Madison Bullard
6717dad32b Private by default (#18) 2026-01-02 11:52:23 -08:00
Steve Yegge
17c349c965 Merge pull request #26 from Avyukth/main
fix: Enable gt doctor --fix to remediate missing patrol role templates
2026-01-02 11:50:48 -08:00
Subhrajit Makur
1d9249c410 Merge pull request #1 from Avyukth/fix/patrol-roles-per-rig-check
fix: Check patrol role templates per-rig instead of at town level
2026-01-03 00:45:36 +05:30
Avyukth
19be078618 test: Add comprehensive test coverage for patrol roles check
- Add GetAllRoleTemplates tests (basic and content validity)
- Add FixMultipleRigs test for multi-rig fix scenario
- Add DetailsFormat test verifying rig:template prefix format
- Add MalformedRigsJSON test for error handling
- Add EmptyRigsConfig test for edge case
2026-01-03 00:37:08 +05:30
Avyukth
3e5562222d fix: Check patrol role templates per-rig instead of at town level
- PatrolRolesHavePromptsCheck now verifies templates exist in each rig's
  mayor clone at <rig>/mayor/rig/internal/templates/roles/
- Track missing templates by rig using missingByRig map
- Fix copies embedded templates to each rig's location
- Add GetAllRoleTemplates helper to templates package
- Add tests for no-rigs case and multiple-rigs scenarios
2026-01-03 00:34:51 +05:30
gastown/crew/max
ae61d98b1f docs: Add v0.1.1 release notes and [Unreleased] section 2026-01-02 01:49:01 -08:00
313 changed files with 26866 additions and 5246 deletions

View File

@@ -35,7 +35,7 @@ gt peek deacon --lines 20
**Step 2: Check agent bead state**
```bash
bd show gt-deacon 2>/dev/null
bd show hq-deacon 2>/dev/null
# Look for:
# - state: running/working/idle
# - last_activity: when was last update?

View File

@@ -1,7 +1,7 @@
description = """
Archive completed convoys and notify overseer.
Dogs execute this formula when convoys complete. The Deacon detects completed
Dogs work through molecules (poured from this formula) when convoys complete. The Deacon detects completed
convoys (all tracked issues closed) and slings this work to a dog for:
- Generating convoy summary
- Archiving convoy state

View File

@@ -0,0 +1,259 @@
description = """
Feed stranded convoys by dispatching ready work to available polecats.
Dogs execute this formula when the Deacon detects a stranded convoy. A convoy
is stranded when it has ready issues (open, unblocked, no assignee) but no
workers are processing them.
## Dog Contract
This is infrastructure work. You:
1. Receive convoy ID via variable
2. Load convoy and find ready issues
3. Check idle polecat capacity across rigs
4. Dispatch min(ready_issues, idle_polecats) using gt sling
5. Report actions taken
6. Return to kennel
## Variables
| Variable | Source | Description |
|----------|--------|-------------|
| convoy | --var | The stranded convoy ID to feed |
## Single Pass Design
Dog doesn't babysit or wait for completion. The workflow is:
1. Find ready issues in convoy
2. Dispatch each to an available polecat
3. Exit immediately
If convoy is still stranded next Deacon patrol cycle, another dog will be
dispatched. This keeps the system stateless and batch-oriented.
## Failure Modes
| Situation | Action |
|-----------|--------|
| Convoy not found | Exit with error, notify Deacon |
| No ready issues | Exit success (false positive, convoy is fine) |
| No idle polecats | Exit success, note in report (will retry next cycle) |
| Sling fails | Continue with remaining issues, note failures |"""
formula = "mol-convoy-feed"
version = 1
[squash]
trigger = "on_complete"
template_type = "work"
include_metrics = true
[[steps]]
id = "load-convoy"
title = "Load convoy and identify ready issues"
description = """
Load the convoy and find issues ready for dispatch.
**1. Check assignment:**
```bash
gt hook # Shows convoy in hook_bead or vars
```
**2. Load convoy details:**
```bash
gt convoy status {{convoy}} --json
```
**3. Identify ready issues:**
For each tracked issue in the convoy:
```bash
bd show <issue-id> --json
```
An issue is "ready" if ALL of these are true:
- status = "open" (NOT in_progress, closed, or hooked)
- not in blocked list (check: bd blocked --json)
- assignee is empty OR assignee session is dead
Check blocked status:
```bash
bd blocked --json
# If issue ID appears here, it's blocked (skip it)
```
Check assignee session if set:
```bash
# If assignee like "gastown/polecats/nux"
tmux has-session -t gt-gastown-polecat-nux 2>/dev/null && echo "alive" || echo "dead"
```
**4. Build ready list:**
Collect all ready issues with their metadata:
- Issue ID
- Title
- Priority
- Rig (extracted from prefix)
Sort by priority (P0 first) for dispatch order.
**Exit criteria:** Ready issues identified and prioritized."""
[[steps]]
id = "check-capacity"
title = "Check polecat capacity across rigs"
needs = ["load-convoy"]
description = """
Determine how many polecats are available for dispatch.
**1. For each rig that has ready issues:**
```bash
gt polecats <rig>
# Shows polecat status: idle, working, etc.
```
**2. Count available capacity:**
Available polecats are those that:
- Exist in the rig's polecat pool
- Currently idle (no hooked work)
- Session is running
**3. Calculate dispatch count:**
```
dispatch_count = min(ready_issues, available_polecats)
```
If dispatch_count = 0:
- Log: "No capacity available, will retry next cycle"
- Proceed to report step (no dispatches to make)
**4. Match issues to rigs:**
For each ready issue, determine target rig from issue prefix:
- gt-* issues → gastown rig
- bd-* issues → beads rig
- etc.
**Exit criteria:** Dispatch plan created with issue→rig mappings."""
[[steps]]
id = "dispatch-work"
title = "Dispatch ready issues to polecats"
needs = ["check-capacity"]
description = """
Sling each ready issue to an available polecat.
**For each issue in dispatch plan:**
```bash
# Dispatch issue to the appropriate rig
# This spawns a fresh polecat or assigns to idle one
gt sling <issue-id> <rig>
# Example:
gt sling gt-abc123 gastown
gt sling bd-xyz789 beads
```
**Track results:**
For each dispatch:
- Success: Note issue ID, target rig, polecat assigned
- Failure: Note issue ID, error message
**Important notes:**
- `gt sling` handles polecat selection automatically
- It will spawn a new polecat if none available
- The polecat gets the issue hooked and starts immediately
- Don't wait for polecat to complete - fire and forget
**If sling fails:**
- Continue with remaining issues
- Note the failure for the report
- Don't escalate individual failures (will retry next cycle)
**Exit criteria:** All dispatchable issues have been slung."""
[[steps]]
id = "report-results"
title = "Generate and send feeding report"
needs = ["dispatch-work"]
description = """
Create summary report of convoy feeding actions.
**1. Generate report:**
```markdown
## Convoy Feed Report: {{convoy}}
**Ready issues found**: {{ready_count}}
**Polecats available**: {{available_count}}
**Issues dispatched**: {{dispatch_count}}
### Dispatched Work
{{#each dispatched}}
- {{issue_id}}: {{title}} → {{rig}}/{{polecat}}
{{/each}}
### Skipped (no capacity)
{{#if skipped}}
{{#each skipped}}
- {{issue_id}}: {{title}} (will retry next cycle)
{{/each}}
{{else}}
(none)
{{/if}}
### Errors
{{#if errors}}
{{#each errors}}
- {{issue_id}}: {{error}}
{{/each}}
{{else}}
(none)
{{/if}}
```
**2. Send to Deacon:**
```bash
gt mail send deacon/ -s "Convoy fed: {{convoy}}" -m "$(cat <<EOF
Convoy {{convoy}} feeding complete.
Dispatched: {{dispatch_count}}/{{ready_count}} issues
{{#if errors}}Errors: {{error_count}}{{/if}}
{{report_summary}}
EOF
)"
```
**3. Update convoy (optional):**
If convoy has a notify field, could add a note about feeding activity.
Not required - the dispatch tracking handles visibility.
**Exit criteria:** Report generated and sent."""
[[steps]]
id = "return-to-kennel"
title = "Signal completion and return to kennel"
needs = ["report-results"]
description = """
Signal work complete and return to available pool.
**1. Signal completion to Deacon:**
```bash
gt mail send deacon/ -s "DOG_DONE $(hostname)" -m "Task: convoy-feed
Convoy: {{convoy}}
Ready: {{ready_count}}
Dispatched: {{dispatch_count}}
Status: COMPLETE
Ready for next assignment."
```
**2. Return to kennel:**
Dog returns to available state in the pool. Deacon will assign next work
or retire the dog if pool is oversized.
**Exit criteria:** Deacon notified, dog ready for next work or retirement."""
[vars]
[vars.convoy]
description = "The convoy ID to feed"
required = true

View File

@@ -1,7 +1,7 @@
description = """
Propagate cross-rig dependency resolution.
Dogs execute this formula when dependencies resolve across rig boundaries.
Dogs work through molecules (poured from this formula) when dependencies resolve across rig boundaries.
When an issue in one rig closes, dependent issues in other rigs may unblock.
This formula handles:
- Finding cross-rig dependents

View File

@@ -1,7 +1,7 @@
description = """
Generate daily digest for overseer (Mayor).
Dogs execute this formula on a scheduled basis (daily, or triggered by plugin)
Dogs work through molecules (poured from this formula) on a scheduled basis (daily, or triggered by plugin)
to create summary digests of Gas Town activity. This aggregates:
- Work completed across all rigs
- Issues filed and closed

View File

@@ -1,7 +1,7 @@
description = """
Find and reassign orphaned work.
Dogs execute this formula to scan for orphaned state across the town:
Dogs work through molecules (poured from this formula) to scan for orphaned state:
- Issues marked in_progress with no active polecat
- Molecules attached but worker gone
- Merge queue entries with dead owners

View File

@@ -0,0 +1,385 @@
description = """
Conflict resolution workflow for polecats handling merge conflicts.
This molecule guides a polecat through resolving merge conflicts for a previously
submitted MR that failed to rebase. The workflow uses the merge-slot gate to
serialize conflict resolution and prevent racing.
## Task Recognition
Conflict resolution tasks are created by the Refinery when a mechanical rebase
fails. They are identified by:
- Title prefix: "Resolve merge conflicts:"
- Metadata fields in description: Original MR, Branch, Conflict SHA
## Key Differences from Regular Polecat Work
| Aspect | Regular Work | Conflict Resolution |
|--------|--------------|---------------------|
| Branch source | Create new branch | Checkout existing MR branch |
| Merge path | Submit to queue via `gt done` | Push directly to main |
| Issue closure | Refinery closes after merge | Close MR bead yourself |
| Serialization | None | Merge-slot gate required |
## Variables
| Variable | Source | Description |
|----------|--------|-------------|
| task | hook_bead | The conflict-resolution task ID |
| original_mr | task metadata | The MR bead that had conflicts |
| branch | task metadata | The branch to rebase |
| conflict_sha | task metadata | Main SHA when conflict occurred |
## Failure Modes
| Situation | Action |
|-----------|--------|
| Merge slot held | Wait (--wait flag adds you to queue) |
| Complex conflicts | Use judgment; escalate if unsure |
| Tests fail after resolve | Fix them before pushing |
| Resolution unclear | Read original issue for context |"""
formula = "mol-polecat-conflict-resolve"
version = 1
[[steps]]
id = "load-task"
title = "Load task and extract metadata"
description = """
Initialize your session and understand the conflict resolution task.
**1. Prime your environment:**
```bash
gt prime # Load role context
bd prime # Load beads context
```
**2. Check your hook:**
```bash
gt hook # Shows your pinned molecule and hook_bead
```
**3. Read the conflict resolution task:**
```bash
bd show {{task}}
```
**4. Extract metadata from the task description:**
The task description contains structured metadata:
```
## Metadata
- Original MR: <mr-id>
- Branch: <branch>
- Conflict with: <target>@<main-sha>
- Original issue: <source-issue>
- Retry count: <count>
```
Parse and note:
- **original_mr**: The MR bead ID (you'll close this after merge)
- **branch**: The branch to checkout and rebase
- **source_issue**: The original work issue (read for context if needed)
- **retry_count**: How many times this has been attempted
**5. Understand the context:**
If the conflict seems complex, read the original issue:
```bash
bd show <source-issue> # What was the original work?
```
**Exit criteria:** You have all metadata and understand the conflict context."""
[[steps]]
id = "acquire-slot"
title = "Acquire merge slot"
needs = ["load-task"]
description = """
Acquire exclusive access to the merge slot before proceeding.
The merge slot prevents multiple conflict-resolution polecats from racing
to push to main simultaneously (the "Monkey Knife Fight" problem).
**1. Check slot availability:**
```bash
bd merge-slot check --json
```
**2. Acquire the slot:**
```bash
bd merge-slot acquire --holder=$(whoami) --wait --json
```
The `--wait` flag adds you to the waiters queue if the slot is held.
You'll proceed when the current holder releases.
**3. Verify acquisition:**
The output should show:
```json
{"available": false, "holder": "your-name", ...}
```
If you're in the waiters list, wait for the holder to release. Check
periodically:
```bash
bd merge-slot check --json
```
**Important:** Once you have the slot, complete the workflow promptly.
Other polecats may be waiting.
**Exit criteria:** You hold the merge slot exclusively."""
[[steps]]
id = "checkout-branch"
title = "Checkout and prepare the conflicting branch"
needs = ["acquire-slot"]
description = """
Fetch and checkout the branch that needs conflict resolution.
**1. Ensure clean workspace:**
```bash
git status # Should be clean
git stash list # Should be empty
```
If dirty, clean up first (stash or discard).
**2. Fetch latest state:**
```bash
git fetch origin
git fetch origin {{branch}}:refs/remotes/origin/{{branch}}
```
**3. Checkout the branch:**
```bash
git checkout -b temp-resolve origin/{{branch}}
```
Using `temp-resolve` as the local branch name keeps things clear.
**4. Verify the branch state:**
```bash
git log --oneline -5 # Recent commits
git log origin/main..HEAD # Commits not on main
```
**Exit criteria:** On temp-resolve branch, ready to rebase."""
[[steps]]
id = "rebase-resolve"
title = "Rebase onto main and resolve conflicts"
needs = ["checkout-branch"]
description = """
Perform the rebase and resolve any conflicts.
**1. Start the rebase:**
```bash
git rebase origin/main
```
**2. If conflicts occur:**
For each conflicted file:
```bash
git status # See conflicted files
git diff # See conflict markers
```
**Resolve using your judgment:**
- Read both versions carefully
- Consider the original intent (from source issue)
- If the MR was adding a feature, preserve that addition
- If the MR was fixing a bug, ensure the fix remains
**After resolving each file:**
```bash
git add <resolved-file>
git rebase --continue
```
**3. If stuck on a conflict:**
- Read the original issue for context: `bd show <source-issue>`
- If still unclear, escalate to Witness:
```bash
gt mail send <rig>/witness -s "HELP: Complex conflict" -m "Task: {{task}}
File: <conflicted-file>
Issue: Cannot determine correct resolution"
```
**4. Verify rebase success:**
```bash
git log --oneline origin/main..HEAD # Your commits rebased
git status # Clean working tree
```
**Exit criteria:** Branch successfully rebased onto origin/main."""
[[steps]]
id = "run-tests"
title = "Run tests to verify resolution"
needs = ["rebase-resolve"]
description = """
Verify the resolution doesn't break anything.
**1. Run the test suite:**
```bash
go test ./... # Or appropriate test command
```
**ALL TESTS MUST PASS.** Do not push with failures.
**2. If tests fail:**
- Determine if it's a resolution error or pre-existing
- If your resolution broke something: fix it
- If pre-existing: file a bead, but still must fix before pushing
```bash
# Quick check: does main pass?
git stash
git checkout origin/main
go test ./...
git checkout temp-resolve
git stash pop
```
**3. Run build check:**
```bash
go build ./...
```
**Exit criteria:** All tests pass, build succeeds."""
[[steps]]
id = "push-to-main"
title = "Push resolved changes directly to main"
needs = ["run-tests"]
description = """
Push the resolved branch directly to main.
**Important:** Unlike normal polecat work, conflict resolution pushes directly
to main. This is because:
1. The original MR was already reviewed/approved by being in the queue
2. We're just resolving conflicts, not adding new functionality
3. Going back through the queue would create an infinite loop
**1. Rebase one more time (in case main moved):**
```bash
git fetch origin
git rebase origin/main
```
If new conflicts: resolve them (return to rebase-resolve step).
**2. Push to main:**
```bash
git push origin temp-resolve:main
```
**3. Verify the push:**
```bash
git log origin/main --oneline -3 # Your commits should be there
```
**Exit criteria:** Changes are on origin/main."""
[[steps]]
id = "close-beads"
title = "Close the original MR bead and this task"
needs = ["push-to-main"]
description = """
Close the beads to complete the work chain.
**1. Close the original MR bead:**
```bash
bd close {{original_mr}} --reason="merged after conflict resolution"
```
This completes the MR that was blocked on conflicts.
**2. Close the source issue (if not already closed):**
```bash
bd show <source-issue> # Check status
bd close <source-issue> --reason="merged via conflict resolution"
```
The Refinery normally closes issues after merge, but since we pushed
directly to main, we handle it here.
**3. Sync beads:**
```bash
bd sync
```
**Exit criteria:** Original MR and source issue are closed."""
[[steps]]
id = "release-slot"
title = "Release merge slot"
needs = ["close-beads"]
description = """
Release the merge slot so other polecats can proceed.
**1. Release the slot:**
```bash
bd merge-slot release --holder=$(whoami) --json
```
**2. Verify release:**
```bash
bd merge-slot check --json
```
Should show either:
- `available: true` (no one waiting)
- `holder: <next-waiter>` (slot passed to next in queue)
**Exit criteria:** Merge slot released."""
[[steps]]
id = "cleanup-and-exit"
title = "Clean up and close task"
needs = ["release-slot"]
description = """
Clean up workspace and close the conflict resolution task.
**1. Clean up local branch:**
```bash
git checkout main
git branch -D temp-resolve
git fetch origin
git reset --hard origin/main
```
**2. Verify clean state:**
```bash
git status # Clean
git stash list # Empty
```
**3. Close this task:**
```bash
bd close {{task}} --reason="Conflicts resolved and merged to main"
```
**4. Signal completion:**
```bash
gt done
```
You're now recyclable. The Witness knows you've completed conflict resolution.
**Exit criteria:** Task closed, workspace clean, polecat recyclable."""
[vars]
[vars.task]
description = "The conflict resolution task ID assigned to this polecat"
required = true
[vars.original_mr]
description = "The original MR bead ID (extracted from task metadata)"
required = true
[vars.branch]
description = "The branch to rebase (extracted from task metadata)"
required = true

View File

@@ -1,22 +1,26 @@
description = """
Full polecat work lifecycle from assignment through merge-ready handoff.
Full polecat work lifecycle from assignment through MR submission.
This molecule guides a polecat through a complete work assignment. Each step
has clear entry/exit criteria and specific commands to run. A polecat can
crash after any step and resume from the last completed step.
## Polecat Contract
## Polecat Contract (Ephemeral Model)
You are an autonomous worker. You:
You are an ephemeral worker. You:
1. Receive work via your hook (pinned molecule + issue)
2. Execute the work following this formula
3. Signal completion to Witness (who verifies and merges)
4. Wait for Witness to terminate your session
2. Work through molecule steps using `bd ready` / `bd close <step>`
3. Submit to merge queue via `gt done`
4. Become recyclable - Refinery handles the rest
**Important:** This formula defines the template. Your molecule already has step
beads created from it. Use `bd ready` to find them - do NOT read this file directly.
**You do NOT:**
- Push directly to main (Refinery merges)
- Kill your own session (Witness does cleanup)
- Skip verification steps (quality gates exist for a reason)
- Close your own issue (Refinery closes after merge)
- Wait for merge (you're done at MR submission)
- Handle rebase conflicts (Refinery dispatches fresh polecats for that)
## Variables
@@ -33,7 +37,7 @@ You are an autonomous worker. You:
| Context filling | Use gt handoff to cycle to fresh session |
| Unsure what to do | Mail Witness, don't guess |"""
formula = "mol-polecat-work"
version = 3
version = 4
[[steps]]
id = "load-context"
@@ -374,21 +378,24 @@ git diff origin/main...HEAD # Your changes (expected)
**Exit criteria:** Branch pushed, workspace clean, no cruft."""
[[steps]]
id = "close-issue"
title = "Close the assigned issue"
id = "prepare-for-review"
title = "Prepare work for review"
needs = ["cleanup-workspace"]
description = """
Mark the issue as complete in beads.
Verify work is complete and ready for merge queue.
**1. Close with a summary:**
```bash
bd close {{issue}} --reason "Implemented: <brief summary of what was done>"
```
**Note:** Do NOT close the issue. The Refinery will close it after successful merge.
This enables conflict-resolution retries without reopening closed issues.
**2. Verify closure:**
**1. Verify the issue shows your work:**
```bash
bd show {{issue}}
# Status should show 'closed'
# Status should still be 'in_progress' (you're working on it)
```
**2. Add completion notes:**
```bash
bd update {{issue}} --notes "Implemented: <brief summary of what was done>"
```
**3. Sync beads:**
@@ -396,44 +403,55 @@ bd show {{issue}}
bd sync
```
**Exit criteria:** Issue closed in beads, synced to remote."""
**Exit criteria:** Issue updated with completion notes, beads synced."""
[[steps]]
id = "signal-complete"
title = "Signal completion to Witness"
needs = ["close-issue"]
id = "submit-and-exit"
title = "Submit to merge queue and exit"
needs = ["prepare-for-review"]
description = """
Notify Witness you're done and wait for termination.
Submit your work to the merge queue. You become recyclable after this.
**1. Update your agent state:**
**Ephemeral Polecat Model:**
Once you submit, you're done. The Refinery will:
1. Process your merge request
2. Handle rebasing (mechanical rebases done automatically)
3. Close your issue after successful merge
4. Create conflict-resolution tasks if needed (fresh polecat handles those)
**1. Submit with gt done:**
```bash
# Your agent bead should reflect completion
gt mol done # Or equivalent command
gt done
```
**2. Send POLECAT_DONE mail:**
```bash
gt mail send <rig>/witness -s "POLECAT_DONE $(hostname)" -m "Exit: MERGED
Issue: {{issue}}
Branch: $(git branch --show-current)
Commits: $(git log --oneline origin/main..HEAD | wc -l | tr -d ' ')
This single command:
- Creates an MR bead in the merge queue
- Notifies the Witness (POLECAT_DONE)
- Updates your agent state to 'done'
- Reports cleanup status (ZFC compliance)
Work complete. Ready for merge queue."
**2. Verify submission:**
You should see output like:
```
✓ Work submitted to merge queue
MR ID: gt-xxxxx
Source: polecat/<name>
Target: main
Issue: {{issue}}
```
**3. WAIT FOR WITNESS:**
Do NOT exit or kill your session. The Witness will:
1. Verify your git state is clean
2. Send MERGE_READY to Refinery
3. Wait for MERGED confirmation
4. Kill your session
**3. You're recyclable:**
Your work is in the queue. The Witness knows you're done.
Your sandbox can be cleaned up - all work is pushed to origin.
You may see a ~30-60 second delay while this happens.
If you don't get killed within 5 minutes, mail Witness again.
If you have context remaining, you may:
- Pick up new work from `bd ready`
- Or use `gt handoff` to cycle to a fresh session
**CRITICAL:** Do not exit yourself. Do not run `exit`. Just wait.
If the Refinery needs conflict resolution, it will dispatch a fresh polecat.
You do NOT need to wait around.
**Exit criteria:** Witness terminates your session (you won't reach this)."""
**Exit criteria:** MR submitted, Witness notified, polecat recyclable."""
[vars]
[vars.issue]

View File

@@ -1,7 +1,7 @@
description = """
Clean stale sessions and garbage collect.
Dogs execute this formula to clean up dead sessions, orphaned processes, and
Dogs work through molecules (poured from this formula) to clean up dead sessions, orphaned processes, and
other system cruft. This is the garbage collector for Gas Town's runtime:
- Dead tmux sessions (no Claude process)
- Orphaned Claude processes (no tmux parent)

View File

@@ -1,14 +1,14 @@
description = "Per-rig worker monitor patrol loop.\n\nThe Witness is the Pit Boss for your rig. You watch polecats, nudge them toward\ncompletion, verify clean git state before kills, and escalate stuck workers.\n\n**You do NOT do implementation work.** Your job is oversight, not coding.\n\n## Design Philosophy\n\nThis patrol follows Gas Town principles:\n- **Discovery over tracking**: Observe reality each cycle, don't maintain state\n- **Events over state**: POLECAT_DONE mail triggers cleanup wisps\n- **Cleanup wisps as finalizers**: Pending cleanups are wisps, not queue entries\n- **Task tool for parallelism**: Subagents inspect polecats, not molecule arms\n\n## Patrol Shape (Linear, Deacon-style)\n\n```\ninbox-check ─► process-cleanups ─► check-refinery ─► survey-workers\n │\n ┌──────────────────────────────────────────────────┘\n ▼\n check-swarm ─► ping-deacon ─► patrol-cleanup ─► context-check ─► loop-or-exit\n```\n\nNo dynamic arms. No fanout gates. No persistent nudge counters.\nState is discovered each cycle from reality (tmux, beads, mail)."
description = "Per-rig worker monitor patrol loop.\n\nThe Witness is the Pit Boss for your rig. You watch polecats, nudge them toward\ncompletion, verify clean git state before kills, and escalate stuck workers.\n\n**You do NOT do implementation work.** Your job is oversight, not coding.\n\n## Ephemeral Polecat Model\n\nPolecats are truly ephemeral - done at MR submission, recyclable immediately:\n\n```\nPolecat lifecycle: spawning → working → mr_submitted → nuked\nMR lifecycle: created → queued → processed → merged (Refinery handles)\n```\n\nOnce a polecat's branch is pushed (cleanup_status=clean), the polecat can be\nnuked immediately. The MR continues independently in the Refinery. If conflicts\narise, Refinery creates a NEW conflict-resolution task for a NEW polecat.\n\n**Key principle**: Polecat lifecycle is separate from MR lifecycle.\n\n## Design Philosophy\n\nThis patrol follows Gas Town principles:\n- **Discovery over tracking**: Observe reality each cycle, don't maintain state\n- **Events over state**: POLECAT_DONE mail triggers immediate cleanup\n- **Ephemeral by default**: Clean polecats are nuked immediately, no waiting\n- **Cleanup wisps for exceptions**: Only created when intervention needed\n- **Task tool for parallelism**: Subagents inspect polecats, not molecule arms\n\n## Patrol Shape (Linear, Deacon-style)\n\n```\ninbox-check ─► process-cleanups ─► check-refinery ─► survey-workers\n │\n ┌──────────────────────────────────────────────────┘\n ▼\n check-timer-gates ─► check-swarm ─► ping-deacon ─► patrol-cleanup ─► context-check ─► loop-or-exit\n```\n\nNo dynamic arms. No fanout gates. No persistent nudge counters.\nState is discovered each cycle from reality (tmux, beads, mail)."
formula = 'mol-witness-patrol'
version = 2
[[steps]]
description = "Check inbox and handle messages.\n\n```bash\ngt mail inbox\n```\n\nFor each message:\n\n**POLECAT_STARTED**:\nA new polecat has started working. Acknowledge and archive.\n```bash\n# Acknowledge startup (optional: log for activity tracking)\ngt mail archive <message-id>\n```\nNo action needed beyond acknowledgment - archive immediately.\n\n**POLECAT_DONE / LIFECYCLE:Shutdown**:\nCreate a cleanup wisp for this polecat:\n```bash\nbd create --wisp --title \"cleanup:<polecat>\" --description \"Verify and cleanup polecat <name>\" --labels cleanup,polecat:<name>,state:pending\n```\nThe wisp's existence IS the pending cleanup. Process in next step.\n**Do NOT archive yet** - archive after cleanup completes (in MERGED handling).\n\n**MERGED**:\nA branch was merged successfully. Complete the cleanup.\n```bash\n# Find the cleanup wisp for this polecat\nbd list --wisp --labels=polecat:<name>,state:merge-requested --status=open\n\n# If found, proceed with full polecat nuke:\n# - Kill Claude session\n# - Delete worktree\n# - Delete branch\n# - Remove agent bead\ngt polecat nuke <name>\n\n# Burn the cleanup wisp\nbd close <wisp-id>\n\n# NOW archive both the MERGED mail and the original POLECAT_DONE mail\n# (The POLECAT_DONE message ID should be tracked in the cleanup wisp or MR bead)\ngt mail archive <merged-message-id>\ngt mail archive <polecat-done-message-id> # If tracked\n```\nArchive after cleanup is complete.\n\n**HELP / Blocked**:\nAssess the request. Can you help? If not, escalate to Mayor:\n```bash\ngt mail send mayor/ -s \"Escalation: <polecat> needs help\" -m \"<details>\"\n```\nArchive after handling (escalated or resolved):\n```bash\ngt mail archive <message-id>\n```\n\n**HANDOFF**:\nRead predecessor context. Continue from where they left off.\nArchive after absorbing context:\n```bash\ngt mail archive <message-id>\n```\n\n**SWARM_START**:\nMayor initiating batch polecat work. Initialize swarm tracking.\n```bash\n# Parse swarm info from mail body: {\"swarm_id\": \"batch-123\", \"beads\": [\"bd-a\", \"bd-b\"]}\nbd create --wisp --title \"swarm:<swarm_id>\" --description \"Tracking batch: <swarm_id>\" --labels swarm,swarm_id:<swarm_id>,total:<N>,completed:0,start:<timestamp>\n```\nArchive after creating swarm tracking wisp:\n```bash\ngt mail archive <message-id>\n```\n\n**Hygiene principle**: Archive messages after they're fully processed.\nKeep only: active work, unprocessed requests. Inbox should be near-empty."
description = "Check inbox and handle messages.\n\n```bash\ngt mail inbox\n```\n\nFor each message:\n\n**POLECAT_STARTED**:\nA new polecat has started working. Acknowledge and archive.\n```bash\n# Acknowledge startup (optional: log for activity tracking)\ngt mail archive <message-id>\n```\nNo action needed beyond acknowledgment - archive immediately.\n\n**POLECAT_DONE / LIFECYCLE:Shutdown**:\n\n*EPHEMERAL MODEL*: Polecats are truly ephemeral - done at MR submission,\nrecyclable immediately. Once the branch is pushed (cleanup_status=clean),\nthe polecat can be nuked. The MR lifecycle continues independently in the\nRefinery. If conflicts arise, Refinery creates a NEW conflict-resolution\ntask for a NEW polecat.\n\nPolecat lifecycle: spawning → working → mr_submitted → nuked\nMR lifecycle: created → queued → processed → merged (handled by Refinery)\n\nThe handler (HandlePolecatDone) will:\n1. Check cleanup_status from agent bead\n2. If \"clean\" (branch pushed): AUTO-NUKE immediately, archive mail\n3. If dirty: Create cleanup wisp for manual intervention\n\n```bash\n# The handler does this automatically:\n# - For clean state: gt polecat nuke <name> → archive mail\n# - For dirty state: create wisp → process in next step\n```\n\nCleanup wisps are only created when something is wrong (uncommitted changes,\nunpushed commits). Most POLECAT_DONE messages result in immediate nuke.\n\n**MERGED**:\nA branch was merged successfully. This is informational in the ephemeral model\nsince the polecat was already nuked after MR submission.\n\nIf a cleanup wisp exists (dirty state), complete the cleanup:\n```bash\n# Find the cleanup wisp for this polecat\nbd list --wisp --labels=polecat:<name>,state:merge-requested --status=open\n\n# If found, proceed with full polecat nuke:\ngt polecat nuke <name>\n\n# Burn the cleanup wisp\nbd close <wisp-id>\n```\nArchive after cleanup is complete.\n\n**HELP / Blocked**:\nAssess the request. Can you help? If not, escalate to Mayor:\n```bash\ngt mail send mayor/ -s \"Escalation: <polecat> needs help\" -m \"<details>\"\n```\nArchive after handling (escalated or resolved):\n```bash\ngt mail archive <message-id>\n```\n\n**HANDOFF**:\nRead predecessor context. Continue from where they left off.\nArchive after absorbing context:\n```bash\ngt mail archive <message-id>\n```\n\n**SWARM_START**:\nMayor initiating batch polecat work. Initialize swarm tracking.\n```bash\n# Parse swarm info from mail body: {\"swarm_id\": \"batch-123\", \"beads\": [\"bd-a\", \"bd-b\"]}\nbd create --wisp --title \"swarm:<swarm_id>\" --description \"Tracking batch: <swarm_id>\" --labels swarm,swarm_id:<swarm_id>,total:<N>,completed:0,start:<timestamp>\n```\nArchive after creating swarm tracking wisp:\n```bash\ngt mail archive <message-id>\n```\n\n**Hygiene principle**: Archive messages after they're fully processed.\nKeep only: active work, unprocessed requests. Inbox should be near-empty."
id = 'inbox-check'
title = 'Process witness mail'
[[steps]]
description = "Find and process cleanup wisps (the finalizer pattern).\n\n```bash\n# Find all cleanup wisps\nbd list --wisp --labels=cleanup --status=open\n```\n\nFor each cleanup wisp, check its state label:\n\n## State: pending (needs verification → MERGE_READY)\n\n1. **Extract polecat name** from wisp title/labels\n\n2. **Pre-kill verification**:\n```bash\ncd polecats/<name>\ngit status # Must be clean\ngit log origin/main..HEAD # Commits should be pushed\nbd show <assigned-issue> # Issue closed or deferred\n```\n\n3. **Get branch and issue info**:\n```bash\n# Get current branch\ngit rev-parse --abbrev-ref HEAD\n\n# Get the hook_bead from agent bead\nbd show <agent-bead> # Look for hook_bead field\n```\n\n4. **Verify productive work** (ZFC - you make the call):\n - Check git log for commits mentioning the issue\n - Legitimate exceptions: already fixed, duplicate, deferred\n - If closing as 'done' with no commits, flag for review\n\n5. **If clean**: Send MERGE_READY to refinery\n```bash\ngt mail send <rig>/refinery -s \"MERGE_READY <polecat>\" -m \"Branch: <branch>\nIssue: <issue-id>\nPolecat: <polecat>\nVerified: clean git state, issue closed\"\n```\nThen update the wisp to merge-requested state:\n```bash\nbd update <wisp-id> --labels cleanup,polecat:<name>,state:merge-requested\n```\n**Do NOT kill the polecat yet** - wait for MERGED confirmation from refinery.\n\n6. **If dirty**: Leave wisp open, log the issue, retry next cycle.\n\n## State: merge-requested (waiting for refinery)\n\nSkip - waiting for MERGED mail from refinery. The inbox-check step handles\nMERGED messages and completes these cleanup wisps.\n\n**Parallelism**: Use Task tool subagents to process multiple cleanups concurrently.\nEach cleanup is independent - perfect for parallel execution."
description = "Process cleanup wisps (exception handling for dirty polecats).\n\nIn the ephemeral model, cleanup wisps are only created when a polecat has\ndirty state (uncommitted changes, unpushed commits) that prevented immediate\nnuke. Most polecats are nuked immediately on POLECAT_DONE and never create wisps.\n\n```bash\n# Find all cleanup wisps\nbd list --wisp --labels=cleanup --status=open\n```\n\nIf no wisps, skip this step (most common case in ephemeral model).\n\nFor each cleanup wisp, investigate and resolve the dirty state:\n\n## State: pending (needs investigation)\n\n1. **Extract polecat name** from wisp title/labels\n\n2. **Diagnose the problem**:\n```bash\ncd polecats/<name>\ngit status # What's uncommitted?\ngit stash list # Any stashed work?\ngit log origin/main..HEAD # Any unpushed commits?\n```\n\n3. **Resolution options**:\n - **Uncommitted changes**: Commit and push, then nuke\n - **Stashed work**: Pop and commit, or discard if not valuable\n - **Unpushed commits**: Push to origin, then nuke\n - **All valuable work lost**: Escalate to Mayor for recovery\n\n4. **If resolvable locally**: Fix and nuke\n```bash\n# Example: push unpushed commits\ngit push origin HEAD\n\n# Then nuke\ngt polecat nuke <name>\n\n# Close the wisp\nbd close <wisp-id> --reason \"Resolved: pushed commits, nuked\"\n```\n\n5. **If needs escalation**: Send RECOVERY_NEEDED to Mayor\n```bash\ngt mail send mayor/ -s \"RECOVERY_NEEDED <rig>/<polecat>\" \\\n -m \"Cleanup Status: <status>\nBranch: <branch>\nIssue: <issue-id>\n\nCannot auto-resolve. Please advise.\"\n```\nLeave wisp open until Mayor resolves.\n\n## State: merge-requested (legacy, rare)\n\nThis state was used before the ephemeral model. If found, the polecat is\nwaiting for a MERGED signal. The inbox-check step handles these.\n\n**Parallelism**: Use Task tool subagents to process multiple cleanups concurrently.\nEach cleanup is independent - perfect for parallel execution."
id = 'process-cleanups'
needs = ['inbox-check']
title = 'Process pending cleanup wisps'
@@ -20,15 +20,21 @@ needs = ['process-cleanups']
title = 'Ensure refinery is alive'
[[steps]]
description = "Survey all polecats using agent beads (ZFC: trust what agents report).\n\n**Step 1: List polecat agent beads**\n\n```bash\nbd list --type=agent --json\n```\n\nFilter the JSON output for entries where description contains `role_type: polecat`.\nEach polecat agent bead has fields in its description:\n- `role_type: polecat`\n- `rig: <rig-name>`\n- `agent_state: running|idle|stuck|done`\n- `hook_bead: <current-work-id>`\n\n**Step 2: For each polecat, check agent_state**\n\n| agent_state | Meaning | Action |\n|-------------|---------|--------|\n| running | Actively working | Check progress (Step 3) |\n| idle | No work assigned | Auto-nuke if clean (Step 3a) |\n| stuck | Self-reported stuck | Handle stuck protocol |\n| done | Work complete | Verify cleanup triggered (see Step 4a) |\n\n**Step 3: For running polecats, assess progress**\n\nCheck the hook_bead field to see what they're working on:\n```bash\nbd show <hook_bead> # See current step/issue\n```\n\nYou can also verify they're responsive:\n```bash\ntmux capture-pane -t gt-<rig>-<name> -p | tail -20\n```\n\nLook for:\n- Recent tool activity → making progress\n- Idle at prompt → may need nudge\n- Error messages → may need help\n\n**Step 3a: For idle polecats, auto-nuke if clean**\n\nWhen agent_state=idle, the polecat has no work assigned. Check if it's safe to nuke:\n\n```bash\n# Check git status in the polecat's worktree\ncd polecats/<name>\ngit status --porcelain # Should be empty (clean)\ngit log origin/main..HEAD # Should have no unpushed commits\n```\n\n**If clean** (no uncommitted changes, no unpushed commits):\n```bash\n# Safe to nuke - no work to lose\ngt polecat nuke <name>\n```\nLog the auto-nuke for audit purposes. No escalation needed.\n\n**If dirty** (uncommitted or unpushed work):\n```bash\n# Escalate to Mayor - polecat has work that might be valuable\ngt mail send mayor/ -s \\\"IDLE_DIRTY: <polecat> has uncommitted work\\\" \\\n -m \\\"Polecat: <name>\nState: idle (no hook_bead)\nGit status: <uncommitted-files>\nUnpushed commits: <count>\n\nPlease advise: recover work or discard?\\\"\n```\n\n**Rationale**: Idle polecats with clean git state are pure overhead. They have\nno work and no state worth preserving. Nuking them immediately frees resources\nand reduces noise. Only escalate when there's actual work at risk.\n\n**Step 4: Decide action**\n\n| Observation | Action |\n|-------------|--------|\n| agent_state=running, recent activity | None |\n| agent_state=running, idle 5-15 min | Gentle nudge |\n| agent_state=running, idle 15+ min | Direct nudge with deadline |\n| agent_state=stuck | Assess and help or escalate |\n| agent_state=done | Verify cleanup triggered (see Step 4a) |\n\n**Step 4a: Handle agent_state=done**\n\nCheck if a cleanup wisp exists for this polecat:\n```bash\nbd list --wisp --labels=polecat:<name> --status=open\n```\n\nIf cleanup wisp exists:\n- state:pending → Will be processed in process-cleanups\n- state:merge-requested → Waiting for refinery MERGED response\n\nIf NO cleanup wisp exists (POLECAT_DONE mail missed):\nCreate one to trigger the cleanup flow:\n```bash\nbd create --wisp --title \"cleanup:<polecat>\" --description \"Discovered done polecat without cleanup wisp\" --labels cleanup,polecat:<name>,state:pending\n```\nThis ensures done polecats eventually get cleaned up even if mail was lost.\n\n**Step 5: Execute nudges**\n```bash\ngt nudge <rig>/polecats/<name> \"How's progress? Need help?\"\n```\n\n**Step 6: Escalate if needed**\n```bash\ngt mail send mayor/ -s \"Escalation: <polecat> stuck\" \\\n -m \"Polecat <name> reports stuck. Please intervene.\"\n```\n\n**Parallelism**: Use Task tool subagents to inspect multiple polecats concurrently.\n\n**ZFC Principle**: Trust agent_state from beads. Don't infer state from PID/tmux."
description = "Survey all polecats using agent beads (ZFC: trust what agents report).\n\n**Step 1: List polecat agent beads**\n\n```bash\nbd list --type=agent --json\n```\n\nFilter the JSON output for entries where description contains `role_type: polecat`.\nEach polecat agent bead has fields in its description:\n- `role_type: polecat`\n- `rig: <rig-name>`\n- `agent_state: running|idle|stuck|done`\n- `hook_bead: <current-work-id>`\n\n**Step 2: For each polecat, check agent_state**\n\n| agent_state | Meaning | Action |\n|-------------|---------|--------|\n| running | Actively working | Check progress (Step 3) |\n| idle | No work assigned | Auto-nuke if clean (Step 3a) |\n| stuck | Self-reported stuck | Handle stuck protocol |\n| done | Work complete | Verify cleanup triggered (see Step 4a) |\n\n**Step 3: For running polecats, assess progress**\n\nCheck the hook_bead field to see what they're working on:\n```bash\nbd show <hook_bead> # See current step/issue\n```\n\nYou can also verify they're responsive:\n```bash\ntmux capture-pane -t gt-<rig>-<name> -p | tail -20\n```\n\nLook for:\n- Recent tool activity → making progress\n- Idle at prompt → may need nudge\n- Error messages → may need help\n\n**Step 3a: For idle polecats, auto-nuke if clean**\n\nWhen agent_state=idle, the polecat has no work assigned. Check if it's safe to nuke:\n\n```bash\n# Check git status in the polecat's worktree\ncd polecats/<name>\ngit status --porcelain # Should be empty (clean)\ngit log origin/main..HEAD # Should have no unpushed commits\n```\n\n**If clean** (no uncommitted changes, no unpushed commits):\n```bash\n# Safe to nuke - no work to lose\ngt polecat nuke <name>\n```\nLog the auto-nuke for audit purposes. No escalation needed.\n\n**If dirty** (uncommitted or unpushed work):\n```bash\n# Escalate to Mayor - polecat has work that might be valuable\ngt mail send mayor/ -s \\\"IDLE_DIRTY: <polecat> has uncommitted work\\\" \\\n -m \\\"Polecat: <name>\nState: idle (no hook_bead)\nGit status: <uncommitted-files>\nUnpushed commits: <count>\n\nPlease advise: recover work or discard?\\\"\n```\n\n**Rationale**: Idle polecats with clean git state are pure overhead. They have\nno work and no state worth preserving. Nuking them immediately frees resources\nand reduces noise. Only escalate when there's actual work at risk.\n\n**Step 4: Decide action**\n\n| Observation | Action |\n|-------------|--------|\n| agent_state=running, recent activity | None |\n| agent_state=running, idle 5-15 min | Gentle nudge |\n| agent_state=running, idle 15+ min | Direct nudge with deadline |\n| agent_state=stuck | Assess and help or escalate |\n| agent_state=done | Verify cleanup triggered (see Step 4a) |\n\n**Step 4a: Handle agent_state=done**\n\nIn the ephemeral model, polecats with agent_state=done and cleanup_status=clean\nshould already be nuked by HandlePolecatDone. Finding one here indicates:\n\n1. **Stale agent bead** - polecat was nuked but bead remains\n ```bash\n # Verify polecat doesn't exist anymore\n ls polecats/<name> 2>/dev/null || echo \"Already nuked\"\n ```\n If nuked, the agent bead is stale. Clean it up or ignore.\n\n2. **Cleanup wisp exists** - polecat has dirty state needing intervention\n ```bash\n bd list --wisp --labels=polecat:<name> --status=open\n ```\n Process in process-cleanups step.\n\n3. **No wisp, polecat exists** - POLECAT_DONE mail was missed\n Try auto-nuke directly (ephemeral model):\n ```bash\n # Check cleanup_status and nuke if clean\n gt polecat nuke <name> # Will fail if dirty\n ```\n If nuke fails (dirty state), create cleanup wisp for investigation.\n\n**Step 5: Execute nudges**\n```bash\ngt nudge <rig>/polecats/<name> \"How's progress? Need help?\"\n```\n\n**Step 6: Escalate if needed**\n```bash\ngt mail send mayor/ -s \"Escalation: <polecat> stuck\" \\\n -m \"Polecat <name> reports stuck. Please intervene.\"\n```\n\n**Parallelism**: Use Task tool subagents to inspect multiple polecats concurrently.\n\n**ZFC Principle**: Trust agent_state from beads. Don't infer state from PID/tmux."
id = 'survey-workers'
needs = ['check-refinery']
title = 'Inspect all active polecats'
[[steps]]
description = "Check for expired timer gates and escalate as needed.\n\nTimer gates are async wait conditions with a timeout. When the timeout expires,\nthe gate should be escalated to the overseer for human intervention.\n\n**Step 1: Run timer gate check**\n```bash\nbd gate check --type=timer --escalate\n```\n\nThis command:\n1. Finds all open gate issues with await_type=timer\n2. Checks if `now > created_at + timeout`\n3. Escalates expired gates via `gt escalate` (HIGH severity)\n4. Reports summary of gate status\n\n**Step 2: Review output**\n\nIf expired gates were found and escalated:\n- The escalation creates an audit trail bead\n- Overseer will be notified via mail\n- Gate remains open until manually resolved\n\nIf no expired gates:\n- Continue patrol normally\n\n**Note**: Timer gates do NOT auto-close on expiration. They escalate.\nThis ensures human oversight of timeout conditions.\n\n**Parallelism**: This is a single command, no parallel execution needed."
id = 'check-timer-gates'
needs = ['survey-workers']
title = 'Check timer gates for expiration'
[[steps]]
description = "If Mayor started a batch (SWARM_START), check if all polecats have completed.\n\n**Step 1: Find active swarm tracking wisps**\n```bash\nbd list --wisp --labels=swarm --status=open\n```\nIf no active swarm, skip this step.\n\n**Step 2: Count completed polecats for this swarm**\n\nExtract from wisp labels: swarm_id, total, completed, start timestamp.\nCheck how many cleanup wisps have been closed for this swarm's polecats.\n\n**Step 3: If all complete, notify Mayor**\n```bash\ngt mail send mayor/ -s \"SWARM_COMPLETE: <swarm_id>\" -m \"All <total> polecats merged.\nDuration: <minutes> minutes\nSwarm: <swarm_id>\"\n\n# Close the swarm tracking wisp\nbd close <swarm-wisp-id> --reason \"All polecats merged\"\n```\n\nNote: Runs every patrol cycle. Notification sent exactly once when all complete."
id = 'check-swarm-completion'
needs = ['survey-workers']
needs = ['check-timer-gates']
title = 'Check if active swarm is complete'
[[steps]]
@@ -38,7 +44,7 @@ needs = ['check-swarm-completion']
title = 'Ping Deacon for health check'
[[steps]]
description = "Verify inbox hygiene before ending patrol cycle.\n\n**Step 1: Check inbox state**\n```bash\ngt mail inbox\n```\n\nInbox should contain ONLY:\n- Unprocessed messages (just arrived, will handle next cycle)\n- Active work markers (POLECAT_DONE waiting for MERGED confirmation)\n\n**Step 2: Archive any stale messages**\n\nLook for messages that were processed but not archived:\n- POLECAT_STARTED older than this cycle → archive\n- HELP/Blocked that was escalated → archive\n- SWARM_START that created tracking wisp → archive\n\n```bash\n# For each stale message found:\ngt mail archive <message-id>\n```\n\n**Step 3: Verify cleanup wisp hygiene**\n\nCheck that all cleanup wisps are in valid states:\n```bash\nbd list --wisp --labels=cleanup --status=open\n```\n\n- state:pending → Will be processed next cycle\n- state:merge-requested → Waiting for refinery\n\nIf any cleanup wisp is older than expected (>1 hour in merge-requested state),\nthe refinery may be stuck. This was checked in check-refinery step.\n\n**Goal**: Inbox should have ≤5 active messages at end of cycle."
description = "Verify inbox hygiene before ending patrol cycle.\n\n**Step 1: Check inbox state**\n```bash\ngt mail inbox\n```\n\nIn the ephemeral model, most POLECAT_DONE messages are handled immediately\n(auto-nuke) and archived. Inbox should contain ONLY:\n- Unprocessed messages (just arrived, will handle next cycle)\n- MERGED notifications (informational, archive after reading)\n\n**Step 2: Archive any stale messages**\n\nLook for messages that were processed but not archived:\n- POLECAT_STARTED older than this cycle → archive\n- POLECAT_DONE that was auto-nuked → should be archived already\n- MERGED notifications → archive after acknowledging\n- HELP/Blocked that was escalated → archive\n- SWARM_START that created tracking wisp → archive\n\n```bash\n# For each stale message found:\ngt mail archive <message-id>\n```\n\n**Step 3: Verify cleanup wisp hygiene**\n\nIn the ephemeral model, cleanup wisps should be rare (only for dirty polecats):\n```bash\nbd list --wisp --labels=cleanup --status=open\n```\n\n- state:pending → Needs investigation in process-cleanups\n- state:merge-requested → Legacy state, handle in inbox-check\n\nIf cleanup wisps are accumulating, investigate why polecats aren't clean.\n\n**Goal**: Inbox should be nearly empty. Cleanup wisps should be rare."
id = 'patrol-cleanup'
needs = ['ping-deacon']
title = 'End-of-cycle inbox hygiene'
@@ -50,7 +56,7 @@ needs = ['patrol-cleanup']
title = 'Check own context limit'
[[steps]]
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."
id = 'loop-or-exit'
needs = ['context-check']
title = 'Loop or exit for respawn'

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
gt-gastown-polecat-dementus

View File

@@ -1,4 +0,0 @@
{
"database": "beads.db",
"jsonl_export": "issues.jsonl"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-09eim",
"branch": "polecat/toast-1767088545235",
"target": "main",
"source_issue": "toast-1767088545235",
"worker": "",
"rig": "gastown",
"title": "Merge: toast-1767088545235",
"priority": 2,
"created_at": "2025-12-30T02:01:08.537717-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-0a0vr",
"branch": "polecat/furiosa-1767087671424",
"target": "main",
"source_issue": "furiosa-1767087671424",
"worker": "",
"rig": "gastown",
"title": "Merge: furiosa-1767087671424",
"priority": 2,
"created_at": "2025-12-30T01:53:07.730594-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-0h89l",
"branch": "polecat/furiosa-1767084006859",
"target": "main",
"source_issue": "furiosa-1767084006859",
"worker": "",
"rig": "gastown",
"title": "Merge: furiosa-1767084006859",
"priority": 2,
"created_at": "2025-12-30T00:47:11.803227-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-215tk",
"branch": "polecat/warboy-1767106060799",
"target": "main",
"source_issue": "warboy-1767106060799",
"worker": "",
"rig": "gastown",
"title": "Merge: warboy-1767106060799",
"priority": 2,
"created_at": "2025-12-30T10:40:55.503776-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-2c4o0",
"branch": "polecat/dementus-1767087772272",
"target": "main",
"source_issue": "dementus-1767087772272",
"worker": "",
"rig": "gastown",
"title": "Merge: dementus-1767087772272",
"priority": 2,
"created_at": "2025-12-30T02:06:35.286507-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-2hirc",
"branch": "polecat/capable-1767084028536",
"target": "main",
"source_issue": "capable-1767084028536",
"worker": "",
"rig": "gastown",
"title": "Merge: capable-1767084028536",
"priority": 2,
"created_at": "2025-12-30T01:03:19.471054-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-2puev",
"branch": "polecat/dementus-1767081113622",
"target": "main",
"source_issue": "dementus-1767081113622",
"worker": "dementus-1767081113622",
"rig": "gastown",
"title": "Merge: dementus-1767081113622",
"priority": 2,
"created_at": "2025-12-30T00:05:15.468509-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-2tspu",
"branch": "polecat/furiosa-dogs",
"target": "main",
"source_issue": "furiosa-dogs",
"worker": "",
"rig": "gastown",
"title": "Merge: furiosa-dogs",
"priority": 2,
"created_at": "2025-12-30T10:42:17.458391-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-3gepq",
"branch": "polecat/toast-1767081120579",
"target": "main",
"source_issue": "toast-1767081120579",
"worker": "toast-1767081120579",
"rig": "gastown",
"title": "Merge: toast-1767081120579",
"priority": 2,
"created_at": "2025-12-30T00:05:15.468721-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-4a9y4",
"branch": "polecat/slit-1767138831931",
"target": "main",
"source_issue": "slit-1767138831931",
"worker": "",
"rig": "gastown",
"title": "Merge: slit-1767138831931",
"priority": 2,
"created_at": "2025-12-30T16:15:39.347085-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-4nobz",
"branch": "polecat/capable-1767140263101",
"target": "main",
"source_issue": "capable-1767140263101",
"worker": "",
"rig": "gastown",
"title": "Merge: capable-1767140263101",
"priority": 2,
"created_at": "2025-12-30T16:26:48.128098-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-4q7wh",
"branch": "polecat/nux-1767141948667",
"target": "main",
"source_issue": "nux-1767141948667",
"worker": "",
"rig": "gastown",
"title": "Merge: nux-1767141948667",
"priority": 2,
"created_at": "2025-12-30T16:51:43.00565-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-5ggcs",
"branch": "polecat/slit-1767082302712",
"target": "main",
"source_issue": "slit-1767082302712",
"worker": "",
"rig": "gastown",
"title": "Merge: slit-1767082302712",
"priority": 2,
"created_at": "2025-12-30T00:18:54.19263-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-643ie",
"branch": "polecat/slit-1767141951901",
"target": "main",
"source_issue": "slit-1767141951901",
"worker": "",
"rig": "gastown",
"title": "Merge: slit-1767141951901",
"priority": 2,
"created_at": "2025-12-30T16:56:13.685311-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-6l7h1",
"branch": "polecat/morsov-dogs",
"target": "main",
"source_issue": "morsov-dogs",
"worker": "",
"rig": "gastown",
"title": "Merge: morsov-dogs",
"priority": 2,
"created_at": "2025-12-30T10:41:30.109352-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-804je",
"branch": "polecat/dementus-1767146229184",
"target": "main",
"source_issue": "dementus-1767146229184",
"worker": "",
"rig": "gastown",
"title": "Merge: dementus-1767146229184",
"priority": 2,
"created_at": "2025-12-30T18:01:50.012819-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-860md",
"branch": "polecat/capable-1767146233256",
"target": "main",
"source_issue": "capable-1767146233256",
"worker": "",
"rig": "gastown",
"title": "Merge: capable-1767146233256",
"priority": 2,
"created_at": "2025-12-30T18:03:37.998767-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-9g6md",
"branch": "polecat/nux-1767082300311",
"target": "main",
"source_issue": "nux-1767082300311",
"worker": "",
"rig": "gastown",
"title": "Merge: nux-1767082300311",
"priority": 2,
"created_at": "2025-12-30T00:18:32.959791-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-9hfky",
"branch": "polecat/toast-1767140378007",
"target": "main",
"source_issue": "toast-1767140378007",
"worker": "",
"rig": "gastown",
"title": "Merge: toast-1767140378007",
"priority": 2,
"created_at": "2025-12-30T16:28:18.459411-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-aa1jz",
"branch": "polecat/keeper-dogs",
"target": "main",
"source_issue": "keeper-dogs",
"worker": "",
"rig": "gastown",
"title": "Merge: keeper-dogs",
"priority": 2,
"created_at": "2025-12-30T10:36:28.247719-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-apft7",
"branch": "polecat/capable-1767084028536",
"target": "main",
"source_issue": "capable-1767084028536",
"worker": "",
"rig": "gastown",
"title": "Merge: capable-1767084028536",
"priority": 2,
"created_at": "2025-12-30T01:04:07.334023-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-bnfus",
"branch": "polecat/rictus-1767138835254",
"target": "main",
"source_issue": "rictus-1767138835254",
"worker": "",
"rig": "gastown",
"title": "Merge: rictus-1767138835254",
"priority": 2,
"created_at": "2025-12-30T16:27:17.228997-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-bx4ki",
"branch": "polecat/keeper-dogs",
"target": "main",
"source_issue": "keeper-dogs",
"worker": "",
"rig": "gastown",
"title": "Merge: keeper-dogs",
"priority": 2,
"created_at": "2025-12-30T10:53:39.674941-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-c7qtp",
"branch": "polecat/rictus-1767084016819",
"target": "main",
"source_issue": "rictus-1767084016819",
"worker": "",
"rig": "gastown",
"title": "Merge: rictus-1767084016819",
"priority": 2,
"created_at": "2025-12-30T00:49:18.337909-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-cfpd8",
"branch": "polecat/capable-mq-events",
"target": "main",
"source_issue": "capable-mq",
"worker": "",
"rig": "gastown",
"title": "Merge: capable-mq",
"priority": 2,
"created_at": "2025-12-30T01:14:13.648371-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-cpxxv",
"branch": "polecat/organic-1767106082951",
"target": "main",
"source_issue": "organic-1767106082951",
"worker": "",
"rig": "gastown",
"title": "Merge: organic-1767106082951",
"priority": 2,
"created_at": "2025-12-30T10:42:25.228746-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-djv74",
"branch": "polecat/nux-1767081106779",
"target": "main",
"source_issue": "nux-1767081106779",
"worker": "nux-1767081106779",
"rig": "gastown",
"title": "Merge: nux-1767081106779",
"priority": 2,
"created_at": "2025-12-30T00:05:15.468625-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-dufx1",
"branch": "polecat/capable-1767140263101",
"target": "main",
"source_issue": "capable-1767140263101",
"worker": "",
"rig": "gastown",
"title": "Merge: capable-1767140263101",
"priority": 2,
"created_at": "2025-12-30T16:24:39.547495-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-e0p84",
"branch": "polecat/toast-1767081120579",
"target": "main",
"source_issue": "toast-1767081120579",
"worker": "toast-1767081120579",
"rig": "gastown",
"title": "Merge: toast-1767081120579",
"priority": 2,
"created_at": "2025-12-30T00:05:15.468573-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-gdbcb",
"branch": "polecat/rictus-1767141956287",
"target": "main",
"source_issue": "rictus-1767141956287",
"worker": "",
"rig": "gastown",
"title": "Merge: rictus-1767141956287",
"priority": 2,
"created_at": "2025-12-30T16:47:36.875216-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-gnuat",
"branch": "polecat/dementus-1767081113622",
"target": "main",
"source_issue": "dementus-1767081113622",
"worker": "dementus-1767081113622",
"rig": "gastown",
"title": "Merge: dementus-1767081113622",
"priority": 2,
"created_at": "2025-12-30T00:05:15.468374-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-gres0",
"branch": "polecat/nux-1767084010093",
"target": "main",
"source_issue": "nux-1767084010093",
"worker": "",
"rig": "gastown",
"title": "Merge: nux-1767084010093",
"priority": 2,
"created_at": "2025-12-30T00:48:40.079116-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-hrhts",
"branch": "polecat/cheedo-1767146245543",
"target": "main",
"source_issue": "cheedo-1767146245543",
"worker": "",
"rig": "gastown",
"title": "Merge: cheedo-1767146245543",
"priority": 2,
"created_at": "2025-12-30T18:00:27.283919-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-i6xqu",
"branch": "polecat/toast-1767146237529",
"target": "main",
"source_issue": "toast-1767146237529",
"worker": "",
"rig": "gastown",
"title": "Merge: toast-1767146237529",
"priority": 2,
"created_at": "2025-12-30T18:03:32.883944-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-i7tmd",
"branch": "polecat/rictus-1767084016819",
"target": "main",
"source_issue": "rictus-1767084016819",
"worker": "",
"rig": "gastown",
"title": "Merge: rictus-1767084016819",
"priority": 2,
"created_at": "2025-12-30T00:58:46.110174-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-i9y2a",
"branch": "polecat/toast-1767146237529",
"target": "main",
"source_issue": "toast-1767146237529",
"worker": "",
"rig": "gastown",
"title": "Merge: toast-1767146237529",
"priority": 2,
"created_at": "2025-12-30T18:04:15.705404-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-iai8v",
"branch": "polecat/nux-1767082300311",
"target": "main",
"source_issue": "nux-1767082300311",
"worker": "",
"rig": "gastown",
"title": "Merge: nux-1767082300311",
"priority": 2,
"created_at": "2025-12-30T00:16:15.874394-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-jl4ze",
"branch": "polecat/dementus-1767084022436",
"target": "main",
"source_issue": "dementus-1767084022436",
"worker": "",
"rig": "gastown",
"title": "Merge: dementus-1767084022436",
"priority": 2,
"created_at": "2025-12-30T00:49:44.391479-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-jsoiw",
"branch": "polecat/dag-1767146241770",
"target": "main",
"source_issue": "dag-1767146241770",
"worker": "",
"rig": "gastown",
"title": "Merge: dag-1767146241770",
"priority": 2,
"created_at": "2025-12-30T18:03:10.025552-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-klu0r",
"branch": "polecat/nux-1767083432904",
"target": "main",
"source_issue": "nux-1767083432904",
"worker": "",
"rig": "gastown",
"title": "Merge: nux-1767083432904",
"priority": 2,
"created_at": "2025-12-30T00:35:43.911656-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-l2b6v",
"branch": "polecat/slit-1767084013378",
"target": "main",
"source_issue": "slit-1767084013378",
"worker": "",
"rig": "gastown",
"title": "Merge: slit-1767084013378",
"priority": 2,
"created_at": "2025-12-30T00:49:46.335483-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-nduix",
"branch": "polecat/nux-1767138828269",
"target": "main",
"source_issue": "nux-1767138828269",
"worker": "",
"rig": "gastown",
"title": "Merge: nux-1767138828269",
"priority": 2,
"created_at": "2025-12-30T16:17:54.718789-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-npu0m",
"branch": "polecat/imperator-1767106079026",
"target": "main",
"source_issue": "imperator-1767106079026",
"worker": "",
"rig": "gastown",
"title": "Merge: imperator-1767106079026",
"priority": 2,
"created_at": "2025-12-30T10:40:11.954481-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-nq5l9",
"branch": "polecat/nux-1767087680976",
"target": "main",
"source_issue": "nux-1767087680976",
"worker": "",
"rig": "gastown",
"title": "Merge: nux-1767087680976",
"priority": 2,
"created_at": "2025-12-30T13:43:41.691922-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-nu47q",
"branch": "polecat/rictus-1767087768853",
"target": "main",
"source_issue": "rictus-1767087768853",
"worker": "",
"rig": "gastown",
"title": "Merge: rictus-1767087768853",
"priority": 2,
"created_at": "2025-12-30T01:54:12.913353-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-pulkh",
"branch": "polecat/ace-dogs",
"target": "main",
"source_issue": "ace-dogs",
"worker": "",
"rig": "gastown",
"title": "Merge: ace-dogs",
"priority": 2,
"created_at": "2025-12-30T10:36:01.970507-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-qduud",
"branch": "polecat/furiosa-1767084006859",
"target": "main",
"source_issue": "furiosa-1767084006859",
"worker": "",
"rig": "gastown",
"title": "Merge: furiosa-1767084006859",
"priority": 2,
"created_at": "2025-12-30T00:48:06.518381-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-r099o",
"branch": "polecat/imperator-1767106079026",
"target": "main",
"source_issue": "imperator-1767106079026",
"worker": "",
"rig": "gastown",
"title": "Merge: imperator-1767106079026",
"priority": 2,
"created_at": "2025-12-30T10:46:40.452899-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-sp1tv",
"branch": "polecat/rictus-1767081110235",
"target": "main",
"source_issue": "rictus-1767081110235",
"worker": "rictus-1767081110235",
"rig": "gastown",
"title": "Merge: rictus-1767081110235",
"priority": 2,
"created_at": "2025-12-30T00:05:15.468677-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-svmj8",
"branch": "polecat/cheedo-1767088553821",
"target": "main",
"source_issue": "cheedo-1767088553821",
"worker": "",
"rig": "gastown",
"title": "Merge: cheedo-1767088553821",
"priority": 2,
"created_at": "2025-12-30T10:37:17.028645-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-t072g",
"branch": "polecat/nux-1767084010093",
"target": "main",
"source_issue": "nux-1767084010093",
"worker": "",
"rig": "gastown",
"title": "Merge: nux-1767084010093",
"priority": 2,
"created_at": "2025-12-30T00:50:06.177433-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-tjy9r",
"branch": "polecat/capable-1767074974673",
"target": "main",
"source_issue": "capable-1767074974673",
"worker": "capable-1767074974673",
"rig": "gastown",
"title": "Merge: capable-1767074974673",
"priority": 2,
"created_at": "2025-12-30T00:05:15.468769-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-tpq7i",
"branch": "polecat/keeper-1767074342207",
"target": "main",
"source_issue": "keeper-1767074342207",
"worker": "keeper-1767074342207",
"rig": "gastown",
"title": "Merge: keeper-1767074342207",
"priority": 2,
"created_at": "2025-12-30T00:05:15.468817-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-u65t8",
"branch": "polecat/valkyrie-1767106008400",
"target": "main",
"source_issue": "valkyrie-1767106008400",
"worker": "",
"rig": "gastown",
"title": "Merge: valkyrie-1767106008400",
"priority": 2,
"created_at": "2025-12-30T10:43:03.505961-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-ug23r",
"branch": "polecat/cheedo-1767088553821",
"target": "main",
"source_issue": "cheedo-1767088553821",
"worker": "",
"rig": "gastown",
"title": "Merge: cheedo-1767088553821",
"priority": 2,
"created_at": "2025-12-30T02:00:38.571996-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-w4v1o",
"branch": "polecat/furiosa-dogs",
"target": "main",
"source_issue": "furiosa-dogs",
"worker": "",
"rig": "gastown",
"title": "Merge: furiosa-dogs",
"priority": 2,
"created_at": "2025-12-30T11:01:55.023855-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-x1xf4",
"branch": "polecat/slit-1767087730371",
"target": "main",
"source_issue": "slit-1767087730371",
"worker": "",
"rig": "gastown",
"title": "Merge: slit-1767087730371",
"priority": 2,
"created_at": "2025-12-30T01:52:04.349503-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-xv6b6",
"branch": "polecat/dementus-1767140140908",
"target": "main",
"source_issue": "dementus-1767140140908",
"worker": "",
"rig": "gastown",
"title": "Merge: dementus-1767140140908",
"priority": 2,
"created_at": "2025-12-30T16:23:04.504091-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-yh051",
"branch": "polecat/rictus-1767084016819",
"target": "main",
"source_issue": "rictus-1767084016819",
"worker": "",
"rig": "gastown",
"title": "Merge: rictus-1767084016819",
"priority": 2,
"created_at": "2025-12-30T00:48:16.329248-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-yjrb7",
"branch": "polecat/furiosa-dogs",
"target": "main",
"source_issue": "furiosa-dogs",
"worker": "",
"rig": "gastown",
"title": "Merge: furiosa-dogs",
"priority": 2,
"created_at": "2025-12-30T10:52:57.896189-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-yqxcq",
"branch": "polecat/furiosa-1767141944421",
"target": "main",
"source_issue": "furiosa-1767141944421",
"worker": "",
"rig": "gastown",
"title": "Merge: furiosa-1767141944421",
"priority": 2,
"created_at": "2025-12-30T16:49:14.139123-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-zet9d",
"branch": "polecat/nux-1767087680976",
"target": "main",
"source_issue": "nux-1767087680976",
"worker": "",
"rig": "gastown",
"title": "Merge: nux-1767087680976",
"priority": 2,
"created_at": "2025-12-30T01:50:53.298145-08:00"
}

View File

@@ -1,11 +0,0 @@
{
"id": "gt-zvfnu",
"branch": "polecat/furiosa-1767138824776",
"target": "main",
"source_issue": "furiosa-1767138824776",
"worker": "",
"rig": "gastown",
"title": "Merge: furiosa-1767138824776",
"priority": 2,
"created_at": "2025-12-30T16:09:55.272069-08:00"
}

View File

@@ -35,6 +35,17 @@
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "gt costs record"
}
]
}
]
}
}

View File

@@ -0,0 +1,71 @@
---
name: handoff
description: >
Hand off to a fresh Claude session. Use when context is full, you've finished
a logical chunk of work, or need a fresh perspective. Work continues from hook.
allowed-tools: "Bash(gt handoff:*),Bash(gt mail send:*)"
version: "1.0.0"
author: "Gas Town"
---
# Handoff - Session Cycling for Gas Town Agents
Hand off your current session to a fresh Claude instance while preserving work context.
## When to Use
- Context getting full (approaching token limit)
- Finished a logical chunk of work
- Need a fresh perspective on a problem
- Human requests session cycling
## Usage
```
/handoff [optional message]
```
## How It Works
1. If you provide a message, it's sent as handoff mail to yourself
2. `gt handoff` respawns your session with a fresh Claude
3. New session auto-primes via SessionStart hook
4. Work continues from your hook (pinned molecule persists)
## Examples
```bash
# Simple handoff (molecule persists, fresh context)
/handoff
# Handoff with context notes
/handoff "Found the bug in token refresh - check line 145 in auth.go first"
```
## What Persists
- **Hooked molecule**: Your work assignment stays on your hook
- **Beads state**: All issues, dependencies, progress
- **Git state**: Commits, branches, staged changes
## What Resets
- **Conversation context**: Fresh Claude instance
- **TodoWrite items**: Ephemeral, session-scoped
- **In-memory state**: Any uncommitted analysis
## Implementation
When invoked, execute:
1. If user provided a message, send handoff mail:
```bash
gt mail send <your-address> -s "HANDOFF: Session cycling" -m "<message>"
```
2. Run the handoff command:
```bash
gt handoff
```
The new session will find your handoff mail and hooked work automatically.

33
.githooks/pre-push Executable file
View File

@@ -0,0 +1,33 @@
#!/bin/bash
# Block PRs by preventing pushes to arbitrary feature branches.
# Gas Town agents push to main (crew) or polecat/* branches (polecats).
# PRs are for external contributors only.
# Allowed patterns:
# main, beads-sync - Direct work branches
# polecat/* - Polecat working branches (Refinery merges these)
while read local_ref local_sha remote_ref remote_sha; do
branch="${remote_ref#refs/heads/}"
case "$branch" in
main|beads-sync|polecat/*)
# Allowed branches
;;
*)
echo "ERROR: Invalid branch for Gas Town agents."
echo ""
echo "Blocked push to: $branch"
echo ""
echo "Allowed branches:"
echo " main - Crew workers push here directly"
echo " polecat/* - Polecat working branches"
echo " beads-sync - Beads synchronization"
echo ""
echo "Do NOT create PRs. Push to main or let Refinery merge polecat work."
exit 1
;;
esac
done
exit 0

View File

@@ -0,0 +1,51 @@
name: Block Internal PRs
on:
pull_request:
types: [opened, reopened]
jobs:
block-internal-prs:
name: Block Internal PRs
# Only run if PR is from the same repo (not a fork)
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- name: Close PR and comment
uses: actions/github-script@v7
with:
script: |
const prNumber = context.issue.number;
const branch = context.payload.pull_request.head.ref;
const body = [
'**Internal PRs are not allowed.**',
'',
'Gas Town agents push directly to main. PRs are for external contributors only.',
'',
'To land your changes:',
'```bash',
'git checkout main',
'git merge ' + branch,
'git push origin main',
'git push origin --delete ' + branch,
'```',
'',
'See CLAUDE.md: "Crew workers push directly to main. No feature branches. NEVER create PRs."'
].join('\n');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: body
});
await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
state: 'closed'
});
core.setFailed('Internal PR blocked. Push directly to main instead.');

View File

@@ -33,6 +33,36 @@ jobs:
fi
echo "No .beads/issues.jsonl changes detected"
# Verify committed formulas allow build without go:generate
# This catches issues where go install @latest would fail
check-embedded-formulas:
name: Check embedded formulas
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
- name: Build without go:generate
run: |
# This must succeed with committed formulas only
# If this fails, run: go generate ./... && git add -A && git commit
go build -v ./cmd/gt
- name: Verify formulas are in sync
run: |
# Regenerate and check for differences
go generate ./internal/formula/...
if ! git diff --exit-code internal/formula/formulas/; then
echo ""
echo "ERROR: Committed formulas are out of sync with .beads/formulas/"
echo "Run: go generate ./... && git add -A && git commit"
exit 1
fi
test:
name: Test
runs-on: ubuntu-latest
@@ -71,3 +101,31 @@ jobs:
with:
version: latest
args: --timeout=5m
integration:
name: Integration Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
- name: Configure Git
run: |
git config --global user.name "CI Bot"
git config --global user.email "ci@gastown.test"
- name: Install beads (bd)
run: go install github.com/steveyegge/beads/cmd/bd@latest
- name: Build gt
run: go build -v -o gt ./cmd/gt
- name: Add to PATH
run: echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
- name: Integration Tests
run: go test -tags=integration -timeout=5m -v ./internal/cmd/...

45
.github/workflows/integration.yml vendored Normal file
View File

@@ -0,0 +1,45 @@
name: Integration Tests
on:
pull_request:
paths:
- 'internal/cmd/install.go'
- 'internal/cmd/rig.go'
- 'internal/config/**'
- 'internal/routing/**'
- 'internal/cmd/*_integration_test.go'
- '.github/workflows/integration.yml'
jobs:
integration:
name: Integration Tests
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
cache: true
- name: Configure Git
run: |
git config --global user.name "CI Bot"
git config --global user.email "ci@gastown.test"
- name: Install beads (bd)
run: go install github.com/steveyegge/beads/cmd/bd@latest
- name: Add to PATH
run: echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
- name: Generate embedded files
run: go generate ./internal/formula/...
- name: Build
run: go build -v ./cmd/gt
- name: Run integration tests
run: go test -v -tags=integration -timeout=4m ./internal/cmd/...

16
.gitignore vendored
View File

@@ -17,6 +17,9 @@
.DS_Store
Thumbs.db
# Claude Code local state
.claude/
# Test
coverage.out
*.test
@@ -29,7 +32,20 @@ gt
# Runtime state
state.json
.runtime/
# Beads runtime state (not tracked)
# Formulas ARE tracked for `go install @latest` - see bottom of file
.beads/redirect
.beads/issues.jsonl
.beads/interactions.jsonl
.beads/metadata.json
.beads/mq/
.beads/last-touched
.beads/daemon-*.log.gz
.beads-wisp/
# Clone-specific CLAUDE.md (regenerated locally per clone)
CLAUDE.md
# Embedded formulas are committed so `go install @latest` works
# Run `go generate ./...` after modifying .beads/formulas/

View File

@@ -29,6 +29,11 @@ linters:
- (os).Chdir
- (os).MkdirAll
- (fmt).Sscanf
# fmt.Fprintf/Fprintln errors are typically safe to ignore for logging
- fmt.Fprintf
- fmt.Fprintln
- (fmt).Fprintf
- (fmt).Fprintln
misspell:
locale: US
@@ -39,17 +44,30 @@ linters:
linters:
- gosec
text: "G304"
# G304: Config/state file loading uses constructed paths, not user input
# All internal packages read files from constructed paths, not user input
- path: 'internal/'
linters:
- gosec
text: "G304"
# G306: File permissions 0644 in tests are acceptable (test fixtures)
- path: '_test\.go'
linters:
- gosec
text: "G306"
# G302/G306: Non-sensitive operational files (state, config, logs) can use 0644
# Internal packages write non-sensitive operational data files
- path: 'internal/'
linters:
- gosec
text: "G306|G302"
# G302/G306: Directory/file permissions 0700/0750 are acceptable
- linters:
- gosec
text: "G302.*0700|G301.*0750"
# G204: Safe subprocess launches with validated arguments (tmux, git, etc.)
- path: 'internal/tmux/|internal/git/|internal/cmd/'
# G204: Safe subprocess launches with validated arguments (internal tools)
# All internal packages use subprocess calls for trusted internal tools
- path: 'internal/'
linters:
- gosec
text: 'G204'

View File

@@ -29,3 +29,22 @@ This file exists for compatibility with tools that look for AGENTS.md.
- NEVER stop before pushing - that leaves work stranded locally
- NEVER say "ready to push when you are" - YOU must push
- If push fails, resolve and retry until it succeeds
## Dependency Management
Periodically check for outdated dependencies:
```bash
go list -m -u all | grep '\['
```
Update direct dependencies:
```bash
go get <package>@latest
go mod tidy
go build ./...
go test ./...
```
Check release notes for breaking changes before major version bumps.

View File

@@ -5,6 +5,179 @@ All notable changes to the Gas Town project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.2.1] - 2026-01-05
Bug fixes, security hardening, and new `gt config` command.
### Added
- **`gt config` command** - Manage agent settings (model, provider) per-rig or globally
- **`hq-` prefix for patrol sessions** - Mayor and Deacon sessions use town-prefixed names
- **Doctor hooks-path check** - Verify Git hooks path is configured correctly
- **Block internal PRs** - Pre-push hook and GitHub Action prevent accidental internal PRs (#117)
- **Dispatcher notifications** - Notify dispatcher when polecat work completes
- **Unit tests** - Added tests for `formatTrackBeadID` helper, done redirect, hook slot E2E
### Fixed
#### Security
- **Command injection prevention** - Validate beads prefix to prevent injection (gt-l1xsa)
- **Path traversal prevention** - Validate crew names to prevent traversal (gt-wzxwm)
- **ReDoS prevention** - Escape user input in mail search (gt-qysj9)
- **Error handling** - Handle crypto/rand.Read errors in ID generation
#### Convoy & Sling
- **Hook slot initialization** - Set hook slot when creating agent beads during sling (#124)
- **Cross-rig bead formatting** - Format cross-rig beads as external refs in convoy tracking (#123)
- **Reliable bd calls** - Add `--no-daemon` and `BEADS_DIR` for reliable beads operations
#### Rig Inference
- **`gt rig status`** - Infer rig name from current working directory
- **`gt crew start --all`** - Infer rig from cwd for batch crew starts
- **`gt prime` in crew start** - Pass as initial prompt in crew start commands
- **Town default_agent** - Honor default agent setting for Mayor and Deacon
#### Session & Lifecycle
- **Hook persistence** - Hook persists across session interruption via `in_progress` lookup (gt-ttn3h)
- **Polecat cleanup** - Clean up stale worktrees and git tracking
- **`gt done` redirect** - Use ResolveBeadsDir for redirect file support
#### Build & CI
- **Embedded formulas** - Sync and commit formulas for `go install @latest`
- **CI lint fixes** - Resolve lint and build errors
- **Flaky test fix** - Sync database before beads integration tests
## [0.2.0] - 2026-01-04
Major release featuring the Convoy Dashboard, two-level beads architecture, and significant multi-agent improvements.
### Added
#### Convoy Dashboard (Web UI)
- **`gt dashboard` command** - Launch web-based monitoring UI for Gas Town (#71)
- **Polecat Workers section** - Real-time activity monitoring with tmux session timestamps
- **Refinery Merge Queue display** - Always-visible MR queue status
- **Dynamic work status** - Convoy status columns with live updates
- **HTMX auto-refresh** - 10-second refresh interval for real-time monitoring
#### Two-Level Beads Architecture
- **Town-level beads** (`~/gt/.beads/`) - `hq-*` prefix for Mayor mail and cross-rig coordination
- **Rig-level beads** - Project-specific issues with rig prefixes (e.g., `gt-*`)
- **`gt migrate-agents` command** - Migration tool for two-level architecture (#nnub1)
- **TownBeadsPrefix constant** - Centralized `hq-` prefix handling
- **Prefix-based routing** - Commands auto-route to correct rig via `routes.jsonl`
#### Multi-Agent Support
- **Pluggable agent registry** - Multi-agent support with configurable providers (#107)
- **Multi-rig management** - `gt rig start/stop/restart/status` for batch operations (#11z8l)
- **`gt crew stop` command** - Stop crew sessions cleanly
- **`spawn` alias** - Alternative to `start` for all role subcommands
- **Batch slinging** - `gt sling` supports multiple beads to a rig in one command (#l9toz)
#### Ephemeral Polecat Model
- **Immediate recycling** - Polecats recycled after each work unit (#81)
- **Updated patrol formula** - Witness formula adapted for ephemeral model
- **`mol-polecat-work` formula** - Updated for ephemeral polecat lifecycle (#si8rq.4)
#### Cost Tracking
- **`gt costs` command** - Session cost tracking and reporting
- **Beads-based storage** - Costs stored in beads instead of JSONL (#f7jxr)
- **Stop hook integration** - Auto-record costs on session end
- **Tmux session auto-detection** - Costs hook finds correct session
#### Conflict Resolution
- **Conflict resolution workflow** - Formula-based conflict handling for polecats (#si8rq.5)
- **Merge-slot gate** - Refinery integration for ordered conflict resolution
- **`gt done --phase-complete`** - Gate-based phase handoffs (#si8rq.7)
#### Communication & Coordination
- **`gt mail archive` multi-ID** - Archive multiple messages at once (#82)
- **`gt mail --all` flag** - Clear all mail for agent ergonomics (#105q3)
- **Convoy stranded detection** - Detect and feed stranded convoys (#8otmd)
- **`gt convoy --tree`** - Show convoy + child status tree
- **`gt convoy check`** - Cross-rig auto-close for completed convoys (#00qjk)
#### Developer Experience
- **Shell completion** - Installation instructions for bash/zsh/fish (#pdrh0)
- **`gt prime --hook`** - LLM runtime session handling flag
- **`gt doctor` enhancements** - Session-hooks check, repo-fingerprint validation (#nrgm5)
- **Binary age detection** - `gt status` shows stale binary warnings (#42whv)
- **Circuit breaker** - Automatic handling for stuck agents (#72cqu)
#### Infrastructure
- **SessionStart hooks** - Deployed during `gt install` for Mayor role
- **`hq-dog-role` beads** - Town-level dog role initialization (#2jjry)
- **Watchdog chain docs** - Boot/Deacon lifecycle documentation (#1847v)
- **Integration tests** - CI workflow for `gt install` and `gt rig add` (#htlmp)
- **Local repo reference clones** - Save disk space with `--reference` cloning
### Changed
- **Handoff migrated to skills** - `gt handoff` now uses skills format (#nqtqp)
- **Crew workers push to main** - Documentation clarifies no PR workflow for crew
- **Session names include town** - Mayor/Deacon sessions use town-prefixed names
- **Formula semantics clarified** - Formulas are templates, not instructions
- **Witness reports stopped** - No more routine Mayor reports (saves tokens)
### Fixed
#### Daemon & Session Stability
- **Thread-safety** - Added locks for agent session resume support
- **Orphan daemon prevention** - File locking prevents duplicate daemons (#108)
- **Zombie tmux cleanup** - Kill zombie sessions before recreating (#vve6k)
- **Tmux exact matching** - `HasSession` uses exact match to prevent prefix collisions
- **Health check fallback** - Prevents killing healthy sessions on tmux errors
#### Beads Integration
- **Mayor/rig path** - Use correct path for beads to prevent prefix mismatch (#38)
- **Agent bead creation** - Fixed during `gt rig add` (#32)
- **bd daemon startup** - Circuit breaker and restart logic (#2f0p3)
- **BEADS_DIR environment** - Correctly set for polecat hooks and cross-rig work
#### Agent Workflows
- **Default branch detection** - `gt done` no longer hardcodes 'main' (#42)
- **Enter key retry** - Reliable Enter key delivery with retry logic (#53)
- **SendKeys debounce** - Increased to 500ms for reliability
- **MR bead closure** - Close beads after successful merge from queue (#52)
#### Installation & Setup
- **Embedded formulas** - Copy formulas to new installations (#86)
- **Vestigial cleanup** - Remove `rigs/` directory and `state.json` files
- **Symlink preservation** - Workspace detection preserves symlink paths (#3, #75)
- **Golangci-lint errors** - Resolved errcheck and gosec issues (#76)
### Contributors
Thanks to all contributors for this release:
- @kiwiupover - README updates (#109)
- @michaellady - Convoy dashboard (#71), ResolveBeadsDir fix (#54)
- @jsamuel1 - Dependency updates (#83)
- @dannomayernotabot - Witness fixes (#87), daemon race condition (#64)
- @markov-kernel - Mayor session hooks (#93), daemon init recommendation (#95)
- @rawwerks - Multi-agent support (#107)
- @jakehemmerle - Daemon orphan race condition (#108)
- @danshapiro - Install role slots (#106), rig beads dir (#61)
- @vessenes - Town session helpers (#91), install copy formulas (#86)
- @kustrun - Init bugs (#34)
- @austeane - README quickstart fix (#44)
- @Avyukth - Patrol roles per-rig check (#26)
## [0.1.1] - 2026-01-02
### Fixed
- **Tmux keybindings scoped to Gas Town sessions** - C-b n/p no longer override default tmux behavior in non-GT sessions (#13)
### Added
- **OSS project files** - CHANGELOG.md, .golangci.yml, RELEASING.md
- **Version bump script** - `scripts/bump-version.sh` for releases
- **Documentation fixes** - Corrected `gt rig add` and `gt crew add` CLI syntax (#6)
- **Rig prefix routing** - Agent beads now use correct rig-specific prefixes (#11)
- **Beads init fix** - Rig beads initialization targets correct database (#9)
## [0.1.0] - 2026-01-02
### Added

View File

@@ -1,4 +1,4 @@
.PHONY: build install clean test
.PHONY: build install clean test generate
BINARY := gt
BUILD_DIR := .
@@ -12,7 +12,10 @@ LDFLAGS := -X github.com/steveyegge/gastown/internal/cmd.Version=$(VERSION) \
-X github.com/steveyegge/gastown/internal/cmd.Commit=$(COMMIT) \
-X github.com/steveyegge/gastown/internal/cmd.BuildTime=$(BUILD_TIME)
build:
generate:
go generate ./...
build: generate
go build -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY) ./cmd/gt
ifeq ($(shell uname),Darwin)
@codesign -s - -f $(BUILD_DIR)/$(BINARY) 2>/dev/null || true

147
README.md
View File

@@ -16,7 +16,7 @@ Multi-agent orchestrator for Claude Code. Track work with convoys; sling to agen
- **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+** - for full stack mode (optional for minimal mode)
- **tmux 3.0+** - recommended for the full experience (the Mayor session is the primary interface)
- **Claude Code CLI** - [claude.ai/code](https://claude.ai/code)
## Quick Start
@@ -25,30 +25,58 @@ Multi-agent orchestrator for Claude Code. Track work with convoys; sling to agen
# Install
go install github.com/steveyegge/gastown/cmd/gt@latest
# Create workspace
gt install ~/gt
# Ensure Go binaries are in your PATH (add to ~/.zshrc or ~/.bashrc)
export PATH="$PATH:$HOME/go/bin"
# Create workspace (--git auto-initializes git repository)
gt install ~/gt --git
cd ~/gt
# Add a project
gt rig add myproject https://github.com/you/repo.git
# Create a convoy and sling work (standard workflow)
# Create your personal workspace
gt crew add <yourname> --rig myproject
# Start working
cd myproject/crew/<yourname>
```
For advanced multi-agent coordination, use the Mayor session:
```bash
gt mayor attach # Enter the Mayor's office
```
Inside the Mayor session, you're talking to Claude with full town context:
> "Help me fix the authentication bug in myproject"
The Mayor will create convoys, dispatch workers, and coordinate everything. You can also run CLI commands directly:
```bash
# Create a convoy and sling work (CLI workflow)
gt convoy create "Feature X" issue-123 issue-456 --notify --human
gt sling issue-123 myproject
gt sling issue-456 myproject
# Track progress on dashboard
# Track progress
gt convoy list
# Switch between agent sessions
gt agents
```
## Core Concepts
**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.
```
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
└── Mayor Global coordinator
```
**Hook**: Each agent has a hook where work hangs. On wake, run what's on your hook.
@@ -57,6 +85,26 @@ Town (~/gt/) Your workspace
## Workflows
### Full Stack (Recommended)
The primary Gas Town experience. Agents run in tmux sessions with the Mayor as your interface.
```bash
gt start # Start Gas Town (daemon + Mayor session)
gt mayor attach # Enter Mayor session
# Inside Mayor session, just ask:
# "Create a convoy for issues 123 and 456 in myproject"
# "What's the status of my work?"
# "Show me what the witness is doing"
# Or use CLI commands:
gt convoy create "Feature X" issue-123 issue-456
gt sling issue-123 myproject # Spawns polecat automatically
gt convoy list # Dashboard view
gt agents # Navigate between sessions
```
### Minimal (No Tmux)
Run individual Claude Code instances manually. Gas Town just tracks state.
@@ -68,18 +116,6 @@ claude --resume # Agent reads mail, runs work
gt convoy list # Check progress
```
### Full Stack (Tmux)
Agents run in tmux sessions. Daemon manages lifecycle.
```bash
gt daemon start # Start lifecycle manager
gt convoy create "Feature X" issue-123 issue-456
gt sling issue-123 myproject # Spawns polecat automatically
gt sling issue-456 myproject # Another worker
gt convoy list # Dashboard view
```
### Pick Your Roles
Gas Town is modular. Run what you need:
@@ -199,6 +235,22 @@ gt <role> attach # Jump into any agent session
# e.g., gt mayor attach, gt witness attach
```
### Configuration
```bash
gt config agent list [--json] # List all agents (built-in + custom)
gt config agent get <name> # Show agent configuration
gt config agent set <name> <cmd> # Create or update custom agent
gt config agent remove <name> # Remove custom agent (built-ins protected)
gt config default-agent [name] # Get or set town default agent
```
**Example**: Use a cheaper model for most work:
```bash
gt config agent set claude-glm "claude-glm --model glm-4"
gt config default-agent claude-glm
```
Most other work happens through agents - just ask them.
### For Agents
@@ -227,6 +279,63 @@ gt doctor # Health check
gt doctor --fix # Auto-repair
```
## Dashboard
Web-based dashboard for monitoring Gas Town activity.
```bash
# Start the dashboard
gt dashboard --port 8080
# Open in browser
open http://localhost:8080
```
**Features:**
- **Convoy tracking** - View all active convoys with progress bars and work status
- **Polecat workers** - See active worker sessions and their activity status
- **Refinery status** - Monitor merge queue and PR processing
- **Auto-refresh** - Updates every 10 seconds via htmx
Work status indicators:
| Status | Color | Meaning |
|--------|-------|---------|
| `complete` | Green | All tracked items done |
| `active` | Green | Recent activity (< 1 min) |
| `stale` | Yellow | Activity 1-5 min ago |
| `stuck` | Red | Activity > 5 min ago |
| `waiting` | Gray | No assignee/activity |
## Shell Completions
Enable tab completion for `gt` commands:
### Bash
```bash
# Add to ~/.bashrc
source <(gt completion bash)
# Or install permanently
gt completion bash > /usr/local/etc/bash_completion.d/gt
```
### Zsh
```bash
# Add to ~/.zshrc (before compinit)
source <(gt completion zsh)
# Or install to fpath
gt completion zsh > "${fpath[1]}/_gt"
```
### Fish
```bash
gt completion fish > ~/.config/fish/completions/gt.fish
```
## Roles
| Role | Scope | Job |

View File

@@ -184,7 +184,7 @@ Gas Town is modular. Enable only what you need:
|--------------|-------|----------|
| **Polecats only** | Workers | Manual spawning, no monitoring |
| **+ Witness** | + Monitor | Automatic lifecycle, stuck detection |
| **+ Refinery** | + Merge queue | PR review, code integration |
| **+ Refinery** | + Merge queue | MR review, code integration |
| **+ Mayor** | + Coordinator | Cross-project coordination |
## Troubleshooting

116
docs/architecture.md Normal file
View File

@@ -0,0 +1,116 @@
# Gas Town Architecture
Technical architecture for Gas Town multi-agent workspace management.
## Two-Level Beads Architecture
Gas Town uses a two-level beads architecture to separate organizational coordination
from project implementation work.
| Level | Location | Prefix | Purpose |
|-------|----------|--------|---------|
| **Town** | `~/gt/.beads/` | `hq-*` | Cross-rig coordination, Mayor mail, agent identity |
| **Rig** | `<rig>/mayor/rig/.beads/` | project prefix | Implementation work, MRs, project issues |
### Town-Level Beads (`~/gt/.beads/`)
Organizational chain for cross-rig coordination:
- Mayor mail and messages
- Convoy coordination (batch work across rigs)
- Strategic issues and decisions
- **Town-level agent beads** (Mayor, Deacon)
- **Role definition beads** (global templates)
### Rig-Level Beads (`<rig>/mayor/rig/.beads/`)
Project chain for implementation work:
- Bugs, features, tasks for the project
- Merge requests and code reviews
- Project-specific molecules
- **Rig-level agent beads** (Witness, Refinery, Polecats)
## Agent Bead Storage
Agent beads track lifecycle state for each agent. Storage location depends on
the agent's scope.
| Agent Type | Scope | Bead Location | Bead ID Format |
|------------|-------|---------------|----------------|
| Mayor | Town | `~/gt/.beads/` | `hq-mayor` |
| Deacon | Town | `~/gt/.beads/` | `hq-deacon` |
| Dogs | Town | `~/gt/.beads/` | `hq-dog-<name>` |
| Witness | Rig | `<rig>/.beads/` | `<prefix>-<rig>-witness` |
| Refinery | Rig | `<rig>/.beads/` | `<prefix>-<rig>-refinery` |
| Polecats | Rig | `<rig>/.beads/` | `<prefix>-<rig>-polecat-<name>` |
### Role Beads
Role beads are global templates stored in town beads with `hq-` prefix:
- `hq-mayor-role` - Mayor role definition
- `hq-deacon-role` - Deacon role definition
- `hq-witness-role` - Witness role definition
- `hq-refinery-role` - Refinery role definition
- `hq-polecat-role` - Polecat role definition
Each agent bead references its role bead via the `role_bead` field.
## Agent Taxonomy
### Town-Level Agents (Cross-Rig)
| Agent | Role | Persistence |
|-------|------|-------------|
| **Mayor** | Global coordinator, handles cross-rig communication and escalations | Persistent |
| **Deacon** | Daemon beacon - receives heartbeats, runs plugins and monitoring | Persistent |
| **Dogs** | Long-running workers for cross-rig batch work | Variable |
### Rig-Level Agents (Per-Project)
| Agent | Role | Persistence |
|-------|------|-------------|
| **Witness** | Monitors polecat health, handles nudging and cleanup | Persistent |
| **Refinery** | Processes merge queue, runs verification | Persistent |
| **Polecats** | Ephemeral workers assigned to specific issues | Ephemeral |
## Directory Structure
```
~/gt/ Town root
├── .beads/ Town-level beads (hq-* prefix)
│ ├── config.yaml Beads configuration
│ ├── issues.jsonl Town issues (mail, agents, convoys)
│ └── routes.jsonl Prefix → rig routing table
├── mayor/ Mayor config
│ └── town.json Town configuration
└── <rig>/ Project container (NOT a git clone)
├── config.json Rig identity and beads prefix
├── .beads/ → mayor/rig/.beads Symlink to canonical beads
├── .repo.git/ Bare repo (shared by worktrees)
├── mayor/rig/ Mayor's clone (canonical beads)
├── refinery/rig/ Worktree on main
├── witness/ No clone (monitors only)
├── crew/<name>/ Human workspaces
└── polecats/<name>/ Worker worktrees
```
## Beads Routing
The `routes.jsonl` file maps issue ID prefixes to their storage locations:
```jsonl
{"prefix":"hq","path":"/Users/stevey/gt/.beads"}
{"prefix":"gt","path":"/Users/stevey/gt/gastown/mayor/rig/.beads"}
```
This enables transparent cross-rig beads operations:
```bash
bd show hq-mayor # Routes to town beads
bd show gt-xyz # Routes to gastown rig beads
```
## See Also
- [reference.md](reference.md) - Command reference
- [molecules.md](molecules.md) - Workflow molecules
- [identity.md](identity.md) - Agent identity and BD_ACTOR

View File

@@ -225,7 +225,7 @@ EOF
gt escalate --type decision --issue $ISSUE "Caching approach needs decision"
# 3. Exit cleanly
gt done --exit ESCALATED
gt done --status ESCALATED
```
## Mayor Startup Check

View File

@@ -25,7 +25,7 @@ MR: <mr-id> # if exit=MERGED
Branch: <branch>
```
**Trigger**: `gt polecat done` command generates this automatically.
**Trigger**: `gt done` command generates this automatically.
**Handler**: Witness creates a cleanup wisp for the polecat.

View File

@@ -26,6 +26,31 @@ Protomolecule (frozen template) ─── Solid
| **Wisp** | Ephemeral molecule for patrol cycles (never synced) |
| **Digest** | Squashed summary of completed molecule |
## Common Mistake: Reading Formulas Directly
**WRONG:**
```bash
# Reading a formula file and manually creating beads for each step
cat .beads/formulas/mol-polecat-work.formula.toml
bd create --title "Step 1: Load context" --type task
bd create --title "Step 2: Branch setup" --type task
# ... creating beads from formula prose
```
**RIGHT:**
```bash
# Cook the formula into a proto, pour into a molecule
bd cook mol-polecat-work
bd mol pour mol-polecat-work --var issue=gt-xyz
# Now work through the step beads that were created
bd ready # Find next step
bd close <step-id> # Complete it
```
**Key insight:** Formulas are source templates (like source code). You never read
them directly during work. The `cook``pour` pipeline creates step beads for you.
Your molecule already has steps - use `bd ready` to find them.
## Navigating Molecules
Molecules help you track where you are in multi-step workflows.

View File

@@ -102,6 +102,9 @@ bd list --type=role --label=mode:degraded
## Boot: The Deacon's Watchdog
> See [Watchdog Chain](watchdog-chain.md) for the complete Daemon/Boot/Deacon
> architecture and design rationale.
Boot is a dog (Deacon helper) that triages the Deacon's health. The daemon pokes
Boot instead of the Deacon directly, centralizing the "when to wake" decision in
an agent that can reason about it.
@@ -171,7 +174,7 @@ task nature matters.
~/gt/deacon/dogs/boot/
```
Session name: `gt-deacon-boot`
Session name: `gt-boot`
Created/maintained by `bd doctor`.

225
docs/polecat-lifecycle.md Normal file
View File

@@ -0,0 +1,225 @@
# Polecat Lifecycle
> Understanding the three-layer architecture of polecat workers
## Overview
Polecats have three distinct lifecycle layers that operate independently. Confusing
these layers leads to heresies like "idle polecats" and misunderstanding when
recycling occurs.
## The Three Layers
| Layer | Component | Lifecycle | Persistence |
|-------|-----------|-----------|-------------|
| **Session** | Claude (tmux pane) | Ephemeral | Cycles per step/handoff |
| **Sandbox** | Git worktree | Persistent | Until nuke |
| **Slot** | Name from pool | Persistent | Until nuke |
### Session Layer
The Claude session is **ephemeral**. It cycles frequently:
- After each molecule step (via `gt handoff`)
- On context compaction
- On crash/timeout
- After extended work periods
**Key insight:** Session cycling is **normal operation**, not failure. The polecat
continues working—only the Claude context refreshes.
```
Session 1: Steps 1-2 → handoff
Session 2: Steps 3-4 → handoff
Session 3: Step 5 → gt done
```
All three sessions are the **same polecat**. The sandbox and slot persist throughout.
### Sandbox Layer
The sandbox is the **git worktree**—the polecat's working directory:
```
~/gt/gastown/polecats/Toast/
```
This worktree:
- Exists from `gt sling` until `gt polecat nuke`
- Survives all session cycles
- Contains uncommitted work, staged changes, branch state
- Is independent of other polecat sandboxes
The Witness never destroys sandboxes mid-work. Only `nuke` removes them.
### Slot Layer
The slot is the **name allocation** from the polecat pool:
```bash
# Pool: [Toast, Shadow, Copper, Ash, Storm...]
# Toast is allocated to work gt-abc
```
The slot:
- Determines the sandbox path (`polecats/Toast/`)
- Maps to a tmux session (`gt-gastown-Toast`)
- Appears in attribution (`gastown/polecats/Toast`)
- Is released only on nuke
## Correct Lifecycle
```
┌─────────────────────────────────────────────────────────────┐
│ gt sling │
│ → Allocate slot from pool (Toast) │
│ → Create sandbox (worktree on new branch) │
│ → Start session (Claude in tmux) │
│ → Hook molecule to polecat │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Work Happens │
│ │
│ Session cycles happen here: │
│ - gt handoff between steps │
│ - Compaction triggers respawn │
│ - Crash → Witness respawns │
│ │
│ Sandbox persists through ALL session cycles │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ gt done │
│ → Polecat signals completion to Witness │
│ → Session exits (no idle waiting) │
│ → Witness receives POLECAT_DONE event │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Witness: gt polecat nuke │
│ → Verify work landed (merged or in MQ) │
│ → Delete sandbox (remove worktree) │
│ → Kill tmux session │
│ → Release slot back to pool │
└─────────────────────────────────────────────────────────────┘
```
## What "Recycle" Means
**Session cycling**: Normal. Claude restarts, sandbox stays, slot stays.
```bash
gt handoff # Session cycles, polecat continues
```
**Sandbox recreation**: Repair only. Should be rare.
```bash
gt polecat repair Toast # Emergency: recreate corrupted worktree
```
Session cycling happens constantly. Sandbox recreation should almost never happen
during normal operation.
## Anti-Patterns
### Idle Polecats
**Myth:** Polecats wait between tasks in an idle state.
**Reality:** Polecats don't exist without work. The lifecycle is:
1. Work assigned → polecat spawned
2. Work done → polecat nuked
3. There is no idle state
If you see a polecat without work, something is broken. Either:
- The hook was lost (bug)
- The session crashed before loading context
- Manual intervention corrupted state
### Manual State Transitions
**Anti-pattern:**
```bash
gt polecat done Toast # DON'T: external state manipulation
gt polecat reset Toast # DON'T: manual lifecycle control
```
**Correct:**
```bash
# Polecat signals its own completion:
gt done # (from inside the polecat session)
# Only Witness nukes polecats:
gt polecat nuke Toast # (from Witness, after verification)
```
Polecats manage their own session lifecycle. The Witness manages sandbox lifecycle.
External manipulation bypasses verification.
### Sandboxes Without Work
**Anti-pattern:** A sandbox exists but no molecule is hooked.
This means:
- The polecat was spawned incorrectly
- The hook was lost during crash
- State corruption occurred
**Recovery:**
```bash
# From Witness:
gt polecat nuke Toast # Clean slate
gt sling gt-abc gastown # Respawn with work
```
### Confusing Session with Sandbox
**Anti-pattern:** Thinking session restart = losing work.
```bash
# Session ends (handoff, crash, compaction)
# Work is NOT lost because:
# - Git commits persist in sandbox
# - Staged changes persist in sandbox
# - Molecule state persists in beads
# - Hook persists across sessions
```
The new session picks up where the old one left off via `gt prime`.
## Session Lifecycle Details
Sessions cycle for these reasons:
| Trigger | Action | Result |
|---------|--------|--------|
| `gt handoff` | Voluntary | Clean cycle to fresh context |
| Context compaction | Automatic | Forced by Claude Code |
| Crash/timeout | Failure | Witness respawns |
| `gt done` | Completion | Session exits, Witness takes over |
All except `gt done` result in continued work. Only `gt done` signals completion.
## Witness Responsibilities
The Witness monitors polecats but does NOT:
- Force session cycles (polecats self-manage via handoff)
- Interrupt mid-step (unless truly stuck)
- Recycle sandboxes between steps
The Witness DOES:
- Respawn crashed sessions
- Nudge stuck polecats
- Nuke completed polecats (after verification)
- Handle escalations
## Related Documentation
- [Understanding Gas Town](understanding-gas-town.md) - Role taxonomy and architecture
- [Polecat Wisp Architecture](polecat-wisp-architecture.md) - Molecule execution
- [Propulsion Principle](propulsion-principle.md) - Why work triggers immediate execution

View File

@@ -12,7 +12,7 @@ They execute molecule steps sequentially, closing each step as they complete it.
| Type | Storage | Use Case |
|------|---------|----------|
| **Regular Molecule** | `.beads/` (synced) | Discrete deliverables, audit trail |
| **Wisp** | `.beads-wisp/` (ephemeral) | Patrol cycles, operational loops |
| **Wisp** | `.beads/` (ephemeral, type=wisp) | Patrol cycles, operational loops |
Polecats typically use **regular molecules** because each assignment has audit value.
Patrol agents (Witness, Refinery, Deacon) use **wisps** to prevent accumulation.

View File

@@ -215,6 +215,28 @@ gt doctor # Health check
gt doctor --fix # Auto-repair
```
### Configuration
```bash
# Agent management
gt config agent list [--json] # List all agents (built-in + custom)
gt config agent get <name> # Show agent configuration
gt config agent set <name> <cmd> # Create or update custom agent
gt config agent remove <name> # Remove custom agent (built-ins protected)
# Default agent
gt config default-agent [name] # Get or set town default agent
```
**Built-in agents**: `claude`, `gemini`, `codex`
**Custom agents**: Define per-town in `mayor/town.json`:
```bash
gt config agent set claude-glm "claude-glm --model glm-4"
gt config agent set claude "claude-opus" # Override built-in
gt config default-agent claude-glm # Set default
```
### Rig Management
```bash
@@ -323,7 +345,7 @@ Deacon, Witness, and Refinery run continuous patrol loops using wisps:
|-------|-----------------|----------------|
| **Deacon** | `mol-deacon-patrol` | Agent lifecycle, plugin execution, health checks |
| **Witness** | `mol-witness-patrol` | Monitor polecats, nudge stuck workers |
| **Refinery** | `mol-refinery-patrol` | Process merge queue, review PRs |
| **Refinery** | `mol-refinery-patrol` | Process merge queue, review MRs |
```
1. bd mol wisp mol-<role>-patrol

View File

@@ -0,0 +1,154 @@
# Test Coverage and Quality Review
**Reviewed by**: polecat/gus
**Date**: 2026-01-04
**Issue**: gt-a02fj.9
## Executive Summary
- **80 test files** covering **32 out of 42 packages** (76% package coverage)
- **631 test functions** with 192 subtests (30% use table-driven pattern)
- **10 packages** with **0 test coverage** (2,452 lines)
- **1 confirmed flaky test** candidate
- Test quality is generally good with moderate mocking
---
## Coverage Gap Inventory
### Packages Without Tests (Priority Order)
| Priority | Package | Lines | Risk | Notes |
|----------|---------|-------|------|-------|
| **P0** | `internal/lock` | 402 | **CRITICAL** | Multi-agent lock management. Bugs cause worker collisions. Already has `execCommand` mockable for testing. |
| **P1** | `internal/events` | 295 | HIGH | Event bus for audit trail. Mutex-protected writes. Core observability. |
| **P1** | `internal/boot` | 242 | HIGH | Boot watchdog lifecycle. Spawns tmux sessions. |
| **P1** | `internal/checkpoint` | 216 | HIGH | Session crash recovery. Critical for polecat continuity. |
| **P2** | `internal/tui/convoy` | 601 | MEDIUM | TUI component. Harder to test but user-facing. |
| **P2** | `internal/constants` | 221 | LOW | Mostly configuration constants. Low behavioral risk. |
| **P3** | `internal/style` | 331 | LOW | Output formatting. Visual only. |
| **P3** | `internal/claude` | 80 | LOW | Claude settings parsing. |
| **P3** | `internal/wisp` | 52 | LOW | Ephemeral molecule I/O. Small surface. |
| **P4** | `cmd/gt` | 12 | TRIVIAL | Main entry point. Minimal code. |
**Total untested lines**: 2,452
---
## Flaky Test Candidates
### Confirmed: `internal/feed/curator_test.go`
**Issue**: Uses `time.Sleep()` for synchronization (lines 59, 71, 119, 138)
```go
// Give curator time to start
time.Sleep(50 * time.Millisecond)
...
// Wait for processing
time.Sleep(300 * time.Millisecond)
```
**Risk**: Flaky under load, CI delays, or slow machines.
**Fix**: Replace with channel-based synchronization or polling with timeout:
```go
// Wait for condition with timeout
deadline := time.Now().Add(time.Second)
for time.Now().Before(deadline) {
if conditionMet() {
break
}
time.Sleep(10 * time.Millisecond)
}
```
---
## Test Quality Analysis
### Strengths
1. **Table-driven tests**: 30% of tests use `t.Run()` (192/631)
2. **Good isolation**: Only 2 package-level test variables
3. **Dedicated integration tests**: 15 files with explicit integration/e2e naming
4. **Error handling**: 316 uses of `if err != nil` in tests
5. **No random data**: No `rand.` usage in tests (deterministic)
6. **Environment safety**: Uses `t.Setenv()` for clean env var handling
### Areas for Improvement
1. **`testing.Short()`**: Only 1 usage. Long-running tests should check this.
2. **External dependencies**: 26 tests skip when `bd` or `tmux` unavailable - consider mocking more.
3. **time.Sleep usage**: Found in `curator_test.go` - should be eliminated.
---
## Test Smells (Minor)
| Smell | Location | Severity | Notes |
|-------|----------|----------|-------|
| Sleep-based sync | `feed/curator_test.go` | HIGH | See flaky section |
| External dep skips | Multiple files | LOW | Reasonable for integration tests |
| Skip-heavy file | `tmux/tmux_test.go` | LOW | Acceptable - tmux not always available |
---
## Priority List for New Tests
### Immediate (P0)
1. **`internal/lock`** - Critical path
- Test `Acquire()` with stale lock cleanup
- Test `Check()` with live/dead PIDs
- Test `CleanStaleLocks()` with mock tmux sessions
- Test `DetectCollisions()`
- Test concurrent lock acquisition (race detection)
### High Priority (P1)
2. **`internal/events`**
- Test `Log()` file creation and append
- Test `write()` mutex behavior
- Test payload helpers
- Test graceful handling when not in workspace
3. **`internal/boot`**
- Test `IsRunning()` with stale markers
- Test `AcquireLock()` / `ReleaseLock()` cycle
- Test `SaveStatus()` / `LoadStatus()` round-trip
- Test degraded mode path
4. **`internal/checkpoint`**
- Test `Read()` / `Write()` round-trip
- Test `Capture()` git state extraction
- Test `IsStale()` with various durations
- Test `Summary()` output
### Medium Priority (P2)
5. **`internal/tui/convoy`** - Consider golden file tests for view output
6. **`internal/constants`** - Test any validation logic
---
## Missing Test Types
| Type | Current State | Recommendation |
|------|--------------|----------------|
| Unit tests | Good coverage where present | Add for P0-P1 packages |
| Integration tests | 15 dedicated files | Adequate |
| E2E tests | `browser_e2e_test.go` | Consider more CLI E2E |
| Fuzz tests | None | Consider for parsers (`formula/parser.go`) |
| Benchmark tests | None visible | Add for hot paths (`lock`, `events`) |
---
## Actionable Next Steps
1. **Fix flaky test**: Refactor `feed/curator_test.go` to use channels/polling
2. **Add lock tests**: Highest priority - bugs here break multi-agent
3. **Add events tests**: Core observability must be tested
4. **Add checkpoint tests**: Session recovery is critical path
5. **Run with race detector**: `go test -race ./...` to catch data races
6. **Consider `-short` flag**: Add `testing.Short()` checks to slow tests

Some files were not shown because too many files have changed in this diff Show More