feat(witness): Implement Witness MVP for automated polecat lifecycle

Implements the core Witness functionality:

- gt witness start: Creates tmux session with Claude, theming, auto-priming
- gt witness stop: Kills tmux session and updates state
- gt witness status: Shows session state reconciled with tmux
- Shutdown handler: Verifies git clean state before cleanup, sends nudges
- Auto-spawn: Spawns polecats for ready work up to configurable capacity
- Health checks: Monitors polecat activity, nudges stuck workers, escalates

Also updates handoff to include polecat name in lifecycle requests.

Closes: gt-53w6, gt-mxyj, gt-5wtw, gt-cpm2, gt-es1i

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-20 09:32:44 -08:00
parent c01e965d37
commit 6cfab58e86
4 changed files with 581 additions and 45 deletions

View File

@@ -321,6 +321,25 @@ Check gt mail inbox for messages received during transition.
return nil
}
// getPolecatName extracts the polecat name from the tmux session.
// Returns empty string if not a polecat session.
func getPolecatName() string {
out, err := exec.Command("tmux", "display-message", "-p", "#{session_name}").Output()
if err != nil {
return ""
}
sessionName := strings.TrimSpace(string(out))
// Polecat sessions: gt-<rig>-<name>
if strings.HasPrefix(sessionName, "gt-") {
parts := strings.SplitN(sessionName, "-", 3)
if len(parts) >= 3 {
return parts[2] // The polecat name
}
}
return ""
}
// sendLifecycleRequest sends the lifecycle request to our manager.
func sendLifecycleRequest(manager string, role Role, action HandoffAction, townRoot string) error {
if manager == "human" {
@@ -329,14 +348,21 @@ func sendLifecycleRequest(manager string, role Role, action HandoffAction, townR
return nil
}
// For polecats, include the specific name
polecatName := ""
if role == RolePolecat {
polecatName = getPolecatName()
}
subject := fmt.Sprintf("LIFECYCLE: %s requesting %s", role, action)
body := fmt.Sprintf(`Lifecycle request from %s.
Action: %s
Time: %s
Polecat: %s
Please verify state and execute lifecycle action.
`, role, action, time.Now().Format(time.RFC3339))
`, role, action, time.Now().Format(time.RFC3339), polecatName)
// Send via bd mail (syntax: bd mail send <recipient> -s <subject> -m <body>)
cmd := exec.Command("bd", "mail", "send", manager,