ADR 0009: AgentDO on the Agents SDK with the Pi Durable harness
- Status: Accepted. Superseded in part by ADR 0016 (Vertex overflow, caps) and ADR 0011 (workspace tools). Updated 2026-10-10.
- Date: 2026-10-08
- Decider: Project owner
Context
Section titled “Context”Phase 6 needs a durable agent with a model and tool loop (AGENTS.md sections 13.4, 25). On
2026-10-02 Cloudflare released PiHarness in the Agents SDK with @earendil-works/pi-durable
(beta). With it, Pi runs inside a Durable Object, persists transcripts in its SQLite, and resumes
after eviction.
Decision
Section titled “Decision”AgentDO(agents Worker) extends the Agents SDKAgentand runsPiHarness. It implementsAgentRuntime. No Pi type crosses that boundary. One instance per logical agent ID.- Models: one pi-ai provider,
rhumbatron, with modelstier-haiku,tier-sonnet,tier-opus. Requests go to OpenRouter through the AI Gateway. A payload hook sends the tier’s free-model fallback list (ADR 0007). Agents do not use the Vertex backup yet. - Tools:
complete_task(a typed Intent, section 26.1) andfail_task. Until Workspaces exist (Phase 8), completing a Task means declaring its Intent. Both tools are idempotent. - Routing: deterministic rules, Clef-flash only for the generic case (floors still apply), a
Decision Receipt per attempt in D1 plus
model.route.decided. - Escalation: two intelligence failures at a tier escalate one tier. Two failures at opus stop the Task (re-planning is later work). Transport failures retry once at the same tier. Each attempt resets the Pi session (fresh context).
- Budgets: a gate before every model request caps calls per run (6, 10, 10 by tier) and agent
calls per day (40, below the OpenRouter free limit). A budget stop blocks the Task, blocks its
dependents, and marks the Change
budget_blocked. - Liveness: AgentDO checks the run every 60 seconds while it is active and sets no timers when
idle. A run that ends without a terminal tool counts as
no_outcome. After 15 checks, AgentDO aborts the run (timeout). - The agents Worker deploys through
modules/durable-worker(ADR 0005). Migration v1 addsAgentDOas a SQLite class.
PiHarness and Pi Durable are beta APIs and may change. Only agent-do.ts, models.ts, and
task-tools.ts import them.
Diagram
Section titled “Diagram”One run, as AgentDO.start and its callbacks implement it today.
flowchart TD wake["AgentDO.start (wake consumer or retryTask)"] --> step["nextStep: retry, escalate, replan, or stop"] step --> route["Route the tier: rules, then Clef-flash"] route --> prov["chooseProvider: OpenRouter or Vertex, once per run"] prov --> ctx["Context packet, snapshot to R2"] ctx --> rcpt["Decision Receipt (D1) and model.route.decided"] rcpt --> claims["Acquire advisory Claims (ADR 0015)"] claims --> pi["PiHarness session: tier-T or tier-T-vertex"] pi --> gate["beforeModelCall: budget and daily caps"] gate --> mcall["Model call through AI Gateway"] mcall --> tools["Tool calls"] tools --> pi tools -- "complete_task or fail_task" --> finish["finishRun: release Claims, record outcome"] check["checkRun every 60 s<br/>15 checks: timeout"] --> finish finish -- "retry or escalate: retryTask in 5 s" --> wake
Update (2026-10-10)
Section titled “Update (2026-10-10)”- Agents now use Gemini on Vertex. AgentDO chooses the provider once per run: OpenRouter first, Vertex
when OpenRouter is used up for the day, or Vertex always when
MODEL_PROVIDER = "vertex"(dev). Each tier has a second Pi model,tier-<t>-vertex(ADR 0016). - The budget numbers changed. Calls per run are 16, 32, and 32 by tier (
MAX_CALLS_PER_RUN). The daily caps are 400 agent calls on all providers and 45 OpenRouter calls (ADR 0016). - Tools now include
list_files,read_file,write_file, andrun_commandfor Workspaces (ADR 0011), in addition tocomplete_taskandfail_task. - Runs take advisory Claims (ADR 0015). Self-scheduled callbacks go through the daily alarm cap (ADR 0019).