* fix: always send handoff mail
* fix: remove trailing slash from mayor in detectSenderFromCwd
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add functions to wake Claude Code's event loop in detached tmux sessions:
- IsSessionAttached: Check if session has attached clients
- WakePane: Always trigger SIGWINCH via resize dance
- WakePaneIfDetached: Smart wrapper that skips attached sessions
When Claude runs in a detached tmux session, its TUI library may not
process stdin until a terminal event occurs. Attaching triggers SIGWINCH
which wakes the event loop. WakePane simulates that by resizing the pane
down 1 row then back up.
NudgeSession and NudgePane now call WakePaneIfDetached after sending
Enter, covering all 22 nudge call sites in the codebase.
Fixes: gt-6s75ln
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
The procps-ng kill binary (version 4.0.4+) has an argument parsing issue
where negative PIDs like "-12345" are misinterpreted as options because
they start with a dash. This causes the binary to fall back to "-1" which
means "all processes", resulting in kill(-1, signal) being called.
This was discovered through an extensive murder investigation after 26
Claude AI instances were killed when running TestCleanupOrphanedSessions.
Each investigator left notes for their successor, eventually leading to
the discovery that:
- exec.Command("bash", "-c", "kill -KILL -PGID") is SAFE (uses bash builtin)
- exec.Command("kill", "-KILL", "-PGID") is FATAL (uses /usr/bin/kill)
Verified via strace:
/usr/bin/kill -KILL -12345 → kill(-1, SIGKILL) # WRONG!
/usr/bin/kill -KILL -- -12345 → kill(-12345, SIGKILL) # Correct!
The fix adds "--" before negative PGID arguments to explicitly end option
parsing, ensuring the negative number is treated as a PID/PGID argument.
Full investigation: https://github.com/groblegark/gastown/blob/main/MURDER_INVESTIGATION.md
Co-authored-by: Refinery <matthew.baker@pihealth.ai>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
The ready command was incorrectly using RigMayorPath() which resolves to
<rig>/mayor/rig, causing BEADS_DIR to be set to a non-existent path like
/home/baldvin/gt/jbrs/mayor/rig/.beads instead of the actual database at
/home/baldvin/gt/jbrs/.beads.
This caused \"bd ready --json\" to fail with \"no beads database found\" when
called by gt ready, even though the database existed at the rig root.
Fix by using r.BeadsPath() which returns the rig root path. The beads
redirect system at <rig>/.beads/redirect already handles routing to
mayor/rig/.beads when appropriate.
Also updated getFormulaNames() and getWispIDs() calls to use the correct
path consistently.
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
When nuking a polecat while your shell is cd'd into its worktree,
the shell becomes completely broken (even `echo hello` fails).
Add a check before deletion that detects if the current working
directory is inside the polecat's worktree. If so, return an error
with helpful instructions to cd elsewhere first.
The check runs ALWAYS, even with --force, because this is about
shell safety not data loss. You can't bypass it - just cd out first.
Fixes#942
gt handoff was calling KillPaneProcesses which killed Claude Code
(the pane process) before RespawnPane could be called. This caused
handoff to silently fail with no respawn.
Add KillPaneProcessesExcluding function that allows excluding specific
PIDs from being killed. The self-handoff path now excludes the current
process and its parent (Claude Code) so gt handoff survives long enough
to call RespawnPane. The -k flag on respawn-pane handles final cleanup.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat(dashboard): comprehensive control panel with expand/collapse
- Add 13 panels: Convoys, Polecats, Sessions, Activity, Mail, Merge Queue,
Escalations, Rigs, Dogs, System Health, Open Issues, Hooks, Queues
- Add Mayor status banner and Summary/Alerts section
- Implement instant client-side expand/collapse (no page reload)
- Add responsive grid layout for different window sizes
- Parallel data fetching for faster load times
- Color-coded mail by sender, chronological ordering
- Full titles visible in expanded views (no truncation)
- Auto-refresh every 10 seconds via HTMX
* fix(web): update tests and lint for dashboard control panel
- Update MockConvoyFetcher with 11 new interface methods
- Update MockConvoyFetcherWithErrors with matching methods
- Update test assertions for new template structure:
- Section headers ("Gas Town Convoys" -> "Convoys")
- Work status badges (badge-green, badge-yellow, badge-red)
- CI/merge status display text
- Empty state messages ("No active convoys")
- Fix linting: explicit _, _ = for fmt.Sscanf returns
Tests and linting now pass with the new dashboard features.
* perf(web): add timeouts and error logging to dashboard
Performance and reliability improvements:
- Add 8-second overall fetch timeout to prevent stuck requests
- Add per-command timeouts: 5s for bd/sqlite3, 10s for gh, 2s for tmux
- Add helper functions runCmd() and runBdCmd() with context timeout
- Add error logging for all 14 fetch operations
- Handler now returns partial data if timeout occurs
This addresses slow loading and "stuck" dashboard issues by ensuring
commands cannot hang indefinitely.
agentBeadToAddress() expected gt- prefixed IDs but actual agent beads
use hq- prefix (e.g., hq-mayor instead of gt-mayor). This caused
"no agent found" errors when sending mail to valid addresses like mayor/.
- Add CreatedBy field to agentBead struct
- Handle hq-mayor and hq-deacon as town-level agents
- Use created_by field for rig-level agents (e.g., beads/crew/emma)
- Fall back to parsing description for role_type/rig fields
- Keep legacy gt- prefix handling for backwards compatibility
Closes: gt-1309e2
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
For self-handoff, calling KillPaneProcesses kills the gt handoff
process itself before it can execute RespawnPane, leaving the pane
dead with no respawn. The fix is to rely on respawn-pane -k which
handles killing and respawning atomically.
The remote handoff path is unaffected - it correctly calls
KillPaneProcesses because the caller is in a different session.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add `gt dolt` command with subcommands to manage the Dolt SQL server:
- start/stop/status: Control server lifecycle
- logs: View server logs
- sql: Open interactive SQL shell
- list: List available rig databases
- init-rig: Initialize new rig database
- migrate: Migrate from old .beads/dolt/ layout
The command detects both servers started via `gt dolt start` and
externally-started dolt processes by checking port 3307.
Closes: hq-05caeb
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously `make install` used `go install` which put the binary in ~/go/bin
without codesigning, while PATH used ~/.local/bin - causing chronic stale
binary issues. Now install depends on build (which codesigns on macOS) and
copies to the correct location.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove all bd sync references and SQLite-specific code from gastown:
**Formulas (agent priming):**
- mol-polecat-work: Remove bd sync step from prepare-for-review
- mol-sync-workspace: Replace sync-beads step with verify-beads (Dolt check)
- mol-polecat-conflict-resolve: Remove bd sync from close-beads
- mol-polecat-code-review: Remove bd sync from summarize-review and complete-and-exit
- mol-polecat-review-pr: Remove bd sync from complete-and-exit
- mol-convoy-cleanup: Remove bd sync from archive-convoy
- mol-digest-generate: Remove bd sync from send-digest
- mol-town-shutdown: Replace sync-state step with verify-state
- beads-release: Replace restart-daemons with verify-install (no daemons with Dolt)
**Templates (role priming):**
- mayor.md.tmpl: Update session end checklist to remove bd sync steps
- crew.md.tmpl: Remove bd sync references from workflow and checklist
- polecat.md.tmpl: Update self-cleaning model and session close docs
- spawn.md.tmpl: Remove bd sync from completion steps
- nudge.md.tmpl: Remove bd sync from completion steps
**Go code:**
- session_manager.go: Remove syncBeads function and call
- rig_dock.go: Remove bd sync calls from dock/undock
- crew/manager.go: Remove runBdSync, update Pristine function
- crew_maintenance.go: Remove bd sync status output
- crew.go: Update pristine command help text
- polecat.go: Make sync command a no-op with deprecation message
- daemon/lifecycle.go: Remove bd sync from startup sequence
- doctor/beads_check.go: Update fix hints and Fix to use bd import not bd sync
- doctor/rig_check.go: Remove sync status check, simplify BeadsConfigValidCheck
- beads/beads.go: Update primeContent to remove bd sync references
With Dolt backend, beads changes are persisted immediately to the sql-server.
There is no separate sync step needed.
Part of epic: hq-e4eefc (SQLite removal)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Gas Town uses Dolt exclusively. Remove all bd sync and bd daemon
references from agent priming, templates, formulas, and docs.
With Dolt backend:
- Beads changes are automatically persisted
- No manual sync needed (no bd sync)
- No daemon needed (no bd daemon)
Updated files:
- polecat-CLAUDE.md template
- Role templates (crew, mayor, polecat)
- Message templates (spawn, nudge)
- Formulas (polecat-work, sync-workspace, shutdown, etc.)
- Reference docs
Part of hq-4f2f0c: Remove bd sync/daemon from agent priming
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace direct sqlite3 CLI calls in getTrackedIssues and isTrackedByConvoy
with bd dep list commands that work with any beads backend (SQLite or Dolt).
- getTrackedIssues: Use bd dep list --direction=down --type=tracks --json
- isTrackedByConvoy: Use bd dep list --direction=up --type=tracks --json
This enables convoy commands to work with the Dolt backend.
Fixes: hq-e4eefc.2
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove all code that calls bd daemon commands, as bd daemon functionality
has been removed from beads:
- Delete internal/beads/daemon.go (CheckBdDaemonHealth, StopAllBdProcesses, etc.)
- Delete internal/beads/daemon_test.go
- Delete internal/doctor/bd_daemon_check.go (BdDaemonCheck health check)
- Remove bd daemon health check from gt status
- Remove bd daemon stopping from gt down
- Remove bd daemon cleanup from gt install
- Remove BdDaemonCheck registration from gt doctor
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Raw `go build` produces unsigned binaries that macOS kills. Add a
BuiltProperly ldflag that make build sets, and check it at startup.
If missing, print an error directing users to use make build.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When gt handoff killed pane processes before respawning, the pane would
be destroyed (since remain-on-exit defaults to off), causing respawn-pane
to fail with "can't find pane" error.
Fix: Set remain-on-exit=on before killing processes, so the pane survives
process death and can be respawned. This restores tmux session reuse on
handoffs.
Changes:
- Add SetRemainOnExit method to tmux package
- Call SetRemainOnExit(true) before KillPaneProcesses in:
- Local handoff (runHandoff)
- Remote handoff (handoffRemoteSession)
- Mayor attach respawn (runMayorAttach)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add the ability to force dark or light mode colors for CLI output,
overriding the automatic terminal background detection.
Changes:
- Add CLITheme field to TownSettings for persisting preference
- Add GetThemeMode() and HasDarkBackground() to ui package for
theme detection with GT_THEME env var override
- Add ApplyThemeMode() to explicitly set lipgloss dark background
- Add 'gt theme cli' subcommand to view/set CLI theme preference
- Initialize theme in CLI startup (persistentPreRun)
- Add comprehensive tests for theme mode functionality
Usage:
- gt theme cli # show current theme
- gt theme cli dark # force dark mode
- gt theme cli light # force light mode
- gt theme cli auto # auto-detect (default)
- GT_THEME=dark gt status # per-command override
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Fixes#915
`gt convoy check` was failing to detect closed beads in external rig databases,
causing convoys to remain perpetually open despite tracked work being completed.
Changes:
- Modified getTrackedIssues() to parse external:rig:id format and track rig ownership
- Added getExternalIssueDetails() to query external rig databases by running bd show
from the rig directory
- Changed from issueIDs []string to issueRefs []issueRef struct to track both ID and
rig name for each dependency
The fix enables proper cross-rig convoy completion by querying the appropriate database
(town or rig) for each tracked bead's status.
Testing: Verified that convoy hq-cv-u7k7w tracking external:claycantrell:cl-niwe now
correctly detects the closed status and auto-closes the convoy.
- Add quality gates (lint, format, tests) as step 1 before committing
- Support both npm and Go project types
- Add explicit warning: "DO NOT commit if lint or tests fail"
- Explain why manual checks are needed (worktrees may not trigger hooks)
Fixes hq-lint1
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
When sending mail notifications, the canonical address format (rig/name)
doesn't distinguish between crew workers (session: gt-rig-crew-name) and
polecats (session: gt-rig-name). This caused notifications to fail for
crew workers in other rigs.
Solution: Try both possible session IDs when the address is ambiguous,
using the first one that has an active session.
Supersedes PR #896 which only handled slash-to-dash conversion.
Fixes: gt-h5btjg
The 'gt namepool' command was showing 'mad-max' for all rigs because
it created the pool with defaults instead of loading config. This made
it impossible to see if a rig had custom theme settings.
Load config before creating the pool, matching the logic in manager.go
that actually spawns polecats. Theme and CustomNames come from
settings/config.json, not from the state file.
Co-authored-by: Claude <noreply@anthropic.com>
* fix(witness): detect and ignore stale POLECAT_DONE messages
Add timestamp validation to prevent witness from nuking newly spawned
polecat sessions when processing stale POLECAT_DONE messages from
previous sessions.
- Add isStalePolecatDone() to compare message timestamp vs session created time
- If message timestamp < session created time, message is stale and ignored
- Add unit tests for timestamp parsing and stale detection logic
Fixes#909
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(mail): add --stale flag to gt mail archive
Add ability to archive stale messages (sent before current session started).
This prevents old messages from cycling forever in patrol inbox.
Changes:
- Add --stale and --dry-run flags to gt mail archive
- Move stale detection helpers to internal/session/stale.go for reuse
- Add ParseAddress to parse mail addresses into AgentIdentity
- Add SessionCreatedAt to get tmux session start time
Usage:
gt mail archive --stale # Archive all stale messages
gt mail archive --stale --dry-run # Preview what would be archived
Co-Authored-By: GPT-5.2 Codex <noreply@openai.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: GPT-5.2 Codex <noreply@openai.com>
Two issues fixed:
1. gt hook <convoy-id> now runs bd update from town root, ensuring
proper prefix-based routing for convoys (hq-*) in town beads.
2. gt hook show now also searches town beads for hooked items,
allowing agents to find hooked convoys regardless of their
current workspace location.
This enables the convoy-driver workflow where any agent can hook
a convoy and have it displayed via gt hook show.
Fixes: hq-y845
Gas town agents need to ignore working-file directories like .logs,
.runtime, and .claude, but Beads provides its own .gitignore handling
in `bd init`, creating a .beads/.gitignore file which ignores the
relevant Beads working files while allowing .beads/issues.jsonl
to be tracked correctly. PR #753 broke this, causing new polecats
to attempt to merge their changed .gitignore into the project repo,
ultimately breaking bd sync and causing issues to become untracked.
The misclassified-wisps check could detect issues that should be wisps
but couldn't fix them because bd update lacked an --ephemeral flag.
Now that beads supports `bd update <id> --ephemeral` (steveyegge/beads#1263),
implement the actual fix to mark detected issues as ephemeral.
Closes#852
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix(molecule): use Dependencies from bd show instead of empty DependsOn
Bug: Molecule step dependency checking was broken because bd list
doesn't populate the DependsOn field (it's always empty). Only bd show
returns dependency info in the Dependencies field.
This caused all open steps to appear "ready" regardless of actual
dependencies - the polecat would start blocked steps prematurely.
Fix: Call ShowMultiple() after List() to fetch full issue details
including Dependencies, then check Dependencies instead of DependsOn.
Affected functions:
- findNextReadyStep() in molecule_step.go
- getMoleculeProgressInfo() in molecule_status.go
- runMoleculeCurrent() in molecule_status.go
Tests:
- Added TestFindNextReadyStepWithBdListBehavior to verify fix
- Added TestOldBuggyBehavior to demonstrate the bug
- Updated existing tests to use fixed algorithm
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(molecule): use Dependencies from bd show instead of empty DependsOn
Bug: Molecule step dependency checking was broken because bd list
doesn't populate the DependsOn field (it's always empty). Only bd show
returns dependency info in the Dependencies field.
This caused all open steps to appear "ready" regardless of actual
dependencies - the polecat would start blocked steps prematurely.
Fix: Call ShowMultiple() after List() to fetch full issue details
including Dependencies, then check Dependencies instead of DependsOn.
Also filter to only check "blocks" type dependencies - ignore "parent-child"
relationships which are just structural, not blocking.
Affected functions:
- findNextReadyStep() in molecule_step.go
- getMoleculeProgressInfo() in molecule_status.go
- runMoleculeCurrent() in molecule_status.go
Tests:
- Added TestFindNextReadyStepWithBdListBehavior to verify fix
- Added TestOldBuggyBehavior to demonstrate the bug
- Updated existing tests to use fixed algorithm
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: julianknutsen <julianknutsen@users.noreply.github>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add validateRecipient() to check that mail recipients correspond to
existing agents before sending. This prevents mail from being stored
with invalid assignees that won't match inbox queries.
The validation queries agent beads and checks if any match the
recipient identity. The only special case is "overseer" which is the
human operator and doesn't have an agent bead.
Tests create a temporary isolated beads database with test agents
to validate both success and failure cases. Tests are skipped if
bd CLI is not available (e.g., in CI).
Fixes gt-0y8qa
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
When a rig is removed with `gt rig remove`, the route entry in
routes.jsonl was not being cleaned up. This caused problems when
re-adding the rig with a different prefix, resulting in duplicate
entries and prefix mismatch errors.
The fix calls beads.RemoveRoute() during rig removal to clean up
the route entry from routes.jsonl.
Fixes#899
Co-authored-by: dementus <julianknutsen@users.noreply.github>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
vars.mode had both required=true and default="conservative", which
causes formula validation to fail with:
vars.mode: cannot have both required:true and default
This prevented gt doctor from dispatching cleanup work to dogs.
Remove required=true since the default value ensures the variable
is always populated.
Co-authored-by: mayor <ec2-user@ip-172-31-43-79.ec2.internal>
ListUnread() was returning all open messages in beads mode instead of
filtering out messages marked as read. This caused `gt mail inbox --unread`
to show all messages even when they had the "read" label.
The fix unifies the code path for legacy and beads modes - both now
filter by the msg.Read field, which is correctly populated from the
"read" label via ToMessage().
Note: `gt mail read` intentionally does NOT mark messages as read
(to preserve handoff messages). Users should use `gt mail mark-read`
to explicitly mark messages as read.
Fixes gt-izcp85
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This ensures Claude Code starts in normal editor mode rather than
potentially using vim mode, which can cause issues with automated
text input via tmux send-keys.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Add hung-session-detection step to deacon patrol
Detects and surgically recovers Gas Town sessions where Claude API
call is stuck indefinitely. These appear "running" (tmux session
exists) but aren't processing work.
Safety checks (ALL must pass before recovery):
1. Session matches Gas Town pattern exactly (gt-*-witness, etc)
2. Session shows waiting state (Clauding/Deciphering/etc)
3. Duration >30min AND (zero tokens OR duration >2hrs)
4. NOT showing active tool execution (⏺ markers)
This closes a gap where existing zombie-scan only catches processes
not in tmux sessions.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(orphan): protect all tmux sessions, not just Gas Town ones
The orphan cleanup was killing Claude processes in user's personal tmux
sessions (e.g., "loomtown", "yaad") because only sessions with gt-* or
hq-* prefixes were protected.
Changes:
- Renamed getGasTownSessionPIDs() to getTmuxSessionPIDs()
- Now protects ALL tmux sessions regardless of name prefix
- Updated variable names for clarity (gasTownPIDs -> protectedPIDs)
The TTY="?" check is not reliable during certain operations (startup,
session transitions), so explicit protection of all tmux sessions is
necessary to prevent killing user's personal Claude instances.
Fixes#923
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: mayor <ec2-user@ip-172-31-43-79.ec2.internal>
Co-authored-by: Claude <noreply@anthropic.com>
When a hooked bead has attached_molecule (formula workflow), the polecat
was being told "run bd show <bead-id>" first, then seeing molecule context
later. The polecat would follow the first instruction and work directly
on the bead, ignoring the formula steps entirely.
Now checks for attached_molecule FIRST and gives different instructions:
- If molecule attached: "Work through molecule steps - see CURRENT STEP"
- If no molecule: "Run bd show <bead-id>"
Also adds explicit warning: "Skip molecule steps or work on base bead directly"
to the DO NOT list when a molecule is attached.
Co-authored-by: julianknutsen <julianknutsen@users.noreply.github>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Replace bd create --ephemeral wisp with simple file append to
~/.gt/costs.jsonl. This ensures the stop hook never fails due to:
- Dolt server not running (connection refused)
- Dolt connection stale (invalid connection)
- Database temporarily unavailable
The costs.jsonl approach:
- Stop hook appends JSON line (fire-and-forget, ~0ms)
- gt costs --today reads from log file
- gt costs digest aggregates log entries into permanent beads
This is Option 1 from gt-99ls5z design bead.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add checkStaleBinaryWarning() call to persistentPreRun (was only in
deprecated function)
- Fix GetRepoRoot() to look in correct location ($GT_ROOT/gastown/mayor/rig)
- Use hasGtSource() with os.Stat instead of shell test command
Agents will now see warnings when running gt with a stale binary.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Gas Town has migrated to Dolt for beads storage. The bd version
check was blocking all commands when bd hangs/crashes.
Added crew, polecat, witness, refinery, status, mail, hook, prime,
nudge, seance, doctor, and dolt to the exempt list.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tests ensure:
- All SessionStart hooks with gt prime include --hook flag
- registry.toml session-prime includes all required roles
These catch the seance discovery bug before it breaks handoffs.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
KillSession was leaving orphaned Claude/node processes because pgrep -P
only finds direct children. Processes that reparent to init (PID 1) were
missed.
Changes:
- Kill entire process group first using kill -TERM/-KILL -<pgid>
- Add getProcessGroupID() and getProcessGroupMembers() helpers
- Update KillSessionWithProcesses, KillSessionWithProcessesExcluding,
and KillPaneProcesses to use process group killing
- Fix EnsureSessionFresh to use KillSessionWithProcesses instead of
basic KillSession
Fixes: gt-w1dcvq
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When polecats are nuked, Claude child processes could survive and become
orphans, leading to memory exhaustion (observed: 142 orphaned processes
consuming ~56GB RAM).
This commit:
1. Increases the SIGTERM→SIGKILL grace period from 100ms to 2s to give
processes time to clean up gracefully
2. Adds orphan cleanup to `gt polecat nuke` that runs after session
termination to catch any processes that escaped
3. Adds a new `gt cleanup` command for manual orphan removal
The orphan detection uses aggressive tmux session verification to find
ALL Claude processes not in any active session, not just those with
PPID=1.
Fixes: gh-736
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add CleanupOrphanedSessions() function that runs at `gt start` time to
detect and kill zombie tmux sessions (sessions where tmux is alive but
the Claude process has died).
This prevents:
- Session name conflicts when restarting agents
- Resource accumulation from orphaned sessions
- Process accumulation that can overwhelm the system
The function scans for sessions with `gt-*` and `hq-*` prefixes, checks
if Claude is running using IsClaudeRunning(), and kills zombie sessions
using KillSessionWithProcesses() for proper cleanup.
Fixes#700
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Call beads.EnsureCustomTypes before attempting to create a convoy.
This fixes invalid issue type: convoy errors that occur when town
beads do not have custom types configured (e.g., incomplete install
or manually initialized beads).
The EnsureCustomTypes function uses caching (in-memory + sentinel file)
so this adds negligible overhead to convoy create.
Fixes: gt-1b8eg9
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The npm package @gastown/gt was never published because the release
workflow used OIDC trusted publishing which requires initial manual
setup on npm.org. Changed to use NPM_TOKEN secret for authentication.
Also added npm install option to README.
Fixes#867
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The `gt hooks` command was not discovering settings at:
- <rig>/crew/.claude/settings.json (crew-level, inherited by all members)
- <rig>/polecats/.claude/settings.json (polecats-level)
This caused confusion when debugging hooks since Claude Code inherits
from parent directories, so hooks were executing but not shown by
`gt hooks`.
Also fixed: skip .claude directories when iterating crew members.
Fixes: gh-735
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
FetchPolecats() was showing all tmux sessions system-wide without
filtering by the workspace's registered rigs. This caused unrelated
refineries (like roxas) to appear in the dashboard.
Now loads rigs.json and only displays sessions for registered rigs,
matching the filtering behavior already used in FetchMergeQueue().
Fixes gh-868
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>