Quickstart
A working project in one command, starting from an empty directory or an existing one — no console, no card, no API keys to copy.
AI/LLM: this page is available in plain markdown at /docs/quickstart.md
You need Node.js 20 or later. There is no card form and no console to visit — every example below is the exact command and the exact output the CLI prints.
Provision what you need
Run it from the project root. It reads what the project already says it needs and fills in the gaps:
npx extraorbital provision .Provisioning 1 resource for .
mongo MONGODB_URI · unfilled in .env.local
✓ Created project cosmic-otter → .extraorbital.json
✓ Provisioned mongo/default (database cosmic-otter-default)
✓ Wrote 1 variable to .env.local — MONGODB_URI
→ Commented out your own MONGODB_URI so the provisioned value wins
1 resource created · no card requiredYour placeholder MONGODB_URI= was commented out, because dotenv keeps the first
definition it sees and a real credential below an empty one would never be read.
Run it again and nothing happens, which is the point:
npx extraorbital provision .
# ✓ Nothing to provision — every variable we support already has a valuePreview without changing anything with --dry-run.
Identity, with no console visit
Nothing above named a project or an account, and that is by design, not by magic:
- The machine name is generated locally, with zero setup. Every install derives a
stable label like
brave-fox-a3f2from the host and user running it (overridable withEXTRAORBITAL_MACHINE) and sends it on every request, soextraorbital listand the ledger can tell your laptop apart from a fleet of agents without you ever registering one. - The project is generated too. The first
addorprovisionin a directory with no.extraorbital.jsoninvents a name (cosmic-otter), creates it, and writes the pointer file — that's the✓ Created project …line above. - A token is the one thing that still needs a human, and only the first time. If
there is no cached credential and no
EXTRAORBITAL_TOKEN, the very first command on a machine prints this before doing anything else:
→ No identity found. Signing in…
Open https://extraorbital.dev/device and enter code B4VX-7T2Q
Opened your browser
⠋ Waiting for confirmation…Approve it once in a browser — this works over SSH and inside a container, since
only the code needs to reach a browser, not the CLI — and the command you actually
ran continues right where it left off. The token is cached in
~/.extraorbital/credentials.json at mode 0600, so every later command, on that
machine, skips this entirely.
For a container that should never see a browser, skip the wait: mint a key from
/settings/keys and export it. EXTRAORBITAL_TOKEN is checked
before any cache, so the run below prints none of the sign-in block above:
export EXTRAORBITAL_TOKEN=eo_live_…
npx extraorbital provision .There is no anonymous path: every resource still belongs to a human's account, one human approval unlocks it, and everything after that — the machine label, the project, every following provision — is autonomous.
Both commands write a fenced block to .env (or .env.local, if the project
already has one), and both are idempotent — the same address always returns the
same resource and the same credentials:
npx extraorbital add redis
npx extraorbital add redis
npx extraorbital add redisdoes exactly what this does:
npx extraorbital add rediswhich is what makes both commands safe in a boot script, a retry loop or a CI job.
How autopilot decides
extraorbital provision reads three signals, and only ever looks for the exact
variable names the catalog publishes — it cannot invent a
resource:
.env.example(or.env.sample,.env.template) — a declared contract, and the strongest signal- A variable present but unfilled in
.envor.env.local— empty, or left at a placeholder likeyour-bucketor<connection string> - The variable's exact name in your source —
process.env.MONGODB_URI,os.environ["MONGODB_URI"],os.Getenv("MONGODB_URI"), in any language
Then it subtracts everything that already holds a real value, and provisions one
resource per service that is left, at slug default. node_modules, dist,
.next, build output and lockfiles are never scanned, so a dependency mentioning
MONGODB_URI does not provision you a database. --dry-run prints the plan and the
reason for each line without changing anything:
npx extraorbital provision . --dry-runWould provision 2 resources for .
mongo MONGODB_URI · declared in .env.example
redis UPSTASH_REDIS_REST_URL +1 · used in packages/worker/src/queue.ts
Left alone: 5 variables that already have a valueUse it
The credentials are standard, so any client works unchanged:
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
const s3 = new S3Client({ region: process.env.S3_REGION });
await s3.send(
new PutObjectCommand({ Bucket: process.env.S3_BUCKET, Key: "hello.txt", Body: "hi" }),
);When a human is needed
Every resource starts on the Prototype plan's free allowance — no card, no quota request. A provision is only refused once the account is past that allowance, or already holds as many of that resource as the Prototype plan permits:
$ npx extraorbital add s3
! Your team has spent its Prototype allowance and cannot add s3. Move to a paid plan by
having a human open the link below — then you are billed only for what you use.
A human must link a payment method to continue:
https://extraorbital.dev/link/fl_8a2c91d4e7b3
Link expires in 24h · extraorbital link for a fresh URL
Exit code 3 (payment required)Only new provisioning is refused — everything already running keeps running, and every existing credential keeps working. An agent that would rather not fail at all can mint the same link ahead of time:
npx extraorbital linkOn a paid plan there is no resource ceiling: $20 a month, then only what you use, at what it costs us. The agent never sees a card.
What you can provision
| Resource | Command | Writes | Free on Prototype |
|---|---|---|---|
| MongoDB | add mongodb | MONGODB_URI | 512 MB, up to 5 |
| S3 storage | add s3 | S3_BUCKET and 4 more | 1 GB, 10K simple + 2K advanced ops/mo |
| Redis | add redis | REDIS_URL, UPSTASH_REDIS_REST_* | 256 MB, 500K commands/mo, up to 5 |
| Vector | add vector | UPSTASH_VECTOR_REST_* | 10K queries + 10K updates/day, up to 5 |
| QStash | add qstash | QSTASH_URL, QSTASH_TOKEN and 2 more | 1,000 messages/day, up to 5 |
| Auth | add authlocker | AUTHLOCKER_CLIENT_ID, AUTHLOCKER_CLIENT_SECRET, AUTHLOCKER_ISSUER | fair use; SMS on a shared ceiling |
| AI Gateway | add ai | OPENROUTER_API_KEY, OPENROUTER_BASE_URL | first $5.00 of small models |
| Git | add git | GIT_URL, GIT_USERNAME, GIT_TOKEN | 30 repositories, 100 MB each |
| Stripe | add stripe | STRIPE_SECRET_KEY, NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY | free — one shared test account |
Allowances are counted across the account rather than per resource, so five databases share one 512 MB rather than getting 512 MB each, and they last as long as the resource is used — a Prototype resource nothing has touched for 30 days is deleted, after a warning a week out. On a paid plan nothing expires, backups run, and usage costs what it costs us — see pricing for the table.
Only the two model-key services meter usage today; the rest report metered: false
rather than printing a measured-looking $0.00.
Everything above is provisioned for your project alone, with one exception: Stripe hands out test-mode keys to a single account every ExtraOrbital project shares. It is the fastest way to build a checkout flow with no human in the loop, and it is not somewhere to keep anything — read that page before you use it.
Verify it and run it unattended
See everything in the project, including resources other machines added:
npx extraorbital list cosmic-otter · 2 resources · $0.00 this month
RESOURCE STATUS CREATED BY CREATED THIS MONTH
mongo/default active brave-fox-a3f2 Aug 1 09:14 — (not metered)
s3/default active brave-fox-a3f2 Aug 1 09:16 — (not metered)Check every credential on every boot:
npx extraorbital check✓ mongo/default credentials valid (reachable in 44ms)
✓ s3/default credentials valid (reachable in 91ms)
2 of 2 healthycheck exits 0 when the whole environment is good, which makes it the ideal first
line of an agent's boot script. check --fix re-provisions anything missing and
rewrites the block.
In CI, skip the browser with a key from /settings/keys:
export EXTRAORBITAL_TOKEN=eo_live_…
npx extraorbital provision .
npx extraorbital check --quiet || npx extraorbital check --fixEvery command takes --json and exits with a distinct code, so a supervising agent
can branch without parsing text. See exit codes.
Teams, projects and multiple instances
Resources belong to a team and a project, and one project can hold several
instances of the same resource — any part you leave out defaults to default:
npx extraorbital add mongodb --team vercel
npx extraorbital add mongodb --team vercel --project skills.dev
npx extraorbital add mongodb --team vercel --project skills.dev --slug analyticsA project id may be a plain name or a domain — cosmic-otter and skills.dev are
both valid. A directory belongs to one team and project pair, written to
.extraorbital.json, which we encourage you to commit:
{
"projectId": "skills.dev",
"teamId": "team_9c1f77a2_vercel"
}Set the pair once with init, and later commands need no flags at all:
npx extraorbital init --team vercel --project skills.dev
npx extraorbital provisionPassing --team or --project that disagrees with the committed pair is an error
rather than a silent second home for your resources. If you made a mistake, move the
directory deliberately:
npx extraorbital switch --team acme --project skills.devNext
- CLI reference — every command and flag
- API reference — the REST surface behind the CLI