Skip to content
Rookery OS

RookeryOS — Agent Pod Lifecycle

From provisioning to teardown — the complete lifecycle of an agent pod

Lifecycle Overview

┌─────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
│  CREATE  │───►│ PROVISION │───►│ BOOTSTRAP│───►│  RUNNING  │───►│ TEARDOWN │
│  Request │    │ K8s Pod   │    │ chelper  │    │  Active   │    │ Delete   │
└─────────┘    └──────────┘    └──────────┘    └──────────┘    └──────────┘
                                    │                                │
                                    ▼                                ▼
                               ┌──────────┐                    ┌──────────┐
                               │  FAILED   │                    │ CLEANUP  │
                               │  Retry    │                    │ PVC, NS  │
                               └──────────┘                    └──────────┘

Phase 1: Create Request

The lifecycle begins when a tenant or admin requests a new agent.

Request Sources

SourceTrigger
Agent FactoryUser completes the agent creation wizard in Console
APIPOST /api/v1/agents with agent configuration
ProvisionerAutomatic re-provisioning after pod failure

Agent Configuration

interface AgentConfig {
  name: string;                    // Display name
  namespace: string;               // K8s namespace
  tier: 'starter' | 'pro' | 'business' | 'enterprise' | 'navigator';
  llm_model: string;              // e.g., 'zai/glm-4.5'
  soul: string;                   // SOUL.md content
  personality: PersonalityConfig;
  tools: ToolConfig[];
  connectors: ConnectorConfig[];
  enable_sidecar: boolean;        // Dual-container?
  enable_cookie_vault: boolean;
  enable_hitl: boolean;
  resources: ResourceConfig;
}

Tier Selection

TierPod TypeSidecarCookie VaultPVCMax Lifetime
StarterSingleNoNo5GiUnlimited
ProDualYesYes10GiUnlimited
BusinessDualYesYes20GiUnlimited
EnterpriseDualYesYes50GiUnlimited
NavigatorSingleNoNoNone24 hours

Phase 2: Provisioning

The Agent Provisioner creates the Kubernetes resources.

Provisioner Flow

API Request
  │
  ├── 1. Validate agent config
  │     Check required fields, tier limits, quotas
  │
  ├── 2. Generate namespace (production pods)
  │     Format: agent-blue-heron-{agent-id-prefix}
  │     Or use shared namespace (navigator)
  │
  ├── 3. Apply RBAC
  │     ServiceAccount, Role, RoleBinding
  │     Workload Identity binding (production only)
  │
  ├── 4. Apply NetworkPolicy
  │     Production: allow Platform API + internet
  │     Navigator: restricted egress, no cross-pod
  │
  ├── 5. Create PVC (production only)
  │     StorageClass: standard
  │     Size: based on tier
  │
  ├── 6. Generate pod manifest
  │     Template: agent-pod-v2.yaml (dual) or navigator-pod.yaml (single)
  │     Inject: env vars, secrets, resource limits
  │
  ├── 7. Create HTTPRoute
  │     Hostname: {agent-slug}.pods.agentworksstudio.com
  │     Backend: agent service
  │
  ├── 8. Create KEDA HTTPScaledObject
  │     Enable scale-to-zero
  │     Min: 0, Max: based on tier
  │
  └── 9. Submit to K8s API
        kubectl apply -f manifest.yaml
        Pod starts → Phase 3

Provisioner Files

apps/agent-provisioner/src/
├── provisioner.ts              # Production pod provisioning
└── navigator-provisioner.ts   # Navigator pod provisioning

Phase 3: Bootstrap (chelper)

Once the pod starts, chelper runs as a s6-overlay oneshot before Hudson Gateway starts.

Bootstrap Sequence

Pod Running
  │
  ├── tini (PID 1)
  │     └── s6-overlay
  │           │
  │           ├── init-config-gen (oneshot)
  │           │     1. Read env vars (AGENT_ID, TENANT_ID, etc.)
  │           │     2. Fetch agent config from Platform API
  │           │     3. Generate hudson.json config file
  │           │     4. Write to HUDSON_STATE_DIR
  │           │
  │           └── init-chelper (oneshot, depends on init-config-gen)
  │                 1. Wait for sidecar CDP (localhost:9222)
  │                 │    Timeout: 30 seconds
  │                 │    Retries: every 2 seconds
  │                 │
  │                 2. Validate PVC mount
  │                 │    Check HUDSON_STATE_DIR is writable
  │                 │    Create directory structure if fresh
  │                 │
  │                 3. Restore cookies from vault
  │                 │    IF ENABLE_COOKIE_VAULT=true:
  │                 │      Fetch encrypted cookies from API
  │                 │      Decrypt with DEK from Secret Manager
  │                 │      Inject into browser context
  │                 │
  │                 4. Exit 0 → Hudson can start
  │                    (or Exit 1 → pod fails, restart)

Bootstrap Failure Handling

FailureAction
Sidecar CDP timeoutPod restart (kubelet will retry)
PVC mount failurePod fails, manual intervention
Cookie vault errorContinue without cookies (non-fatal)
Config fetch failurePod restart with backoff

s6-overlay Service Graph

init-config-gen (oneshot)
  │
  └──► init-chelper (oneshot)
         │
         ├──► svc-nginx (longrun)
         │      nginx -g 'daemon off;'
         │
         └──► svc-hudson (longrun)
                node dist/entry.js gateway run

Phase 4: Running

Once bootstrapped, the pod serves agent requests.

Request Flow

Client (Console / API / Direct)
  │
  ├── HTTPS to {agent-slug}.pods.agentworksstudio.com
  │
  ├── GKE Gateway (34.102.157.95)
  │     ├── TLS termination
  │     └── HTTPRoute → pod IP
  │
  ├── Kernel :8080 (nginx)
  │     ├── /api/* → Hudson Gateway :3001
  │     ├── /socket.io/* → Hudson WebSocket
  │     └── /* → Static assets
  │
  └── Hudson Gateway
        ├── Parse request
        ├── Check Lighthouse knowledge
        ├── LLM call (if needed)
        ├── Tool execution
        │     ├── Browser actions → Sidecar :9222 (CDP)
        │     ├── Terminal commands → sandbox
        │     └── API calls → external services
        ├── Memory operations
        │     ├── Read SOUL.md
        │     └── Update memory files
        └── Return response

Browser Interaction Flow

Agent needs to interact with a website:
  │
  ├── Hudson → CDP → Sidecar Chromium
  │     Navigate to URL
  │     Page loads
  │
  ├── Login Detector checks for auth pages
  │     ├── No login → continue automation
  │     │     Browser-Use distills DOM → LLM tokens
  │     │     Agent processes content
  │     │
  │     └── Login detected → HITL Controller
  │           Pause agent execution
  │           WebSocket event → Console shows alert
  │           Human opens noVNC → authenticates
  │           Cookies captured → encrypted → stored
  │           Agent resumes with authenticated session
  │
  └── Agent completes task with browser data

Health Monitoring

CheckIntervalAction on Failure
Kernel health (:8080/health)30sPod restart
Sidecar CDP (:9222)60sSidecar restart (if possible)
Browser-Use (:9223/health)60sService restart
PVC disk space5mAlert if >80%
Cookie freshnessOn useRe-auth if expired

Phase 5: Teardown

When an agent is deleted or its lifetime expires.

Teardown Triggers

TriggerAction
Admin deletionVia Console or API
Tenant deletionVia Console
Navigator TTLAuto-delete after 24 hours
Pod crash loopManual intervention
Billing failureGrace period then delete

Teardown Flow

Delete Request
  │
  ├── 1. Stop accepting new requests
  │     KEDA HTTPScaledObject → scale to 0
  │
  ├── 2. Wait for in-flight requests
  │     Grace period: 30 seconds
  │
  ├── 3. Delete HTTPRoute
  │     Remove subdomain routing
  │
  ├── 4. Delete KEDA HTTPScaledObject
  │
  ├── 5. Delete pod
  │     kubectl delete pod -n {namespace}
  │
  ├── 6. Delete PVC
  │     kubectl delete pvc agent-workspace -n {namespace}
  │
  ├── 7. Delete namespace (production)
  │     kubectl delete namespace agent-blue-heron-{id}
  │     Removes all resources: RBAC, NetworkPolicy, etc.
  │
  ├── 8. Clean cookie vault
  │     DELETE FROM cookie_vault WHERE agent_id = $1
  │
  └── 9. Update agent status in database
        status: 'deleted'
        (Lighthouse documents preserved at tenant level)

Navigator pods have a TTL controller:

# Automatically deletes after 24 hours
metadata:
  annotations:
    navigator-ttl: "24h"

No PVC to clean up — all data is ephemeral.


Pod States

StateDescriptionUser-Visible
provisioningK8s resources being created"Setting up your agent..."
bootstrappingchelper running"Initializing..."
startingHudson Gateway loading"Almost ready..."
healthyAll checks passingGreen indicator
degradedSidecar or non-critical service downYellow indicator
unhealthyKernel or critical service downRed indicator
scaling_downKEDA scaling to zero"Agent is sleeping"
scaling_upKEDA scaling from zero"Waking up agent..."
terminatingGraceful shutdown"Agent shutting down"
failedBootstrap or runtime failure"Agent encountered an error"

File Locations

apps/agent-provisioner/src/
├── provisioner.ts                    # Production provisioning logic
└── navigator-provisioner.ts         # Navigator provisioning logic

infrastructure/docker/rookery-kernel/
├── Dockerfile                        # Kernel image
└── rootfs/etc/s6-overlay/
    ├── s6-rc.d/
    │   ├── init-config-gen/          # Config generation service
    │   ├── init-chelper/             # Bootstrap validation service
    │   ├── svc-hudson/               # Hudson Gateway service
    │   └── svc-nginx/                # nginx service
    └── scripts/chelper               # Bootstrap executable

apps/hudson-gateway/src/bootstrap/
└── chelper.ts                        # TypeScript bootstrap logic

infrastructure/k8s/templates/
└── agent-pod-v2.yaml                 # Dual-container pod template

infrastructure/k8s/navigator/
└── navigator-pod.yaml                # Single-container template