Sessions
Run one conversation across many turns, persist it, branch it, and steer it live.
A session is one conversation spanning many runs: open it with agent.session(), and each turn continues where the last left off. You never thread a session id by hand. These examples assume an agent from Run an agent.
Run turns
agent.supports("resume")full matrixsession.run works like the agent’s own, returning the same awaitable, iterable handle:
const session = agent.session({ cwd: "./repo" });
await session.run("Review this repo for unhandled rejections.");
const fixes = await session.run("Fix the issues you found.");
console.log(fixes.text);A session is a thread: the settings you open it with — model, effort, cwd, env, mcp, extraArgs — are fixed for its lifetime and ride every turn, so session.run takes only per-turn options (attachments, schema, systemPrompt, readOnly, signal). Passing a setting per-turn throws InvalidOptions; to run under different settings, open a new session, or fork this one to keep the history.
Turns queue: a run called while another is in flight starts when it settles, threaded automatically. A failed turn rejects the turns queued behind it; calling run again retries from the last good point.
session.close() ends the conversation and releases whatever it holds — in ACP mode, the connection behind it. Turns still queued reject, a closed session refuses new ones (InvalidOptions), and calling it twice is safe. session.id stays valid, so you can resume later.
Persist and continue later
session.id is a plain string, set once the first turn reveals it. Store it anywhere and continue from any process:
const session = agent.session();
await session.run("Start reviewing this repo.");
await save("review-session", session.id);
// Days later:
const resumed = agent.session({ resume: await load("review-session") });
await resumed.run("Continue with src/.");Conversation state lives with the CLI, so nothing else needs persisting. Iterating a turn surfaces the session event early, so you can persist the id before the first turn even ends.
Branch a conversation
Where the CLI can copy-on-resume (sessionFork: claude-code, opencode, Kilo Code, Pi), fork: true branches instead of continuing — session.id becomes the new conversation’s id:
const mainline = agent.session({ resume: saved });
const experiment = agent.session({ fork: true, resume: saved });Resuming one id into two sessions without fork is a relay, not a branch: both continue the same conversation, in whatever order their turns arrive.
Which agents run sessions
Every built-in adapter opens a session. Continuing one needs resume, which agent.supports("resume") guards; where it is false, agent.session({ resume }) throws and a session can only start fresh. Agents in ACP mode add steering, covered next; the Mode and Resume columns in the matrix mark both.
Steer an ACP-mode session
Some agents run sessions in ACP mode, holding one connection open instead of respawning per turn. That connection unlocks two things: steering the turn as it runs, and visibility into permission requests. Gate on session.supports("steer").
Steer a running turn
session.steer(text) injects guidance into the turn that is currently running:
const session = agent.session();
const turn = session.run("Migrate config/ to TypeScript.");
if (session.supports("steer")) {
session.steer("Skip the legacy directory.");
}
await turn;Steering adds guidance to an autonomous turn; it does not add an approval gate. On stdout-mode agents, steer throws UnsupportedCapability; guard and degrade, as with any capability.
Watch permission requests
An ACP-mode agent asks permission before some tools. AnyAgent answers for you, allowing so a run never blocks, and surfaces each exchange as a permission-request event carrying the agent’s own options:
for await (const event of session.run("Refactor the auth module.")) {
if (event.type === "permission-request") {
console.log(`[allowed ${event.name}]`, event.options.map((o) => o.label));
}
}Answering requests yourself (session.respond, an onPermission handler)
arrives with a later release; today session.supports("respond") is false
everywhere.