diff --git a/src/content/docs/agents/concepts/harness.mdx b/src/content/docs/agents/concepts/harness.mdx new file mode 100644 index 00000000000..7c406ea799a --- /dev/null +++ b/src/content/docs/agents/concepts/harness.mdx @@ -0,0 +1,114 @@ +--- +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 +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, or is reached through it. + +## 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. + +## 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 + +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/).** 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. + +**[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). + +## Related resources + + + + + + diff --git a/src/content/docs/agents/harnesses/index.mdx b/src/content/docs/agents/harnesses/index.mdx index 57f72e1a164..11d629c457f 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 [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. 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: