Harnesses
The harness is the engine that runs the model loop inside a wake: it calls the model, executes the tools the model asks for, and repeats until the turn ends. You pick one per agent — and swapping it changes nothing else about the agent.
Two harnesses, in a nutshell
native(...)is the default: teaspill owns the loop, works with any model provider, and records every step durably — the finest-grained recovery. Start here.claudeAgentSdk(...)runs the loop through the Claude Agent SDK: pick it when you specifically want Claude Code's behavior — its session semantics, its context management — inside a durable agent.
The choice is one field in your agent definition:
harness: native({
model: "claude-sonnet-4-5",
systemPrompt: "Research the topic, then spawn a summarizer.",
ingressUrl: process.env.RESTATE_INGRESS_URL!,
})
harness: claudeAgentSdk({
model: "claude-sonnet-4-5",
systemPrompt: "Research the topic, then spawn a summarizer.",
sessionStore: "/data/casdk-sessions",
ingressUrl: process.env.RESTATE_INGRESS_URL!,
})
What never changes
Everything around the loop is identical whichever harness runs it:
- The same platform tools (
spawn_agent,send_message,wait,finish, …) and the same workspace tools, with the same behavior. - The same timeline events — a UI reading the timeline can't tell which harness produced it, beyond a field on
run_startedsaying so. - The same exactly-once guarantee on every side-effecting tool call: spawning a child or running a command happens once, no matter how the run is retried.
So harness choice is a per-agent behavior decision, not an architecture decision. A researcher on the native harness can spawn a summarizer on the Claude Agent SDK harness and neither notices.
How to choose
Default to native. It is the shortest path, it works with any provider, and its step-level recovery means the least repeated work after a crash. Its context management is teaspill's own: when a conversation crosses the configured context budget, the harness writes a summarization event and the model continues on the folded context — history stays complete for readers.
Reach for the Claude Agent SDK harness when the behavior you want is Claude Code's: you've tuned prompts against it, you rely on its compaction and session handling, or you're migrating an existing Claude Code workflow into a durable agent. The trade is provider lock-in and coarser recovery for fidelity to a loop you already trust.
Neither choice is final — the harness is per agent, and changing it doesn't touch your tools, your schemas, or anything already on the timeline.
The durability difference
Both harnesses survive crashes; they differ in how much of a run's interior survives.
The native harness records every step: each model call and tool call is its own recorded step, so a crash mid-run resumes at the last completed step. The Claude Agent SDK harness keeps a durable session as its working memory across wakes; if the session is ever missing or out of date, it rebuilds a fresh one from the timeline and continues — nothing is lost, at the cost of a slower first turn.
On each wake the SDK harness checks its stored session against the timeline's position. If the session is present, produced by the same pinned SDK version, and consistent with the last committed event, it resumes warm — the fast path, and the normal one when the session store lives on a persistent volume. Any mismatch triggers a cold rebuild: the canonical timeline is projected into a fresh session, which is slower but always correct, because the timeline — not the session — is the source of truth. Running without a persistent session store means every fresh process cold-rebuilds; that is a sanctioned degraded mode, not a failure.
Next steps
Harness configuration — model options, tool restrictions, context budgets, session stores — is covered field by field in Building agents. To see agents cooperate regardless of harness, continue to Multi-agent patterns.