Skip to main content

Polecat Lifecycle

Understanding the three-layer architecture of polecat workers

Overview

Polecats have three distinct lifecycle layers that operate independently. The key design principle: clean completion retires the live polecat session. The agent identity and merge evidence persist, but completed sessions do not return to the idle reuse pool.

Operating States

Polecats use these primary operating states:

StateDescriptionHow it happens
WorkingActively doing assigned workNormal operation after gt sling
IdleAvailable before assignmentSpawned or explicitly prepared for work
DoneWork completed and session retiredAfter gt done completes successfully
StalledSession stopped mid-workInterrupted, crashed, or timed out without being nudged
ZombieCompleted work but failed to exitgt done failed during cleanup

State cycle (happy path):

         ┌──────────┐
│ IDLE │──── gt sling
└────┬─────┘
v
┌──────────┐
│ WORKING │<──── session active, hook set
└────┬─────┘
│ gt done
v
┌──────────┐
│ DONE │──── branch/MR evidence preserved, session exits
└──────────┘

No idle reuse in the happy path. Polecats move: IDLE -> WORKING -> DONE.

Key distinctions:

  • Working = actively executing. Session alive, hook set, doing work.
  • Idle = not yet assigned and safe to use.
  • Done = work done, session killed, waiting for cleanup/refinery outcome.
  • Stalled = supposed to be working, but stopped. Needs Witness intervention.
  • Zombie = finished work, tried to exit, but cleanup failed. Stuck in limbo.

The Retired Completion Model

Polecat identity persists after completing work, but the live session does not. When a polecat finishes its assignment:

  1. Signals completion via gt done
  2. Pushes branch, submits MR to merge queue
  3. Clears its hook (work is done)
  4. Sets agent state to "done"
  5. Kills its own session using PID-excluding cleanup
  6. Leaves branch/MR metadata for Witness/refinery cleanup

The next gt sling allocates available capacity without reusing a completed session that still has branch/MR or cleanup state attached.

Why Retire Sessions?

  • Preserved identity — The polecat's agent bead, CV chain, and work history persist
  • Simpler lifecycle — Clean completion has one terminal session path
  • Done means retired — Session dies, cleanup/refinery owns remaining state

What About Pending Merges?

The Refinery owns the merge queue. Once gt done submits work:

  • The branch is pushed to origin
  • Work exists in the MQ, not in the polecat
  • If rebase fails, Refinery creates a conflict-resolution task
  • The completed polecat is not reused while pending MR or cleanup state remains

The Three Layers

The Problem: Three Concepts Were Conflated

Early designs treated polecats as monolithic. This caused recurring issues:

ConceptLifecycleOld behavior
IdentityLong-lived (name, CV, ledger)Destroyed on nuke
SandboxPer-assignment (worktree, branch)Destroyed on nuke
SessionEphemeral (Claude context window)= polecat lifetime

Separating these three layers keeps completed sessions out of the idle reuse pool, preserves capability records (CV, completion history), and lets cleanup/refinery own branch and worktree state after handoff.

Layer Summary

LayerComponentLifecyclePersistence
IdentityAgent bead, CV chain, work historyPermanentNever dies
SandboxGit worktree, branchPer active assignment/cleanup windowCreated for work, retired after cleanup
SessionClaude (tmux pane), context windowEphemeral per stepCycles per step/handoff

Identity Layer

The polecat's identity is permanent. It includes:

  • Agent bead (created once, never deleted)
  • CV chain (work history accumulates across all assignments)
  • Mailbox and attribution record

Identity survives all session cycles and sandbox resets. In the HOP model, this IS the polecat — everything else is infrastructure that comes and goes. See Polecat Identity below for details.

Session Layer

The Claude session is ephemeral. It cycles frequently:

  • After each molecule step (via gt handoff)
  • On context compaction
  • On crash/timeout
  • After extended work periods

Key insight: Session cycling is normal operation, not failure. The polecat continues working—only the Claude context refreshes.

Session 1: Steps 1-2 → handoff
Session 2: Steps 3-4 → handoff
Session 3: Step 5 → gt done

All three sessions are the same polecat. The sandbox persists throughout.

Sandbox Layer

The sandbox is the git worktree—the polecat's working directory:

~/gt/gastown/polecats/Toast/

This worktree:

  • Exists while the polecat is active or awaiting cleanup
  • Survives handoff/session cycles during an assignment
  • Is not synced to main or branch-deleted by gt done
  • Contains uncommitted work, staged changes, branch state during active work

Witness/refinery cleanup owns sandbox retirement after durable handoff. Explicit gt polecat nuke remains the manual destructive path.

Branch Preservation (After Completion)

When work completes, gt done leaves the feature branch and MR metadata intact:

# Handled by gt done
git push origin polecat/<name>/<issue>@<suffix>
# Branch and metadata remain available for refinery/review/cleanup

When new work is slung:

# Create fresh branch from current main
git checkout -b polecat/<name>/<new-issue>+<timestamp>
# Start working

Completed sandboxes are not treated as reusable idle worktrees while branch, MR, or cleanup state remains attached.

Slot Layer

The slot is the name allocation from the polecat pool:

# Pool: [Toast, Shadow, Copper, Ash, Storm...]
# Toast is allocated to work gt-abc

The slot:

  • Determines the sandbox path (polecats/Toast/)
  • Maps to a tmux session (gt-gastown-Toast)
  • Appears in attribution (gastown/polecats/Toast)
  • Persists until explicit nuke

Correct Lifecycle

┌─────────────────────────────────────────────────────────────┐
│ gt sling │
│ → Find idle polecat OR allocate slot from pool (Toast) │
│ → Create/repair sandbox (worktree on new branch) │
│ → Start session (Claude in tmux) │
│ → Hook molecule to polecat │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│ Work Happens │
│ │
│ Session cycles happen here: │
│ - gt handoff between steps │
│ - Compaction triggers respawn │
│ - Crash → Witness respawns │
│ │
│ Sandbox persists through ALL session cycles │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│ gt done (retired model) │
│ → Push branch to origin │
│ → Submit work to merge queue (MR bead) │
│ → Set agent state to "done" │
│ → Kill session │
│ │
│ Work now lives in MQ. Polecat session is retired. │
│ Branch/MR metadata remains for refinery and cleanup. │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│ Refinery: merge queue │
│ → Rebase and merge to target branch │
│ (main or integration branch — see below) │
│ → Close the issue │
│ → If conflict: create task for available polecat │
│ │
│ Integration branch path: │
│ → MRs from epic children merge to integration/<epic> │
│ → When all children closed: land to main as one commit │
└─────────────────────────────────────────────────────────────┘

What "Recycle" Means

Session cycling: Normal. Claude restarts, sandbox stays, slot stays.

gt handoff  # Session cycles, polecat continues

Sandbox setup: For active work. gt sling prepares a fresh branch for the assignment.

gt sling gt-xyz gastown  # Allocates capacity and prepares branch

Session cycling happens constantly. Sandbox setup/cleanup is tied to assignments.

Anti-Patterns

Manual State Transitions

Anti-pattern:

gt polecat done Toast    # DON'T: external state manipulation
gt polecat reset Toast # DON'T: manual lifecycle control

Correct:

# Polecat signals its own completion:
gt done # (from inside the polecat session)

# Only explicit nuke destroys polecats:
gt polecat nuke Toast # (destroys sandbox, identity persists)

Polecats manage their own session lifecycle. External manipulation bypasses verification.

Sandboxes Without Work (Idle vs Done vs Stalled)

An idle polecat has no hook, no session, and no completion/MR cleanup state — this is available capacity.

A done polecat has completed work and exited, but branch/MR or cleanup state may still be attached. It is not reusable until cleanup resolves that state.

A stalled polecat has a hook but no session — this is a failure:

  • The session crashed and wasn't nudged back to life
  • The hook was lost during a crash
  • State corruption occurred

Recovery for stalled:

# Witness respawns the session in the existing sandbox
# Or, if unrecoverable:
gt polecat nuke Toast # Clean up the stalled polecat
gt sling gt-abc gastown # Respawn with fresh polecat

Confusing Session with Sandbox

Anti-pattern: Thinking session restart = losing work.

# Session ends (handoff, crash, compaction)
# Work is NOT lost because:
# - Git commits persist in sandbox
# - Staged changes persist in sandbox
# - Molecule state persists in beads
# - Hook persists across sessions

The new session picks up where the old one left off via gt prime.

Session Lifecycle Details

Sessions cycle for these reasons:

TriggerActionResult
gt handoffVoluntaryClean cycle to fresh context
Context compactionAutomaticForced by Claude Code
Crash/timeoutFailureWitness respawns
gt doneCompletionSession exits, polecat goes done

All except gt done result in continued work. Only gt done signals completion and retires the completed polecat session.

Witness Responsibilities

The Witness monitors polecats but does NOT:

  • Force session cycles (polecats self-manage via handoff)
  • Interrupt mid-step (unless truly stuck)
  • Reuse polecats after completion while cleanup/MR state remains

The Witness DOES:

  • Detect and nudge stalled polecats (sessions that stopped unexpectedly)
  • Clean up zombie polecats (sessions where gt done failed)
  • Respawn crashed sessions
  • Handle escalations from stuck polecats (polecats that explicitly asked for help)

Polecat Identity

Key insight: Polecat identity is permanent; sessions are ephemeral, sandboxes are persistent.

In the HOP model, every entity has a chain (CV) that tracks:

  • What work they've done
  • Success/failure rates
  • Skills demonstrated
  • Quality metrics

The polecat name (Toast, Shadow, etc.) is a slot from a pool — persistent until explicit nuke. The agent identity that executes as that polecat accumulates a work history across all assignments.

POLECAT IDENTITY (permanent)      SESSION (ephemeral)     SANDBOX (assignment-scoped)
├── CV chain ├── Claude instance ├── Git worktree
├── Work history ├── Context window ├── Branch
├── Skills demonstrated └── Dies on handoff └── Retired after cleanup
└── Credit for work or gt done by gt sling

This distinction matters for:

  • Attribution - Who gets credit for the work?
  • Skill routing - Which agent is best for this task?
  • Cost accounting - Who pays for inference?
  • Federation - Agents having their own chains in a distributed world

Implementation Status

As of 2026-03-07 (gt-o8g8 audit), all core lifecycle operations are shipped and running in production. See design/polecat-lifecycle-patrol.md § 10 for the full implementation matrix and design/persistent-polecat-pool.md for phase-by-phase shipping status.

Key files:

  • internal/cmd/done.go — work submission, done-state handoff, session retirement
  • internal/cmd/sling.go + polecat_spawn.go — capacity allocation, branch setup
  • internal/cmd/handoff.go — session cycling for all roles
  • internal/witness/handlers.go — cleanup pipeline, POLECAT_DONE routing, zombie/orphan detection
  • internal/polecat/manager.go — stale detection, done-state projection, pool management