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

> ## Agent Instructions
> To build and serve your own model, start at /deploy/development/quickstart and /deploy/development/overview. Deploying is the default path: reactor init scaffolds a workspace, reactor auth login authenticates, and reactor model deploy registers the model, publishes the release with the weights/ folder, and activates it on Reactor's GPUs, in one command from that workspace. Docker must be running, because the publish step builds the image locally. Bump model.version in reactor.yaml before redeploying a change, because a release that already has an image is reactivated as it is. Deployment access is granted per account, so contact team@reactor.inc if a deploy is refused. Every key in reactor.yaml is documented at /deploy/platform/reactor-yaml. Model code imports reactor_runtime; Python client code imports reactor_sdk. The runtime overview explains the model interface. Running the model on your own machine with reactor run is optional and needs a GPU you attach with --gpus; /deploy/development/local-testing covers that loop and pairs a complete brightness model with a Python client test in a separate brightness-test workspace.
> Reactor hosts multiple models, each with its own connect slug (modelName) and command/event schema. The video model catalog — slug, typed SDK package, and links to its schema — is at /model-api-reference/overview. Robotics policy documentation starts at /robotics/overview; X-WAM observations, actions, and client integration are under /robotics/xwam/; Cosmos3 Nano Policy DROID is under /robotics/cosmos/nano-policy-droid/. Some models expose one slug per experience (e.g. HappyOyster); always take the slug from the model's own pages, never guess it.
> Fastest path to a working app: `npx create-reactor-app my-app --model=<slug>` scaffolds a complete app with secure auth wired up. Typed TypeScript SDKs are published as @reactor-models/<model>; Python uses the base reactor-sdk package.
> Auth: exchange an API key (rk_...) for a JWT via POST https://api.reactor.inc/tokens from your server. Never put the API key in client-side code.
> Append .md to any docs URL for clean Markdown. Search these docs via the MCP server at https://docs.reactor.inc/mcp.

# DreamZero DROID reference

> Camera mapping, state commands, action layout, and episode lifecycle.

Connect to `reactor/dreamzero` through the SDK and keep the session open while exchanging
observations and predictions. A **camera track** is a named stream of successive images from one
camera; publishing it attaches that stream to the session.

## API at a glance

| Direction | What crosses the connection |
| - | - |
| Your client → model | Three camera streams, measured joint/gripper state, and a task prompt. |
| Model → your client | `action_chunk` messages; `data.actions` contains 24 × 8 joint/gripper targets. |

Chunks stream as observations arrive; there is no separate predict command or execution
acknowledgement. Your application validates the output and executes it through its own controller.

New to Reactor? [How the API works](/robotics/how-the-api-works) explains sessions, tracks,
commands, and the difference between an SDK message and the data returned by the example helper. For
a complete script, use [Get your first actions](/robotics/dreamzero/droid/quickstart).

## Camera inputs

Publish RGB `uint8` arrays shaped `(H, W, 3)` on all three named tracks after `READY`.

| Track | View | RoboLab observation key |
| - | - | - |
| `exterior_1` | Primary exterior | `observation/exterior_image_0_left` |
| `exterior_2` | Second exterior | `observation/exterior_image_1_left` |
| `wrist` | Wrist | `observation/wrist_image_left` |

The model resizes input images to `(180, 320)`. RoboLab's default second exterior image is black;
keep that mapping explicit. Reversing the exterior tracks can leave the primary view black without
producing a protocol error.

## Commands

Call `session.send(command, payload)` with these payloads:

| Command | Payload | Constraint |
| - | - | - |
| `set_prompt` | `{"prompt": "put the banana in the bowl"}` | Nonempty, at most 500 characters |
| `set_joint_position` | `{"joint_position": [0, -0.6, 0, -2.5, 0, 1.9, 0]}` | Seven measured joint positions, radians |
| `set_gripper_position` | `{"gripper_position": 0.0}` | Measured normalized closure: `0` open, `1` closed |
| `set_video_preview` | `{"video_preview": true}` | Optional; default `false` |
| `reset` | `{}` | End the episode |

Joint order is the DROID arm order, corresponding to `panda_joint1` through `panda_joint7` in
RoboLab. Send finite measured values, not the preceding commanded targets. State and camera tracks
travel asynchronously; sending state first is useful ordering, not an atomic observation
transaction.

## Action output

The `action_chunk` envelope contains this `data` payload:

| Field | Meaning |
| - | - |
| `actions` | `(24, 8)` nested array: seven joints followed by gripper |
| `chunk_index` | Prediction counter within the current episode |
| `obs_seq` | Largest frame ingest counter in the selected observation window |
| `inference_seconds` | Model-reported inference duration; excludes client transport |

When measured state is supplied, the model's inverse transform produces **absolute joint targets in
radians**. Do not add the measured joints again or integrate rows as velocities. With unset joint
state, zeros are substituted and the returned joints instead reflect relative predictions. Gripper
output is continuous normalized closure. Validate its range locally before mapping it to your
controller; the endpoint does not guarantee all predictions lie within physical limits.

The reference simulator uses 15 Hz control: 24 rows represent 1.6 seconds of targets if all are
executed. That control rate is independent of inference chunk arrival rate.

`predicted_video` is a composite video output. It carries black frames while preview is disabled;
enabling `set_video_preview` adds decoding work. Preview frames are predictions, not sensor input.

## Streaming and episode state

The first chunk uses one frame per camera. Subsequent chunks use a rolling window of up to four
frames per view, padding short histories with the oldest frame. Inference waits until every camera
has delivered a new frame since the preceding chunk. Missing one view can stall the whole loop.

`obs_seq` is the largest server ingest counter among frames selected for a chunk. It is not a client
request ID, capture timestamp, or proof that a chunk includes a particular just-published frame. A
chunk already in flight can arrive after you update the observations. Rejecting counters older than
those already consumed prevents replay, but does not establish exact frame pairing.

`set_prompt` returns `prompt_accepted`. A different prompt re-anchors the causal cache; it is not an
episode reset. `reset` returns `episode_reset`, clears the prompt and measured robot state, and
restarts the episode counters when inference restarts. The first action has `chunk_index: 0`; its
`obs_seq` need not be zero because frames have already been ingested. After reset, discard pending
actions and send fresh state, frames, and a prompt. A model reset does not stop the robot.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.