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