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();
await session.run("Review this repo for unhandled rejections.");
const fixes = await session.run("Fix the issues you found.");
console.log(fixes.text);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.
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 except Cline runs sessions; agent.supports("resume") is the guard, and agent.session() throws where it is false. Agents that hold a live connection add steering, covered next; the Sessions column in the matrix marks them.
Steer a live session
Some agents hold a live connection, keeping one session open instead of respawning per turn. That native 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 agents without a live connection, steer throws UnsupportedCapability; guard and degrade, as with any capability.
Watch permission requests
A live 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.