# Orgo API: Full Documentation > Launch cloud computers that AI agents can control and interact with. Every computer is a full Linux desktop with a browser and the standard userland, reachable over HTTP and VNC. Computers boot in under 500 ms and run continuously until you stop them. ## Use cases People use Orgo computers in three common ways: 1. **Drive a computer with a model provider.** Wire an Anthropic, OpenAI, Google, or any OpenAI-compatible model to an Orgo computer through the `/v1/chat/completions` endpoint. The model screenshots, clicks, types, and runs commands until the task is done. Useful for automating data entry, combining several tools into one interface, or driving software that doesn't expose an API. 2. **Install an agent inside the computer.** Run OpenClaw, Hermes Agent, or any other CLI agent inside the desktop so it has a continuous, persistent runtime. 3. **Run developer CLIs on a computer.** Run Claude Code, Codex, or similar agentic CLIs on a computer that stays online across sessions and is reachable from any device. ## What Orgo is not - **Not a browser.** Tools like Browserbase give an agent a browser tab. Orgo gives it a full computer, so a single machine can browse the web, save files, run code, and install desktop applications. Use a browser tool if you only need the browser. Use Orgo if you need a computer. - **Not an AI agent.** Orgo provides the computer; it does not provide the agent. Bring Claude Computer Use, OpenAI's CUA, Hermes Agent, OpenClaw, or your own loop — Orgo is what they run on. - **Not a general cloud platform.** Orgo runs one thing: persistent desktops for AI agents. That focus shapes the rest — sub-second boots, defaults tuned for computer use, and an API designed around what agents actually do. ## Base URL ``` https://www.orgo.ai/api ``` ## Authentication All requests require a Bearer token in the `Authorization` header: ``` Authorization: Bearer sk_live_your_api_key_here ``` Get a key at https://www.orgo.ai/start. ### Key scopes Every API key has one of two scopes: - **Account-wide** (default). Can access every workspace you own. - **Workspace-scoped**. Locked to a single workspace. Returns 403 on every other workspace, cannot create new workspaces, and cannot move computers between workspaces. Pick the scope when creating a key in workspace settings. When a workspace-scoped key is used outside its workspace, the response is: ```json { "error": "This API key is scoped to workspace . It cannot access workspace . Use an account-wide key, or create a key scoped to the target workspace.", "code": "workspace_scope_mismatch", "key_workspace_id": "", "target_workspace_id": "" } ``` Use workspace-scoped keys for CI, third-party integrations, and any other context where a key leak should not put every other workspace at risk. ## Resource hierarchy ``` User └── Workspaces └── Computers ``` Workspaces group related computers. Use them to separate environments (production, staging) or independent projects. `/projects` continues to work as a deprecated alias for `/workspaces`. Existing integrations that target the old path keep working. ## Status values A computer's `status` can be: - `creating`. Provisioning a fresh VM. - `starting`. Booting up. - `running`. Available and accepting commands. - `stopping`. Shutting down. - `stopped`. Powered off. Can be restarted. - `restarting`. Reboot in progress. - `suspended`. Plan limit enforcement put the computer over its allowed quota. Upgrade or delete other computers to resume. - `deleting`. Removal in progress. - `error`. Provisioning or runtime error. ## Identifiers Every computer returns: - `id`. The Orgo computer UUID. - `instance_id`. Stable identifier for the underlying compute instance. Use this to build same-origin connection URLs (`https://www.orgo.ai/desktops/{instance_id}/...`). - `fly_instance_id`. Deprecated alias for `instance_id`. Returned for backwards compatibility. --- ## Workspaces ### Create workspace ``` POST /workspaces ``` **Request body:** ```json { "name": "my-workspace" } ``` **Response:** ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "name": "my-workspace", "user_id": "...", "status": "active", "created_at": "2026-04-07T10:00:00Z" } ``` ### List workspaces ``` GET /workspaces ``` Returns workspaces owned by or shared with you. ### Get workspace ``` GET /workspaces/{id} ``` Returns the workspace and its computers. ### Delete workspace ``` DELETE /workspaces/{id} ``` Deletes the workspace and all its computers. --- ## Computers ### Create computer ``` POST /computers ``` Creates a virtual computer in a workspace. Boots in under 500 ms. **Request body:** ```json { "workspace_id": "550e8400-e29b-41d4-a716-446655440000", "name": "agent-1", "os": "linux", "ram": 4, "cpu": 1, "disk_size_gb": 8, "resolution": "1280x720x24", "auto_stop_minutes": 0 } ``` | Field | Type | Default | Notes | |---|---|---|---| | `workspace_id` | string | required | ID of parent workspace. | | `name` | string | required | Unique within the workspace. | | `os` | string | `linux` | Currently linux only. | | `ram` | int | `4` | 4, 8, 16, 32, or 64 GB. Capped by plan. | | `cpu` | int | `1` | 1, 2, 4, 8, or 16 cores. Capped by plan. | | `disk_size_gb` | int | `8` | Capped by plan. | | `resolution` | string | `1280x720x24` | `WIDTHxHEIGHTxDEPTH`. | | `auto_stop_minutes` | int | unset | Suspend after this many minutes of inactivity. Unset or `0` keeps the computer always-on. | **Response:** ```json { "id": "a3bb189e-8bf9-3888-9912-ace4e6543002", "name": "agent-1", "workspace_id": "550e8400-e29b-41d4-a716-446655440000", "os": "linux", "ram": 4, "cpu": 1, "resolution": "1280x720x24", "status": "running", "url": "https://orgo.ai/workspaces/.../computers/...", "created_at": "2026-04-07T10:35:00Z", "instance_id": "a3881618", "hostname": "www.orgo.ai", "connection_url": "https://www.orgo.ai/desktops/a3881618", "vnc_password": "a06db12a8683df96" } ``` The last four fields (`instance_id`, `hostname`, `connection_url`, `vnc_password`) are the single-call connect surface. Everything needed to open a VNC session is in this one response. No follow-up `GET /computers/{id}` or `GET /computers/{id}/vnc-password` is required. `fly_instance_id` is also returned as a deprecated alias for `instance_id`. **Optimal flow (1 control-plane call + 1 readiness probe):** ```js const r = await fetch('https://www.orgo.ai/api/computers', { method: 'POST', headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ workspace_id, name: 'agent-1' }), }); const c = await r.json(); // Poll the proxy edge until the desktop answers (typically ~300 ms with a golden snapshot). while ((await fetch(c.connection_url, { method: 'HEAD' })).status >= 500) { await new Promise(s => setTimeout(s, 100)); } // Open the full noVNC web client. window.location = c.connection_url; // Or open a raw WebSocket VNC connection: // new RFB(el, `wss://${c.hostname}/websockify?token=${c.vnc_password}`, { credentials: { password: c.vnc_password } }); ``` The `vnc_password` rotates on every restart. Do not persist it across restart cycles. Fetch fresh from the create response or `GET /computers/{id}`. ### Get computer ``` GET /computers/{id} ``` Returns the same fields as create (status, hostname, connection_url, vnc_password, etc.). ### Delete computer ``` DELETE /computers/{id} ``` ### Get VNC password ``` GET /computers/{id}/vnc-password ``` **Response:** ```json { "password": "abc123..." } ``` Used to authenticate to the computer's WebSocket APIs (terminal, audio, events, VNC). The same value is returned on `POST /computers` and `GET /computers/{id}` as `vnc_password`. Prefer those if you already have the response in hand. --- ## Computer lifecycle ### Start ``` POST /computers/{id}/start ``` ### Stop ``` POST /computers/{id}/stop ``` ### Restart ``` POST /computers/{id}/restart ``` Stops the computer then starts it again. Preserves disk state. ### Get auto-stop setting ``` GET /computers/{id}/auto-stop ``` **Response:** ```json { "auto_stop_minutes": 0, "configurable": true } ``` ### Update auto-stop setting ``` PATCH /computers/{id}/auto-stop ``` **Request body:** ```json { "auto_stop_minutes": 0 } ``` `0` keeps the computer always-on. A positive integer suspends after that many minutes of inactivity. Auto-stop is disabled by default. --- ## Computer management ### Clone ``` POST /computers/{id}/clone ``` Creates a copy with the same disk state. The new computer's name is suffixed with `(clone)`. Counts toward your plan's computer limit. **Response:** ```json { "id": "b4cc290f-9bf9-3888-9912-ace4e6543003", "name": "agent-1 (clone)", "status": "running", "instance_id": "b4cc290f" } ``` ### Resize ``` PATCH /computers/{id}/resize ``` Live-resizes a running computer. CPU and memory update via cgroups and virtio-mem hotplug. Disk expansion runs `resize2fs` in the background. **Request body** (all fields optional): ```json { "vcpus": 4, "mem_gb": 8, "disk_size_gb": 30, "bandwidth_limit_mbps": 1000 } ``` | Field | Notes | |---|---| | `vcpus` | 1, 2, 4, 8, or 16. Capped by plan. | | `mem_gb` | 4, 8, 16, 32, or 64. Capped by plan. | | `disk_size_gb` | Grow only. Shrinking is not supported. | | `bandwidth_limit_mbps` | Capped by plan. | Returns `409` if the computer is not running. ### Move to another workspace ``` PATCH /computers/{id}/move ``` **Request body:** ```json { "workspace_id": "550e8400-e29b-41d4-a716-446655440099" } ``` `project_id` is accepted as a deprecated alias for `workspace_id`. Both source and destination workspaces must be owned by you. --- ## Computer actions All actions take the computer ID in the path. The computer must be in `running` state. ### Screenshot ``` GET /computers/{id}/screenshot ``` **Response:** ```json { "image": "iVBORw0KGgoAAAANSUhEUgAA..." } ``` Base64-encoded PNG. ### Click ``` POST /computers/{id}/click ``` **Request body:** ```json { "x": 500, "y": 300, "button": "left", "double": false } ``` `button`: `left` or `right`. `double`: optional double-click. ### Drag ``` POST /computers/{id}/drag ``` **Request body:** ```json { "start_x": 100, "start_y": 100, "end_x": 500, "end_y": 400, "button": "left", "duration": 0.5 } ``` ### Type text ``` POST /computers/{id}/type ``` **Request body:** ```json { "text": "hello world" } ``` ### Press key ``` POST /computers/{id}/key ``` **Request body:** ```json { "key": "Enter" } ``` Examples: `Enter`, `Tab`, `Escape`, `ctrl+c`, `ctrl+shift+t`, `cmd+a`. ### Scroll ``` POST /computers/{id}/scroll ``` **Request body:** ```json { "direction": "down", "amount": 3 } ``` ### Wait ``` POST /computers/{id}/wait ``` **Request body:** ```json { "seconds": 2 } ``` Pauses for the given number of seconds (0-60). `duration` is accepted as a deprecated alias for `seconds`. ### Bash ``` POST /computers/{id}/bash ``` **Request body:** ```json { "command": "ls -la /home" } ``` **Response:** ```json { "stdout": "...", "stderr": "", "exit_code": 0 } ``` ### Exec (Python) ``` POST /computers/{id}/exec ``` **Request body:** ```json { "code": "print(2 + 2)", "timeout": 10 } ``` --- ## Computer-use agents The `/v1/chat/completions` endpoint is OpenAI-compatible. Add a `computer_id` field on the request body and the chosen model will run a full computer-use loop on that computer until it finishes the task or hits `max_steps`. ``` POST /v1/chat/completions ``` **Request body:** ```json { "model": "claude-sonnet-4-6", "computer_id": "a3bb189e-8bf9-3888-9912-ace4e6543002", "messages": [ { "role": "user", "content": "Open Firefox and search for the Anthropic blog" } ] } ``` Supported models: - `claude-opus-4-7` - `claude-opus-4-6` - `claude-sonnet-4-6` (default) - `claude-haiku-4-5` The dotted forms (`claude-sonnet-4.6`, etc.) are accepted as aliases for the dashed canonical names. To use a different provider (OpenAI, Google, Nous Research, etc.) directly, point that provider's SDK at an Orgo computer using the per-action endpoints (`/computers/{id}/screenshot`, `/click`, `/type`, etc.) and run your own agent loop. See the model integration guides. Pass `stream: true` to stream tokens. Pass `thread_id` to continue a previous conversation. --- ## WebSocket APIs WebSocket APIs connect directly to the computer's host, not through `orgo.ai/api`. Use the password from `GET /computers/{id}/vnc-password`. ### Terminal (interactive PTY) ``` wss://www.orgo.ai/desktops/{instance_id}/ws/terminal?token={password}&cols=80&rows=24 ``` **Client to server:** - `{"type": "input", "data": "ls\n"}` - `{"type": "resize", "cols": 120, "rows": 40}` - `{"type": "ping"}` **Server to client:** - `{"type": "output", "data": "..."}` - `{"type": "exit", "code": 0}` - `{"type": "pong"}` - `{"type": "error", "message": "..."}` ### Audio (live PCM stream) ``` wss://www.orgo.ai/desktops/{instance_id}/ws/audio?token={password} ``` Format: signed 16-bit little-endian, 24 kHz, mono. 20 ms frames (960 bytes), about 48 KB/s. The server first sends a JSON `started` frame, then binary PCM frames continuously. **Client to server:** `{"type": "stop"}`, `{"type": "ping"}`. ### Events (desktop event stream) ``` wss://www.orgo.ai/desktops/{instance_id}/ws/events?token={password} ``` Subscribe to desktop events. **Subscribe:** ```json { "type": "subscribe", "event_types": ["window_focus", "clipboard"] } ``` **Event types:** - `window_focus`. Focused window changed. - `window_open`. A new window opened. - `window_close`. A window closed. - `clipboard`. Clipboard contents changed. - `file_change`. File system change. - `screen_change`. Visible content changed. - `audio_stream_start`, `audio_stream_stop`. - `process_start`, `process_stop`. - `idle`, `active`. **Event format:** ```json { "type": "event", "event": { "type": "window_focus", "timestamp": "2026-04-07T10:35:00Z", "data": { "title": "Firefox", "pid": 1234 } } } ``` ### VNC (display) WebSocket VNC (RFB-over-WebSocket). Used by noVNC, the `orgo-vnc` React component, and any websockify-compatible client: ``` wss://www.orgo.ai/desktops/{instance_id}/ws/websockify?token={password} ``` Connection base — append `/ws/websockify`, `/ws/terminal`, or `/ws/audio`: ``` https://www.orgo.ai/desktops/{instance_id} ``` The `{password}` value comes from `GET /computers/{id}/vnc-password`. It rotates on every restart, so fetch fresh and do not hardcode. ```js // Minimal browser example. Works with any RFB client. import RFB from '@novnc/novnc'; const computer = await fetch(`https://www.orgo.ai/api/computers/${id}`, { headers: { Authorization: `Bearer ${apiKey}` } }).then(r => r.json()); const { password } = await fetch( `https://www.orgo.ai/api/computers/${id}/vnc-password`, { headers: { Authorization: `Bearer ${apiKey}` } } ).then(r => r.json()); const rfb = new RFB( document.getElementById('screen'), `wss://www.orgo.ai/desktops/${computer.instance_id}/ws/websockify?token=${encodeURIComponent(password)}`, { credentials: { password } } ); // Common knobs. rfb.viewOnly = true; // read-only. No input from client. rfb.scaleViewport = true; // Fit display to container. rfb.clipViewport = false; // No scrollbars; clip overflow. rfb.resizeSession = false; // Request guest resize to match. rfb.qualityLevel = 6; // 0 (lowest) to 9 (highest). Default 6. rfb.compressLevel = 2; // 0 (none) to 9 (max). Default 2. rfb.showDotCursor = false; // Dot fallback when remote cursor hidden. rfb.background = 'transparent'; // CSS background. ``` For React, the `orgo-vnc` package wraps this with the same options as props. See [Embed VMs](/guides/embed-vms). --- ## Streaming (RTMP) Stream a computer's display to RTMP destinations (Twitch, YouTube, or a custom server). ### Start stream ``` POST /computers/{id}/stream/start ``` **Request body:** ```json { "connection_name": "twitch-main" } ``` `connection_name` references an RTMP connection saved in your account settings. ### Get stream status ``` GET /computers/{id}/stream/status ``` ### Stop stream ``` POST /computers/{id}/stream/stop ``` --- ## Files ### Upload file ``` POST /files/upload ``` Multipart form-data: - `file`. The file. - `workspaceId`. Workspace ID (required). `projectId` is accepted as a deprecated alias. - `desktopId`. Computer ID (optional). Attaches the file to a specific computer. ### List files ``` GET /files?workspaceId={workspace_id}&desktopId={computer_id} ``` ### Export file from computer ``` POST /files/export ``` **Request body:** ```json { "desktopId": "a3bb189e-8bf9-3888-9912-ace4e6543002", "path": "/home/user/output.csv" } ``` Pulls a file from inside the computer and stores it. ### Download file ``` GET /files/download?id={file_id} ``` Returns a temporary signed download URL. ### Delete file ``` DELETE /files/delete?id={file_id} ``` --- ## Errors Errors return standard HTTP codes with a JSON body: ```json { "error": "Description of what went wrong" } ``` Common codes: - `400`. Invalid request body. - `401`. Missing or invalid API key. - `403`. Plan limit reached, or you don't own the resource. - `404`. Resource not found. - `409`. Conflict (for example, resize while not running). - `500`. Server error. When a plan limit blocks an action, the response includes an `upgradeTier` field hinting at the lowest tier that allows the action: ```json { "error": "Computer limit reached. You have 5/5 computers.", "upgradeTier": "team" } ``` --- ## Plan limits Per-computer maximums vary by plan. See https://orgo.ai/pricing for current limits and pricing. --- ## Deprecated aliases For backwards compatibility, the API accepts the following deprecated names. New clients should use the new names. | Deprecated | Use instead | Where | |---|---|---| | `/projects` | `/workspaces` | Path | | `project_id` | `workspace_id` | Request and response bodies | | `projectId` | `workspaceId` | Files endpoints | | `fly_instance_id` | `instance_id` | Computer response | Responses to `/projects/*` requests include a `Deprecation: true` header and a `Link` header pointing to the workspaces documentation. --- ## CLI The Orgo CLI gives you complete control over your cloud computers from the terminal: launch and manage workspaces and computers, open an interactive shell, run multi-turn AI agent sessions with persistent history, and pipe machine-readable output into any other tool. ### Install ```bash # macOS / Linux — installs Node 22 LTS + the CLI in one step. # Downloads official Node prebuilts directly from nodejs.org into ~/.orgo/node, # isolated from any existing Node toolchain. No sudo required. curl -fsSL https://orgo.ai/install.sh | bash # Or with an existing Node 20+ npm install -g orgo ``` The install script writes a self-contained wrapper to `~/.local/bin/orgo` that pins both the Node binary and the CLI entry path. Only `~/.local/bin` needs to be on `PATH`. ### Sign in ```bash orgo login ``` Runs a device-code OAuth flow in the browser, then saves a credential under `~/.orgo/credentials.json` (mode `0600`). Set `ORGO_PROFILE=` to use a separate identity per environment (e.g. dev vs prod). ### Commands ```text orgo Show account, workspace, recent computers orgo login / logout / whoami Account management orgo workspaces (ws) List, create, switch workspaces orgo computers (c) List, create, start, stop, restart, delete computers orgo ssh Interactive shell on a computer (WebSocket) orgo agent Multi-turn AI agent TUI (resumable sessions) orgo run "" One-shot agent run (pipe-friendly) orgo resume [id] Resume a prior agent session orgo sessions List saved agent sessions orgo api-keys Manage API keys (workspace-scoped supported) orgo billing Credits, top-ups, billing portal orgo completion --install Install bash/zsh/fish tab completion ``` Every command accepts `--json` for machine-readable output and `--help` for details. TTY detection switches to plain text + JSON when stdout isn't a terminal, so the CLI works equally well for humans and scripts. ### Create a computer ```bash # Interactive by default — prompts for workspace, name, RAM, CPU with validation. orgo computers create # Headless: pass everything as flags. orgo computers create \ --workspace my-workspace \ --name agent-1 \ --ram 4 \ --cpu 1 ``` Valid values: `--ram` in {4, 8, 16, 32, 64} GB; `--cpu` in {1, 2, 4, 8, 16}. ### SSH ```bash orgo ssh computer-name # --cwd /some/path to land elsewhere (default /root/Desktop) ``` Opens an interactive terminal session over WebSocket. Disconnect sequences mirror OpenSSH: | Sequence | Action | |----------------------------------|----------------------------------------------| | `~.` at start of line | OpenSSH-style disconnect | | `Ctrl+C` `Ctrl+C` within 800 ms | Discoverable disconnect (forgiving alt) | | `Ctrl+D` or `exit` | Standard shell exit | | Single `Ctrl+C` | Forwarded to remote (interrupts the process) | ### Agent TUI ```bash orgo agent ``` Multi-turn agent with full conversation history, live tool-call rendering, and persistent sessions. Slash commands inside the TUI: | Command | Action | |-----------------|---------------------------------------------------| | `/help` | List slash commands | | `/info` | Current computer, model, session, token usage | | `/computer` | Switch the agent to a different computer (picker) | | `/model` | Switch model — default `claude-opus-4-7` | | `/sessions` | List saved sessions | | `/resume` | Resume a prior session (picker) | | `/compact` | Summarize older turns to shrink context | | `/usage` | Token usage for this session | | `/screenshot` | Save the live screenshot and open it | | `/save ` | Set the session title | | `/clear` | Clear the on-screen log (keeps history) | | `/reset` | Start a fresh session on the same computer | | `/exit` / `/quit` | Leave the agent | Sessions auto-persist to `~/.orgo/sessions/` after every turn — Ctrl+C loses nothing. ### One-shot run (for scripts and CI) ```bash orgo run "open chrome and search for hermes" --computer agent-1 ``` Streams text, tool calls, and tool results to stdout. Add `--json` for a single structured object at the end: ```json { "text": "Chrome is open on the Google homepage...", "tool_calls": [{ "id": "toolu_...", "name": "computer", "input": { "action": "screenshot" } }], "tool_results": [{ "tool_use_id": "toolu_...", "display": "[screenshot]" }], "usage": { "prompt_tokens": 1420, "completion_tokens": 312, "total_tokens": 1732 }, "computer": { "id": "...", "name": "agent-1" } } ``` ### Resume a session ```bash orgo resume # interactive picker orgo resume <id> # direct orgo sessions # list saved sessions ``` ### API keys ```bash orgo api-keys list orgo api-keys create --name ci --workspace my-workspace orgo api-keys delete <id> ``` Keys can be scoped to a single workspace — useful for CI tokens that should only see one project's resources. ### Environment variables | Variable | Purpose | |----------------------|------------------------------------------------------------| | `ORGO_API_KEY` | Use this key directly (skips `~/.orgo/credentials.json`) | | `ORGO_API_BASE_URL` | Point at a different API host | | `ORGO_PROFILE` | Credential profile (default: `default`) | | `ORGO_JSON=1` | Force JSON output everywhere | | `ORGO_NO_COLOR=1` | Disable ANSI colors (also respects `NO_COLOR`) | ### Shell completion Bash, zsh, and fish completion scripts ship with the CLI. To enable for your current shell: ```bash orgo completion --install ``` Completion is dynamic — `orgo ssh <Tab>` queries your live computers, `orgo workspaces use <Tab>` queries your workspaces, etc. --- ## Claude Code skill For users of Claude Code, Orgo ships a drop-in [Agent Skill](https://docs.claude.com/en/docs/agents-and-tools/agent-skills/overview) — a single `SKILL.md` file that teaches Claude when and how to spin up an Orgo computer. Once installed, Claude Code discovers it automatically and triggers it on relevant prompts (browser automation, visual testing, sandboxed runs, anything that needs a real GUI). ### Install Personal install (all your Claude Code projects): ```bash mkdir -p ~/.claude/skills/computer && \ curl -fsSL https://orgo.ai/skills/computer/SKILL.md \ -o ~/.claude/skills/computer/SKILL.md ``` Project install (this repo only, can be committed for teammates): ```bash mkdir -p .claude/skills/computer && \ curl -fsSL https://orgo.ai/skills/computer/SKILL.md \ -o .claude/skills/computer/SKILL.md ``` Restart Claude Code if it's already running. ### Try it ```text spin up an orgo computer and screenshot the orgo.ai homepage open chrome on my orgo computer, sign into github, take a screenshot test how my dev server renders at https://localhost:3000 on a real browser ``` The skill follows Claude's [progressive disclosure](https://docs.claude.com/en/docs/agents-and-tools/agent-skills/overview) model: ~100 tokens of metadata at startup (so it's effectively free until triggered), then the full body loads only when one of these prompts matches. ### What's inside The skill teaches Claude: - **One-shot agent runs** — `orgo run "<prompt>" --computer <name>` with `--json` for piping. - **Interactive TUI** — `orgo agent` with persistent, resumable sessions in `~/.orgo/sessions/`. - **Shell access** — `orgo ssh <name>` with OpenSSH-style disconnect. - **Provisioning** — `orgo computers create` interactive or with flags. - **Screenshots** — both via the agent and via direct REST. - **Pricing awareness** — defaults to reusing existing computers before spinning up new ones. - **Guardrails** — explicit "when NOT to use" so Claude doesn't reach for a cloud VM when Read/Edit/Bash/curl on the user's machine would do. ### View or audit the source ```bash curl -fsSL https://orgo.ai/skills/computer/SKILL.md ``` It's plain markdown with YAML frontmatter (`name: computer`, plus a description telling Claude when to use it). MIT-licensed. ### Where it works | Surface | How to install | |---|---| | Claude Code (CLI / IDE) | Drop into `~/.claude/skills/computer/` | | claude.ai | Settings → Features → upload as a `.zip` containing the `computer/` folder | | Claude API | Upload via `/v1/skills` endpoints (workspace-shared) | Full docs: https://docs.orgo.ai/guides/skill --- ## SDK (Python) ```bash pip install orgo ``` ```python from orgo import Computer # Create or attach to a workspace, and provision a computer in one call. computer = Computer(workspace="my-workspace", name="agent-1") screenshot = computer.screenshot() computer.left_click(500, 300) computer.type("hello world") output = computer.bash("ls -la") ``` Reads `ORGO_API_KEY` from the environment. ### TypeScript The `orgo` npm package is the **CLI** as of v2.0 — it's no longer a JavaScript SDK. For programmatic access from Node or TypeScript: - **Use any OpenAI SDK** with `baseURL: 'https://www.orgo.ai/api/v1'` against `/v1/chat/completions` for computer-use agent flows (see the OpenAI-compatible endpoint section above). - **Call the REST endpoints** directly with `fetch` for low-level control over computers, screenshots, clicks, bash, etc. A first-class standalone TypeScript SDK is planned. Until then, the OpenAPI spec at <https://docs.orgo.ai/api-reference/openapi.json> is the source of truth for typed clients. --- ## Quickstart (cURL) ```bash export ORGO_API_KEY=sk_live_... # 1. Create workspace WS=$(curl -s -X POST https://www.orgo.ai/api/workspaces \ -H "Authorization: Bearer $ORGO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "my-workspace"}' | jq -r .id) # 2. Create computer CPU=$(curl -s -X POST https://www.orgo.ai/api/computers \ -H "Authorization: Bearer $ORGO_API_KEY" \ -H "Content-Type: application/json" \ -d "{\"workspace_id\": \"$WS\", \"name\": \"agent-1\"}" | jq -r .id) # 3. Take a screenshot curl -s https://www.orgo.ai/api/computers/$CPU/screenshot \ -H "Authorization: Bearer $ORGO_API_KEY" \ | jq -r .image | base64 -d > screenshot.png # 4. Click and type curl -s -X POST https://www.orgo.ai/api/computers/$CPU/click \ -H "Authorization: Bearer $ORGO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"x": 500, "y": 300}' curl -s -X POST https://www.orgo.ai/api/computers/$CPU/type \ -H "Authorization: Bearer $ORGO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"text": "hello"}' # 5. Run a bash command curl -s -X POST https://www.orgo.ai/api/computers/$CPU/bash \ -H "Authorization: Bearer $ORGO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"command": "uname -a"}' # 6. Let Claude drive the computer curl -s -X POST https://www.orgo.ai/api/v1/chat/completions \ -H "Authorization: Bearer $ORGO_API_KEY" \ -H "Content-Type: application/json" \ -d "{ \"model\": \"claude-sonnet-4-6\", \"computer_id\": \"$CPU\", \"messages\": [ {\"role\": \"user\", \"content\": \"Open Firefox and search for the Anthropic blog\"} ] }" ``` --- ## Migrating to Orgo from a VPS Orgo gives an AI agent a full Linux cloud computer to operate — desktop, browser, shell, files, and a built-in HTTP control API. This section moves [Hermes Agent](https://hermes-agent.nousresearch.com/) or [OpenClaw](https://openclaw.ai) from DigitalOcean, Fly.io, or Hetzner onto an Orgo cloud computer with memory, skills, sessions, and configuration preserved. ### Comparison Chart | | VPS (DigitalOcean / Fly.io / Hetzner) | Orgo | |---|---|---| | You manage | OS, firewall, VNC, browser, fonts, TLS, monitoring, backups | Nothing | | Time to a usable desktop | 1–3 hours of `apt install` | 1 API call, < 500 ms boot | | Shape | Headless Linux, SSH only | Linux desktop (Xfce, Firefox, VNC) + HTTP API | | Click / type / screenshot | Build with xdotool + VNC | Built in | | Shell from your laptop | `ssh user@host` | `computer.bash(...)` | | Python from your laptop | Jupyter | `computer.exec(...)` | | File transfer | `scp` / `rsync` | `/files/upload`, `/files/export` | | HTTP API access | Floating IP + DNS + TLS (your job) | `www.orgo.ai/api/desktops/{instance_id}/proxy/<path>` (your API key), automatic TLS | | Per-VM VNC, terminal, audio creds | Manual | `/vnc-password`, `/terminal`, `/audio` | | Live-resize CPU / RAM / disk | Usually a reboot | `PATCH /resize`, no reboot | | Snapshot / clone with disk state | Manual | `POST /clone` | | Uptime | You patch and restart | Continuous by default | Orgo is purpose-built for agents that operate a desktop, browser, or any app without a programmatic API (browser automation, RPA, 24/7 message gateways). Pure headless backend scripts are equally well served by a VPS. ### Agent state locations Both agents keep everything they care about in one hidden directory under `$HOME`: **Hermes Agent** state directory: `~/.hermes/` ``` ~/.hermes/ ├── .env # API keys (mode 0600 — preserve perms on restore) ├── config.yaml # configuration ├── SOUL.md # personality definition ├── sessions/ # chat history ├── memories/ # long-term memory ├── skills/ # learned + installed skills ├── cron/ # scheduled tasks ├── hooks/ # webhooks ├── pairing/ # messaging-platform pairing data (device-bound) ├── whatsapp/ # WhatsApp Web session (device-bound, re-pair) ├── logs/ # gateway + agent logs ├── image_cache/ # cached generated/received images └── audio_cache/ # cached audio ``` Binary symlinked at `~/.local/bin/hermes` (non-root) or `/usr/local/bin/hermes` (root install). Systemd user unit at `~/.config/systemd/user/hermes-gateway.service` when run as a service. **OpenClaw** state directory: `~/.openclaw/` ``` ~/.openclaw/ ├── openclaw.json # config: model provider, gateway port, etc. └── workspace/ ├── AGENTS.md # injected agent spec ├── SOUL.md # personality ├── TOOLS.md # tool spec └── skills/ └── <skill>/SKILL.md ``` Binary is the npm-installed `openclaw` on `$PATH`. Daemon registered via `openclaw onboard --install-daemon` (systemd-user on Linux, launchd on macOS). ### The five-step recipe Same shape regardless of source platform and agent. Only the file-transfer step changes. 1. **Snapshot** the agent's state directory on the source machine into a tarball. 2. **Provision** an Orgo computer sized for the agent. 3. **Transfer** the tarball into the Orgo computer. 4. **Install** the agent on the Orgo computer with the upstream installer. 5. **Restore** the tarball, start the daemon, verify. ### Recipe: Hermes Agent Stop the gateway on the source so sqlite flushes cleanly, then snapshot: ```bash # On the source machine df -h ~ # sanity-check disk room systemctl --user stop hermes-gateway 2>/dev/null || true pkill -f 'hermes gateway' 2>/dev/null || true tar czf /tmp/hermes-state.tgz -C "$HOME" .hermes ls -lh /tmp/hermes-state.tgz ``` Provision the Orgo computer via REST or the CLI: ```bash # REST curl -X POST https://www.orgo.ai/api/computers \ -H "Authorization: Bearer $ORGO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"workspace_id":"WORKSPACE_ID","name":"hermes-prod","ram":8,"cpu":4,"disk_size_gb":32}' # → save the returned id as $COMPUTER_ID # CLI orgo computers create --workspace WORKSPACE_ID --name hermes-prod --ram 8 --cpu 4 --disk 32 ``` Run shell commands in the VM via `POST /computers/{id}/bash`, or `orgo ssh hermes-prod` for an interactive terminal. Transfer the tarball (always-works path is `POST /files/upload`): ```bash curl -X POST https://www.orgo.ai/api/files/upload \ -H "Authorization: Bearer $ORGO_API_KEY" \ -F "file=@/tmp/hermes-state.tgz" \ -F "workspaceId=$WORKSPACE_ID" \ -F "desktopId=$COMPUTER_ID" ``` Install Hermes on the Orgo computer: ```python computer.bash( "curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash" ) ``` Restore state on top of the fresh skeleton and start the gateway: ```python computer.bash(""" set -e rm -rf ~/.hermes/sessions ~/.hermes/memories ~/.hermes/skills \\ ~/.hermes/whatsapp ~/.hermes/cron ~/.hermes/hooks \\ ~/.hermes/pairing ~/.hermes/image_cache ~/.hermes/audio_cache tar xzf /root/Desktop/hermes-state.tgz -C "$HOME" chmod 600 ~/.hermes/.env """) computer.bash("hermes gateway install") computer.bash("systemctl --user start hermes-gateway") ``` Verify: ```python print(computer.bash("hermes doctor")) print(computer.bash("ls ~/.hermes/sessions/ | head")) print(computer.bash("systemctl --user status hermes-gateway --no-pager")) ``` ### Recipe: OpenClaw Same shape, different state dir and installer: ```bash # On the source df -h ~ # Linux source systemctl --user stop openclaw 2>/dev/null || true # macOS source launchctl unload ~/Library/LaunchAgents/ai.openclaw.plist 2>/dev/null || true tar czf /tmp/openclaw-state.tgz -C "$HOME" .openclaw ``` ```bash # Create curl -X POST https://www.orgo.ai/api/computers \ -H "Authorization: Bearer $ORGO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"workspace_id":"WORKSPACE_ID","name":"openclaw-prod","ram":8,"cpu":4,"disk_size_gb":32}' # → save the returned id as $COMPUTER_ID # Upload tarball via /files/upload (lands at /root/Desktop/), then: curl -X POST https://www.orgo.ai/api/computers/$COMPUTER_ID/bash \ -H "Authorization: Bearer $ORGO_API_KEY" -H "Content-Type: application/json" \ -d '{"command":"curl -fsSL https://openclaw.ai/install.sh | bash"}' curl -X POST https://www.orgo.ai/api/computers/$COMPUTER_ID/bash \ -H "Authorization: Bearer $ORGO_API_KEY" -H "Content-Type: application/json" \ -d '{"command":"set -e; rm -rf ~/.openclaw; mkdir -p ~/.openclaw; tar xzf /root/Desktop/openclaw-state.tgz -C \"$HOME\"; openclaw onboard --install-daemon; openclaw gateway status"}' ``` ### Transfer methods by source platform The Orgo `/files/upload` endpoint works from any machine with network access to api.orgo.ai. Platform-specific paths below are alternatives when the source is behind NAT or direct upload from the source is preferred. **DigitalOcean** — droplets expose standard SSH: ```bash scp root@droplet.example.com:/tmp/hermes-state.tgz . curl -X POST https://www.orgo.ai/api/files/upload \ -H "Authorization: Bearer $ORGO_API_KEY" \ -F "file=@hermes-state.tgz" \ -F "workspaceId=$WORKSPACE_ID" \ -F "desktopId=$COMPUTER_ID" ``` For a consistent point-in-time copy under live traffic, take a DigitalOcean snapshot first. https://docs.digitalocean.com/products/snapshots/ **Fly.io** — Machines have no public SSH listener. They are reachable only over Fly's wireguard mesh, which `flyctl` sets up. Use `flyctl ssh sftp`: ```bash flyctl ssh console -a YOUR_APP -C "tar czf /tmp/hermes-state.tgz -C /root .hermes" flyctl ssh sftp get -a YOUR_APP /tmp/hermes-state.tgz ./hermes-state.tgz curl -X POST https://www.orgo.ai/api/files/upload \ -H "Authorization: Bearer $ORGO_API_KEY" \ -F "file=@hermes-state.tgz" \ -F "workspaceId=$WORKSPACE_ID" \ -F "desktopId=$COMPUTER_ID" ``` Snapshot the volume first if the agent uses one: `flyctl volumes snapshots create`. https://fly.io/docs/flyctl/ssh-sftp/ **Hetzner Cloud** — same shape as DigitalOcean: ```bash scp root@your-hetzner-ip:/tmp/hermes-state.tgz . curl -X POST https://www.orgo.ai/api/files/upload \ -H "Authorization: Bearer $ORGO_API_KEY" \ -F "file=@hermes-state.tgz" \ -F "workspaceId=$WORKSPACE_ID" \ -F "desktopId=$COMPUTER_ID" ``` For consistency, take a Hetzner snapshot first. https://docs.hetzner.com/cloud/servers/getting-started/back-up-snapshot/ **Any other VPS** — if you have SSH, the recipe is always: `tar` the state dir → `scp` to your laptop → upload to Orgo via `/files/upload`. If the source can reach the public internet, skip your laptop and `curl` the upload directly from the source. ### What carries over, what does not In the tarball, ready to use after restore: - LLM API keys (`~/.hermes/.env` or `~/.openclaw/openclaw.json`) - Learned skills, long-term memory, chat sessions - Slack / Discord / Telegram bot tokens (in `.env`, re-read on gateway start) - Hermes hooks and per-user cron entries inside `~/.hermes/cron/` Re-pair or re-install on the new computer: - WhatsApp Web session (device-bound — re-scan QR) - iMessage bridge (device-bound — re-link) - Systemd unit files (re-run `hermes gateway install` or `openclaw onboard --install-daemon`) - journald system logs (not migrated; application logs in `~/.hermes/logs/` do carry) - System `crontab -e` entries (only `~/.hermes/cron/` carries) - OS packages you installed by hand (the agent installers pull what they need) - Floating IPs / custom DNS — reach the desktop's API via `www.orgo.ai/api/desktops/{instance_id}/proxy/<path>` (your API key) instead ### Gotchas - **sqlite needs disk headroom.** Hermes and OpenClaw both use sqlite. `fsync` returns `EIO` (Errno 5) on a full disk. Size the computer with at least 2× the state-dir size as free disk. - **Do not leave the source live with the same bridge tokens.** Two gateways with the same Slack/Discord/Telegram bot token race for inbound messages. Stop the source first, verify on Orgo, then delete. - **`hermes setup` rewrites `.env`.** Restore *after* install. Do not re-run the wizard or it overwrites the API keys you brought over. - **Inbound webhooks don't hit the VM directly.** There's no public per-VM hostname; reach the desktop's API through the authenticated proxy (`https://www.orgo.ai/api/desktops/{instance_id}/proxy/<path>`, with your Orgo API key), or run gateways in outbound/socket mode (Slack Socket Mode, Telegram long-polling). ### Smoke test `hermes doctor` / `openclaw doctor` only confirm the binary works. To verify state truly restored, ask the agent something only it would know: ```bash curl -X POST https://www.orgo.ai/api/computers/$COMPUTER_ID/bash \ -H "Authorization: Bearer $ORGO_API_KEY" -H "Content-Type: application/json" \ -d '{"command":"hermes chat \"What did we last discuss in our previous session?\""}' # OR for OpenClaw curl -X POST https://www.orgo.ai/api/computers/$COMPUTER_ID/bash \ -H "Authorization: Bearer $ORGO_API_KEY" -H "Content-Type: application/json" \ -d '{"command":"openclaw send self \"What was our last topic?\""}' ``` A generic "I don't have past memory" reply means `~/.hermes/sessions/` (or the OpenClaw `workspace/`) didn't restore — re-check the `tar xzf` step and that you didn't extract before the install step ran. ### Troubleshooting - **Gateway won't start.** `journalctl --user -u hermes-gateway -n 80` (or `-u openclaw`). Most common: `.env` lost 0600 mode or `hermes setup` ran a second time and wiped it. Re-restore, then `chmod 600 ~/.hermes/.env`. - **sqlite locked / fsync EIO.** Check `df -h /`. If full, live-resize the disk: `curl -X PATCH https://www.orgo.ai/api/computers/$COMPUTER_ID/resize -H "Authorization: Bearer $ORGO_API_KEY" -H "Content-Type: application/json" -d '{"disk_size_gb": 64}'`. - **Bot unresponsive in Slack/Discord/Telegram.** Two gateways racing on the same token. Stop the source: `systemctl --user stop hermes-gateway` (or `openclaw`). Wait 30 s, retest. - **WhatsApp QR won't load.** Pairing is bound to the old device fingerprint. `rm -rf ~/.hermes/whatsapp && hermes whatsapp` to re-pair. - **Upload landed but file is missing.** `POST /files/upload` lands files at `/root/Desktop/<filename>`. Verify with `computer.bash("ls -lh /root/Desktop/")`. Missing → check the curl response — usually a `workspaceId` / `desktopId` mismatch. ### Rollback Keep the source machine powered on but with its gateway stopped until you're satisfied. If Orgo doesn't work: ```bash # On the source — re-enable systemctl --user start hermes-gateway # Hermes systemctl --user start openclaw # OpenClaw ``` Only delete the source after a few hours of clean operation on Orgo. ### Sizing | Workload | RAM | CPU | |---|---|---| | Single user, terminal chat | 8 GB | 4 cores | | Skills, browser tools, gateway | 16 GB | 4 to 8 cores | | Long-running flows with many tools | 32 GB+ | 8 cores | ### Full script One bash file that runs the whole Hermes migration with `curl` + `jq`. Set `ORGO_API_KEY`, `WORKSPACE_ID`, and `SOURCE_TARBALL`. ```bash #!/usr/bin/env bash set -e : "${ORGO_API_KEY:?Missing ORGO_API_KEY}" : "${WORKSPACE_ID:?Missing WORKSPACE_ID}" SOURCE_TARBALL="${SOURCE_TARBALL:-$HOME/Downloads/hermes-state.tgz}" API="https://www.orgo.ai/api" AUTH="Authorization: Bearer $ORGO_API_KEY" JSON="Content-Type: application/json" # 1. Create computer RESP=$(curl -sS -X POST "$API/computers" -H "$AUTH" -H "$JSON" \ -d "{\"workspace_id\":\"$WORKSPACE_ID\",\"name\":\"hermes-prod\",\"ram\":8,\"cpu\":4,\"disk_size_gb\":32}") COMPUTER_ID=$(echo "$RESP" | jq -r .id) HOSTNAME=$(echo "$RESP" | jq -r .hostname) echo "Created $COMPUTER_ID at https://$HOSTNAME" # 2. Upload tarball (lands at /root/Desktop/<filename>) curl -sS -X POST "$API/files/upload" -H "$AUTH" \ -F "file=@$SOURCE_TARBALL" \ -F "workspaceId=$WORKSPACE_ID" \ -F "desktopId=$COMPUTER_ID" > /dev/null # Helper: run a bash command inside the VM run() { curl -sS -X POST "$API/computers/$COMPUTER_ID/bash" -H "$AUTH" -H "$JSON" \ -d "$(jq -n --arg c "$1" '{command:$c}')" echo } # 3. Install Hermes run "curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash" # 4. Restore state on top of the fresh skeleton run 'set -e rm -rf ~/.hermes/sessions ~/.hermes/memories ~/.hermes/skills \ ~/.hermes/whatsapp ~/.hermes/cron ~/.hermes/hooks \ ~/.hermes/pairing ~/.hermes/image_cache ~/.hermes/audio_cache tar xzf /root/Desktop/hermes-state.tgz -C "$HOME" chmod 600 ~/.hermes/.env' # 5. Install + start the gateway run "hermes gateway install" run "systemctl --user start hermes-gateway" # 6. Verify run "hermes doctor" echo echo "Done. https://$HOSTNAME" ``` Swap the install URL + state-dir paths to migrate OpenClaw with the same script (replace step 3 with `curl -fsSL https://openclaw.ai/install.sh | bash`; in step 4 use `~/.openclaw` instead of `~/.hermes/...`; in step 5 use `openclaw onboard --install-daemon`). ### References - Hermes Agent docs: https://hermes-agent.nousresearch.com/docs - Hermes Agent repo: https://github.com/NousResearch/hermes-agent - OpenClaw site: https://openclaw.ai - OpenClaw repo: https://github.com/openclaw/openclaw - OpenClaw `AGENTS.md` spec: https://github.com/openclaw/openclaw/blob/main/AGENTS.md - DigitalOcean snapshots: https://docs.digitalocean.com/products/snapshots/ - Fly.io SSH and SFTP: https://fly.io/docs/flyctl/ssh-sftp/ - Fly volume snapshots: https://fly.io/docs/volumes/snapshots/ - Hetzner snapshots: https://docs.hetzner.com/cloud/servers/getting-started/back-up-snapshot/ - Orgo migration page (this section, in MDX): https://docs.orgo.ai/guides/migrate --- ## Documentation Full docs: https://docs.orgo.ai