# Run a local robot room

Actuator Science is building a physical experimentation API for agents. This
guide runs its existing room/booking implementation in local software simulation.
Experiment-oriented capability requests, monetary owner approval and physical
scene guarantees remain planned; use only the documented current endpoints.
[Product direction](../../README.md) and [API status](ROOM_API.md).

Run these commands from `physical-ai-lab/` using Python 3.11+. Use an existing
compatible environment where possible; no Apple simulator is involved.

```sh
python -m venv .venv
.venv/bin/python -m pip install -e '.[dev,mujoco,mcp]'
.venv/bin/python -m pytest -q tests/test_mcp_room_profile.py tests/test_workshop_robot_starter_service.py
```

Dependencies alone do not admit a native execution profile. Qualify the intended
host before preparing a room. Output directories must be fresh; keep old attempts.

## Local customer workspace

An operator can prepare an owner account and a default workspace. Passwords are
entered twice at the private terminal prompt, never in command arguments:

```sh
.venv/bin/physical-lab access --db .pal/control.sqlite3 create-owner \
  --email owner@example.test --name 'Local owner'
.venv/bin/physical-lab serve --db .pal/control.sqlite3 --host 127.0.0.1 --port 8000
```

Open `http://127.0.0.1:8000/console` on that computer. Sign in, create a project,
then create a named project key for your client. Save its secret privately when
shown; subsequent listings contain metadata only. A new workspace has zero
development credits. An operator may explicitly supply `--credits N` at creation,
or use `--workspace-id prj_…` to attach an existing unowned tenant without changing
its credits, projects or legacy credentials. Use the exact same database as the
room/API/worker when attaching existing room capacity.

For local recovery, run `physical-lab access --db PATH reset-password --email
ADDRESS`. Reset revokes browser sessions. Revoke separate API keys explicitly in
the console. Sessions expire after one hour or 15 idle minutes. Owner sign-in is
limited to loopback; public signup and hosted authentication are separate work.
There is no customer payment or credit-grant control.

The [workspace API](ROOM_API.md#workspace-and-access) supports the same project
and key operations for authorized agents. Existing booked-room credentials and
the twelve default MCP tools retain their meaning.

## Explore and book an experiment

Once inventory and its native profiles are admitted, an operator can explicitly
publish a reviewed scene/configuration for local customers. Use the same database,
room and matching owned quote used for registration:

```sh
.venv/bin/physical-lab farm --db PATH publish-configuration \
  --owner prj_OWNER --room-id room_ID --quote-id quote_ID \
  --name 'Reviewed experiment setup' --capability workshop.robot-live.run@4 \
  --share-scene
```

Replace the IDs and capability with actual admitted records. `--share-scene`
attests rights to share the scene, objects, cameras and criteria. Existing rooms
and private customer scenes are not automatically published. No customer may
publish operator inventory or bypass a missing/current qualification. Supported
setup adapters are qualified SO-100 capture/session, paused NexArm and continuous
NexArm; each requires its own existing profile. Prefer the protected continuous
NexArm capability `workshop.nexarm-continuous.run@2` for that room type.

In `/console`, select a project under **Explore rooms**, inspect a published
configuration and save an experiment with explicit wall time, command count and
development-credit cap. Saving creates a project revision/template and starts
no compute. **Review quote** prepares the declared state and checks a finite
window; **Hold this window** provisionally excludes capacity; **Confirm booking**
uses the existing credit reservation/job transaction. The USD price is a preview;
taxes are uncalculated and no payment is collected. A quote that exceeds the cap
is rejected; the application never raises that cap automatically.

Leave the scheduled start blank for a start one minute after quoting, allowing
time to review and confirm, or choose a future start. Start time is advisory;
occupied/quarantined capacity and missing workers can delay or prevent dispatch. Paused generations retain their existing
two-hour authorization limit. Continuous runs start fresh and inherit no other
customer's checkpoint. Existing incompatible private generations require an
explicit reset through the retained state API; the console never resets silently.

Connect/inspect the booking to see original native images, clocks and measured
joint state. Numeric targets send one explicit 50 ms row through the existing
command interface. **Close and save** requests completion; inspect actual
publication or failure before downloading the original result bundle. Reconnect
to the same booking. For a lost mutation response, **Retry original request**
retains its body/key/deadline; after reload inspect saved holds/bookings before
starting replacement work. Passive image polling does not renew idle sign-in.

Agents use the same [HTTP/SDK operations](ROOM_API.md#room-exploration-and-saved-experiments).
Set `PAL_MCP_TOOL_PROFILE=onboarding` explicitly for room/project setup and calendar
tools in addition to booked-room controls. The default `room` profile remains the
same twelve tools. Neither profile grants credits or physical hardware access.

## Inspect usage and download results

In `/console`, open **Usage / results**. Select a project and filter by execution
status, room, API key and UTC date. Daily activity and the CSV use the same
creation-date cohort and current settlement. Balance cards refresh from
server snapshots; passive polling does not keep an idle owner signed in.

**Inspect result** separates execution/publication, original task criteria and
credit charges. Inputs, measurements, original native pixels, provenance and
stop/recovery records remain inspectable after the allocation ends. Unfinished
SO-100 criteria remain provisional; a failed job does not become task success.
Use **Prepare verified download**, then download the original bundle. An
ambiguous preparation can be retried against the same run without duplicate
copies. The current copy adapter supports the five booked-room capabilities.

An authorized `WorkshopClient` offers the same flow:

```python
history = workshop.usage(project_id, {"status": "succeeded", "limit": 25})
detail = workshop.result_detail(project_id, job_id)
copy = workshop.prepare_result_export(project_id, job_id)
original_bytes = workshop.download_result_export(project_id, copy["id"])
with open("original-result.json", "xb") as stream:
    stream.write(original_bytes)
```

The SDK verifies exact bytes, project/job/input binding and original manifests.
For independent offline verification, copy the packaged
`physical_ai_lab/workshop/results/reader.py` beside the download and run:

```sh
python -I -S reader.py original-result.json --expected-sha256 STORED_EXPORT_SHA256
```

Use the metadata's actual SHA-256. No simulator, account or service connection
is needed for this reader. It verifies integrity, not a publisher signature or
hardware accuracy. Keep the original bundle, including upstream provenance.

Delivery copies are capped at 64 MiB each, 256 MiB per workspace and 1 GiB
globally, with finite metadata quotas. Larger copies are rejected without
changing originals; existing recording limits still apply. Ordinary local
copies have no automatic expiry. Hosted retention and summary deletion are not
activated. See [the exact API and policies](ROOM_API.md#usage-result-detail-and-verified-delivery-copies).

Only a local operator may create an explicitly disposable retention fixture:

```sh
.venv/bin/python -m physical_ai_lab.workshop.results.cli --db DISPOSABLE_DB \
  --owner prj_OWNER --project wpr_PROJECT create-fixture --job job_JOB \
  --attest-task-owned-disposable
```

Use actual IDs from a task-owned disposable database. `inspect --export wexp_ID`
shows the absolute seven-day deadline and pins. After that deadline,
`expire-fixture --export wexp_ID --expected-version N --expected-sha256 SHA`
removes only eligible fixture-copy bytes transactionally and preserves its
identity/charge reference. Active dependencies block expiry. This is an explicit
fixture rehearsal, not a cleanup command for `.pal`, local recordings, checkpoints
or prior evidence. No recurring deletion process is installed.

## SO-100 room with browser, HTTP and MCP

Qualify the base/capture profiles and the current one-booking session profile:

```sh
.venv/bin/python scripts/qualify_workshop_robot_capture.py \
  --out .pal/local-room/capture
.venv/bin/python scripts/qualify_workshop_robot_session.py \
  --base-profile .pal/local-room/capture/base-live/profile.json \
  --capture-profile .pal/local-room/capture/profile.json \
  --out .pal/local-room/session
.venv/bin/python scripts/prepare_workshop_robot_session_demo.py \
  --base-profile .pal/local-room/capture/base-live/profile.json \
  --capture-profile .pal/local-room/capture/profile.json \
  --profile .pal/local-room/session/profile.json \
  --out .pal/local-room/demo --api-url http://127.0.0.1:8827
```

Choose a free port. Preparation creates a private database, room, capacity-one
pool and credentials; it starts no booking or native process. Run the API and
worker commands in `.pal/local-room/demo/commands.txt` in separate terminals.
They include the exact profile flags and database/pool paths. Open the private
browser URL in `private-access.json`, inspect the room, and confirm a calendar
booking only when the client is ready. Keep that file and its token private.

The browser uses the same quote, booking and job authority as HTTP/MCP. Supply
the confirmed booking and token to the [starter client](TRY_A_ROBOT_ROOM.md).
An existing booking needs no new quote or replacement job merely to reconnect.

The scripted plan in the prepared directory is an explicit example controller.
For an independent agent trial, give the agent the task and observations and let
it author targets. Keep the distinction in the reported result.

## NexArm pair and continuous customer SDK

NexArm requires separately obtained, reviewed vendor assets; they are not
redistributed by this repository. The adapter checks the source identity.
Use [room types](ROOM_TYPES.md) to choose the paused pair or continuous room.
The [SDK guide](ROBOT_CUSTOMER_SDK.md) includes configuration, profile-qualified
setup and installed-client reproduction commands. Native qualification runners
are `scripts/qualify_nexarm_room.py` and `scripts/qualify_nexarm_continuous.py`.
Pass `--help` for their asset and output parameters.

## MCP server

Install the MCP extra, set `PAL_API_URL` to the local API and supply the existing
project credential in `PAL_API_KEY` through a local secret mechanism. Start:

```sh
.venv/bin/python -m physical_ai_lab.mcp_server
```

The default `room` profile exposes 12 booked-room operations. It does not create
an account or booking. Set `PAL_MCP_TOOL_PROFILE=full` explicitly when operating
the broader retained catalog. [Tool and HTTP mapping](ROOM_API.md).

## Verify changes

```sh
.venv/bin/python -m pytest -q
.venv/bin/python scripts/audit_repository.py --out evidence/repository-audit.json
```

Run the relevant genuine native qualification and complete API/worker/client
proof for any changed execution path. Unit tests alone do not admit a profile.
The audit reports static dependencies and counts; it cannot authorize deletion
of modules, dynamic dependencies, assets or saved versions.
