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

# Quickstart

> Start a session, stream it live, and steer it

This quickstart defines an agent, starts a session, streams its event log, and sends a follow-up message with a scoped client token.

For the finished version, see the [example app](https://github.com/diggerhq/oc-sessions-demos); for every endpoint, the [API / SDK reference](/agent-sessions/api-reference).

<Tip>Want to click through it first? The [dashboard](https://app.opencomputer.dev) creates agents and credentials, then streams and steers the session live — a fast way to see the flow before wiring it into code.</Tip>

## Prerequisites

You need an OpenComputer API key and an Anthropic key:

```bash theme={null}
OPENCOMPUTER_API_KEY=osb_...
ANTHROPIC_API_KEY=sk-ant-...
```

<Tip>Grab your OpenComputer API key from [app.opencomputer.dev](https://app.opencomputer.dev). Sessions run **Managed** (billed to your OpenComputer credits, no key — the default) or on your own provider key (Anthropic for the default `claude` runtime). This quickstart uses a key; for Managed, drop the `key` and pass `credential: "managed"`.</Tip>

## 1. Create an agent

An agent stores reusable configuration: name, runtime, model, prompt, and model credential.

<CodeGroup>
  ```ts TypeScript SDK theme={null}
  import { OpenComputer } from "@opencomputer/sdk";

  const oc = new OpenComputer({ apiKey: process.env.OPENCOMPUTER_API_KEY! });

  const agent = await oc.agents.create({
    name: "quickstart-coder",
    runtime: "claude",
    model: "anthropic/claude-opus-4-8",
    prompt: "Work in /workspace. Say progress. Ask only when blocked.",
    key: process.env.ANTHROPIC_API_KEY,
    limits: { turns: 4, turnSeconds: 600 },
  });
  ```

  ```http REST API theme={null}
  POST https://api.opencomputer.dev/v3/agents
  Authorization: Bearer $OPENCOMPUTER_API_KEY
  Content-Type: application/json

  {
    "name": "quickstart-coder",
    "runtime": "claude",
    "model": "anthropic/claude-opus-4-8",
    "prompt": "Work in /workspace. Say progress. Ask only when blocked.",
    "key": "sk-ant-...",
    "limits": { "turns": 4, "turn_seconds": 600 }
  }
  ```
</CodeGroup>

Response:

```json theme={null}
{ "id": "agt_...", "name": "quickstart-coder", "active_revision": { "number": 1 } }
```

<Note>Your model `key` is held in OpenComputer's [secret store](/sandboxes/secrets) (encrypted, write-only) and **never enters the sandbox**. The agent runs with a placeholder; an **egress proxy substitutes the real key in-flight** on the outbound model-provider call. Reuse one key across agents via a [credential](/agent-sessions/credentials).</Note>

<Tip>`POST /agents` is idempotent by agent name, so it is fine to call this during application startup.</Tip>

<Tip>Prefer OpenAI? Set `runtime: "codex"` and `model: "openai/gpt-5-codex"` with an OpenAI `key` — every other step in this guide is identical. See [Runtimes](/agent-sessions/runtimes).</Tip>

## 2. Start a session

A session starts work immediately and returns a browser-safe `client_token` for that one session.

<CodeGroup>
  ```ts TypeScript SDK theme={null}
  const session = await oc.sessions.create({
    agent: agent.id,
    input: "Create a todo app with local storage and a clean dark UI.",
  });

  // session.id + session.clientToken — hand the token to your frontend
  ```

  ```http REST API theme={null}
  POST https://api.opencomputer.dev/v3/sessions
  Authorization: Bearer $OPENCOMPUTER_API_KEY
  Content-Type: application/json

  {
    "agent": "agt_...",
    "input": "Create a todo app with local storage and a clean dark UI."
  }
  ```
</CodeGroup>

Response:

```json theme={null}
{
  "session": { "id": "ses_...", "status": "queued", "head": 1 },
  "client_token": "eyJ..."
}
```

<Tip>**Working on a repo?** Pass [`sources`](/agent-sessions/repos) to check code out before turn 1 — the GitHub token never enters the sandbox. For a registered repo, `sha` is optional (OpenComputer resolves `ref`→HEAD and pins it):</Tip>

<CodeGroup>
  ```ts TypeScript SDK theme={null}
  const session = await oc.sessions.create({
    agent: agent.id,
    input: "Fix the failing test on this branch, then open a PR.",
    sources: [{ repo: "acme/web", ref: "main" }],
  });
  ```

  ```http REST API theme={null}
  POST https://api.opencomputer.dev/v3/sessions
  Authorization: Bearer $OPENCOMPUTER_API_KEY
  Content-Type: application/json

  {
    "agent": "agt_...",
    "input": "Fix the failing test on this branch, then open a PR.",
    "sources": [{ "repo": "acme/web", "ref": "main" }]
  }
  ```
</CodeGroup>

The agent can then open a PR with `github_publish_pull_request` and [watch](/agent-sessions/watches) it — it wakes when checks finish or a reviewer comments.

## 3. Stream events

Use the `client_token` in the browser. Ask for `progress` for a good activity feed, or `internal` for an operator/debug view.

<CodeGroup>
  ```ts TypeScript SDK theme={null}
  import { connectSession } from "@opencomputer/sdk";

  // in your frontend, with the session's client token
  const live = await connectSession({ sessionId, clientToken });

  for await (const event of live.events({ level: "progress" })) {
    render(event); // reconnects from the last seq automatically
  }
  ```

  ```js EventSource theme={null}
  const url = new URL(`${OC}/v3/sessions/${sessionId}/events`);
  url.search = new URLSearchParams({ stream: "sse", level: "progress", token: clientToken });

  const events = new EventSource(url.toString());
  events.onmessage = (message) => render(JSON.parse(message.data));
  ```
</CodeGroup>

Each event's `seq` is sent as the SSE `id`, so `EventSource` resumes automatically with `Last-Event-ID` after a dropped connection.

## 4. Render by `type`

Switch on the event `type`. Do not parse prose to decide whether work finished or failed.

```json theme={null}
[
  { "type": "agent.message", "body": { "text": "Done." } },
  { "type": "tool.call", "body": { "args_summary": "npm test" } },
  { "type": "exec.completed", "body": { "exit_code": 0 } },
  { "type": "turn.completed", "body": { "yield_reason": "completed" } }
]
```

Handle `turn.completed.body.yield_reason` explicitly:

| `yield_reason`                                      | UI behavior                                 |
| --------------------------------------------------- | ------------------------------------------- |
| `completed`                                         | Show the final result.                      |
| `needs_input`                                       | Show the agent's question and enable reply. |
| `deadline_exceeded`, `budget_exceeded`, `max_turns` | Explain which limit stopped the turn.       |
| `error`, `canceled`                                 | Show a stopped/error state.                 |

## 5. Steer the session

Post follow-up messages with the same `client_token`. An idle session wakes and continues with its prior context.

<CodeGroup>
  ```ts TypeScript SDK theme={null}
  await live.steer("Add a filter for completed tasks.", { idempotencyKey: "msg_01" });
  ```

  ```http REST API theme={null}
  POST https://api.opencomputer.dev/v3/sessions/ses_.../messages
  Authorization: Bearer $CLIENT_TOKEN
  Content-Type: application/json

  {
    "text": "Add a filter for completed tasks.",
    "idempotency_key": "msg_01"
  }
  ```
</CodeGroup>

Response:

```json theme={null}
{
  "event": { "id": "evt_...", "seq": 14 },
  "session": { "id": "ses_...", "status": "queued", "head": 14 }
}
```

## Production checklist

* Keep the org API key and your model key server-side.
* Add app auth before minting or returning a `client_token`.
* Set `limits` on the agent or session.
* Use `idempotency_key` for every user action you might retry.
* Use `level=user` for customer-facing chat, `level=progress` for activity feeds, and `level=internal` only for debugging.
* Register a [webhook](/agent-sessions/webhooks) when your backend needs push delivery after the tab closes.

## Next steps

<CardGroup cols={2}>
  <Card title="Events" icon="timeline" href="/agent-sessions/events">
    Event shape, levels, cursors, and resume behavior.
  </Card>

  <Card title="Repos & GitHub" icon="github" href="/agent-sessions/repos">
    Check out private repositories without putting GitHub tokens in the sandbox.
  </Card>

  <Card title="Example app" icon="github" href="https://github.com/diggerhq/oc-sessions-demos">
    Fork a complete app-builder implementation.
  </Card>

  <Card title="API reference" icon="code" href="/agent-sessions/api-reference">
    Endpoint details and response shapes.
  </Card>
</CardGroup>
