> ## 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 catalog of every model — slug, typed SDK package, and links to its schema — is at /model-api-reference/overview. 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.

# ReactorApp

> The class you subclass to define a model.

The class you subclass to define a model. The runtime constructs it once, calls `load()`, then
drives it one step at a time for as long as clients are connected.

```python theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
from reactor_runtime import ReactorApp


class MyModel(ReactorApp):
    state: MyState
    fps = 24

    def load(self, config_path): ...
    def generate(self, input): ...
```

See [Model Anatomy](/deploy/development/reactor-app/model-anatomy) for the walkthrough.

`ReactorModel` and `ReactorPipeline` are the old names for this class. Both still import, with a
deprecation warning.

## Declarations

<ResponseField name="state" type="InputState subclass">
  Annotate a subclass of [`InputState`](/deploy/runtime-reference/inputstate) to
  give clients a `set_<field>` command per public field. The live instance is `self.state`, rebuilt
  each session and `None` between sessions.
</ResponseField>

<ResponseField name="media" type="MediaInput subclass">
  Annotate a subclass of [`MediaInput`](/deploy/runtime-reference/mediainput) to receive
  tracks from clients. Found by its type, so the attribute name is yours; `media` is the
  convention.
</ResponseField>

<ResponseField name="fps" type="float" default="30.0">
  Pin the playout rate. Leave it at the default and each chunk plays over the time its step took.
</ResponseField>

<ResponseField name="buffer_size" type="int | None" default="None">
  How many frames may sit between the model and each client. `None` accepts the runtime's own
  bound. Never applied below one emitted batch.
</ResponseField>

## Runtime handles

Two attributes the runtime binds on your instance. Read them from anywhere: a step, a command
handler, a lifecycle hook, or your own `run()`.

<ResponseField name="output" type="OutputStream">
  The handle onto playout. Change the frame rate, or cut what is queued so nothing from the old
  scene plays after a jump. See [`OutputStream`](/deploy/runtime-reference/outputstream).

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  @event(name="teleport", description="Jump to a new scene.")
  def teleport(self, scene: str) -> None:
      self.engine.load_scene(scene)
      self.output.flush()          # drop frames from the old scene
      self.output.fps = 24         # re-paces what is queued
  ```
</ResponseField>

<ResponseField name="connected" type="asyncio.Event">
  Set while at least one client is connected, cleared when the last one leaves. Await it to hold
  work back until a client is connected.

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  async def run(self) -> None:
      while True:
          await self.connected.wait()
          await self.emit(self.generate(self.state))
  ```
</ResponseField>

## Methods you write

<ResponseField name="load(config_path)" type="None">
  Runs once at startup, before any client connects. Load weights here. `config_path` is the file
  named by `runtime.config` in `reactor.yaml`, or `None` when none is configured.
</ResponseField>

<ResponseField name="process_input()" type="Any">
  Optional and `async`. Returns whatever `generate()` should receive, or raises
  [`ApplicationError`](/deploy/runtime-reference/applicationerror) to skip the step. Defaults to returning `self.state`.
</ResponseField>

<ResponseField name="generate(input)" type="Any">
  One step of inference, synchronous. Returns the result, or raises when the step is invalid for
  the model. The default `run()` calls it, so you write either this or your own `run()`.
</ResponseField>

<ResponseField name="process_output(outcome)" type="Output | None">
  Optional and `async`. Receives a [`StepOutcome`](/deploy/runtime-reference/stepoutcome) and returns the `Output` to
  stream, or `None`. Defaults to re-raising an error and otherwise calling `outcome.to_output()`.
</ResponseField>

<ResponseField name="run()" type="None">
  The loop that drives the three calls above. Override it to write your own; see
  [Controlling the loop](/deploy/development/reactor-app/step-loop#controlling-the-loop).
</ResponseField>

## Methods you call

<ResponseField name="await emit(output)" type="None">
  Put an `Output` on the tracks. Called for you by the default loop; call it yourself only from a
  hand-written `run()`.
</ResponseField>

<ResponseField name="await send(message)" type="None">
  Send a [`ModelMessage`](/deploy/runtime-reference/modelmessage) to every connected
  client.
</ResponseField>
