# Getting Started

Spawn a sandbox for your background agent on ORB Cloud. Five minutes from `curl` to running.

## 1. Get an API key

Two ways, pick one.

**Option A, sign in with GitHub (recommended for humans).** Visit [orbcloud.dev](https://orbcloud.dev) and click "Sign in with GitHub." When the page returns, copy the `orb_…` key. That's the key you use for every call below. The page also gives you a ready-to-paste prompt for your agent, paste it into Claude Code, Codex, Cursor, or any agent and it'll deploy itself.

**Option B, self-serve via email (for agents and CI).** Agents can't click buttons. Register with just an email, the response contains a working key instantly. No waitlist, no payment, no human approval.

```bash
curl -X POST https://api.orbcloud.dev/api/v1/auth/register \
  -H 'Content-Type: application/json' \
  -d '{"email":"you@example.com"}'
```

Save the `api_key`, it's an `orb_…` key. Use it as `Authorization: Bearer orb_…` on every call below.

> **Key hygiene (for agents).** Before calling `/register`, check `./.env`,
> if `ORB_API_KEY=` is already set, reuse it. Only register if no key exists
> in `.env`, in your persistent memory (CLAUDE.md, AGENTS.md, memory store),
> or (if a human is driving) in a saved prompt. After a fresh `/register`,
> append `ORB_API_KEY` to `./.env`, add `.env` to `.gitignore`, and record
> *where the key lives* in your own memory. Emails are unique, a second
> register with the same email returns 409, and without the key saved
> anywhere, the account is unrecoverable until email-OTP recovery ships.

> **Rotating keys.** If you need to rotate: `POST /v1/keys/{key_id}/rotate` with your current key, atomic swap, old key revoked, new key returned.

## 2. Create a Computer

```bash
curl -X POST https://api.orbcloud.dev/v1/computers \
  -H "Authorization: Bearer orb_YOUR_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"name":"my-agent","runtime_mb":2048,"disk_mb":4096}'
```

Save the `id`.

## 3. Write Your Agent

Your agent must be a process that stays alive and accepts work. The simplest pattern: an HTTP server that receives tasks and returns results.

**Python example (agent.py):**

```python
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
import anthropic

client = anthropic.Anthropic()

class Handler(BaseHTTPRequestHandler):
    def do_POST(self):
        body = json.loads(self.rfile.read(int(self.headers['Content-Length'])))

        # Your agent logic here, this LLM call is where ORB checkpoints
        result = client.messages.create(
            model="claude-sonnet-4-20250514",
            max_tokens=4096,
            messages=[{"role": "user", "content": body["task"]}]
        )

        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.end_headers()
        self.wfile.write(json.dumps({"result": result.content[0].text}).encode())

    def log_message(self, format, *args):
        pass

HTTPServer(("0.0.0.0", 8000), Handler).serve_forever()
```

**Node.js example (agent.js):**

```javascript
const http = require('http');
const Anthropic = require('@anthropic-ai/sdk');

const client = new Anthropic();

http.createServer(async (req, res) => {
  if (req.method === 'POST') {
    let body = '';
    req.on('data', chunk => body += chunk);
    req.on('end', async () => {
      const { task } = JSON.parse(body);

      // Your agent logic here, this LLM call is where ORB checkpoints
      const result = await client.messages.create({
        model: 'claude-sonnet-4-20250514',
        max_tokens: 4096,
        messages: [{ role: 'user', content: task }]
      });

      res.writeHead(200, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify({ result: result.content[0].text }));
    });
  }
}).listen(8000);
```

Your agent listens on a port, receives a task via POST, calls an LLM, returns the result. ORB handles the rest.

## 4. Write Your orb.toml

```toml
[agent]
name = "my-agent"
lang = "python"
entry = "agent.py"

[source]
git = "https://github.com/you/your-agent"
branch = "main"

[build]
steps = ["pip install -r requirements.txt"]
working_dir = "/agent/code"

[llm]
base_url = "https://api.anthropic.com"

[ports]
expose = [8000]
```

**[llm]** tells ORB where your agent's LLM provider lives. ORB runs a proxy that intercepts LLM calls for checkpoint optimization.

Set `base_url` to your LLM endpoint:

| Your agent uses | base_url |
|---|---|
| Anthropic (Claude) | `https://api.anthropic.com` |
| OpenAI (GPT) | `https://api.openai.com` |
| Google (Gemini) | `https://generativelanguage.googleapis.com` |
| z.ai Coding Plan | `https://api.z.ai/api/anthropic` |
| OpenRouter | `https://openrouter.ai/api` |
| Groq | `https://api.groq.com/openai` |
| Self-hosted | `https://your-server.com` |

See the full [orb.toml Reference](config-reference.md) for all options.

**[ports]** exposes your agent's HTTP server. Your agent is accessible at `https://{short-id}.orbcloud.dev`.

See the full [orb.toml Reference](config-reference.md) for all options and examples.

## 5. Upload Config

```bash
curl -X POST https://api.orbcloud.dev/v1/computers/COMPUTER_ID/config \
  -H "Authorization: Bearer orb_YOUR_KEY" \
  -H 'Content-Type: application/toml' \
  --data-binary @orb.toml
```

## 6. Build

Clones your repo and installs dependencies. Takes 1-3 minutes.

```bash
curl -m 600 -X POST https://api.orbcloud.dev/v1/computers/COMPUTER_ID/build \
  -H "Authorization: Bearer orb_YOUR_KEY"
```

## 7. Deploy

```bash
curl -X POST https://api.orbcloud.dev/v1/computers/COMPUTER_ID/agents \
  -H "Authorization: Bearer orb_YOUR_KEY" \
  -H 'Content-Type: application/json' \
  -d '{}'
```

Your agent is now running.

## 8. Send Work to Your Agent

Your agent is at `https://COMPUTER_SHORT_ID.orbcloud.dev`. Send it a task:

```bash
curl -X POST https://SHORT_ID.orbcloud.dev \
  -H 'Content-Type: application/json' \
  -d '{"task": "Review this code for security issues: ..."}'
```

The response contains your agent's result.

## 9. Debug

Terminal in the browser, a real bash shell inside your sandbox, with your agent's env already exported. Full prompt, line editing, colors, `vim`/`htop` work.

```
https://api.orbcloud.dev/terminal/COMPUTER_ID
```

Paste any of your `orb_…` API keys when prompted. See [Terminal](terminal.md) for the full feature list, keepalive guarantees, and troubleshooting.

## 10. Destroy

```bash
curl -X DELETE https://api.orbcloud.dev/v1/computers/COMPUTER_ID \
  -H "Authorization: Bearer orb_YOUR_KEY"
```

---

## What to know about persistent state

Your agent's computer persists between tasks. Build artifacts, installed packages, and files in `/agent/` survive across jobs. Your agent can handle multiple tasks without rebuilding.

Your agent automatically sleeps when idle for 2 minutes, freeing RAM while preserving full state. It wakes instantly when it receives work: an LLM response on its outbound API connection, an inbound request to its exposed port at `https://{short-id}.orbcloud.dev/...` (if you set `[ports] expose`), or a scheduled task. Reads to ORB's management API (file listings, state polls, metrics) don't wake the agent.

**Keep your working directories.** Don't delete `/agent/code`, `/agent/data`, or installed packages between jobs. Your agent reuses these across tasks, deleting them will break subsequent runs.

**Clean up temp data.** Cloned repos, downloaded files, and other task-specific data can be cleaned up between jobs to save disk. Delete what your agent created, not what ORB or the build steps set up.

**Redeploy if needed.** If your agent gets into a bad state, redeploy it:

```bash
curl -X POST https://api.orbcloud.dev/v1/computers/COMPUTER_ID/agents \
  -H "Authorization: Bearer orb_YOUR_KEY" \
  -H 'Content-Type: application/json' \
  -d '{}'
```

This starts a fresh agent process on the same computer, all installed packages and build artifacts are still there. No rebuild needed.

