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

# Examples

> Complete authorized Run workflows for creation, evidence, recovery, and lifecycle control.

Each program below is complete and runnable. They use small files only to show where an
application-owned persistence boundary belongs; replace those with the assessment record storage you
already operate. Every program needs an organization API key in `ANTIGEN_API_KEY` and works only
with approved targets.

| Record                    | Stands in for                              |
| ------------------------- | ------------------------------------------ |
| `.antigen-run-id`         | Your durable Run-ID record.                |
| `.antigen-event-position` | The last event sequence you fully handled. |

Two ordering rules make every one of these programs recoverable: write the Run ID as soon as
creation succeeds, and write an event sequence only after that event has been processed.

## Create, observe, and act on a finding

Reads approved targets, creates a Run with explicit Guardrails, persists the Run ID and event
checkpoint, then turns the first finding's remediation into a next action.

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { writeFile } from "node:fs/promises";
import Antigen from "@antigenco/sdk";

const apiKey = process.env.ANTIGEN_API_KEY;
if (!apiKey) throw new Error("Set ANTIGEN_API_KEY to an organization API key.");

const antigen = new Antigen(apiKey);
const approved = await antigen.getApprovedTargets();
const target = approved.find(
  (candidate) => candidate === process.env.ANTIGEN_TARGET,
);
if (!target)
  throw new Error(`Set ANTIGEN_TARGET to one of: ${approved.join(", ")}`);

const run = await antigen
  .agent({
    model: "claude-sonnet-4-6",
    guardrails: "Assess only the approved target.",
  })
  .run([target]);
await writeFile(".antigen-run-id", `${run.id}\n`, { mode: 0o600 });

for await (const event of run) {
  console.log(`${event.sequence}: ${event.summary}`);
  await writeFile(".antigen-event-position", `${event.sequence}\n`, {
    mode: 0o600,
  });
}

const [finding] = await run.findings();
console.log(
  finding
    ? `Next action: ${finding.remediation}`
    : "Completed with no findings.",
);
```

The program prints progress events and either a remediation next action or a completed assessment
with no findings. Both are valid outcomes. If creation fails before an ID is recorded, correct the
credential, target, or request input. If the caller loses its response *after* an ID is recorded,
start from the recovery program below rather than creating another Run.

## Recover after a local interruption or timeout

Restores the saved Run and event position, reads its status, and resumes only the events that follow
the saved checkpoint. Run this after any interruption of the program above.

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { readFile, writeFile } from "node:fs/promises";
import Antigen from "@antigenco/sdk";

const apiKey = process.env.ANTIGEN_API_KEY;
if (!apiKey) throw new Error("Set ANTIGEN_API_KEY to an organization API key.");

const runId = (await readFile(".antigen-run-id", "utf8")).trim();
const saved = await readFile(".antigen-event-position", "utf8").catch(() => "");
const after = saved.trim() === "" ? undefined : Number(saved.trim());
if (after !== undefined && (!Number.isSafeInteger(after) || after < 0)) {
  throw new Error("Invalid saved event position.");
}

const run = await new Antigen(apiKey).runs.get(runId);
console.log(`Recovered Run ${run.id}: ${(await run.status()).status}`);

for await (const event of run.events({ after })) {
  console.log(`${event.sequence}: ${event.summary}`);
  await writeFile(".antigen-event-position", `${event.sequence}\n`, {
    mode: 0o600,
  });
}
console.log(`Settled as ${(await run.status()).status}.`);
```

The event stream ends when the Run reaches a terminal state, so this program needs no separate wait.
Reach for `run.wait` only when you are not consuming events, and treat its `AntigenWaitTimeoutError`
as a local deadline rather than a result:

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { AntigenWaitTimeoutError } from "@antigenco/sdk";

try {
  console.log((await run.wait({ waitTimeoutMs: 300_000 })).status);
} catch (error) {
  if (!(error instanceof AntigenWaitTimeoutError)) throw error;
  console.log("Local wait ended; rerun to observe the same Run.");
}
```

Do not restart at sequence zero unless you intend to reprocess every event as new evidence.

## Create and recover through the HTTP API

Use this when the application owns its own HTTP client and persistence. `curl`, `jq`, and
`ANTIGEN_API_KEY` are the only prerequisites. Confirm the target is approved, create the Run, and
save its ID:

`set -euo pipefail` is what makes the approval check load-bearing: without it the pipeline's exit
status is discarded and the script creates the Run anyway.

```sh theme={"theme":{"light":"github-light","dark":"github-dark"}}
set -euo pipefail

curl --fail-with-body --silent --show-error \
  -H "x-api-key: $ANTIGEN_API_KEY" \
  https://api.antigen.sh/v1/targets \
  | jq -e '.targets | index("example.com")' > /dev/null

curl --fail-with-body --silent --show-error \
  -H "x-api-key: $ANTIGEN_API_KEY" \
  -H 'content-type: application/json' \
  -d '{"model":"claude-sonnet-4-6","targets":["example.com"],"guardrails":"Assess only the approved target."}' \
  https://api.antigen.sh/v1/runs | jq -r '.id' > .antigen-run-id
```

Then read the durable record whenever you need it:

```sh theme={"theme":{"light":"github-light","dark":"github-dark"}}
RUN_ID=$(cat .antigen-run-id)
curl --fail-with-body --silent --show-error \
  -H "x-api-key: $ANTIGEN_API_KEY" \
  "https://api.antigen.sh/v1/runs/$RUN_ID" | jq .
curl --fail-with-body --silent --show-error \
  -H "x-api-key: $ANTIGEN_API_KEY" \
  "https://api.antigen.sh/v1/runs/$RUN_ID/findings" | jq .
```

If a deadline or connection interruption occurs after the Run ID is saved, read
`GET /v1/runs/{runId}` and resume events after the saved sequence. Do not resend the creation
request because the caller did not receive a conclusive response.

## List and read a prior assessment

`runs.list` reads an organization-visible page; `runs.get` reads a record you already saved. The
continuation cursor is opaque and must be returned unchanged.

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { readFile } from "node:fs/promises";
import Antigen from "@antigenco/sdk";

const apiKey = process.env.ANTIGEN_API_KEY;
if (!apiKey) throw new Error("Set ANTIGEN_API_KEY to an organization API key.");

const antigen = new Antigen(apiKey);
const page = await antigen.runs.list({ limit: 50 });
for (const run of page.runs) console.log(`${run.id}: ${run.current.status}`);
if (page.nextCursor) console.log(`Next page cursor: ${page.nextCursor}`);

const runId = (await readFile(".antigen-run-id", "utf8")).trim();
console.log(`Saved Run: ${(await antigen.runs.get(runId)).current.status}`);
```

## Send guidance, then choose a lifecycle action

Reads the stored Run before sending guidance inside its approved scope, then decides an action from
the observed status rather than assuming one is valid.

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { readFile } from "node:fs/promises";
import Antigen from "@antigenco/sdk";

const apiKey = process.env.ANTIGEN_API_KEY;
if (!apiKey) throw new Error("Set ANTIGEN_API_KEY to an organization API key.");

const runId = (await readFile(".antigen-run-id", "utf8")).trim();
const run = await new Antigen(apiKey).runs.get(runId);

const state = await run.status();
console.log(`Before guidance: ${state.status}`);
if (state.status !== "running")
  throw new Error(`Cannot guide a Run that is ${state.status}.`);

const delivery = await run.send(
  "Continue only within the approved target and Guardrails.",
);
console.log(`Delivered ${delivery.id} at ${delivery.deliveredAt}`);
```

`run.stop()` requests a reviewable pause, `run.resume()` applies only to a `stopped` Run, and
`run.cancel()` is terminal. Use each one to express a decision about the assessment. A local timeout
is not a lifecycle action.

These programs produce technical evidence. Turning it into accountable work, and handing an
assessment to another operator, is covered in [Guides](/guides).

Related pages: [TypeScript SDK](/sdk/typescript) for method and option details, [Guides](/guides)
for evidence and recovery decisions, [HTTP API reference](/http-api) for the direct contract, and
[Reliability and security](/reliability-security) for credential expectations.
