Commit Graph

3046 Commits

Author SHA1 Message Date
aleiby
31bd120077 fix(startup): unify agent startup with beacon + instructions in CLI prompt (#977)
All agents now receive their startup beacon + role-specific instructions via
the CLI prompt, making sessions identifiable in /resume picker while removing
unreliable post-startup nudges.

Changes:
- Rename FormatStartupNudge → FormatStartupBeacon, StartupNudgeConfig → BeaconConfig
- Remove StartupNudge() function (no longer needed)
- Remove PropulsionNudge() and PropulsionNudgeForRole() functions
- Update deacon, witness, refinery, polecat managers to include beacon in CLI prompt
- Update boot to inline beacon (can't import session due to import cycle)
- Update daemon/lifecycle.go to include beacon via BuildCommandWithPrompt
- Update cmd/deacon.go to include beacon in startup command
- Remove redundant StartupNudge and PropulsionNudge calls from all startup paths

The beacon is now part of the CLI prompt which is queued before Claude starts,
making it more reliable than post-startup nudges which had timing issues.
SessionStart hook runs gt prime automatically, so PropulsionNudge was redundant.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 18:08:57 -08:00
David Van Couvering
92ccacffd9 feat(sling): add --no-merge flag to skip merge queue (#939)
When contributing to upstream repos or wanting human review before merge,
the --no-merge flag keeps polecat work on a feature branch instead of
auto-merging to main.

Changes:
- Add --no-merge flag to gt sling command
- Store no_merge field in bead's AttachmentFields
- Modify gt done to skip merge queue when no_merge is set
- Push branch and mail dispatcher "READY_FOR_REVIEW" instead
- Add tests for field parsing and sling flag storage

Closes: gt-p7b8

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 18:08:34 -08:00
Harrison
a86c7d954f fix(costs): read token usage from Claude Code transcripts instead of tmux (#941)
* fix(costs): read token usage from Claude Code transcripts instead of tmux

Replace tmux screen-scraping with reading token usage directly from Claude
Code transcript files at ~/.claude/projects/*/. This enables accurate cost
tracking by summing input_tokens, cache_creation_input_tokens,
cache_read_input_tokens, and output_tokens from assistant messages.

Adds model-specific pricing for Opus 4.5, Sonnet 4, and Haiku 3.5 to
calculate USD costs from token counts.

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

* fix(costs): correct Claude project path encoding

The leading slash should become a leading dash, not be stripped.
Claude Code encodes /Users/foo as -Users-foo, not Users-foo.

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

* fix(costs): make --by-role and --by-rig fast by defaulting to today's costs

When using --by-role or --by-rig without a time filter, the command was
querying all historical events from the beads database via expensive bd list
and bd show commands, taking 10+ seconds and returning no data.

Now these flags default to today's costs from the log file (same as --today),
making them fast and showing actual data. This aligns with the new log-file-based
cost tracking architecture.

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

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 18:06:22 -08:00
Artem Bambalov
c94a2301eb fix: align assigneeID format with hooked issue format (#946)
The polecat manager was using rig/name format while sling sets
rig/polecats/name. This caused gt polecat status to show 'done'
for working polecats because GetAssignedIssue couldn't find them.

Fixes gt-oohy
2026-01-25 18:05:44 -08:00
Artem Bambalov
6d18e0a88b fix: use gt handoff flags for mail (#957) 2026-01-25 18:05:41 -08:00
Artem Bambalov
0e0547b3e1 fix(mail): prevent message type failures (#960) 2026-01-25 18:05:11 -08:00
Artem Bambalov
0ff092ae9f fix: allow vars with formula-on-bead slings (#966) 2026-01-25 18:05:08 -08:00
Subhrajit Makur
065d428f76 fix(config): preserve all RuntimeConfig fields in fillRuntimeDefaults (#971)
* fix(config): preserve all RuntimeConfig fields in fillRuntimeDefaults

fillRuntimeDefaults was only copying Command, Args, InitialPrompt, and Env
when creating a copy of RuntimeConfig. This caused fields like PromptMode,
Provider, Session, Hooks, Tmux, and Instructions to be silently dropped.

This broke custom agent configurations, particularly prompt_mode: "none"
which is needed for agents like opencode that don't accept a startup beacon.

Changes:
- Copy all RuntimeConfig fields in fillRuntimeDefaults
- Add comprehensive tests for fillRuntimeDefaults
- Add integration tests for custom agent configs with prompt_mode: none
- Add tests mirroring manual verification: claude-opus, amp, codex, gemini

* fix(config): deep copy slices and nested structs in fillRuntimeDefaults

The original fix preserved all fields but used shallow copies for slices
and nested structs. This could cause mutation of the original config.

Changes:
- Deep copy Args slice (was sharing backing array)
- Deep copy Session, Hooks, Tmux, Instructions structs (were pointer copies)
- Deep copy Tmux.ProcessNames slice
- Add comprehensive mutation isolation tests for all fields
- Fix TestMultipleAgentTypes to test actual built-in presets
- Add TestCustomClaudeVariants to clarify that claude-opus/sonnet/haiku
  are NOT built-in and must be defined as custom agents

Built-in presets: claude, gemini, codex, cursor, auggie, amp, opencode
Custom variants like claude-opus need explicit definition in Agents map.

* docs(test): add manual test settings to TestRoleAgentConfigWithCustomAgent

Document the settings/config.json used for manual verification:
- default_agent: claude-opus
- Custom agents: amp-yolo, opencode-mayor (with prompt_mode: none)
- role_agents mapping for all 6 roles
- Manual test procedure for all 7 built-in agents

* fix(test): address CodeRabbit review feedback

- Fix isClaudeCommand to handle Windows paths and .exe extension
- Use isClaudeCommand helper instead of brittle equality check
- Add skipIfAgentBinaryMissing to tests that depend on external binaries
  (TestMultipleAgentTypes, TestCustomAgentWithAmp)
2026-01-25 18:04:28 -08:00
Artem Bambalov
072c4649de fix: always send handoff mail (#973)
* 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>
2026-01-25 18:04:07 -08:00
aleiby
fe09e59c8c fix(tmux): wake Claude in detached sessions by triggering SIGWINCH (#976)
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>
2026-01-25 18:02:30 -08:00
groblegark
57f062a9b6 fix(tmux): add -- to kill commands to prevent procps-ng argument parsing bug (#928)
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>
2026-01-25 18:01:52 -08:00
baldvin-kovacs
8a8603e6df Fix gt ready using wrong beads path for rigs (#963)
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>
2026-01-25 18:01:27 -08:00
Bo
212f08ad03 fix(polecat): detect when shell is cd'd into worktree before nuke (#969)
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
2026-01-25 18:01:24 -08:00
aleiby
7926d7b3e8 fix(handoff): prevent self-kill during gt handoff (#881) (#882)
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>
2026-01-25 18:00:49 -08:00
Clay Cantrell
aca753296b feat(web): comprehensive dashboard control panel with 13 data panels (#931)
* 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.
2026-01-25 18:00:46 -08:00
mayor
75739cbaaf fix(mail): handle hq- prefixed agent IDs in recipient validation
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>
2026-01-25 16:00:47 -08:00
max
0c791a4d40 fix(handoff): don't KillPaneProcesses on self-handoff
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>
2026-01-25 15:56:15 -08:00
mayor
2ee5e1c5ad feat(dolt): add gt dolt command for server management
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>
2026-01-25 15:34:37 -08:00
mayor
e937717147 fix(build): make install now properly builds, signs, and installs to ~/.local/bin
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>
2026-01-25 14:10:19 -08:00
mayor
b316239d12 chore(gastown): scorched-earth SQLite removal from codebase
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>
2026-01-25 14:08:53 -08:00
mayor
1d260d377b docs(priming): remove bd sync references for Dolt backend
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>
2026-01-25 13:36:22 -08:00
dennis
30e65b5ca7 refactor(convoy): replace SQLite queries with bd dep list commands
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>
2026-01-25 13:33:38 -08:00
george
b178d056f6 refactor: remove bd daemon code from gastown
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>
2026-01-25 13:33:02 -08:00
mayor
2f0f0763cc fix(build): use GT_ROOT for build error path hint
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 22:23:52 -08:00
mayor
b1e8b11948 fix(build): error on raw go build, require make build
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>
2026-01-24 22:23:07 -08:00
mayor
36c7222d5b fix(handoff): preserve tmux session by setting remain-on-exit before kill
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>
2026-01-24 22:17:42 -08:00
Kody Wildfeuer
baf9311bfe feat(theme): add dark mode CLI theme support (#911)
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>
2026-01-24 22:15:48 -08:00
Clay Cantrell
377b4877cd Fix convoy check to query external rig databases for cross-rig tracking (#916)
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.
2026-01-24 21:49:16 -08:00
Mad Dan
9dcddaf13d feat(polecat): add explicit lint/test step to decommission checklist (#934)
- 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>
2026-01-24 21:48:38 -08:00
aleiby
db60489d0f fix(mail): handle crew/polecat ambiguity in notification session lookup (#914)
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
2026-01-24 21:48:16 -08:00
Christian Sieber
63d60f1dcd fix(namepool): display correct theme from config.json (#890)
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>
2026-01-24 21:48:12 -08:00
Artem Bambalov
533caf8e4b Detect and clean stale POLECAT_DONE messages (#913)
* 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>
2026-01-24 21:47:59 -08:00
Dale Navi
f635555f93 fix(hook): complete convoy hooking implementation (#897)
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
2026-01-24 21:47:14 -08:00
Christian Sieber
5bb74b19ed Revert erroneous addition of .beads to agent .gitignore template (#891)
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.
2026-01-24 21:47:09 -08:00
aleiby
9db9fc2af8 fix(doctor): implement Fix for misclassified-wisps check (#878)
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>
2026-01-24 21:47:04 -08:00
Julian Knutsen
3da0d5a7c8 fix(molecule): use Dependencies from bd show instead of empty DependsOn (#901)
* 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>
2026-01-24 21:46:27 -08:00
aleiby
4e4824a6c6 fix(mail): validate recipient exists before sending (#886)
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>
2026-01-24 21:46:09 -08:00
Julian Knutsen
2fb787c7a2 fix(rig): remove route from routes.jsonl on rig remove (#910)
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>
2026-01-24 21:46:05 -08:00
Basit Mustafa
70ca511ee2 fix: remove conflicting required+default in mol-session-gc formula (#919)
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>
2026-01-24 21:46:01 -08:00
aleiby
71077e93dd fix(mail): filter by read status in ListUnread for beads mode (#936)
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>
2026-01-24 21:45:22 -08:00
Ben Tucker
6c86616273 fix(settings): set editorMode to normal for Claude sessions (#929)
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>
2026-01-24 21:45:19 -08:00
Basit Mustafa
3442471a93 fix(orphan): protect all tmux sessions, not just Gas Town ones (#924)
* 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>
2026-01-24 21:45:12 -08:00
Julian Knutsen
f276b9d28a fix(prime): show molecule instructions BEFORE bare bead instructions (#920)
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>
2026-01-24 21:45:09 -08:00
kev
8941e7b049 fix: Updated setup brew command to use correct formula (#903) 2026-01-24 21:45:01 -08:00
Taeun Lee
44fbd6eac7 Update .gitignore (#922)
bd.sock.startlock which captures pid appears and disappears frequently.
2026-01-24 21:44:42 -08:00
joe
2a0420177e refactor(costs): rename wisp references to entries
- querySessionCostWisps → querySessionCostEntries
- Rename variables: wisps → costEntries, todayWisps → todayEntries
- Add comment explaining POSIX O_APPEND atomicity guarantee

Follow-up to code review feedback.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 21:29:57 -08:00
joe
dc3fd47a32 refactor(costs): decouple cost recording from Dolt database
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>
2026-01-24 21:21:20 -08:00
beads/crew/emma
889c5863fa fix(stale): enable stale binary warning and fix source detection
- 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>
2026-01-24 20:52:27 -08:00
mayor
d9f1fe9e48 fix(cmd): add more commands to beads version exempt list
Added handoff, costs, feed, rig, config, install, tap, dnd.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 16:23:24 -08:00
mayor
c4d8e26dcb fix(cmd): exempt most commands from beads version check
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>
2026-01-24 15:35:13 -08:00