> ## Documentation Index
> Fetch the complete documentation index at: https://checkfu.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Sessions and Runs

> Keep durable conversations separate from short-lived executions.

A **Session** is a durable conversation. A **Run** is one execution inside it.
One Session can contain many Runs as people send messages, answer questions,
approve actions, or return days later. How actors, fidelity, portable continue,
and native resume are recorded is in [Session execution graph](/concepts/session-execution-graph).

<Note>
  The CLI and TypeScript SDK tabs require private-alpha artifacts or a source
  checkout. Plain HTTP is the baseline. See [CLI
  access](/getting-started/cli-access) and [TypeScript SDK
  access](/reference/typescript-sdk).
</Note>

| Session                               | Run                                                |
| ------------------------------------- | -------------------------------------------------- |
| Owns the ordered event log            | Owns one execution attempt                         |
| Survives process and sandbox restarts | Starts and settles within one turn or continuation |
| May remain idle for days              | Records its trigger, status, and cost              |

## Start and drive a Session

A Session starts from a deployed Agent and acts as a Principal.

<CodeGroup>
  ```sh CLI theme={"theme":{"light":"github-light","dark":"github-dark"}}
  checkfu session create \
    --agent-deployment "$CHECKFU_AGENT_DEPLOYMENT_ID" \
    --principal "$CHECKFU_PRINCIPAL_ID"
  ```

  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl --request POST https://api.checkfu.com/v1/sessions \
    --header "Authorization: Bearer $CHECKFU_API_KEY" \
    --header "Checkfu-Version: 2026-08-27" \
    --header "Idempotency-Key: create-session-$(uuidgen)" \
    --header "Content-Type: application/json" \
    --data '{
      "agent_deployment_id": "'"$CHECKFU_AGENT_DEPLOYMENT_ID"'",
      "principal": "'"$CHECKFU_PRINCIPAL_ID"'"
    }'
  ```

  ```ts TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const session = await checkfu.sessions.create({
    agent_deployment_id: process.env.CHECKFU_AGENT_DEPLOYMENT_ID!,
    principal: process.env.CHECKFU_PRINCIPAL_ID!,
  })
  ```
</CodeGroup>

Keep the returned `sess_…` ID as `CHECKFU_SESSION_ID`.

Clients start or continue work by appending typed events. The HTTP API has no
separate ephemeral chat resource; the CLI's `session chat` command is a
convenience over Sessions and events.

<CodeGroup>
  ```sh CLI theme={"theme":{"light":"github-light","dark":"github-dark"}}
  checkfu session steer "$CHECKFU_SESSION_ID" \
    "Draft a release note." \
    --principal "$CHECKFU_PRINCIPAL_ID"
  ```

  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl --request POST \
    "https://api.checkfu.com/v1/sessions/$CHECKFU_SESSION_ID/events" \
    --header "Authorization: Bearer $CHECKFU_API_KEY" \
    --header "Checkfu-Version: 2026-08-27" \
    --header "Idempotency-Key: send-message-$(uuidgen)" \
    --header "Content-Type: application/json" \
    --data '{
      "type": "user.message",
      "payload": {
        "content": "Draft a release note.",
        "authored_by": "'"$CHECKFU_PRINCIPAL_ID"'",
        "caused_by": { "kind": "api" }
      }
    }'
  ```

  ```ts TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  await checkfu.sessions.events.send(session.id, {
    type: "user.message",
    payload: {
      content: "Draft a release note.",
      authored_by: process.env.CHECKFU_PRINCIPAL_ID!,
      caused_by: { kind: "api" },
    },
  })
  ```
</CodeGroup>

Every human-authored event names who wrote it (`authored_by`) and why it entered
the Session (`caused_by`). The [event reference](/reference/events) lists the
message, interruption, Custom-tool result, question answer, and Outcome payloads.

## The event log is the source of truth

Every accepted event receives a strictly increasing `seq` within its Session.
Messages, tool calls, ActionApprovals, usage, Run changes, and Session status are
projections of this append-only log.

The write response means “accepted,” not “finished.” Follow the SSE stream or
list events until a persisted settlement event arrives:

<CodeGroup>
  ```sh CLI theme={"theme":{"light":"github-light","dark":"github-dark"}}
  checkfu session follow "$CHECKFU_SESSION_ID" --until-boundary
  ```

  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl --no-buffer \
    "https://api.checkfu.com/v1/sessions/$CHECKFU_SESSION_ID/events/stream" \
    --header "Authorization: Bearer $CHECKFU_API_KEY" \
    --header "Checkfu-Version: 2026-08-27" \
  ```

  ```ts TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const turnBoundaries = new Set([
    "session.status_idle",
    "session.status_completed",
    "session.status_failed",
    "session.status_canceled",
  ])

  for await (const event of checkfu.sessions.events.stream(session.id)) {
    if (turnBoundaries.has(event.type)) break
  }
  ```
</CodeGroup>

The stream can resume from a sequence cursor after a disconnect. [Resume a
stream](/guides/resume-a-stream) covers reconnect and deduplication.

## Status and settlement

| Status         | Meaning                                                                     |
| -------------- | --------------------------------------------------------------------------- |
| `pending`      | Admitted but not yet executing.                                             |
| `provisioning` | A Run is preparing its execution environment.                               |
| `running`      | A Run is executing.                                                         |
| `waiting`      | The Run needs an external action, such as an ActionApproval or tool result. |
| `paused`       | The Session is suspended with no active compute, often for a human answer.  |
| `reconciling`  | Compute finished and declared output or writeback is settling.              |
| `idle`         | The current turn settled; another event can start a Run.                    |
| `completed`    | The Session ended successfully.                                             |
| `failed`       | The Session ended in failure.                                               |
| `canceled`     | The Session was explicitly canceled.                                        |

`idle` settles a turn but does not end the Session. `completed`, `failed`, and
`canceled` are terminal. A closed HTTP response or SSE connection is never a
settlement signal. The [Sessions reference](/reference/sessions#session-status)
contains every legal transition.

`user.interrupt` ends the current turn and returns a reusable Session to `idle`;
it does not make the Session terminal.

## Two freeze horizons

Reproducibility follows one simple split:

* **What the Agent is freezes when the Session is admitted.** The Session pins
  one immutable [AgentDeploymentRevision](/reference/agent-deployments) — the
  Agent release plus the exact HarnessProfile, model-routing, SandboxProfile,
  and resolved Skills coordinates that revision pins — and none of it changes
  for that Session.
* **What the Agent reads resolves at each Run start.** A Project tracking
  `latest` and current Memory content can advance between Runs, but each Run
  records the exact versions it received.

This is why omitting `agent_deployment_revision_number` means “the deployment's
current revision at admission,” not “follow future publishes.” Start a new
Session to adopt a new deployment revision.

## Waiting and continuation

An ActionApproval, Custom-tool call, Question, or Outcome can park a Run in
`waiting`. When the external result arrives, Checkfu continues the same durable
Session without pretending the original process stayed alive.

Multiagent thread messages are different: spawn and send acknowledge durable
custody and the primary continues immediately. Child reports wake or queue work
on the primary without a join continuation.

A Question releases compute and moves the Session to `paused`. Sending
`user.question_answer` starts a continuation Run; `user.interrupt` cancels the
parked turn and returns the Session to `idle`.

## Forking a retained prefix

`POST /v1/sessions/{id}/fork` creates an independent Session from the committed
head or a selected retained event. The copied events keep their IDs and
sequences; a new `session.forked` event marks the branch. Later events on either
Session never alter the other.

When the request selects a Checkpoint, Checkfu clones the corresponding sandbox
state through an eligible Runner and fails closed if that exact state cannot be
adopted. `GET /v1/sessions/{id}/diff` compares the two tails without guessing at
erased or unavailable history.

## Watches and wakeups

A **Watch** lets verified external state wake an idle Session. Provider webhook
bytes are only a hint: Checkfu reads the source again before deciding whether to
start a Run. Watch events stay on the Session's causal log. See
[Watches](/reference/sessions#watches) for lifecycle and eligibility.

## Project mounts

A Project mount places uploaded files or a Git tree at an absolute sandbox
path. It can pin a revision or resolve `latest` at each Run start. Mount paths
cannot overlap. Read-write changes are disposable unless the mount explicitly
enables pull-request writeback. [Projects](/concepts/projects) covers the source,
revision, and writeback model.

For Git mounts, Checkfu validates and indexes Skills found exactly at
`.claude/skills/<name>/SKILL.md` in that Run's frozen revision. These are
repository instructions, not catalog Skills: mounting the repository is the
trust action. A read-enabled Agent receives only a bounded pointer to the
read-only index under `/environment/.checkfu/`; nested, rootless, package-local,
and malformed entries are not announced.

## Memory mounts

A Memory mount requests `read_only` or `read_write` access to one MemoryStore.
Admission clamps that request to the acting Principal's PermissionAssignments, and each Run
records the effective access. At most one writeback-capable store may settle
changes in a turn. See [Memory](/concepts/memory#writeback-at-settlement).

## Turn deadlines

After a Runner accepts a claim, it has 60 seconds to make the harness ready. A
startup timeout requeues the same logical Run for a fresh attempt. Once running,
the absolute deadline is that startup allowance plus the SandboxProfile's
`max_duration_seconds`; crossing it fails the Run with
`runtime.turn_deadline_exceeded`.

<Accordion title="Prompt integrity">
  Before accepting `user.message`, Checkfu detects mixed-script visual
  confusables and bidirectional controls. When it finds one, the author must
  explicitly choose a corrected prompt or preserve the exact original. This
  check applies to authored message text, not mounted files, tool results, or
  Agent output.
</Accordion>

## Next steps

<CardGroup cols={2}>
  <Card title="Sessions API" icon="play" href="/reference/sessions">
    Create, drive, fork, mount, watch, and inspect Sessions.
  </Card>

  <Card title="Events" icon="list-timeline" href="/reference/events">
    Read every durable event type and payload.
  </Card>
</CardGroup>
