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

# Observations and actions

> FastWAM LIBERO camera, request, reply, and reset reference.

| Direction | Payload |
| - | - |
| Client → model | Two camera streams, task instruction, and an eight-value state request |
| Model → client | `action_prediction` with `actions`, `step`, and `inference_seconds`; `command_error` for an invalid request |

A **camera track** is a named stream of RGB images published through the SDK. Video carries the
images; SDK commands carry the task and state. [How the API works](/robotics/how-the-api-works)
introduces sessions, tracks, and the `{type, data}` message envelope.

## Camera tracks

Publish both tracks after the session reaches `READY`. Supply nonempty RGB `uint8` arrays shaped
`(H, W, 3)` in raw LIBERO renderer orientation.

| Track | Simulator observation |
| - | - |
| `exterior_view_1` | `agentview_image` |
| `wrist_view` | `robot0_eye_in_hand_image` |

The service rotates each image by 180°, resizes and center-crops it to 224 × 224, and combines the
exterior view before the wrist view. Do not pre-rotate, concatenate, or normalize the frames in the
client. The upstream evaluator uses 256 × 256 renders; 224 × 224 is the model's processed size, not
a required transport resolution.

A request waits for each track to deliver a frame with or after that request as observed by the
server. This does not establish equal capture times or atomic pairing with state. Keep both tracks
streaming and capture their images and state together in your client.

## Commands

| Command | SDK payload | Meaning |
| - | - | - |
| `set_task_description` | `{"task_description": "Open the drawer."}` | Nonblank instruction, at most 300 characters; changes apply to the next prediction |
| `set_state_json` | `{"state_json": json.dumps(request)}` | Requests a chunk; the serialized string is at most 2,000 characters |
| `reset` | `{}` | Clears pending requests, retained frames, and episode state; keeps the task instruction |

### Prediction request

| Field | Requirement |
| - | - |
| `proprio` | Eight finite numbers, representable as float32, in the order below |
| `chunk_id` | Integer from `0` through `2**63 - 1`; echoed as `step` |
| `seed` | Optional integer in the same range; defaults to `chunk_id` |
| `retry` | Optional client convention to change the serialized request; ignored by prediction |

Booleans, numeric strings, and fractional request IDs are invalid. Additional JSON fields are
ignored. Set the task before requesting a prediction.

| State slice | Meaning | Convention |
| - | - | - |
| `0:3` | End-effector position | XYZ metres, LIBERO world frame |
| `3:6` | End-effector orientation | Axis-angle vector in radians |
| `6:8` | Two measured gripper joint positions | LIBERO joint order, metres |

Convert `robot0_eef_quat` from its `xyzw` quaternion representation to axis-angle. Send physical
state values without applying training-statistic normalization.

## Action reply

The SDK receives `{"type": "action_prediction", "data": {...}}`. The example helper's `next_message`
returns the inner `data` object.

| Field | Shape / type | Meaning |
| - | - | - |
| `actions` | `(32, 7)` finite numbers | Predicted LIBERO controller commands |
| `step` | Integer | Echo of the request's `chunk_id` |
| `inference_seconds` | Number | Model prediction duration; excludes transport and waiting for input frames |

| Action slice | Meaning |
| - | - |
| `0:3` | Translation delta-controller commands |
| `3:6` | Rotation delta-controller commands |
| `6` | Gripper: `-1` open, `+1` close; exactly zero remains `0` |

The first six values use LIBERO controller scaling. They are neither absolute joint targets nor
unscaled metre/radian increments. The service already denormalizes actions and converts the gripper
convention; do not apply those conversions again. All 32 rows are predictions, with no conditioning
prefix to skip. The API supplies no per-row timestamps or mandatory execution frequency.

The reference
[robosuite 1.4.0 OSC pose controller](https://github.com/ARISE-Initiative/robosuite/blob/v1.4.0/robosuite/controllers/config/osc_pose.json)
clips the six motion inputs to `[-1, 1]`, then scales translation by `0.05` metres and rotation by
`0.5` radians. Its
[goal calculation](https://github.com/ARISE-Initiative/robosuite/blob/v1.4.0/robosuite/utils/control_utils.py)
adds translation in the world frame and left-multiplies orientation by the axis-angle rotation.
These are simulator controller semantics, not a calibrated physical-robot mapping.

## Requests, errors, and reset

Use one outstanding request. Match `step` before accepting a reply and consume each request once. A
new state value can replace a pending request. Byte-identical `state_json` does not trigger another
prediction. For a retry, keep `chunk_id` and `seed` and change a `retry` counter; newly received
frames can still change the result.

An empty `state_json` requests nothing. A nonempty malformed request emits `command_error` with
`command` and `reason`, and is dropped while the session remains open. Correct it and send changed
JSON. SDK command rejection is separate and can raise from `send`. An unexpected inference failure
can end the session.

After `reset`, send changed request bytes and fresh frames. Keep IDs increasing so a late reply from
the previous episode cannot match a new request. Reset acknowledges model state changes; it does not
stop or reset your robot.


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