---
title: Session State
description: Persist and resume eve client sessions with durable session IDs and stream cursors.
url: "https://eve.dev/docs/guides/client/continuations"
docs_index: /llms.txt
---

> For an index of all documentation, see [/llms.txt](/llms.txt).

A `ClientSession` is a handle on one session ID, used for messages, controls,
and streams. It also keeps a local `streamIndex` cursor, so reconnects skip
events the handle already read.

## Read and persist state

Save `session.state` after you read a response:

```ts
const { session, delivery } = await client.sessions.create({
  message: "Create a launch checklist.",
});

await delivery.result();
await saveSessionState(session.state);
```

The state holds the ID, the cursor, and an optional routing handle:

```ts
interface ClientSessionState {
  inbox?: string; // opaque; save and restore it unchanged
  sessionId: string;
  streamIndex: number;
  /** Opaque; persist it and pass it back unchanged. eve may extend it. */
  inbox?: string;
}
```

It is a stream cursor, not a transcript. Save events separately when your
application renders chat history.

## Resume a saved session

Attach a fixed handle to the saved ID and restore its cursor:

```ts
import type { ClientSessionState } from "eve/client";

const saved = (await loadSessionState()) as ClientSessionState;
const session = client.sessions.attach(saved.sessionId, saved);

const response = await session.send("Now shorten it.");
console.log((await response.result()).reply);
```

Pass the whole saved state so its optional [`inbox`](/docs/guides/client#faster-sends-with-inbox) value
reaches later sends. `attach()` performs no request. Every later operation targets exactly
`saved.sessionId` and never creates a replacement.

`send()` returns the response to the message the server accepted. If the saved
cursor is behind, the response skips earlier turns, even while another turn is
active or queued. You don't need to read the rest of the stream first. `send()`
throws when the server's reply has no delivery ID, so upgrade the server with
the client.

If a reconnect limit you set ends the stream before the turn finishes or pauses,
`result()` throws instead of returning a partial result.

<a id="waiting-completed-and-reset-sessions" />

## Waiting, completed, and ended sessions

A session that hasn't ended (`session.ended`) accepts more messages through the
same handle. An ended session does not. Start a fresh conversation
with another `client.sessions.create(firstTurn)` call.

```ts
const ended = await session.end({ reason: "Start over" });
await ended.result();
const { session: fresh, delivery } = await client.sessions.create({ message: "Begin again." });
```

The old `session` keeps pointing at its retired ID; `fresh` has a different ID.

## Multiple sessions

Create one handle per conversation:

```ts
const { session: research, delivery: researchDelivery } = await client.sessions.create({
  message: "Research competitors.",
});
const { session: support, delivery: supportDelivery } = await client.sessions.create({
  message: "Draft a support reply.",
});

await Promise.all([researchDelivery.result(), supportDelivery.result()]);
await save("research", research.state);
await save("support", support.state);
```

The shared `Client` holds the base URL, auth, headers, and redirect policy. Each
`ClientSession` holds its fixed ID and stream cursor.

## Reconnect an existing stream

`stream()` starts from the handle's cursor and advances it as you read:

```ts
const session = client.sessions.attach(saved.sessionId, saved);

for await (const event of session.stream()) {
  console.log(event.type);
}
```

Use `send()` for new input. For explicit cursors, tail-relative reads, and
bounded catch-up, see [Streaming](./streaming#open-a-stream-manually).

## What to read next

- [Streaming](./streaming): stream events and reconnect by index
- [Sessions, runs & streaming](../../concepts/sessions-runs-and-streaming): the raw HTTP contract
- [eve channel](../../channels/eve): the ID-addressed routes

---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)