Groups and channels are town-level entities that span rigs, so they
should use the hq- prefix rather than gt- (rig-level).
Changes:
- GroupBeadID: gt-group- → hq-group-
- ChannelBeadID: gt-channel- → hq-channel-
- Add --force flag to bypass prefix validation (town beads may have
mixed prefixes from test runs)
- Update tests and documentation
Also adds docs/beads-native-messaging.md documenting:
- New bead types (gt:group, gt:queue, gt:channel)
- CLI commands (gt mail group, gt mail channel)
- Address resolution logic
- Usage examples
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add beads-native queue management commands to gt mail:
- gt mail queue create <name> --claimers <pattern>
- gt mail queue show <name>
- gt mail queue list
- gt mail queue delete <name>
Also enhanced QueueFields struct with CreatedBy and CreatedAt fields
to support queue metadata tracking.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change ChannelBeadID to use hq-channel-* prefix instead of gt-channel-*
to match the town-level beads database prefix, fixing the "prefix mismatch"
error when creating channels.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement claiming for queue messages using beads-native approach:
- Add claim_pattern field to QueueFields for eligibility checking
- Add MatchClaimPattern function for pattern matching (wildcards supported)
- Add FindEligibleQueues to find all queues an agent can claim from
- Rewrite runMailClaim to use beads-native queue lookup
- Support optional queue argument (claim from any eligible if not specified)
- Use claimed-by/claimed-at labels instead of changing assignee
- Update runMailRelease to work with new claiming approach
- Add comprehensive tests for pattern matching and validation
Queue messages are now claimed via labels:
- claimed-by: <agent-identity>
- claimed-at: <RFC3339 timestamp>
Messages with queue:<name> label but no claimed-by are unclaimed.
Closes gt-xfqh1e.11
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add ChannelFields struct and CRUD operations for channel beads:
- ChannelFields with name, subscribers, status, retention settings
- CreateChannelBead, GetChannelBead, GetChannelByID methods
- SubscribeToChannel, UnsubscribeFromChannel for subscriber management
- UpdateChannelRetention, UpdateChannelStatus for configuration
- ListChannelBeads, LookupChannelByName, DeleteChannelBead
- Unit tests for parsing, formatting, and round-trip serialization
Part of gt-xfqh1e convoy: Beads-native messaging
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add queue bead type for tracking work queues in Gas Town. This includes:
- QueueFields struct with status, concurrency, processing order, and counts
- Parse/Format functions for queue field serialization
- CRUD methods: CreateQueueBead, GetQueueBead, UpdateQueueFields, etc.
- Queue registered in BeadsCustomTypes for bd CLI support
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add type=group to beads schema for mail distribution groups.
Fields:
- name: unique group identifier
- members: addresses, patterns, or group names (can nest)
- created_by: provenance tracking
- created_at: timestamp
Groups support:
- Direct addresses (gastown/crew/max)
- Patterns (*/witness, @crew)
- Nested groups (members can reference other groups)
Part of gt-xfqh1e epic (beads-native messaging).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Polecats were not calling `gt done` after completing work because
the compact PRIME.md context (used after compaction or when the
SessionStart hook is the only context) was missing this critical step.
The Session Close Protocol listed steps 1-6 (git status, add, bd sync,
commit, bd sync, push) but omitted step 7 (`gt done`), which:
- Submits work to the merge queue
- Exits the polecat session
- Allows the witness to spawn new polecats for remaining work
Without `gt done`, polecats would push code and announce "done" but
remain idle in their sessions, blocking the workflow cascade.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
ReconcilePool now detects and kills orphan tmux sessions (sessions without
corresponding polecat directories). This prevents allocation from being
blocked by broken state from crashed polecats.
Changes:
- Add tmux to Manager to check for orphan sessions during reconciliation
- Add ReconcilePoolWith for testable session/directory reconciliation logic
- Always clear hook_bead slot when reopening agent beads (fixes stale hooks)
- Prune stale git worktree entries during reconciliation
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
CountBdDaemons() was using `bd daemon list --json` which triggers
daemon auto-start as a side effect. During shutdown verification,
this caused a new daemon to spawn after all daemons were killed,
resulting in "bd daemon shutdown incomplete: 1 still running" error.
Replaced all `bd daemon killall` calls with pkill in:
- stopBdDaemons()
- restartBdDaemons()
Changed CountBdDaemons() to use pgrep instead of bd daemon list.
Also removed the now-unused parseBdDaemonCount helper function and its tests.
The beads.go run() function uses --no-daemon for faster read operations,
but this fails when the database is out of sync with JSONL (e.g., after
the daemon is killed during shutdown before it can sync).
Adding --allow-stale prevents these failures and makes witness/refinery
startup more reliable after gt down --all.
bd delete --hard --force creates tombstones instead of truly deleting,
which blocks agent bead recreation when polecats are respawned with the
same name. The tombstone is invisible to bd show/reopen but still
triggers UNIQUE constraint on create.
Workaround: Use CloseAndClearAgentBead instead of DeleteAgentBead when
cleaning up agent beads. Closed beads can be reopened by
CreateOrReopenAgentBead.
Changes:
- Add CloseAndClearAgentBead() for soft-delete that allows reopen
- Clears mutable fields (hook_bead, active_mr, cleanup_status, agent_state)
in description before closing to emulate delete --force --hard
- Update RemoveWithOptions to use close instead of delete
- Update RepairWorktreeWithOptions similarly
- Add comprehensive tests documenting the bd bug and verifying the workaround
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
MR beads were being created as regular beads, showing up in `bd ready`
when they should be ephemeral wisps that get cleaned up after merge.
Added Ephemeral field to CreateOptions and set it when creating MR beads.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change EscalationConfig to use Routes map with action strings
- Rename severity "normal" to "medium" per design doc
- Move config from config/ to settings/escalation.json
- Add --source flag for escalation source tracking
- Add Source field to EscalationFields
- Add executeExternalActions() for email/sms/slack with warnings
- Add default escalation config creation in gt install
- Add comprehensive unit tests for config loading
- Update help text with correct severity levels and paths
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Role beads (hq-*-role) are templates that define role characteristics.
They are created during gt install but creation may fail silently.
Without role beads, agents fall back to defaults.
Changes:
- Add beads.AllRoleBeadDefs() as single source of truth for role bead definitions
- Update gt install to use shared definitions
- Add doctor check that detects missing role beads (warning, not error)
- Doctor --fix creates missing role beads
Fixes#371
Co-authored-by: julianknutsen <julianknutsen@users.noreply.github>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add severity-based routing for escalations with config-driven targets.
Changes:
- EscalationConfig type with severity routes and external channels
- beads/beads_escalation.go: Escalation bead operations (create/ack/close/list)
- Refactored gt escalate command with subcommands:
- list: Show open escalations
- ack: Acknowledge an escalation
- close: Resolve with reason
- stale: Find unacknowledged escalations past threshold
- show: Display escalation details
- Added TypeEscalationAcked and TypeEscalationClosed event types
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When bd --no-daemon show <id> does not find an issue, it incorrectly exits
with code 0 (success) but writes the error to stderr and leaves stdout empty.
This causes JSON parse failures throughout gt when code tries to unmarshal
the empty stdout.
This PR handles the bug defensively in all affected code paths:
- beads.go run(): Detect empty stdout + non-empty stderr as error
- beads.go wrapError(): Add 'no issue found' to ErrNotFound patterns
- sling.go: Check len(out) == 0 in multiple functions
- convoy.go getIssueDetails(): Check stdout.Len() == 0
- prime_molecule.go: Check stdout.Len() == 0
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix beads.run() to always explicitly set BEADS_DIR based on the working
directory or explicit override
- This prevents inherited environment variables (e.g., from mayor session
with BEADS_DIR=/home/erik/gt/.beads) from causing prefix mismatch errors
when creating agent beads for rigs
- Update polecat manager to use NewWithBeadsDir for explicitness
- Add comprehensive test coverage for BEADS_DIR routing and validation
- Add SessionLister interface for deterministic orphan session testing
Root cause: When BEADS_DIR was set in the parent environment, all bd
commands used the town database (hq- prefix) instead of the rig database
(gt- prefix), causing "prefix mismatch: database uses 'hq' but you
specified 'gt'" errors during polecat spawn.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a polecat is nuked and re-spawned with the same name, CreateAgentBead
fails with a UNIQUE constraint error because the old agent bead exists as
a tombstone.
This adds CreateOrReopenAgentBead that:
1. First tries to create the agent bead normally
2. If UNIQUE constraint fails, reopens the existing bead and updates fields
Updated both spawn paths in polecat manager to use the new function.
Fixes#332
Co-authored-by: Claude <noreply@anthropic.com>
* fix(down): add refinery shutdown to gt down
Refineries were not being stopped by gt down, causing them to continue
running after shutdown. This adds a refinery shutdown loop before
witnesses, fixing problem P3 from the v2.4 proposal.
Changes:
- Add Phase 1: Stop refineries (gt-<rig>-refinery sessions)
- Renumber existing phases (witnesses now Phase 2, etc.)
- Include refineries in halt event logging
* feat(beads): add StopAllBdProcesses for shutdown
Add functions to stop bd daemon and bd activity processes:
- StopAllBdProcesses(dryRun, force) - main entry point
- CountBdDaemons() - count running bd daemons
- CountBdActivityProcesses() - count running bd activity processes
- stopBdDaemons() - uses bd daemon killall
- stopBdActivityProcesses() - SIGTERM->wait->SIGKILL pattern
This solves problems P1 (bd daemon respawns sessions) and P2 (bd activity
causes instant wakeups) from the v2.4 proposal.
* feat(down): rename --all to --nuke, add new --all and --dry-run flags
BREAKING CHANGE: --all now stops bd processes instead of killing tmux server.
Use --nuke for the old --all behavior (killing the entire tmux server).
New flags:
- --all: Stop bd daemons/activity processes and verify shutdown
- --nuke: Kill entire tmux server (DESTRUCTIVE, with warning)
- --dry-run: Preview what would be stopped without taking action
This solves problem P4 (old --all was too destructive) from the v2.4 proposal.
The --nuke flag now requires GT_NUKE_ACKNOWLEDGED=1 environment variable
to suppress the warning about destroying all tmux sessions.
* feat(down): add shutdown lock to prevent concurrent runs
Add Phase 0 that acquires a file lock before shutdown to prevent race
conditions when multiple gt down commands are run concurrently.
- Uses gofrs/flock for cross-platform file locking
- Lock file stored at ~/gt/daemon/shutdown.lock
- 5 second timeout with 100ms retry interval
- Lock released via defer on successful acquisition
- Dry-run mode skips lock acquisition
This solves problem P6 (concurrent shutdown race) from the v2.4 proposal.
* feat(down): add verification phase for respawn detection
Add Phase 5 that verifies shutdown was complete after stopping all services:
- Waits 500ms for processes to fully terminate
- Checks for respawned bd daemons
- Checks for respawned bd activity processes
- Checks for remaining gt-*/hq-* tmux sessions
- Checks if daemon PID is still running
If anything respawned, warns user and suggests checking systemd/launchd.
This solves problem P5 (no verification) from the v2.4 proposal.
* test(down): add unit tests for shutdown functionality
Add tests for:
- parseBdDaemonCount() - array, object with count, object with daemons, empty, invalid
- CountBdActivityProcesses() - integration test
- CountBdDaemons() - integration test (skipped if bd not installed)
- StopAllBdProcesses() - dry-run mode test
- isProcessRunning() - current process, invalid PID, max PID
These tests cover the core parsing and process detection logic added
in the v2.4 shutdown enhancement.
* fix(review): add tmux check and pkill fallback for bd shutdown
Address review gaps against proposal v2.4 AC:
- AC1: Add tmux availability check BEFORE acquiring shutdown lock
- AC2: Add pkill fallback for bd daemon when killall incomplete
- AC2: Return remaining count from stop functions for error reporting
- Style: interface{} → any (Go 1.18+)
* fix(prime): add validation for --state flag combination
The --state flag should be standalone and not combined with other flags.
Add validation at start of runPrime to enforce this.
Fixes TestPrimeFlagCombinations test failures.
* fix(review): address bot review critical issues
- isProcessRunning: handle pid<=0 as invalid (return false)
- isProcessRunning: handle EPERM as process exists (return true)
- stopBdDaemons: prevent negative killed count from race conditions
- stopBdActivityProcesses: prevent negative killed count from race conditions
* fix(review): critical fixes from deep review
Platform fixes:
- CountBdActivityProcesses: use sh -c "pgrep | wc -l" for macOS compatibility
(pgrep -c flag not available on BSD/macOS)
Correctness fixes:
- stopSession: return (wasRunning, error) to distinguish "stopped" vs "not running"
- daemon.IsRunning: handle error instead of ignoring with blank identifier
- stopBdDaemons/stopBdActivityProcesses: guard against negative killed counts
Safety fixes:
- --nuke: require GT_NUKE_ACKNOWLEDGED=1, don't just warn and proceed
- pkill patterns: document limitation about broad matching
Code cleanup:
- EnsureBdDaemonHealth: remove unused issues variable
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
CreateAgentBead was creating beads with only --labels=gt:agent but
bd create defaults to --type=task. The bd slot set command requires
type=agent to set slots, causing warnings during gt install and
gt rig add.
Fixes#315
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
detectSessionState() and checkSlungWork() both contained identical
logic for finding hooked/in_progress beads assigned to an agent.
Extracted this into findHookedBead() helper function.
Also includes priming subsystem improvements from mayor:
- Add --dry-run flag for testing without side effects
- Add --state flag to output detected state only
- Add --explain flag to show why sections are included
- Add missing filepath import to beads.go
Fixes: bd-hvwnb
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 1 of dynamic priming subsystem:
1. PRIME.md provisioning for all workers (hq-5z76w, hq-ukjrr Part A)
- Added ProvisionPrimeMD to beads package with Gas Town context template
- Provision at rig level in AddRig() so all workers inherit it
- Added fallback provisioning in crew and polecat managers
- Created PRIME.md for existing rigs
2. Post-handoff detection to prevent handoff loop bug (hq-ukjrr Part B)
- Added FileHandoffMarker constant (.runtime/handoff_to_successor)
- gt handoff writes marker before respawn
- gt prime detects marker and outputs "HANDOFF COMPLETE" warning
- Marker cleared after detection to prevent duplicate warnings
3. Priming health checks for gt doctor (hq-5scnt)
- New priming_check.go validates priming subsystem configuration
- Checks: SessionStart hook, gt prime command, PRIME.md presence
- Warns if CLAUDE.md is too large (should be bootstrap pointer)
- Fixable: provisions missing PRIME.md files
This ensures crew workers get Gas Town context (GUPP, hooks, propulsion)
even if the gt prime hook fails, via bd prime fallback.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
hq-u0ach: done.go - Add --cleanup-status flag so agents can pass cleanup
status directly. Removes computeCleanupStatus() which violated ZFC by
having Go compute cleanup status from git state.
hq-z0zqw: beads.go - Remove strings.Contains parsing for ErrNotARepo and
ErrSyncConflict. Per ZFC, Go should transport errors to agents, not parse
them to make decisions. IsBeadsRepo() now uses file existence check.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Two fixes in this commit:
1. daemon/lifecycle.go: Fix agent bead ID pattern for GUPP/orphaned work checks
- Wrong: gt-polecat-<rig>-<name> (e.g., gt-polecat-gastown-nux)
- Correct: <prefix>-<rig>-polecat-<name> (e.g., gt-gastown-polecat-nux)
- Use config.GetRigPrefix() instead of hardcoding gt prefix
- Use beads.ParseAgentBeadID() in extractRigFromAgentID
2. beads/beads.go: Fix invalid --add-label flag in bd create calls
- bd create uses --labels, not --add-label
- bd update uses --add-label (unchanged, was correct)
- Fixed Create, CreateWithID, CreateAgentBead, CreateRigBead
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Per ZFC principle: 'Let agents decide thresholds. Stuck is a judgment call.'
Changes:
- Add health check threshold fields to RoleConfig (ping_timeout,
consecutive_failures, kill_cooldown, stuck_threshold)
- Add LoadStuckConfig() to read thresholds from hq-deacon-role bead
- Update patrol_check.go to use configurable stuck threshold
- Defaults remain as fallbacks when no role bead config exists
Agents can now configure their stuck detection by adding fields to their
role bead, e.g.:
ping_timeout: 45s
consecutive_failures: 5
kill_cooldown: 10m
stuck_threshold: 2h
Fixes: hq-2355b
- Use ResolveBeadsDir() to find beads.db in multi-worktree setups
where .beads/redirect points to the canonical beads location
- Add --allow-stale flag to bd sync command to handle cases where
the daemon is actively writing and staleness check would fail
Fixes hq-0cgd3
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds support for alternative AI runtime backends (Codex, OpenCode) alongside
the default Claude backend through a runtime abstraction layer.
- internal/runtime/runtime.go - Runtime-agnostic helper functions
- Extended RuntimeConfig with provider-specific settings
- internal/opencode/ for OpenCode plugin support
- Updated session managers to use runtime abstraction
- Removed unused ensureXxxSession functions
- Fixed daemon.go indentation, updated terminology to runtime
Backward compatible: Claude remains default runtime.
Co-Authored-By: Ben Kraus <ben@cinematicsoftware.com>
Co-Authored-By: Cameron Palmer <cameronmpalmer@users.noreply.github.com>
When rig/.beads doesn't exist, fall back to mayor/rig/.beads (tracked
beads architecture) with a warning suggesting 'bd doctor' to fix.
This restores behavior that was inadvertently removed in #290, which
simplified SetupRedirect but removed the fallback path.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add custom types config after bd init in daemon tests
- Replace fixed sleeps with poll-based waiting in tmux tests
- Skip beads integration test for JSONL-only repos
Fixes flaky test failures in parallel execution.
The SetupRedirect function was failing for rigs that use the tracked
beads architecture where the canonical beads location is mayor/rig/.beads
and there is no rig-level .beads directory.
This fix now checks for both locations:
1. rig/.beads (with optional redirect to mayor/rig/.beads)
2. mayor/rig/.beads directly (if no rig/.beads exists)
This ensures crew and polecat workspaces get the correct redirect file
pointing to the shared beads database in all configurations.
Closes: gt-jy77g
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add Cursor Agent as compatible agent for Gas Town
Add AgentCursor preset with ProcessNames field for multi-agent detection:
- AgentCursor preset: cursor-agent -p -f (headless + force mode)
- ProcessNames field on AgentPresetInfo for agent detection
- IsAgentRunning(session, processNames) in tmux package
- GetProcessNames(agentName) helper function
Closes: ga-vwr
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: centralize agent preset list in config.go
Replace hardcoded ["claude", "gemini", "codex"] arrays with calls to
config.ListAgentPresets() to dynamically include all registered agents.
This fixes cursor agent not appearing in `gt config agent list` and
ensures new agent presets are automatically included everywhere.
Also updated doc comments to include "cursor" in example lists.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* test: add comprehensive agent client tests
Add tests for agent detection and command generation:
- TestIsAgentRunning: validates process name detection for all agents
(claude/node, gemini, codex, cursor-agent)
- TestIsAgentRunning_NonexistentSession: edge case handling
- TestIsClaudeRunning: backwards compatibility wrapper
- TestListAgentPresetsMatchesConstants: ensures ListAgentPresets()
returns all AgentPreset constants
- TestAgentCommandGeneration: validates full command line generation
for all supported agents
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add Auggie agent, fix Cursor interactive mode
Add Auggie CLI as supported agent:
- Command: auggie
- Args: --allow-indexing
- Supports session resume via --resume flag
Fix Cursor agent configuration:
- Remove -p flag (requires prompt, breaks interactive mode)
- Clear SessionIDEnv (cursor uses --resume with chatId directly)
- Keep -f flag for force/YOLO mode
Updated all test cases for both agents.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(agents): add Sourcegraph AMP as agent preset
Add AgentAmp constant and builtinPresets entry for Sourcegraph AMP CLI.
Configuration:
- Command: amp
- Args: --dangerously-allow-all --no-ide
- ResumeStyle: subcommand (amp threads continue <threadId>)
- ProcessNames: amp
Closes: ga-guq
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: lint error in cleanBeadsRuntimeFiles
Change function to not return error (was always nil).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: beads v0.46.0 compatibility and test fixes
- Add custom types config (agent,role,rig,convoy,event) after bd init calls
- Fix tmux_test.go to use variadic IsAgentRunning signature
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs: update agent documentation for new presets
- README.md: Update agent examples to show cursor/auggie, add built-in presets list
- docs/reference.md: Add cursor, auggie, amp to built-in agents list
- CHANGELOG.md: Add entry for new agent presets under [Unreleased]
Addresses PR #247 review feedback.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Previously, SetupRedirect used os.RemoveAll() which deleted all files
in .beads/ including tracked files like formulas/, README.md, config.yaml.
Now cleanBeadsRuntimeFiles() selectively removes only gitignored runtime
files (*.db, daemon.*, issues.jsonl, etc.) while preserving tracked content.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The agent_state field was recording observable state like "running",
"dead", "idle" which violated the "Discover, Don't Track" principle.
This caused stale state bugs where agents were marked "dead" in beads
but actually running in tmux.
Changes:
- Remove daemon's checkStaleAgents() which marked agents "dead"
- Simplify ensureXxxRunning() to use tmux.IsClaudeRunning() directly
- Remove reportAgentState() calls from gt prime and gt handoff
- Add SetHookBead/ClearHookBead helpers that don't update agent_state
- Use ClearHookBead in gt done and gt unsling
- Simplify gt status to derive state from tmux, not bead
Non-observable states (stuck, awaiting-gate, muted, paused) are still
set because they represent intentional agent decisions that can't be
discovered from tmux state.
Fixes: gt-zecmc
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
gt sling failed when hooking rig-level beads from town root because
bd update doesn't support cross-database routing like bd show does.
The fix adds a ResolveHookDir helper that:
1. Extracts the prefix from bead ID (e.g., "ap-xxx" → "ap-")
2. Looks up the rig path from routes.jsonl
3. Falls back to townRoot if prefix not found
Also removes the BEADS_DIR environment override which was preventing
routing from working correctly.
Fixes#148
* feat: Beads redirect architecture for tracked and local beads
This change implements proper redirect handling so that all rig agents
(Witness, Refinery, Crew, Polecats) can work with both:
- Tracked beads: .beads/ checked into git at mayor/rig/.beads
- Local beads: .beads/ created at rig root during gt rig add
Key changes:
1. SetupRedirect now handles tracked beads by skipping redirect chains.
The bd CLI doesn't support chains (A→B→C), so worktrees redirect
directly to the final destination (mayor/rig/.beads for tracked).
2. ResolveBeadsDir is now used consistently in polecat and refinery
managers instead of hardcoded mayor/rig paths.
3. Rig-level agents (witness, refinery) now use rig beads with rig
prefix instead of town beads. This follows the architecture where
town beads are only for Mayor/Deacon.
4. prime.go simplified to always use ../../.beads for crew redirects,
letting rig-level redirect handle tracked vs local routing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(doctor): Add beads-redirect check for tracked beads
When a repo has .beads/ tracked in git (at mayor/rig/.beads), the rig root
needs a redirect file pointing to that location. This check:
- Detects missing rig-level redirect for tracked beads
- Verifies redirect points to correct location (mayor/rig/.beads)
- Auto-fixes with 'gt doctor --fix'
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: Handle fileLock.Unlock error in daemon
Wrap fileLock.Unlock() return value to satisfy errcheck linter.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add AppendRouteToDir helper and use it to add hq-* route during rig
initialization. This allows rig beads to resolve role beads and other
hq-* prefixed beads stored in town beads.
Uses safe append pattern (load, merge, write) instead of overwriting
to avoid clobbering future rig routes.
Supersedes PR #184 with proper implementation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Town-level services (Mayor, Deacon) now use hq- prefix instead of gt-:
- hq-mayor (was gt-mayor)
- hq-deacon (was gt-deacon)
This distinguishes town-level sessions from rig-level sessions which
continue to use gt- prefix (gt-gastown-witness, gt-gastown-crew-max, etc).
Changes:
- session.MayorSessionName() returns "hq-mayor"
- session.DeaconSessionName() returns "hq-deacon"
- ParseSessionName() handles both hq- and gt- prefixes
- categorizeSession() handles both prefixes
- categorizeSessions() accepts both prefixes
- Updated all tests and documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The TestIntegration test was flaky because it uses the real .beads directory
and the SQLite database could be out of sync with the JSONL file (e.g., after
git pull updates the JSONL but before the database is re-imported).
The fix runs `bd sync --import-only` at the start of the test to ensure
the database is synchronized before running the actual test operations.
Fixes gt-5ww96
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sync with mayor/rig fix: Set hook slot in CreateAgentBead and pass
beadID to UpdateAgentState.
Fixes: mi-619
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Migrate all role bead references from gt-*-role to hq-*-role using
beads.RoleBeadIDTown() function. Role beads are stored in town beads
(~/gt/.beads/) with the hq- prefix.
Changes:
- internal/cmd/prime.go: Use RoleBeadIDTown() for all roles
- internal/doctor/agent_beads_check.go: Use RoleBeadIDTown() for rig agents
- internal/polecat/manager.go: Use RoleBeadIDTown("polecat")
- internal/cmd/crew_add.go: Use RoleBeadIDTown("crew")
- internal/beads/beads.go: Update comments to document hq- convention
- Templates: Update bd show gt-deacon to bd show hq-deacon
Note: Tmux session names remain as gt-* (runtime identifiers).
Bead IDs use hq-* for town-level agents (persistent storage).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>