# romcp v3 API preview

Version 3 ships under the `dominus-cli` package name with romcp command aliases. The local HTTP API uses the `1-preview` contract; its version is independent of the package version.

Implemented: authenticated local HTTP API, JavaScript/TypeScript SDK, connection discovery, tree/instance/selection reads, managed playtest sessions, selected Open Cloud data-store reads, analytics queries, durable discount jobs, event creation and reads, shared MCP services, explicit Studio targeting, and structured errors. Direct product creation/updates remain MCP operations. Public profiling and scene mutations, additional Open Cloud operations, and generated OpenAPI remain later milestones. Existing MCP tools remain available.

## Run from this checkout

Build with `pnpm build`. Start a fresh bridge process with a dedicated API token; an already-running bridge does not acquire new environment settings. Use a free API port distinct from the bridge and admin UI ports. The API is disabled unless `DOMINUS_API_PORT` is set. If an explicitly enabled API cannot start, daemon startup fails rather than silently omitting it.

PowerShell:

```powershell
$env:DOMINUS_API_PORT = '18090'
$env:DOMINUS_API_TOKEN = node -e "process.stdout.write(require('node:crypto').randomBytes(32).toString('base64url'))"
node dist/bridge-daemon.js
```

The bridge uses the existing Studio pairing mechanism. The API token is separate from the bridge token and from any Roblox Open Cloud key. Keep the API token in a trusted local environment; do not put it in source control, URLs, browser code, or a Roblox script. This preview accepts non-browser clients on `127.0.0.1` only. It does not provide team hosting or per-user credential scopes.

The SDK is exported as `dominus-cli/sdk` from a locally built/packed copy of this package. The proposed separate `@dominus/sdk` name is not published. Import the SDK subpath: the package root retains its legacy MCP entry point for compatibility.

```ts
import { createClient, DominusApiError } from 'dominus-cli/sdk';

const dominus = createClient({
  baseUrl: 'http://127.0.0.1:18090/v1',
  token: process.env.DOMINUS_API_TOKEN!,
});

console.log(await dominus.capabilities());
const studios = await dominus.studios.list();
console.table(studios);

// Select an exact ID from discovery, or a previously configured target.
const studio = await dominus.studios.connect({
  connectionId: process.env.DOMINUS_CONNECTION_ID!,
});

try {
  const tree = await studio.scene.tree({
    root: { pathSegments: ['Workspace'] },
    maxDepth: 2,
    maxNodes: 200,
  });
  console.log(tree.roots, { truncated: tree.truncated });
  console.log(await studio.scene.selection());
  if (tree.roots[0]) {
    console.log(await studio.scene.inspect({ targets: [tree.roots[0].ref] }));
  }
} catch (error) {
  if (error instanceof DominusApiError) {
    console.error(error.code, error.status, error.requestId, error.message);
  } else throw error;
}
```

Node 20+ and ESM are supported. Importing the SDK starts no process, reads no credential file, and makes no network request. Calls use the configured local endpoint; redirects are rejected. A selected handle retains its connection ID even when another Studio becomes active. Each new Studio handshake receives a new random ID, including reconnects to the same place. Reconnect by discovering and explicitly selecting a new handle.

## HTTP contract

`POST /v1/cloud/analytics/read` and `client.analytics.read(input)` query aggregated metrics or check an existing pending operation. See [analytics usage and limits](V3_ANALYTICS.md).

`POST /v1/cloud/data-stores/read` and `client.dataStores.read(input)` read selected fields from one explicitly targeted entry without a Studio connection. See [data-store contracts and examples](V3_DATA_STORES.md). The server uses its configured Open Cloud key; clients supply only the separate local API token. Sanitized upstream failures use `CLOUD_ERROR` and HTTP 502.

Managed sessions use `POST /v1/studios/{connectionId}/tests/start|status|stop|context` (one action per route). Start accepts `mode`, `players`, `timeoutMs`, and optional `args`; status and stop require a UUID `runId`; context requires `{}`. These routes require the v3 plugin. The same service validates MCP and API results, including matching the requested run ID.

```ts
const context = await studio.tests.context();
if (!context.success || context.role !== 'edit') throw new Error('Select an edit connection');
const started = await studio.tests.start({ mode: 'play', timeoutMs: 120000 });
if (!started.success) throw new Error(started.error);
const status = await studio.tests.status(started.runId);
console.log(status);
```

Start installs a temporary server deadline Script. A successful response can describe a failed run: inspect `phase`, `failureReason`, and `cleanupRequired`. `ready` remains false until scenario readiness is implemented. Stop must target the matching server runtime handle, not the edit handle; `await serverStudio.tests.stop(runId)` reports `stop-requested`, and final status comes from the originating edit handle. No automatic connection discovery, polling, retry, or cancellation is performed. An HTTP timeout can leave an already-dispatched start running; inspect context before retrying. Full lifecycle limitations are documented in [playtesting progress](V3_PLAYTEST_PROGRESS.md).

Operation rejections return HTTP 200 with `data.success: false`, an `error` string, and optionally `requiresServerConnection`. Transport, authentication, input-validation, and malformed-response errors use non-2xx API error envelopes. This preserves actionable operation evidence without confusing a request failure with a completed test.

Incremental logs are available through `POST /v1/studios/{connectionId}/output` and `studio.output.read()` in the SDK. Pass `cursor`, `limit` (1–500), and optional severity `level`; results include `nextCursor`, `hasMore`, and eviction gaps. See [playtesting progress](V3_PLAYTEST_PROGRESS.md) for retention and clock semantics.

All routes require `Authorization: Bearer <API token>`. Responses include `X-Dominus-API-Version: 1-preview`, `X-Request-ID`, and `Cache-Control: no-store`. Successful bodies are `{ "data": ..., "requestId": "..." }`. Failed bodies are `{ "error": { "code": "...", "message": "..." }, "requestId": "..." }`. Preview contracts may change before v3 stability; the SDK rejects an incompatible API version.

| Route                                             | Input / result                                                                                                                                         |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `GET /v1/capabilities`                            | Implemented API operations and explicit reasons for unavailable feature families. This is the API implementation inventory, not a live profiler probe. |
| `GET /v1/studios`                                 | Connected Studio IDs, place metadata, version, and connection timestamp; excludes project rules and bridge credentials.                                |
| `POST /v1/studios/{connectionId}/scene/tree`      | Optional `root`, `maxDepth` (0–12; default 3), `maxNodes` (1–5000; default 1000). Returns roots, count, and truncation.                                |
| `POST /v1/studios/{connectionId}/scene/inspect`   | `targets` (1–20 instance refs), optional `compact` (default true). Preserves per-target success/failure results and encoded property values.           |
| `POST /v1/studios/{connectionId}/scene/selection` | Empty JSON object. Returns selected instance descriptors.                                                                                              |

POST bodies require `application/json`. Instance references contain an `instanceId` UUID or nonempty `pathSegments`. Tree depth/node limits apply to the existing Studio serializer; the included plugin fix corrects omitted-sibling truncation reporting at the node budget boundary. Rebuild/install the plugin to receive that fix.

The API limits request bodies to 32 KiB, serialized responses to 1 MiB, and concurrent authenticated requests to eight. Narrow scope after `RESPONSE_TOO_LARGE`; artifact retrieval and pagination are not implemented in this slice. Studio reads have a 15-second bridge deadline; the SDK defaults to a 20-second HTTP deadline. Timing out the HTTP caller does not cancel an already-dispatched Studio read. There are no automatic retries.

Errors include `UNAUTHORIZED`, `FORBIDDEN`, `INVALID_REQUEST`, `NOT_FOUND`, `TARGET_DISCONNECTED`, `STUDIO_ERROR`, `INVALID_RESPONSE`, `RESPONSE_TOO_LARGE`, and `BUSY`. The SDK additionally reports `TRANSPORT_ERROR`. Raw Studio failures are not copied into HTTP errors. A successful inspection envelope may still contain failed individual targets; inspect those results.

## Verification and next slice

Scheduled discounts are available through POST `/v1/cloud/discounts/list`, `/schedule`, `/cancel`, and `/resolve`, and the SDK's `client.discounts` methods. Mutations require `confirm: true`; cancellation and resolution require the current job revision. Scheduling persists work for the local bridge and checks the original price first. Listing returns 50-job pages. See [discount contracts and examples](V3_DISCOUNT_JOBS.md), including uncertain-outcome handling and local worker requirements.

Integration tests exercise real local HTTP and WebSocket connections with simulated Studio responders. They cover authentication boundaries, concurrent targeting, stale handles after reconnect, input limits, malformed payloads, selection, per-item failures, and incompatible responses. They do not establish live Studio or profiler compatibility.

Release validation includes an isolated tarball installation, CLI and SDK runtime checks, and strict TypeScript compilation of shipped SDK examples against the installed declarations. The SDK check does not execute the examples or start Studio. Repository tests, Lua suites, typechecking, formatting, and builds cover the local implementation; they do not prove the CI operating-system/Node matrix, npm publication, or live Open Cloud behavior.

Project source discovery and persistent build styles are implemented in the MCP workflows. Remaining release work includes live Studio lifecycle and renderer validation, authorized Open Cloud checks, and a tested migration/release path. Further public API expansion is deferred. Repository design documents describe the longer-term v3 roadmap.
