# CLI reference

> Every extraorbital command — provision, add, list, check, remove, switch, ledger, link.

Run ad hoc with `npx extraorbital`, or install with `npm i -g extraorbital` (aliased
to `eo`). Node 20 or later, and no runtime dependencies. Examples below use the `npx`
form; if you installed it, drop the prefix.

**No sign-in is required to start.** The first run registers the machine with a
keypair and provisions against an account of its own on the Prototype plan — no
browser, no approval. A human is needed only when the allowance runs out and
somebody has to pay, at which point they take ownership of that account. Run
[`login`](#extraorbital-login) if you would rather the resources belong to you from
the outset.

Credentials live in `~/.extraorbital/`: the machine keypair in `machine.json`, a
human session in `credentials.json`, both at mode `0600` inside a `0700` directory,
and the CLI refuses to use either if the permissions are looser. The team and
project a directory belongs to live in `.extraorbital.json`, which is a pointer
rather than a secret and is safe to commit:

```json title=".extraorbital.json"
{
  "projectId": "skills.dev",
  "teamId": "team_9c1f77a2_vercel",
  "server": "https://extraorbital.dev"
}
```

## Commands

| Command | Does |
| --- | --- |
| [`provision [dir]`](#extraorbital-provision) | Provision everything the project needs and is missing |
| [`add <resource> [dir]`](#extraorbital-add) | Provision one named resource |
| [`list`](#extraorbital-list) | Every resource in the project |
| [`check [dir]`](#extraorbital-check) | Verify each fenced block against a live resource |
| [`remove <resource> [dir]`](#extraorbital-remove) | Deprovision and delete its block |
| [`init [name] [dir]`](#extraorbital-init) | Set the team and project pair up front |
| [`switch [dir]`](#extraorbital-switch) | Point this directory at another team or project |
| [`login`](#extraorbital-login) · [`whoami`](#extraorbital-whoami) | Identity |
| [`projects`](#extraorbital-projects) · [`teams`](#extraorbital-teams) | Manage what resources belong to |
| [`ledger`](#extraorbital-ledger) · [`link`](#extraorbital-link) · [`open`](#extraorbital-open) | Spend, billing, dashboard |

## extraorbital provision

Reads the directory, works out which supported variables have no value yet, and
provisions exactly those. Idempotent: a second run provisions nothing.

```bash
npx extraorbital provision [dir] [--dry-run] [--yes] [--no-env]
```

```txt
Provisioning 2 resources for .

  mongo  MONGODB_URI · declared in .env.example
  s3     S3_BUCKET +4 · used in src/upload.ts

✓ Provisioned mongo/default (database skills-dev-703c90-default)
✓ Wrote 1 variable to .env — MONGODB_URI

✓ Provisioned s3/default (bucket skills-dev-703c90-default, us-east-1)
✓ Wrote 5 variables to .env

2 resources created · no card required
```

Nothing there asked for payment, and nothing will until the account passes its
free allowance — see [pricing](/pricing).

| Flag | Default | Description |
| --- | --- | --- |
| `[dir]` | `.` | Directory to read and write in |
| `--dry-run` | off | Print the plan and the reason for each line, change nothing |
| `--yes`, `-y` | off | Skip the confirmation prompt at an interactive terminal |
| `--no-env` | off | Print credentials to stdout, write nothing |

The three signals it reads, and what it skips, are in
[how autopilot decides](/docs/quickstart#how-autopilot-decides). It never prompts when
stdin is not a terminal, so an agent or a CI job runs it unattended.

Everything is provisioned at slug `default`. A second instance is a deliberate `add`.

## extraorbital add

Provisions one resource and writes its credentials. Idempotent on
`(team, project, service, slug)`, so it is safe in a loop, a retry or on every boot.

```bash
npx extraorbital add <resource> [dir] [--slug <name>] [--team <slug>] [--project <id>] [options]
```

| Flag | Default | Description |
| --- | --- | --- |
| `<resource>` | — | `s3`, `mongo` (or `mongodb`), `redis`, `vector`, `qstash`, `authlocker` (or `auth`), `ai` (the [AI Gateway](/docs/resources/ai-gateway)), `git`, `stripe` |
| `[dir]` | `.` | Directory to write in |
| `--slug` | `default` | A named second instance in the same project |
| `--team` | from `.extraorbital.json` | Refused when it disagrees with a pinned pair |
| `--project` | from `.extraorbital.json` | Refused when it disagrees with a pinned pair |
| `--no-env` | off | Print credentials to stdout, write nothing |

Resource options come from the server's catalog rather than being hardcoded, so a new
service needs no CLI release: `--region`, `--public`, `--dimensions`,
`--embedding-model`, `--similarity-function`, `--max-budget`, `--model-tier`.
Amounts are in dollars, so `--max-budget 10` is ten dollars. Each is documented
on its resource page.

Running it twice is not an error:

```txt
→ s3/default already exists — returned existing credentials
→ .env unchanged
```

## extraorbital list

Every resource in the project, including ones other machines provisioned. Aliased to
`ls`.

```bash
npx extraorbital list [--all] [--project <id>] [--json]
```

```txt
  skills.dev · 4 resources · $4.99 this month

  RESOURCE         STATUS  CREATED BY         CREATED       THIS MONTH
  s3/default       active  brave-fox-a3f2     Aug 1 09:14   —            (not metered)
  mongo/analytics  active  brave-fox-a3f2     Aug 1 09:20   —            (not metered)
  redis/default    active  steady-crane-77e1  Aug 2 14:41   —            (not metered)
  openrouter/default  active  brave-fox-a3f2  Aug 3 11:02   $4.99        (budget $10.00)
```

## extraorbital check

Verifies that every fenced block in `.env` and `.env.local` maps to a live resource
whose credentials still authenticate. Exit `0` means the whole environment is good,
which makes it the ideal first line of an agent's boot script.

```bash
npx extraorbital check [dir] [--fix] [--quiet] [--json]
```

```txt
✓ s3/default       credentials valid (reachable in 91ms)
✓ mongo/analytics  credentials valid (reachable in 142ms)
✗ redis/default    resource removed on Jul 28

  Fix with: extraorbital add redis --slug default

2 of 3 healthy · exit code 1
```

`--fix` re-provisions what is missing and rewrites the block in the file it came from.

## extraorbital remove

Deprovisions a resource and deletes its fenced block. Stateful resources keep data
recoverable for seven days. Aliased to `rm`, and requires `--yes` when stdin is not a
terminal.

```bash
npx extraorbital remove <resource>/<slug> [dir] [--yes] [--force]
```

```txt
✓ Removed mongo/analytics (recoverable until Aug 12)
✓ Removed MONGODB_URI block from .env
```

## extraorbital init

Sets the team and project pair once, so later commands take no flags. Optional:
`provision` and `add` create a project when there is none.

```bash
npx extraorbital init [name] [dir] [--team <slug>] [--label <label>]
```

```bash
npx extraorbital init --team vercel --project skills.dev
npx extraorbital init scraper-prod
```

## extraorbital switch

Points this directory at another team or project, and the only way to change the
pinned pair. Any flag you leave out keeps its current value.

```bash
npx extraorbital switch [dir] [--team <slug>] [--project <id>] [--create]
```

```bash
npx extraorbital switch --team acme
npx extraorbital switch --project skills.dev
npx extraorbital switch --project brand-new --create
```

Existing resources stay where they are: `switch` changes what this directory points
at, not what a resource belongs to.

## extraorbital login

Signs a **human** in, with a device-code flow that works over SSH and inside
containers. It is never implicit: a command that needs an identity and has none
registers the machine instead, so an agent is never blocked waiting for a browser.
Use this when you want the resources to belong to your account rather than to the
machine's — or `--login` on any command to do it in one step.

```bash
npx extraorbital login [--token <token>] [--no-browser] [--logout]
```

```txt
  Open https://extraorbital.dev/device and enter code HXKD-9F2A

⠋ Waiting for confirmation…
✓ Signed in as severin
  Token cached in ~/.extraorbital/credentials.json
```

| Flag | Description |
| --- | --- |
| `--token <token>` | Skip the browser and use a token directly. For CI. Also read from `EXTRAORBITAL_TOKEN` |
| `--no-browser` | Print the URL instead of opening a browser |
| `--logout` | Delete the cached credentials |

## extraorbital whoami

```txt
  user       severin
  namespace  swift-heron-9c1f
  machine    brave-fox-a3f2
  team       vercel (owner)
  project    skills.dev (.extraorbital.json)
  plan       prototype · no human linked
  token      expires in 6d
```

## extraorbital projects

```bash
npx extraorbital projects                  # list
npx extraorbital projects new <name>       # create without pointing at it
npx extraorbital projects rm <name> --yes  # delete; refuses while resources remain
```

Use [`switch --project`](#extraorbital-switch) to point a directory at one.

## extraorbital teams

Everyone has a default team; these exist for when you want more than one, or want to
share resources with a person or a fleet.

```bash
npx extraorbital teams                          # list
npx extraorbital teams new <slug> [--name "…"]  # create
npx extraorbital teams members [--team <slug>]  # who is in it
npx extraorbital teams add-member <email> [--role admin|member]
```

```txt
  TEAM           ROLE   MEMBERS  PROJECTS  RESOURCES  THIS MONTH  CREATED
▸ default        owner  1        3         5          $5.40       Aug 1
  scraper-fleet  owner  3        1         2          $0.41       Aug 4

  ▸ current team · extraorbital switch --team <slug> to move this directory
```

## extraorbital ledger

Spend, in the terminal, with graphs. Defaults to the current month grouped by project.
Aliased to `usage`. Bars are block characters so they paste cleanly into an issue; a
non-TTY gets a plain table.

```bash
npx extraorbital ledger [--group-by <dim>] [--month <yyyy-mm>] [--items] [--csv|--json]
```

```txt
  August 2026 · namespace swift-heron-9c1f

  $5.40 this month   $0.19/day avg · projected $5.89

  skills.dev     ████████████████████████████ $4.99
  lunar-moth     ██                           $0.41
                 └─────────────────────────────────┘
                 $0                              $5

  DAILY  Aug 1 ──────────────────────────── Aug 14
         ▁▃▂▅▇▆▄▃▅█▆▄▃▂▄▅▇█▆▅▃▂▁▂▃▅▆▇█▆▄▂

Prototype allowance covers $5.00 of this · $0.40 billable · extraorbital link
```

| Flag | Default | Description |
| --- | --- | --- |
| `--group-by <dim>` | `project` | `project`, `resource`, `service`, `machine`, `day`, `metric` |
| `--month <yyyy-mm>` | current | Billing month |
| `--from` / `--to` | — | Explicit ISO range, overrides `--month` |
| `--project`, `--resource` | all | Filters |
| `--items` | off | Line items instead of an aggregate |
| `--csv` / `--json` | — | Export formats |
| `--no-graph` | off | Plain table. Implied when stdout is not a TTY |

## extraorbital link

Prints the URL a human opens to move the team to a paid plan, lifting every free
ceiling.
The agent never sees or handles payment details. See
[When a human is needed](/docs/quickstart#when-a-human-is-needed).

```bash
npx extraorbital link
# → https://extraorbital.dev/link/fl_8a2c91d4e7b3
```

## extraorbital open

Opens the dashboard, deep-linked to where you are.

```bash
npx extraorbital open         # the current project
npx extraorbital open ledger  # /spend
npx extraorbital open project lunar-moth
npx extraorbital open resource s3/default
```

## Global flags and environment

| Flag | Env | Default |
| --- | --- | --- |
| `--server <url>` | `EXTRAORBITAL_SERVER_URL` | `https://extraorbital.dev` |
| `--token <token>` | `EXTRAORBITAL_TOKEN` | cached credentials |
| `--team <slug>` | `EXTRAORBITAL_TEAM` | from `.extraorbital.json` |
| `--project <id>` | `EXTRAORBITAL_PROJECT_ID` | from `.extraorbital.json` |
| `--env-file <path>` | `EXTRAORBITAL_ENV_FILE` | `.env.local` if it exists, else `.env` |
| `--json` | — | Machine-readable output on stdout, logs on stderr |
| `--quiet` / `--verbose` | — | normal |
| `--no-color` | `NO_COLOR` | colour when a TTY |
| `--login` | — | Sign a human in first, instead of using this machine |
| `--no-login` | — | Exit 4 rather than registering this machine |

Reads look at both `.env` and `.env.local`; writes go to one file. A project that has
a `.env.local` gets its credentials there, because it has already decided that is
where secrets live.

## Exit codes

Distinct codes so a supervising agent can branch without parsing text.

| Code | Meaning | The agent should |
| --- | --- | --- |
| `0` | Success | Continue |
| `1` | Generic failure, or `check` failed | Read stderr; likely re-run with `--fix` |
| `2` | Usage error, including a pinned-pair conflict | Fix the command; do not retry as-is |
| `3` | Payment required | Surface the link URL to a human and wait |
| `4` | Not authenticated, with `--no-login` set | Supply a token, or drop the flag and let the machine register |
| `5` | Provisioning in progress | Retry with backoff; another worker holds the lease |
| `6` | Rate limited | Respect `Retry-After` |
| `7` | Upstream provider failure | Retry; the resource is left retryable |

## Agents and CI

Non-interactive by construction: pass a token, get JSON, branch on exit codes.

```bash title="boot.sh"
#!/usr/bin/env bash
set -euo pipefail

# Idempotent: provisions on first boot, no-ops afterwards.
npx extraorbital provision .
npx extraorbital check --quiet || npx extraorbital check --fix
```

```bash
npx extraorbital provision --json | jq -r '.provisioned[].resource'
# mongo/default
# s3/default
```

---

More for agents: [Docs index](https://extraorbital.dev/sitemap.md) · [llms.txt](https://extraorbital.dev/llms.txt) · [agents.md](https://extraorbital.dev/agents.md)
