Commit Graph

1741 Commits

Author SHA1 Message Date
riker
c3fb9c6027 fix(dog): properly set identity for dog sessions
Three fixes to make dog dispatch work end-to-end:

1. Add BuildDogStartupCommand in loader.go
   - Similar to BuildPolecatStartupCommand/BuildCrewStartupCommand
   - Passes AgentName to AgentEnv so BD_ACTOR is exported in startup command

2. Use BuildDogStartupCommand in dog.go
   - Removes ineffective SetEnvironment calls (env vars set after shell starts
     don't propagate to already-running processes)

3. Add "dog" case in mail_identity.go detectSenderFromRole
   - Dogs now use BD_ACTOR for mail identity
   - Without this, dogs fell through to "overseer" and couldn't find their mail

Tested: dog alpha now correctly sees inbox as deacon/dogs/alpha

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 11:15:29 -08:00
riker
2590e3de3b fix(dog): spawn session and set BD_ACTOR for dog dispatch
Recovered from reflog - these commits were lost during a rebase/force-push.

Dogs are directories with state files but no sessions. When `gt dog dispatch`
assigned work and sent mail, nothing executed because no session existed.

Changes:
1. Spawn tmux session after dispatch (gt-<town>-deacon-<dogname>)
2. Set BD_ACTOR=deacon/dogs/<name> so dogs can find their mail
3. Add dog case to AgentEnv for proper identity

Session spawn is non-blocking - if it fails, mail was sent and human can
manually start the session.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 11:15:29 -08:00
ec9a07cec1 feat(dog): add 'gt dog done' command for dogs to mark themselves idle
Dogs can now reset their own state to idle after completing work:

  gt dog done        # Auto-detect from BD_ACTOR
  gt dog done alpha  # Explicit name

This solves the issue where dog sessions would complete work but remain in
"working" state because nothing processed the DOG_DONE mail. Now dogs can
explicitly mark themselves idle before handing off.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 11:15:29 -08:00
1c8d0891e1 fix(session): increase ClaudeStartTimeout from 60s to 120s
Fixes intermittent 'timeout waiting for runtime prompt' errors that occur
when Claude takes longer than 60s to start under load or on slower machines.

Resolves: hq-j2wl

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 11:15:29 -08:00
eed6284e3c feat(security): add GIT_AUTHOR_EMAIL per agent type
Phase 1 of agent security model: Set distinct email addresses for each
agent type to improve audit trail clarity.

Email format:
- Town-level: {role}@gastown.local (mayor, deacon, boot)
- Rig-level: {rig}-{role}@gastown.local (witness, refinery)
- Named agents: {rig}-{role}-{name}@gastown.local (polecat, crew)

This makes git log filtering by agent type trivial and provides a
foundation for per-agent key separation in future phases.

Refs: hq-biot
2026-01-25 11:15:29 -08:00
ad6322b414 feat(mayor): add escalation check to startup protocol
Mayor now checks `gt escalate list` between hook and mail checks at startup.
This ensures pending escalations from other agents are handled promptly.

Other roles (witness, refinery, polecat, crew, deacon) are unaffected -
they create escalations but don't handle them at startup.
2026-01-25 11:15:29 -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
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
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
mayor
d4126bb876 test(config): add hook configuration validation tests
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>
2026-01-24 00:05:58 -08:00
dag
be96bb0050 fix(tmux): kill process group to prevent orphaned processes
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>
2026-01-22 21:45:10 -08:00
capable
bebf425ac5 fix(polecat): kill orphaned Claude processes when nuking polecats
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>
2026-01-22 21:43:23 -08:00
toast
ee5221889f fix: clean up orphaned tmux sessions at gt start time
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>
2026-01-22 21:42:27 -08:00
furiosa
73d577e3c3 fix(convoy): ensure custom types registered before creating convoy
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>
2026-01-22 21:41:25 -08:00
dementus
493507ad4e fix(hooks): discover crew-level and polecats-level settings
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>
2026-01-22 21:39:31 -08:00
nux
232fc79cd5 fix(dashboard): filter polecats by registered rigs
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>
2026-01-22 21:38:24 -08:00
rictus
429f8e96ef feat(tmux): enable clipboard integration in mayor sessions
Add set-clipboard option to EnableMouseMode function so copied text
goes to system clipboard via OSC 52 terminal escape sequences.

Closes #843

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 21:36:13 -08:00
mayor
83ddef4f88 fix(rig): dock/undock require main branch to prevent silent failures
Docking on non-main branches silently fails because rig identity beads
live on main. The dock appeared to work but was lost on checkout to main.

Now dock/undock check current branch and error with helpful message:
"cannot dock: must be on main branch (currently on X)"

Fixes hq-kc7

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 21:27:38 -08:00
Erik LaBianca
14435cacad fix: update test assertions and set BEADS_DIR in EnsureCustomTypes (#853)
* fix: update test assertions and set BEADS_DIR in EnsureCustomTypes

- Update TestBuildAgentStartupCommand to check for 'exec env' instead
  of 'export' (matches current BuildStartupCommand implementation)
- Add 'config' command handling to fake bd script in manager_test.go
- Set BEADS_DIR env var when running bd config in EnsureCustomTypes
  to ensure bd operates on the correct database during agent bead creation
- Apply gofmt formatting

These fixes address pre-existing test failures on main.

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

* fix: inject mock in TestRoleLabelCheck_NoBeadsDir for Windows CI

The test was failing on Windows CI because bd is not installed,
causing exec.LookPath("bd") to fail and return "beads not installed"
before checking for the .beads directory.

Inject an empty mock beadShower to skip the LookPath check, allowing
the test to properly verify the "No beads database" path.

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

* fix: regenerate formulas and fix unused parameter lint error

- Regenerate mol-witness-patrol.formula.toml to sync with source
- Mark unused hookName parameter with _ in installHookTo

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

* fix(tests): make Windows CI tests pass

- Skip symlink tests on Windows (require elevated privileges)
- Fix GT_ROOT assertion to handle Windows path escaping
- Use platform-appropriate paths in TestNewManager_PathConstruction

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

* Fix tests for quoted env and OS paths

* fix(test): add Windows batch scripts to molecule lifecycle tests

The molecule_lifecycle_test.go tests were failing on Windows CI because
they used Unix shell scripts (#!/bin/sh) for mock bd commands, which
don't work on Windows.

This commit adds Windows batch file equivalents for all three tests:
- TestSlingFormulaOnBeadHooksBaseBead
- TestSlingFormulaOnBeadSetsAttachedMoleculeInBaseBead
- TestDoneClosesAttachedMolecule

Uses the same pattern as writeBDStub() from sling_test.go for
cross-platform test mocks.

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

* fix(test): add Windows batch scripts to more tests

Adds Windows batch script equivalents to tests that use mock bd commands:

molecule_lifecycle_test.go:
- TestSlingFormulaOnBeadHooksBaseBead
- TestSlingFormulaOnBeadSetsAttachedMoleculeInBaseBead
- TestDoneClosesAttachedMolecule

sling_288_test.go:
- TestInstantiateFormulaOnBead
- TestInstantiateFormulaOnBeadSkipCook
- TestCookFormula
- TestFormulaOnBeadPassesVariables

These tests were failing on Windows CI because they used Unix shell
scripts (#!/bin/sh) which don't work on Windows.

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

* fix(test): skip TestSlingFormulaOnBeadSetsAttachedMoleculeInBaseBead on Windows

The test's Windows batch script JSON output causes
storeAttachedMoleculeInBead to fail silently when parsing the bd show
response. This is a pre-existing limitation - the test was failing on
Windows before the batch scripts were added (shell scripts don't work
on Windows at all).

Skip this test on Windows until the underlying JSON parsing issue is
resolved.

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

* chore: re-trigger CI after GitHub Internal Server Error

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 16:43:21 -08:00
Jackson Cantrell
0fb3e8d5fe fix: inherit environment in daemon subprocess calls (#876)
The daemon's exec.Command calls were not explicitly setting cmd.Env,
causing subprocesses to fail when the daemon process doesn't have
the expected PATH environment variable. This manifests as:

  Warning: failed to fetch deacon inbox: exec: "gt": executable file not found in $PATH

When the daemon is started by mechanisms with minimal environments
(launchd, systemd, or shells without full PATH), executables like
gt, bd, git, and sqlite3 couldn't be found.

The fix adds cmd.Env = os.Environ() to all 15 subprocess calls across
three files, ensuring they inherit the daemon's full environment.

Affected commands:
- gt mail inbox/delete/send (lifecycle requests, notifications)
- bd sync/show/list/activity (beads operations)
- git fetch/pull (workspace pre-sync)
- sqlite3 (convoy completion queries)

Fixes #875

Co-authored-by: Jackson Cantrell <cantrelljax@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 16:41:51 -08:00
Rui Chen
16d3a92455 chore: increase timeout for bd version check (#871)
Signed-off-by: Rui Chen <rui@chenrui.dev>
2026-01-22 16:41:42 -08:00
mayor
5cc2995345 chore(release): v0.5.0
All checks were successful
Release / goreleaser (push) Successful in 5m32s
Release / publish-npm (push) Has been skipped
Release / update-homebrew (push) Has been skipped
- Mail improvements: numeric index, hook alias, --body alias, bulk delete, parallel queries
- New aliases: gt bd, gt work, --comment, read
- OpenCode agent preset, config-based role system
- Deacon status line display, hook registry
- Squash merge in refinery
- Crew session stability fixes
- Many bug fixes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 23:05:00 -08:00
mayor
e57297cb1b fix(crew): don't kill pane processes when creating new session
KillPaneProcesses was being called on new sessions before respawn,
which killed the fresh shell and destroyed the pane. This caused
"can't find pane" errors on session creation.

Now KillPaneProcesses is only called when restarting in an existing
session where Claude/Node processes might be running and ignoring
SIGHUP. For new sessions, we just use respawn-pane directly.

Also added retry limit and error checking for the stale session
recovery path.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 22:46:00 -08:00
mayor
dff6c3fb3c feat: add aliases and deacon status line display
- Add 'bd' alias for 'gt bead' command
- Add 'work' alias for 'gt hook' command
- Show deacon icon in mayor status line when running

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 22:40:10 -08:00
mayor
fb4c415127 fix(crew): auto-recover from stale tmux pane references
When a session exists but its pane is gone (e.g., after account switch
or town reboot), 'gt crew at' now detects the "can't find pane" error
and automatically recreates the session instead of failing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 22:39:10 -08:00
dementus
b612df0463 feat(mail): add numeric index support to 'gt mail read'
Allow reading messages by their inbox position (e.g., 'gt mail read 3')
in addition to message ID. The inbox display now shows 1-based index
numbers for easy reference.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 21:55:07 -08:00
toast
785d9adfef feat(mail): add gt mail hook as alias for gt hook attach
Adds gt mail hook <mail-id> command that attaches a mail message to
the agents hook. This provides a more intuitive command path when
working with mail-based workflows.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 21:53:18 -08:00
capable
3d7b109395 feat(mail): add --body as alias for --message/-m in gt mail send
Users naturally try --body for the message body content (same semantic
field as --message but more precise - distinguishes body from subject).
Added as an alias following the same pattern as --address/--identity.

Closes: gt-bn9mt

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 21:52:19 -08:00
nux
b14835b140 fix(refinery): pass convoy ID to convoy check command
The runConvoyCheck function was running `gt convoy check` without
the convoy ID, which checked all open convoys. Now it passes the
specific convoy ID to check only the relevant convoy, as specified
in the requirements.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 21:51:21 -08:00