Updated comment to use "orphaned polecats" instead of "idle polecats".
With the self-cleaning model, polecats self-nuke on completion.
An orphan is from a crash, not a normal idle state.
Closes: gt-7l8y1
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The witness manager was using rig-level beads path to look up role
configuration, but role beads use the hq- prefix and live in town-level
beads. This caused "unexpected end of JSON input" errors when starting
witnesses because the rig database (with gt- prefix) couldn't find
hq-witness-role.
Changed roleConfig() to use townRoot instead of rig.BeadsPath() to
correctly resolve town-level role beads.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Replace ProcessExists() checks in witness and refinery managers with
tmux session detection. Agent liveness should be derived from tmux
session state, not PID probing (per ZFC tracking principles).
- Remove util.ProcessExists() from witness/manager.go and refinery/manager.go
- Delete internal/util/process.go and process_test.go (now unused)
- Foreground mode and Stop() now rely solely on tmux HasSession/KillSession
Closes: hq-yxkdr (recentDeaths already removed)
Closes: hq-1sd4o (ProcessExists removed)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extends the --agent flag with a more general --env flag that allows
setting arbitrary environment variables when starting a witness.
Precedence (highest to lowest):
1. CLI --env overrides
2. Role bead env_vars
3. config.AgentEnv() defaults
Examples:
gt witness start greenplace --env ANTHROPIC_MODEL=claude-3-haiku
gt witness restart greenplace --env DEBUG=1 --env VERBOSE=true
Co-authored-by: joshuavial <git@codewithjv.com>
Create centralized AgentEnv function as single source of truth for all
agent environment variables. All agents now consistently receive:
- GT_ROLE, BD_ACTOR, GIT_AUTHOR_NAME (role identity)
- GT_ROOT, BEADS_DIR (workspace paths)
- GT_RIG, GT_POLECAT/GT_CREW (rig-specific identity)
- BEADS_AGENT_NAME, BEADS_NO_DAEMON (beads config)
- CLAUDE_CONFIG_DIR (optional account selection)
Remove RoleEnvVars in favor of AgentEnvSimple wrapper.
Remove IncludeBeadsEnv flag - beads env vars always included.
Update all manager and cmd call sites to use AgentEnv.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Consolidates all role startup code to use the shared RoleEnvVars()
function, ensuring consistent env vars across tmux SetEnvironment
and Claude startup command exports.
Updated:
- Mayor manager
- Deacon startup (daemon.go)
- Witness manager
- Refinery manager
- Polecat startup (daemon.go)
- BuildPolecatStartupCommand, BuildCrewStartupCommand helpers
This ensures all agents receive the same identity env vars regardless
of startup path.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Agent sessions would fail on startup because send-keys arrived before the
shell was ready, causing 'bad pattern' and 'command not found' errors.
Fix: Create sessions with the command directly using tmux new-session's
command argument. This runs the agent as the pane's initial process,
avoiding shell readiness timing issues entirely.
Updated all agent managers: mayor, deacon, witness, refinery, polecat, crew.
Also fixes pre-existing build error in polecat/manager.go (polecatPath →
clonePath/newClonePath).
Closes#280
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changes polecat worktree structure from:
polecats/<name>/
to:
polecats/<name>/<rigname>/
This gives Claude Code agents a recognizable directory name (e.g., tidepool/)
in their cwd instead of just the polecat name, preventing confusion about
which repo they are working in.
Key changes:
- Add clonePath() method to manager.go and session_manager.go for the actual
git worktree path, keeping polecatDir() for existence checks
- Update Add(), RepairWorktree(), Remove() to use new structure
- Update daemon lifecycle and restart code for new paths
- Update witness handlers to detect both structures
- Update doctor checks (rig_check, branch_check, config_check,
claude_settings_check) for backward compatibility
- All code includes fallback to old structure for existing polecats
Fixes#283
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add WaitForShellReady call before SendKeys in all agent managers
(deacon, mayor, witness, refinery). This prevents intermittent
"can't find pane" errors that occur when the tmux session is
created but the shell isn't ready to receive input yet.
The issue manifests under load (e.g., during `gt up` when multiple
agents start in sequence) where the 200ms delay in SendKeysDelayed
isn't sufficient for the pane to be fully initialized.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Witness was calling BuildAgentStartupCommand with empty rigPath,
causing it to fall back to town-level defaults instead of honoring
rig-specific agent settings (like RigSettings.Agent).
Now passes m.rig.Path so rig agent settings are honored, consistent
with how refinery already passes the rig path.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create mayor.Manager for mayor lifecycle (Start/Stop/IsRunning/Status)
- Create deacon.Manager for deacon lifecycle with respawn loop
- Move session.Manager to polecat.SessionManager (clearer naming)
- Add zombie session detection for mayor/deacon (kills tmux if Claude dead)
- Remove duplicate session startup code from up.go, start.go, mayor.go
- Rename sessMgr -> polecatMgr for consistency
- Make witness/refinery SessionName() public for status display
All agent types now follow the same Manager pattern:
mgr := agent.NewManager(...)
mgr.Start(...)
mgr.Stop()
mgr.IsRunning()
mgr.Status()
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Refactors all agent startup paths (witness, refinery, crew, polecat) to use
a consistent Manager interface with Start(), Stop(), IsRunning(), and
SessionName() methods.
Includes:
- Witness manager with GUPP propulsion nudge for startup
- Refinery manager for engineer sessions
- Crew manager for worker agents
- Session/polecat manager updates
- claude_settings_check doctor check for settings validation
- Settings management consolidated from rig/manager.go
- Settings location moved outside source repos to prevent conflicts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Resolved conflict in internal/witness/manager.go:
- Kept session import (used by PR code)
- Kept PR's more accurate comment for PID check
- Removed duplicate sessionName method introduced by merge
The witness manager's Stop() method was only updating runtime JSON state
without killing the tmux session, causing 'gt rig shutdown' to leave
witness sessions running.
Added sessionName() method and tmux kill-session logic to match the
refinery's existing implementation.
Fixes: bd-gxaf
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Witness handlers (HandlePolecatDone, HandleMerged, etc.) existed in Go
code but were never called - there was no CLI command to invoke them.
This caused polecats to remain in 'done' state after MR merge because
POLECAT_DONE messages were never processed.
Changes:
- Add `gt witness process <rig>` command to process Witness mail
- Fix --wisp flag to --ephemeral in cleanup wisp creation
- Command processes POLECAT_DONE, MERGED, HELP, SWARM_START messages
- Auto-nukes clean polecats, creates cleanup wisps for dirty ones
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 4 of local-only polecat branches: Handle conflict resolution edge case.
Problem: If polecat worktree is nuked before MR merges, the local branch
is gone and conflict resolution can't access it.
Solution: Witness now defers cleanup for polecats with pending MRs:
- HandlePolecatDone creates a cleanup wisp with "merge-requested" state
- Polecat worktree preserved until MERGED signal arrives
- HandleMerged then nukes the polecat (existing behavior)
Also updated mol-polecat-conflict-resolve.formula.toml:
- Removed fetch from origin (branches are local-only now)
- Added instructions to fetch from source polecat's worktree
- Added rig and source_polecat variables
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When the Refinery detects a build error or test failure and refuses
to merge, the polecat was never notified. This fixes the notification
pipeline by:
1. Adding MERGE_FAILED protocol support to Witness:
- PatternMergeFailed regex pattern
- ProtoMergeFailed protocol type constant
- MergeFailedPayload struct with all failure details
- ParseMergeFailed parser function
- ClassifyMessage case for MERGE_FAILED
2. Adding HandleMergeFailed handler to Witness:
- Parses the failure notification
- Sends HIGH priority mail to polecat with fix instructions
- Includes branch, issue, failure type, and error details
3. Adding mail notification in Refinery's handleFailureFromQueue:
- Creates mail.Router for sending protocol messages
- Sends MERGE_FAILED to Witness when merge fails
- Includes failure type (build/tests/conflict) and error
4. Adding comprehensive unit tests:
- TestParseMergeFailed for full body parsing
- TestParseMergeFailed_MinimalBody for minimal body
- TestParseMergeFailed_InvalidSubject for error handling
- ClassifyMessage test cases for MERGE_FAILED
Fixes#114🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Witness and Refinery startup was duplicated across cmd/witness.go, cmd/up.go,
cmd/rig.go, and daemon.go. Worse, not all code paths sent the propulsion nudge
(GUPP - Gas Town Universal Propulsion Principle). Now unified in Manager.Start()
which handles everything including nudges.
Changes:
- witness/manager.go: Full rewrite with session creation, env vars, theming,
WaitForClaudeReady, startup nudge, and propulsion nudge (GUPP)
- refinery/manager.go: Add propulsion nudge sequence after Claude startup
- cmd/witness.go: Simplify to just call mgr.Start(), remove ensureWitnessSession
- cmd/rig.go: Use witness.Manager.Start() instead of inline session creation
- cmd/start.go: Use witness.Manager.Start()
- cmd/up.go: Use witness.Manager.Start(), remove ensureWitness(),
add EnsureSettingsForRole in ensureSession()
- daemon.go: Use witness.Manager.Start() and refinery.Manager.Start() for
unified startup with proper nudges
This ensures all agent startup paths (gt witness start, gt rig boot, gt up,
daemon restarts) consistently apply GUPP propulsion nudges.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create internal/agent package with shared State type and StateManager
- StateManager uses Go generics for type-safe load/save operations
- Update witness and refinery to use shared State type alias
- Replace loadState/saveState implementations with StateManager delegation
- Maintains backwards compatibility through re-exported constants
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Introduces a typed CleanupStatus with constants:
- CleanupClean, CleanupUncommitted, CleanupStash, CleanupUnpushed, CleanupUnknown
Adds helper methods:
- IsSafe(): true for clean status
- RequiresRecovery(): true for uncommitted/stash/unpushed
- CanForceRemove(): true if force flag can bypass
Updated files to use the new type:
- internal/polecat/types.go: Type definition and methods
- internal/polecat/manager.go: Validation logic
- internal/witness/handlers.go: Nuke safety checks
- internal/cmd/done.go: Status reporting
- internal/cmd/polecat.go: Recovery status checks
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create util.ExecWithOutput and util.ExecRun to consolidate repeated
exec.Command patterns across witness/handlers.go and refinery/manager.go.
Changes:
- Add internal/util/exec.go with ExecWithOutput (returns stdout) and
ExecRun (runs command without output)
- Refactor witness/handlers.go to use utility functions (7 call sites)
- Refactor refinery/manager.go, removing unused gitRun/gitOutput methods
- Add comprehensive tests in exec_test.go
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
In multi-remote setups, the code may live on a remote other than
"origin" (e.g., "gastown" for gastown.git). The verifyCommitOnMain
function now iterates through all configured remotes to find the
one containing the default branch with the merged commit.
Changes:
- Add git.Remotes() method to list all configured remote names
- Update verifyCommitOnMain to check all remotes/<defaultBranch>
instead of only origin/<defaultBranch>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add --branch flag to `gt rig add` to specify a custom default branch
instead of auto-detecting from remote. This supports repositories that
use non-standard default branches like `develop` or `release`.
Changes:
- Add --branch flag to `gt rig add` command
- Store default_branch in rig config.json
- Propagate default branch to refinery, witness, daemon, and all commands
- Rename ensureMainBranch to ensureDefaultBranch for clarity
- Add Rig.DefaultBranch() method for consistent access
- Update crew/manager.go and swarm/manager.go to use rig config
Based on PR #49 by @kustrun - rebased and extended with additional fixes.
Co-authored-by: kustrun <kustrun@users.noreply.github.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Witness lifecycle was not reliably killing polecat tmux sessions after
POLECAT_DONE. Sessions were piling up because gt polecat nuke may fail to
kill the session due to rig loading issues or race conditions with
IsRunning checks.
Fix: Kill the tmux session FIRST and unconditionally in NukePolecat,
before calling gt polecat nuke. This ensures the session is always killed
regardless of what happens in the downstream nuke command.
The session name pattern is deterministic (gt-<rig>-<polecat>), so we can
construct it directly from the rigName and polecatName parameters.
Fixes: gt-g9ft5
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Updates HandlePolecatDone to auto-nuke polecats immediately after MR submission
when cleanup_status=clean. This separates polecat lifecycle from MR lifecycle:
- Polecat lifecycle: spawning → working → mr_submitted → nuked
- MR lifecycle: created → queued → processed → merged (handled by Refinery)
Key changes:
- Try auto-nuke for ALL POLECAT_DONE messages regardless of MR status
- If cleanup_status=clean (branch pushed), nuke immediately
- If dirty state, create cleanup wisp for manual intervention
- Cleanup wisps are now exception handling, not the normal flow
Conflict resolution is handled by the Refinery, which creates NEW tasks
for NEW polecats when merge conflicts are detected.
(gt-si8rq.9)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add support for signaling phase completion when a polecat needs to wait
on a gate before continuing. The --phase-complete flag with --gate ID
allows polecats to hand off control while awaiting external conditions.
Changes:
- done.go: Add --phase-complete and --gate flags, PHASE_COMPLETE exit type
- protocol.go: Add Gate field to PolecatDonePayload
- handlers.go: Handle PHASE_COMPLETE by recycling session (keep worktree)
- beads.go: Add AddGateWaiter method for gate registration
This enables multi-phase molecule workflows with async coordination (bd-gxb4)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements automatic nuke of polecats after completion:
- HandlePolecatDone: Auto-nukes immediately for ESCALATED/DEFERRED exits
(no pending MR) when cleanup_status=clean
- HandleMerged: Auto-nukes after verifying commit is on main and
cleanup_status=clean
- HandleLifecycleShutdown: Auto-nukes immediately since shutdown means
no pending work
Safety checks preserved:
- Verifies cleanup_status from agent bead (clean/has_uncommitted/etc)
- Verifies commit is on main before nuking
- Falls back to cleanup wisp if any check fails
New functions:
- NukePolecat(): Executes gt polecat nuke
- AutoNukeIfClean(): Checks safety and nukes if safe
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The getCleanupStatus function in witness/handlers.go and crew removal
in cmd/crew_lifecycle.go were constructing agent bead IDs with hardcoded
"gt-" prefix. This failed for rigs that use a different prefix like "bd-".
Now uses beads.GetPrefixForRig to look up the correct prefix from
routes.jsonl, enabling support for the beads rig and any future rigs
with custom prefixes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add verifyCommitOnMain() check in HandleMerged to ensure the polecat's
commit is actually on main before allowing cleanup. This prevents work
loss when:
- MERGED signal is for a stale MR
- Merge attempt failed after signal was sent
- MR was already merged via different path
The verification uses git merge-base --is-ancestor to confirm the
polecat's HEAD is reachable from main.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add safety check to HandleMerged that verifies cleanup_status from the
polecat's agent bead before allowing nuke. This prevents work loss when:
- MERGED signal arrives for a stale MR (already merged via different path)
- Polecat has new unpushed work since the MR was created
- Race condition between merge and nuke
The Witness now blocks nuke and sets an error for escalation when:
- has_uncommitted: polecat has uncommitted changes
- has_stash: polecat has stashed work
- has_unpushed: polecat has unpushed commits (critical)
Clean status or unknown status (backward compat) allows nuke to proceed.
(gt-5q6jr)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add gt polecat check-recovery command to check cleanup_status from agent bead
- Update gt polecat nuke to block on polecats with unpushed work (use --force to override)
- Add EscalateRecoveryNeeded function for RECOVERY_NEEDED escalations
- Update Witness template with dormant polecat recovery protocol
Prevents accidental data loss when cleaning up dormant polecats that have
unpushed commits. The Witness should now use check-recovery before nuking
and escalate NEEDS_RECOVERY cases to the Mayor.
(gt-cloml)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add protocol message parsing and handlers for polecat→witness communication:
- POLECAT_DONE: Parse completion messages, create cleanup wisps
- HELP: Parse help requests, assess if Witness can help or escalate to Mayor
- MERGED: Parse refinery merge confirmations
- LIFECYCLE:Shutdown: Handle daemon-triggered shutdowns
- SWARM_START: Parse batch work initialization
Files added:
- internal/witness/protocol.go: Message classification and parsing
- internal/witness/handlers.go: Handler implementations with wisp/mail integration
- internal/witness/protocol_test.go: Unit tests for all parsing functions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove Stats fields from witness and refinery types that tracked
observable metrics (total counts, today counts). These are now
handled by the activity stream/beads system instead.
Removed:
- WitnessStats type and Stats field from Witness
- RefineryStats type and Stats field from Refinery
- LastCheckAt field from Witness
- Stats display from gt witness status
- Stats display from gt refinery status
- Stats increment code from refinery.completeMR()
Kept minimal process state:
- RigName, State, PID, StartedAt (both)
- MonitoredPolecats, Config, SpawnedIssues (witness)
- CurrentMR, PendingMRs, LastMergeAt (refinery)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move duplicated processExists function to shared util package:
- Create internal/util/process.go with ProcessExists function
- Add internal/util/process_test.go with basic tests
- Update witness/manager.go to use util.ProcessExists
- Update refinery/manager.go to use util.ProcessExists
- Remove local processExists functions from both files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Prevents data loss from concurrent/interrupted state file writes by using
atomic write pattern (write to .tmp, then rename).
Changes:
- Add internal/util package with AtomicWriteJSON/AtomicWriteFile helpers
- Update witness/manager.go saveState to use atomic writes
- Update refinery/manager.go saveState to use atomic writes
- Update crew/manager.go saveState to use atomic writes
- Update daemon/types.go SaveState to use atomic writes
- Update polecat/namepool.go Save to use atomic writes
- Add comprehensive tests for atomic write utilities
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
All 156 instances of _ = error suppression in non-test code now have
explanatory comments documenting why the error is intentionally ignored.
Categories of intentional suppressions:
- non-fatal: session works without these - tmux environment setup
- non-fatal: theming failure does not affect operation - visual styling
- best-effort cleanup - defer cleanup on failure paths
- best-effort notification - mail/notifications that should not block
- best-effort interrupt - graceful shutdown attempts
- crypto/rand.Read only fails on broken system - random ID generation
- output errors non-actionable - fmt.Fprint to io.Writer
This addresses the silent failure and debugging concerns raised in the
issue by making the intentionality explicit in the code.
Generated with Claude Code https://claude.com/claude-code
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove embedded molecule management from witness - this logic belongs
in molecule definitions (YAML + hooks), not Go code.
Removed:
- WitnessHandoffState, WorkerState types
- Handoff bead management (load/save/ensure)
- Patrol instance creation (ensurePatrolInstance)
- Polecat arm tracking (ensurePolecatArm, closePolecatArm)
- updateWorkerActivity function
Simplified:
- Nudge tracking now uses only SpawnedIssues (in-memory)
- run() no longer loads handoff state or creates patrol instances
- healthCheck() no longer manages tracking arms
Fixed:
- escalateToMayor: bd mail send → gt mail send
- ackMessage: bd mail ack → gt mail archive
The witness now does its core job (health checks, nudges, escalation,
cleanup) without trying to manage molecule state. Molecule tracking
should be handled by the molecule system itself via bd mol commands.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add arm closing to witness cleanup:
- Add closePolecatArm(name, reason) method that:
- Looks up arm ID in handoff state
- Closes the arm issue with the given reason
- Clears arm ID from handoff state
- Call closePolecatArm() at end of cleanupPolecat()
This completes the arm lifecycle: created when polecat discovered,
closed when polecat cleaned up. The Christmas Ornament pattern now
tracks the full polecat lifecycle.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add arm bonding to witness health check:
- Add ensurePolecatArm() method that:
- Checks if arm already exists for polecat (ArmID in WorkerState)
- If not, calls `gt mol bond mol-polecat-arm` with template vars
- Parses arm ID from output and stores in handoff state
- Call ensurePolecatArm() in healthCheck() for each running polecat
This creates the Christmas Ornament pattern where mol-witness-patrol
has dynamically bonded mol-polecat-arm children, one per active polecat.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add patrol instance tracking to witness manager:
- Add PatrolInstanceID to WitnessHandoffState for tracking
- Add ArmID to WorkerState for per-polecat arm tracking
- Add ensurePatrolInstance() method that:
- Checks if patrol instance already exists (from previous session)
- Creates new patrol instance if needed
- Persists instance ID in handoff state
This enables the molecule-based tracking ledger pattern where the
Go-based witness creates beads issues to track its patrol state.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add BranchPushedToRemote() to git package that properly handles
polecat branches without upstream tracking. Update verifyPolecatState
in witness to check that branches are pushed before allowing cleanup.
This prevents the scenario where polecats close issues without pushing
their work, causing all commits to be lost when the worktree is deleted.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>