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

# Reactor

> Connect to models, send commands, upload files, and download recordings with Java

`inc.reactor.sdk.Reactor` represents a client connection and its session. It implements
`AutoCloseable` and is thread-safe. Operations such as connecting and sending commands return
`CompletableFuture` values. See [Installation](/sdk-reference/java/installation) for dependencies
and a complete example, and the
[Reactor Javadoc](https://javadoc.io/doc/inc.reactor/reactor-sdk/1.0.0/inc.reactor.sdk/inc/reactor/sdk/Reactor.html)
for every overload.

The snippets below use an open `Reactor reactor`; command and media operations need a connected
session. Import SDK types from `inc.reactor.sdk`.

## Create a client

Build `ReactorOptions` with the API URL and the model's full `owner/name`, then call
`Reactor.open(options)`. Opening a client does not connect it.

| Option                                      | Meaning                                                                              |
| ------------------------------------------- | ------------------------------------------------------------------------------------ |
| `ReactorOptions.builder(apiUrl, modelName)` | API URL and model name, such as `https://api.reactor.inc` and `reactor/helios`       |
| `.jwt(token)`                               | JWT obtained from your backend                                                       |
| `.local(true)`                              | Enable local development, including accepting a local self-signed certificate        |
| `.dispatcher(dispatcher)`                   | Choose the executor for control events; defaults to a client-owned background thread |

For a local model, set the API URL to `http://localhost:8080` and `.local(true)` explicitly. For
Swing, `.dispatcher(javax.swing.SwingUtilities::invokeLater)` delivers control events on the UI
thread. Frame callbacks run separately; see [Track](/sdk-reference/java/track).

## Authentication

Use `.jwt(token)` in applications distributed to users. A trusted backend can exchange its API key
with `Reactor.fetchJwt(apiUrl, apiKey)`, which returns `CompletableFuture<String>`. That
two-argument call grants everything the key allows. To issue a scoped token, use the four-argument
overload:

```java theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
var scope = JsonValue.object()
        .putArray("models", java.util.List.of(JsonValue.of("reactor/helios")))
        .put("max_sessions", 1)
        .put("expires_after", 3600)
        .build();
String token = Reactor.fetchJwt("https://api.reactor.inc", apiKey, scope, false).join();
```

Run this exchange on your backend, where `apiKey` is held securely. See
[Authentication](/authentication) for token scope and expiry.

## Session lifecycle

| Method                             | Behavior                                                                      |
| ---------------------------------- | ----------------------------------------------------------------------------- |
| `connect()`                        | Create a session and establish the connection                                 |
| `connect(sessionId, connectionId)` | Join an existing session; pass `null` for a new connection slot               |
| `reconnect()`                      | Re-establish the connection on the same session                               |
| `disconnect()`                     | Leave the session, ending it if this client created it                        |
| `close()`                          | Release the client and settle pending operations; safe to call more than once |
| `status()`                         | Read the current `ConnectionStatus`                                           |
| `sessionId()`                      | Read an `Optional<String>` containing the current session ID                  |

Call `disconnect()` before `close()` to end a session you created. Use try-with-resources so the
client is released even on failure. A session joined by ID remains available to its owner after you
disconnect. To restore a connection on the same session, call `reconnect()` without first calling
`disconnect()`.

Receiving tracks resume after reconnect. Sending tracks must be published again before pushing
frames.

`join()` waits and wraps an asynchronous failure in `CompletionException`. Future cancellation stops
waiting for the result; it does not undo an operation already sent. See
[Errors](/sdk-reference/java/types#errors) for handling failures.

## Commands and schema

Use command names and arguments from the model's [API reference](/model-api-reference/overview).
`requestSchema()` returns the running model's schema as `CompletableFuture<JsonValue>`.

```java theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
var reply = reactor.sendCommand("set_prompt", JsonValue.object()
        .put("prompt", "a mountain landscape")
        .build()).join();
reply.ifPresent(message -> System.out.println(message.dataOrNull().toJsonString()));
```

`sendCommand(name)` sends a command with no arguments. Both overloads return
`CompletableFuture<Optional<CommandReply>>`. An empty optional means the model acknowledged the
command without returning a message; it is a successful result.

## Upload files

`uploadFile(Path)` uploads a file; `uploadBytes(byte[], name, mimeType)` uploads bytes already in
memory. Both return a `FileRef`. Pass uploaded files separately from JSON arguments, keyed by the
command's parameter name:

```java theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
var image = reactor.uploadFile(java.nio.file.Path.of("photo.jpg")).join();
reactor.sendCommand("set_image", JsonValue.object().build(),
        java.util.Map.of("image", image)).join();
```

This example requires a model with a `set_image` command accepting an `image` parameter. When a
model accepts file references inside a list or nested object, insert `FileRef.toJsonValue()` into
the JSON arguments instead. See [File uploads](/concepts/file-uploads).

## Recordings

`requestClip(durationSeconds)` requests a recent window; `requestRecording()` requests the session
recording. Each returns a `Clip` once the request is accepted. The media may not be ready yet.
`downloadClip` waits for readiness and assembles a playable file:

```java theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
var clip = reactor.requestClip(10.0).join();
var saved = reactor.downloadClip(clip, java.nio.file.Path.of("clip.mp4"),
        (done, total) -> System.out.println(done + "/" + total)).join();
System.out.println(saved.path());
```

Pass `null` instead of a progress callback if you do not need updates. An overload accepts
`readyTimeoutSeconds` before the callback: it bounds the wait beyond the clip's predicted ready
time. The default waits while the session can still produce the clip. Keep the session open until
the download completes.

Closing the client while a download is running fails its future but does not cancel the download;
the file may still arrive. See [Recordings](/concepts/recordings).

## Events

Register handlers before connecting when you need the initial lifecycle events. Each registration
returns a `Subscription`; call `close()` on it to remove the handler.

| Registration                | Payload                                              |
| --------------------------- | ---------------------------------------------------- |
| `onStatus(handler)`         | `ConnectionStatus`                                   |
| `onError(handler)`          | `ReactorException`                                   |
| `onMessage(handler)`        | Model message as `JsonValue`                         |
| `onRuntimeMessage(handler)` | Platform message as `JsonValue`                      |
| `onCapabilities(handler)`   | Session capabilities as `JsonValue`                  |
| `onSessionId(handler)`      | `Optional<String>`, empty when the session ID clears |

Control events use the configured dispatcher. Media callbacks are registered on individual
[tracks](/sdk-reference/java/track).

## Connection statistics

`getStats()` returns `CompletableFuture<Stats>` for inspecting the connection. Use
`setBitrate(minBps, startBps, maxBps)` to set connection bitrate bounds in bits per second; a
negative value leaves that bound unset. See the
[Stats Javadoc](https://javadoc.io/doc/inc.reactor/reactor-sdk/1.0.0/inc.reactor.sdk/inc/reactor/sdk/Stats.html)
for available measurements.
