From 38bcf02b742a8dc975a955306037b27f3cc188ff Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 29 Oct 2026 17:38:51 +0000 Subject: [PATCH 1/3] [Agents] Add a Harnesses concept and move Runtime up the sidebar --- .../docs/agents/concepts/harnesses.mdx | 68 +++++++++++++++++++ src/content/docs/agents/harnesses/index.mdx | 2 + src/content/docs/agents/runtime/index.mdx | 2 +- 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/content/docs/agents/concepts/harnesses.mdx diff --git a/src/content/docs/agents/concepts/harnesses.mdx b/src/content/docs/agents/concepts/harnesses.mdx new file mode 100644 index 00000000000..d6a23dd0fee --- /dev/null +++ b/src/content/docs/agents/concepts/harnesses.mdx @@ -0,0 +1,68 @@ +--- +title: Harnesses +description: A harness is the agent loop around a model. Learn what a harness does, which harness to start with, and when to build your own on a Durable Object with the Lifecycle. +pcx_content_type: concept +sidebar: + order: 3 +products: + - agents +--- + +import { LinkCard } from "~/components"; + +A harness is a model in a loop. It sends the conversation to the model, runs the tools the model asks for, feeds the results back, and repeats until the model is done. Everything that makes an agent more than a single model call lives in the harness. + +## What a harness does + +A harness usually provides: + +- **The loop.** It calls the model, runs tool calls, handles their results, and decides whether to continue or stop. +- **A transcript.** It stores the session: every message, tool call, and result, so the next turn has the context of the last one. +- **Tools.** It gives the model a set of tools, and runs them when the model asks. +- **Skills.** It loads instructions and resources on demand, so the model only reads them when a task needs them. +- **Extensions.** It has a way to customize the loop, such as adding tools, system prompt sections, or hooks, without forking the harness. +- **Input and output.** It has an API to send prompts in and get answers, events, and the transcript out. + +On Cloudflare, a harness runs in a [Durable Object](/durable-objects/) as a capability of the [Lifecycle](/agents/runtime/lifecycle/). The Durable Object gives each agent its own storage, and the Lifecycle wakes it up to finish a run after an eviction, a deploy, or a crash. That is what makes the harness durable. + +## One API across harnesses + +The harnesses in the Agents SDK share the same shape for sending work in. Each one has `prompt()`, which waits for the answer, and `submit()`, which returns as soon as the prompt is stored. Both take a string, and a `session` option to pick the conversation: + +```ts +// The same calls work whether this.harness is a PiHarness or an OpenCodeHarness. +const { text } = await this.harness.prompt("Summarize today's tickets."); +await this.harness.submit("Draft a reply to ticket 42.", { session: "42" }); +``` + +The Agents SDK keeps this input API the same across harnesses, so you can switch harnesses without rewriting how your app talks to the agent. What each harness returns, such as its events and transcript format, is still specific to that harness. + +## Choose a harness + +**Start with [Pi](/agents/harnesses/pi/).** `PiHarness` runs [Pi Durable](https://earendil.com/posts/pi-durable/), and Pi includes most of what you would otherwise build yourself: sessions and the transcript, a tool registry and [extensions](/agents/harnesses/pi/extensions/), skills, an event stream for clients, and recovery after an eviction, with replay rules for each tool. + +**[Think](/agents/harnesses/think/)** was the first durable harness. It takes a more opinionated approach than Pi, built on the [`Agent` class](/agents/agent-class/) and the AI SDK, with its own conventions for tools, memory, and chat. Older agents often use Think, and it is still supported. + +**[OpenCode](/agents/harnesses/opencode/)** runs OpenCode's agent loop, sessions, tools, and plugins in a Durable Object. Use it when you already work with OpenCode. + +**Build your own** when you need full control over the model call, the message format, or the tool loop. Start from a Durable Object with the [Lifecycle](/agents/runtime/lifecycle/), and add the [capabilities](/agents/runtime/capabilities/) a harness would otherwise give you: + +- [`Sessions`](/agents/runtime/capabilities/sessions/) for the transcript. +- [`Streams`](/agents/runtime/capabilities/streams/) for replies that clients can resume after a disconnect. +- [`WebSockets`](/agents/runtime/capabilities/websockets/) to connect your frontend. +- [`Scheduler`](/agents/runtime/capabilities/scheduler/) to run work later. +- [`MCPClientManager`](/agents/runtime/capabilities/mcp-client-manager/) to give the model MCP tools. + +To write the loop itself as a capability, refer to [Build a capability](/agents/runtime/capabilities/build-a-capability/). + +## The harness and the runtime + +The harness decides what the agent does on each turn. The [runtime](/agents/runtime/) decides where the agent lives and how it stays durable: [routing](/agents/runtime/routing/) sends each request to the right Durable Object, the Lifecycle starts the harness and its capabilities, and [observability](/agents/runtime/observability/) traces what happened. + +With a harness, the parts of the runtime you work with directly are usually routing, [`WebSockets`](/agents/runtime/capabilities/websockets/), and observability. For more information, refer to [If you use a harness](/agents/runtime/#if-you-use-a-harness). + + diff --git a/src/content/docs/agents/harnesses/index.mdx b/src/content/docs/agents/harnesses/index.mdx index 57f72e1a164..2fd5174b46e 100644 --- a/src/content/docs/agents/harnesses/index.mdx +++ b/src/content/docs/agents/harnesses/index.mdx @@ -10,6 +10,8 @@ import { LinkCard } from "~/components"; A harness is the loop that makes an agent behave like an agent instead of a single model call. +For what a harness does and how to choose one, refer to [Harnesses](/agents/concepts/harnesses/) in Concepts. + It is responsible for the turn-by-turn work around the model: building the prompt, loading memory, selecting tools, handling tool results, streaming responses, persisting messages, and deciding whether the agent should continue or stop. To build a new agent, start with the [Pi harness](/agents/harnesses/pi/), which runs Pi Durable in a Durable Object. You can also run [OpenCode](/agents/harnesses/opencode/), or build the loop yourself on top of the [Agents SDK runtime](/agents/runtime/). diff --git a/src/content/docs/agents/runtime/index.mdx b/src/content/docs/agents/runtime/index.mdx index c7b36139f0f..3229c4c6418 100644 --- a/src/content/docs/agents/runtime/index.mdx +++ b/src/content/docs/agents/runtime/index.mdx @@ -3,7 +3,7 @@ title: Runtime description: The Agents SDK runtime is a Durable Object with the Lifecycle installed, a Worker that routes requests to it, and the capabilities you attach to it. pcx_content_type: overview sidebar: - order: 6 + order: 3 group: hideIndex: false products: From 4d0a0a3721e59436d7ce3a5b8de075e7bfe74c8b Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 29 Oct 2026 18:08:24 +0000 Subject: [PATCH 2/3] [Agents] Rework the harness concept around where its pieces live --- .../concepts/{harnesses.mdx => harness.mdx} | 62 +++++++++++++++++-- src/content/docs/agents/harnesses/index.mdx | 2 +- 2 files changed, 59 insertions(+), 5 deletions(-) rename src/content/docs/agents/concepts/{harnesses.mdx => harness.mdx} (50%) diff --git a/src/content/docs/agents/concepts/harnesses.mdx b/src/content/docs/agents/concepts/harness.mdx similarity index 50% rename from src/content/docs/agents/concepts/harnesses.mdx rename to src/content/docs/agents/concepts/harness.mdx index d6a23dd0fee..f56b2481611 100644 --- a/src/content/docs/agents/concepts/harnesses.mdx +++ b/src/content/docs/agents/concepts/harness.mdx @@ -1,6 +1,6 @@ --- -title: Harnesses -description: A harness is the agent loop around a model. Learn what a harness does, which harness to start with, and when to build your own on a Durable Object with the Lifecycle. +title: Harness +description: A harness is the agent loop around a model. Learn what a harness does, where its pieces run on Cloudflare, and which harness to start with. pcx_content_type: concept sidebar: order: 3 @@ -10,7 +10,7 @@ products: import { LinkCard } from "~/components"; -A harness is a model in a loop. It sends the conversation to the model, runs the tools the model asks for, feeds the results back, and repeats until the model is done. Everything that makes an agent more than a single model call lives in the harness. +A harness is a model in a loop. It sends the conversation to the model, runs the tools the model asks for, feeds the results back, and repeats until the model is done. Everything that makes an agent more than a single model call lives in the harness, or is reached through it. ## What a harness does @@ -23,7 +23,47 @@ A harness usually provides: - **Extensions.** It has a way to customize the loop, such as adding tools, system prompt sections, or hooks, without forking the harness. - **Input and output.** It has an API to send prompts in and get answers, events, and the transcript out. -On Cloudflare, a harness runs in a [Durable Object](/durable-objects/) as a capability of the [Lifecycle](/agents/runtime/lifecycle/). The Durable Object gives each agent its own storage, and the Lifecycle wakes it up to finish a run after an eviction, a deploy, or a crash. That is what makes the harness durable. +## Where the pieces live + +A harness is not one process. Its pieces can run in different places, and where each one runs decides what survives a crash, where credentials live, and what you pay for while the agent waits. + +It helps to name three parts: + +| Part | What it is | +| ----------- | ----------------------------------------------------------------------------------------------- | +| The loop | The harness code that calls the model and routes tool calls. | +| The session | The durable record of what happened: prompts, model output, tool calls, and results. | +| The hands | Where the agent acts: a file system, a shell, a browser, or an API. | + +Anthropic describes the same split as [decoupling the brain from the hands](https://www.anthropic.com/engineering/managed-agents). + +On Cloudflare, each agent is a [Durable Object](/durable-objects/): + +- **The loop** runs in the Durable Object. The [Lifecycle](/agents/runtime/lifecycle/) starts it, and wakes the object to finish a run after an eviction, a deploy, or a crash. +- **The session** lives in the Durable Object's SQLite database, next to the loop. +- **The hands** attach to the object as tools, and run wherever the work needs to. + +### A workspace spans several pieces + +The hands are often more than one thing. A [workspace](/agents/tools/filesystem/) from Cloudflare Computer is a good example. To the harness it is one set of tools, such as `read`, `write`, `grep`, and `exec`. Underneath, it coordinates three parts of the platform: + +- **Durable Objects** hold the files. A `Workspace` stores every file in the same SQLite database as the session, so files survive eviction the same way the transcript does. +- **Workers** run code. The JavaScript backend runs each `exec` call in a new [Dynamic Worker](/dynamic-workers/), which can read and write the workspace files but not the agent's bindings or credentials. +- **Containers** run Linux. When a task needs a shell or native binaries, a [sandbox](/agents/tools/sandbox/) attaches a [Container](/containers/) to the object. It starts for a command and stops when the agent goes quiet. + +Because each piece runs separately, a failure stays small. If a container dies, one tool call fails and the model decides what to do next. The session and the loop are still in the Durable Object. + +### When the loop runs in a container + +Some harnesses are command-line programs, such as Claude Code or Codex. They own their loop, tools, and session files, and expect a Linux machine, so they cannot run in a Durable Object. The Container harness runs the CLI in a container, and keeps the session and credentials in the Durable Object. When a container is replaced, the object restores the CLI's session files, and the CLI resumes its session. + +| Arrangement | Loop runs in | Session lives in | If the container dies | +| ------------------------------ | -------------- | ---------------- | ---------------------------------------------------------- | +| Loop in the Durable Object | Durable Object | Durable Object | One tool call fails. The run continues. | +| Loop in a container | Container | Durable Object | The run ends. The next prompt resumes the session. | +| Everything in one container | Container | Container | The session and the run are lost. | + +Keep the loop in the Durable Object when you control the agent loop. Run the loop in a container when you want a specific CLI agent with its own tools, plugins, and settings. ## One API across harnesses @@ -61,8 +101,22 @@ The harness decides what the agent does on each turn. The [runtime](/agents/runt With a harness, the parts of the runtime you work with directly are usually routing, [`WebSockets`](/agents/runtime/capabilities/websockets/), and observability. For more information, refer to [If you use a harness](/agents/runtime/#if-you-use-a-harness). +## Related resources + + + + + diff --git a/src/content/docs/agents/harnesses/index.mdx b/src/content/docs/agents/harnesses/index.mdx index 2fd5174b46e..11d629c457f 100644 --- a/src/content/docs/agents/harnesses/index.mdx +++ b/src/content/docs/agents/harnesses/index.mdx @@ -10,7 +10,7 @@ import { LinkCard } from "~/components"; A harness is the loop that makes an agent behave like an agent instead of a single model call. -For what a harness does and how to choose one, refer to [Harnesses](/agents/concepts/harnesses/) in Concepts. +For what a harness does and how to choose one, refer to [Harness](/agents/concepts/harness/) in Concepts. It is responsible for the turn-by-turn work around the model: building the prompt, loading memory, selecting tools, handling tool results, streaming responses, persisting messages, and deciding whether the agent should continue or stop. From f3f77d773f3ad949a3f2295343c26cb7906d6a58 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 29 Oct 2026 18:17:33 +0000 Subject: [PATCH 3/3] [Agents] Keep API details out of the Harness concept --- src/content/docs/agents/concepts/harness.mdx | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/content/docs/agents/concepts/harness.mdx b/src/content/docs/agents/concepts/harness.mdx index f56b2481611..7c406ea799a 100644 --- a/src/content/docs/agents/concepts/harness.mdx +++ b/src/content/docs/agents/concepts/harness.mdx @@ -67,19 +67,11 @@ Keep the loop in the Durable Object when you control the agent loop. Run the loo ## One API across harnesses -The harnesses in the Agents SDK share the same shape for sending work in. Each one has `prompt()`, which waits for the answer, and `submit()`, which returns as soon as the prompt is stored. Both take a string, and a `session` option to pick the conversation: - -```ts -// The same calls work whether this.harness is a PiHarness or an OpenCodeHarness. -const { text } = await this.harness.prompt("Summarize today's tickets."); -await this.harness.submit("Draft a reply to ticket 42.", { session: "42" }); -``` - -The Agents SDK keeps this input API the same across harnesses, so you can switch harnesses without rewriting how your app talks to the agent. What each harness returns, such as its events and transcript format, is still specific to that harness. +The harnesses in the Agents SDK take work in the same way. You send a prompt and either wait for the answer, or hand it off and let the harness finish in the background, in any session. The Agents SDK keeps this input the same across harnesses, so you can switch harnesses without changing how your app talks to the agent. What comes back, such as events and the transcript format, is still specific to each harness. ## Choose a harness -**Start with [Pi](/agents/harnesses/pi/).** `PiHarness` runs [Pi Durable](https://earendil.com/posts/pi-durable/), and Pi includes most of what you would otherwise build yourself: sessions and the transcript, a tool registry and [extensions](/agents/harnesses/pi/extensions/), skills, an event stream for clients, and recovery after an eviction, with replay rules for each tool. +**Start with [Pi](/agents/harnesses/pi/).** The Pi harness runs [Pi Durable](https://earendil.com/posts/pi-durable/), and Pi includes most of what you would otherwise build yourself: sessions and the transcript, a tool registry and [extensions](/agents/harnesses/pi/extensions/), skills, an event stream for clients, and recovery after an eviction, with replay rules for each tool. **[Think](/agents/harnesses/think/)** was the first durable harness. It takes a more opinionated approach than Pi, built on the [`Agent` class](/agents/agent-class/) and the AI SDK, with its own conventions for tools, memory, and chat. Older agents often use Think, and it is still supported.