# ArmFarm Sandbox: AGENTS.md ## Connect from the rental page Rental page: https://armfarm-dashboard.tail00b78d.ts.net:8443/sandbox/ This guide is public and can be read without signing in or running JavaScript. On the rental page, choose the hardware and start a session. An SSH key downloads automatically; the page supplies the complete connection command for your OS. Run that command on the customer's computer. All commands below run **inside SSH** unless explicitly labeled otherwise. The workspace already contains its tools and configuration; do not install packages or discover controller addresses. An agent given only the page URL can follow its AGENTS.md link. To use an existing rental, obtain the displayed SSH command and the local path to the matching key from the customer. A public URL does not carry their reservation or credentials. Keep private key contents on the customer's computer; never paste or upload them. Reading instructions does not authorize movement. For an authorized task, inspect current camera images, use bounded commands, and do not replay uncertain motion. Other rentals: [Arms](/rental/AGENTS.md), [Sandbox](/sandbox/AGENTS.md), [Cars](/cars/AGENTS.md). ## First move for a person watching the live cameras Keep the rental page's live camera visible and check clearance. Paste this one line in the SSH terminal for a 1-second move. `--watching` means you are actively watching the live feed. A new camera observation and request ID are obtained on every invocation; no JSON or observation ID needs to be copied by hand. ```sh python ~/armfarm_move.py excavator dig --seconds 1 --watching ``` For the dumptruck, with its route clear: ```sh python ~/armfarm_move.py truck forward --seconds 1 --watching ``` Stop your rented hardware: ```sh crew stop ``` This starter executes one bounded pulse, never a motion retry. It refuses stale camera evidence, paused control, unowned devices and invalid actions. An agent must inspect its own fresh images using the SDK/CLI below, rather than treating `--watching` as a substitute for vision. Read the printed receipt ID after a timeout. ## Agent workflow and tool reference Run your agent on your own computer or inside your rented SSH workspace. Give it your task, this guide, and the SSH command from the page. Keep your private SSH key and `.crew.json` token private. The public guide grants no vehicle access. ## Start here Connect with the dashboard's SSH command. In that shell: ```sh crew status excavator crew status truck crew tools crew look excavator ``` The returned image is saved in `evidence/`. Inspect it before deciding to move. Each observation permits one movement for at most 30 seconds after capture; network and queue time count toward that limit. Work one vehicle at a time: look, inspect the image, decide, pulse, then inspect a new look. If the observation expires, acquire and inspect another one. Never skip image inspection to beat the deadline or automatically pair a fresh unseen image with an old decision. The dashboard also shows overhead, arm and cockpit views and four battery cards. A battery reading's age matters: unavailable or stale data is not a fresh reading. Reading this guide does not request motion or an autonomous task. Work only on the customer's explicit objective. The sandbox contains real moving vehicles. Keep people and hands clear. Do not move from historical or stale images. ## Saved excavator poses: use these instead of guessing scoop timing `excavator_go_to` targets `scoop`, `raised` (carry), or `dump` using the saved two-camera red-tape calibration. `excavator_scoop_and_raise` runs scoop then raised. Both adjust bounded `dig` pulses from fresh images, including the existing dirt resistance response. These are visual targets, not fixed-duration macros. For agents: call `look` on `excavator`, inspect the returned image and sweep clearance, then pass that result's `observation_id` to the SDK `call` method. For `excavator_go_to`, the arguments are `{"target_pos": "raised"}` (or `scoop` or `dump`). `excavator_scoop_and_raise` takes no arguments. These are advanced agent tools; the human first-move command above requires no JSON or manual IDs. Each command returns `state: running` and its request ID. It runs on the Pi even if the SSH client disconnects. Poll `crew receipt REQUEST_ID` every couple of seconds; do not submit another movement or replay the command while running. MCP agents can poll `excavator__status`: `pose_operation` reports the same request ID, running/final state and reached target. `crew stop` or the website Stop interrupts the operation. End also revokes movement. A timeout is not permission to retry; query that exact receipt first. When complete, inspect fresh `arm_camera` and `cockpit_camera` images. `reached` does not prove retained dirt or successful delivery. Forward cycling can release a load on the way to another pose. After dumping, swing clear of the truck before changing arm position; raising over the truck can clip it. No automatic alignment is enabled by these tools. Existing primitive controls remain available. ## Build your own tools The live starter exposes `status`, `batteries`, `look`, `arm_camera`, `cockpit_camera`, `hold`, `pulse`, `excavator_go_to`, and `excavator_scoop_and_raise`. Run `crew tools` for the authoritative catalog for this deployment. Simulation may expose additional synthetic tools; they do not control hardware. You can write scripts and modules in your workspace and compose these primitives. Your code uses the same session-scoped API as the CLI and MCP adapter. It does not need root on the physical Pis or access to controller keys or GPIO sockets. ```python from pathlib import Path from rental.sandbox.client import Client crew = Client(Path.home() / '.crew.json') print(crew.status('truck')) view = crew.look('truck') print(view) # Inspect image_file before planning any movement. ``` When the user has requested motion and you have inspected a fresh `look`, one bounded primitive uses the SDK `call` method with the device, tool name `pulse`, arguments `action` and `seconds`, and that inspected result's `observation_id`. Excavator actions: `forward`, `backward`, `steer_left`, `steer_right` (up to 1s each), `dig` (2.8s), `dump` (1s), `swing_left`, `swing_right` (1.8s each). Steering turns the chassis; swing rotates the upper body. Truck actions: `forward`, `backward`, `rotate_left`, `rotate_right` (drive/turn up to 1s), `open`, `close` (bed up/down up to 1.8s). Use canonical action names shown by `crew tools`; no raw GPIO access is needed. Limits are enforced by the physical controller. Use short pulses appropriate to the observed clearance, then inspect a new image. The excavator's dig/dump mechanism is a coupled repeating cycle, not an independent bucket axis. No primitive guarantees obstacle avoidance or successful loading. Each movement requires a new observation. Commands within one vehicle serialize; different vehicles can operate concurrently. Hold the truck stationary while the excavator is over it. Coordinate through your own agent conversation and fresh camera observations. The CLI prints a request ID before motion. After a timeout, query `crew receipt REQUEST_ID`. An unknown outcome is not permission to replay it. ## Stop and finish `crew stop` or **Stop vehicles** revokes motion and requests LOW outputs while keeping the workspace open. Resume explicitly in the page and take a fresh look. If a connection problem pauses control, your workspace is retained. Use **Recover connection** on the page to confirm stopped outputs, then explicitly **Resume control**. Take and inspect a new look before moving. A connection failure is not a rental time limit; it must not be worked around by replaying a command or skipping observation. Camera and read-only status access can remain available while movement is paused. **Receipt not found** alone does not prove that a request never reached a controller; preserve its request ID and investigate. **End session** revokes tool access, confirms controller release, closes SSH and terminates the customer workspace. Save files with SFTP before End. For MCP in the workspace use `python -m rental.sandbox.mcp`. For an agent on your computer, run commands through your session's SSH command, or use the downloaded client configuration with the Python SDK. Do not assume the agent can see your browser; it must inspect returned image files itself. The initial hosted workspace has isolated network access to the sandbox API. Run model/provider tools and download third-party packages on your computer; transfer your own scripts or package wheels over SFTP when needed. ## Battery tools Use `crew call excavator batteries` or `crew call truck batteries`. Both return all four sources: `excavator`, `dumptruck`, `arm_camera`, and `cockpit_camera`. The latter two are the excavator arm and cockpit cameras; there is no separate configured dumptruck-camera battery source. These reads need no observation ID and remain available while control is paused. `crew status` also includes them. Read `battery_v`, `age_seconds`, `sampled_at`, `available`, `stale`, and `status`. Vehicle transmitters normally sample every 600 seconds; cameras every 5 seconds. An unavailable sensor returns null voltage, never zero or a guessed percentage. These are voltage measurements, not calibrated remaining time/charge estimates. Use a new request ID for a new reading; a receipt is a historical snapshot. The current SDK also exposes `crew.batteries('excavator')` / `crew.batteries('truck')` and the CLI shorthand `crew batteries excavator` / `crew batteries truck`. Older running workspaces can use the generic `crew call ... batteries` commands above without upgrading. MCP adapters expose `excavator__batteries` and `truck__batteries` as read-only tools; reload an updated adapter to refresh its catalog. Older adapters can obtain the same readings from their existing status tools without supplying an observation.