# Agents

Markdown twins, /llms.txt, an OpenAPI you can compile into tools, and webhook loops instead of polling — the agent-native surface.

We assume some readers of this site are not people. This page is the map for
them: where the machine-readable copies live, what to name your tools, and
how to run a loop against physical hardware without polling for it.

## Orientation

[/llms.txt](/llms.txt) is the curated index — the pages worth reading, one
line each. [/llms-full.txt](/llms-full.txt) is the entire documentation
concatenated into one file, for a single context load. Every page also has a
markdown twin at `<path>.md` — this page's is
[/docs/sdks/agents.md](/docs/sdks/agents.md) — and a copy-as-markdown button
for humans assembling context by hand.

## The machine surface

[/openapi.json](/openapi.json) is OpenAPI 3.1 with examples on every
operation. Generate one tool per operation, or use the `roborama_*` names
below — they are the names used in the Agent tab of every example on this
site, so the documentation doubles as few-shot material without renaming
anything.

| Tools | What they do |
| --- | --- |
| `roborama_run`, `roborama_eval`, `roborama_verify`, `roborama_matrix`, `roborama_threshold`, `roborama_compare`, `roborama_transfer` | create a run — `POST /v1/runs` with the matching `kind` |
| `roborama_tasks_create`, `roborama_tasks_pilot`, `roborama_tasks_amend`, `roborama_tasks_freeze` | formalize a claim as a Task Spec and walk it to `frozen@vN` |
| `roborama_kits_register`, `roborama_get_kit` | ship customer hardware in; track `received → tracked → available` |
| `roborama_quote` | price a job first: both meters, dollars, queue ETA |
| `roborama_list_robots`, `roborama_list_environments` | the catalogue, with firmware pins and revisions |
| `roborama_get_run`, `roborama_get_episodes`, `roborama_get_report`, `roborama_export_run` | results: statistics, artifacts, the verification report, dataset exports |
| `roborama_create_gate` | register a CI gate on a ref pattern |
| `roborama_get_stream` | WebRTC and MJPEG descriptors for a cell |
| `roborama_usage`, `roborama_set_budget`, `roborama_create_key`, `roborama_purge_data` | governance: metered usage, hard caps, scoped keys, receipted deletion |
| `roborama_calibration_export` | ground-truth bundles for simulator recalibration |

## The Agent tab

Every tabbed example on this site carries an Agent tab: the same call as a
complete tool-use payload, ready to drop into a transcript. The quote
example, in full:

```json
{
  "type": "tool_use",
  "name": "roborama_quote",
  "input": {
    "robot": "g1-edu-pro",
    "environment": "kitchen-std",
    "episodes": 600
  }
}
```

## Loops without polling

`threshold()` is the agent-native primitive: push checkpoints to the
`policy_stream` webhook and receive physical verdicts back. When the soak
tier crosses the target — canonically at 0.992 (n=1188, ci95 0.985–0.995) —
`threshold.crossed` fires, escalation to the verification tier queues, and
`on_verified` fires after confirmation there. Nothing polls; the hardware
calls you.

*Example: an agent-native contract*

**Python**

```python
import roborama  # reads ROBORAMA_API_KEY from the environment

contract = roborama.threshold(
    policy_stream=roborama.PolicyStream(webhook="https://acme.ai/ckpt"),
    target={"success_rate": 0.99, "ci": 0.95, "task": "bin_pick@v1"},
    iterate_on="soak",               # commodity tier, e.g. nori-a3 pods
    escalate_to="g1-edu-pro@fw2.3",  # verification tier on crossing
    monthly_cap_usd=12_000,
)

contract.on_verified(webhook="https://acme.ai/release-gate")
print(contract.id, contract.status)
```

**TypeScript**

```typescript
import Roborama from "@roborama/sdk"; // reads ROBORAMA_API_KEY

const roborama = new Roborama();

const contract = await roborama.runs.create({
  kind: "threshold",
  policy_stream: { webhook: "https://acme.ai/ckpt" },
  target: { success_rate: 0.99, ci: 0.95, task: "bin_pick@v1" },
  iterate_on: "soak", // commodity tier, e.g. nori-a3 pods
  escalate_to: "g1-edu-pro@fw2.3", // verification tier on crossing
  monthly_cap_usd: 12000,
});

await contract.onVerified({ webhook: "https://acme.ai/release-gate" });
console.log(contract.id, contract.status);
```

**cURL**

```bash
curl https://api.roborama.com/v1/runs \
  -H "Authorization: Bearer $ROBORAMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "threshold",
    "policy_stream": { "webhook": "https://acme.ai/ckpt" },
    "target": { "success_rate": 0.99, "ci": 0.95, "task": "bin_pick@v1" },
    "iterate_on": "soak",
    "escalate_to": "g1-edu-pro@fw2.3",
    "monthly_cap_usd": 12000,
    "on_verified": { "webhook": "https://acme.ai/release-gate" }
  }'
```

**Agent (tool-use payload)**

```json
{
  "type": "tool_use",
  "name": "roborama_threshold",
  "input": {
    "policy_stream": { "webhook": "https://acme.ai/ckpt" },
    "target": { "success_rate": 0.99, "ci": 0.95, "task": "bin_pick@v1" },
    "iterate_on": "soak",
    "escalate_to": "g1-edu-pro@fw2.3",
    "monthly_cap_usd": 12000,
    "on_verified": { "webhook": "https://acme.ai/release-gate" }
  }
}
```

The same pattern gates releases. Register a
[CI gate](/docs/guides/ci-gates/) once, then treat `run.completed` and
`regression.detected` deliveries as the verdict. An agent with a webhook
receiver and the tools above can hold a release until the hardware agrees it
should ship.

## Guardrails

Give an agent a scoped key and a hard budget before giving it tools:
`roborama_create_key` with the narrowest scopes that do the job —
`runs:write` for a loop that only launches work, and never `data:purge` —
plus a monthly cap set with `hard=True`. Past the cap, the API refuses new
work with `monthly_budget_exceeded`; outside the scopes, with
`insufficient_scope`. We consider a refused call a feature. Details in
[billing & budgets](/docs/guides/billing-and-budgets/).
