> ## 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 YAM reference

> Bimanual state/action order and capture-time observation metadata.

Connect to `reactor/dreamzero-yam-molmoact2` 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 | Top, left, and right camera streams, measured state for both arms, and a task prompt. |
| Model → your client | `action_chunk` messages; `data.actions` contains 24 × 14 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/yam/quickstart).

## Camera inputs

Publish `top`, `left`, and `right` as RGB `uint8` arrays shaped `(H, W, 3)` after `READY`. They map
respectively to `top_camera-images-rgb`, `left_camera-images-rgb`, and `right_camera-images-rgb` in
the checkpoint. The evaluation transform uses `(176, 320)` images; the endpoint resizes incoming
views. Preserve view identity, mounting, and field of view.

## Commands

| Command | Payload | Constraint |
| - | - | - |
| `set_prompt` | `{"prompt": "put the block in the bin"}` | Nonempty, at most 500 characters |
| `set_left_joint_pos` | `{"left_joint_pos": [0, 0, 0, 0, 0, 0]}` | Six measured joint positions, radians |
| `set_right_joint_pos` | `{"right_joint_pos": [0, 0, 0, 0, 0, 0]}` | Six measured joint positions, radians |
| `set_left_gripper_pos` | `{"left_gripper_pos": 0.0}` | Measured closure: `0` open, `1` closed |
| `set_right_gripper_pos` | `{"right_gripper_pos": 0.0}` | Same convention for the right gripper |
| `set_video_preview` | `{"video_preview": true}` | Optional; default `false` |
| `set_pair_by_capture_time` | `{"pair_by_capture_time": true}` | Optional camera alignment override |
| `reset` | `{}` | End the episode |

The zero joint lists above illustrate payload shape only. Real control requires measured state for
both arms in the checkpoint's native joint order; these are not Cartesian poses.

## Action output

The `action_chunk` message's `data` contains:

| Field | Meaning |
| - | - |
| `actions` | `(24, 14)` nested array |
| `chunk_index` | Prediction counter within the episode |
| `obs_seq` | Largest ingest sequence in the selected camera windows |
| `inference_seconds` | Model-side inference duration, excluding client transport |
| `obs_capture_time_us` | Newest available capture timestamp among consumed frames; nullable |
| `view_skew_us` | Maximum minus minimum of the newest consumed timestamp per view; nullable |

Each row is laid out as follows:

| Columns | Values |
| - | - |
| `0:6` | Left arm's six joint targets |
| `6` | Left gripper |
| `7:13` | Right arm's six joint targets |
| `13` | Right gripper |

Joint targets are **absolute radians for each arm whose measured state is supplied**. An omitted arm
state defaults to zero and leaves that arm's output relative to the zero anchor. Every row is
referenced to the chunk's anchor state, not the preceding row. Do not cumulatively sum rows or add
joint state a second time. Gripper columns are continuous normalized closure; validate and map them
locally. Action width alone does not verify a robot's joint order or calibration.

The API supplies no per-row execution timestamp or controller rate. Establish the cadence from your
YAM data and controller integration; the chunk arrival rate is not the execution rate.

## Capture-time alignment

Capture-time pairing ships disabled. Send `set_pair_by_capture_time` explicitly to enable it;
`pair_by_capture_time_accepted` reports the selected value. The override takes effect from the next
chunk and persists across `reset`. Unset session state follows the deployment default.

When enabled and stamps are available, selection trims camera histories near the slowest view's
newest capture timestamp, with approximately 33 ms tolerance, before selecting each window. It can
wait for usable history. If a newest frame lacks a timestamp, selection falls back to arrival order.
This changes the observations seen by the model, so evaluate it on your capture setup.

`obs_capture_time_us` describes the sender's clock domain. `view_skew_us` requires stamps on all
three newest consumed frames; `obs_capture_time_us` can still be present when skew is null. Neither
field certifies hardware synchronization. Only compute observation age against a compatible clock;
subtracting an unrelated server wall clock does not measure end-to-end latency.

`predicted_video` carries a composite preview when enabled and black frames otherwise. It is
optional diagnostic output and adds decoding work.

## 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.