Skip to main content
About five minutes, no account, and nothing graded.
Three steps, and they are the same three every time you use Pome: start a twin, let your agent work in it, then read what the twin wrote down. It all runs on your own machine. Introduction defines the words this page uses.

Before you start

  • Node 24+ for npx, plus curl and jq for the transcripts below.
  • Your own coding agent — anything that runs a shell command and reads JSON.
That is the whole list: no Pome account, no vendor account, no ANTHROPIC_API_KEY, and no model inference paid for by Pome. Your own agent is both the operator and the actor here. Every output block below is pasted from a real run against a local twin. Two edits are disclosed: bearer tokens are cut short, and the start-up transcripts drop the closing health-check and Ctrl-C lines.
Nothing on this page is graded. No task file, no criteria, no score — and no agent eval is charged, because an eval is only ever burned when a run is graded. A sandbox you start, drive and stop costs you nothing. Grading appears exactly once in this curriculum, at the graded capstone, where the agent under test is sealed off from the criteria that judge it.
One prompt, and your agent does every step below: starts the twin, works in it, and reads back what the twin recorded. The three steps after this are the same run, one beat at a time, with you at the keyboard.
Swap github for slack, stripe, gmail or linear to get one of the other worlds; the work in beat 3 is then that twin’s, and your agent can read what it holds before deciding.Your agent’s wording will differ from anything printed on this page. The tape will not — so when it finishes, read that back yourself with the command under Read the tape. That read is the only account of the run your agent did not write.
1

Start your twin

The twin runs in the foreground and prints the two values every later call needs: the URL it is listening on, and the bearer. Ctrl-C stops it.
The world is one repository, acme/api, holding one open bug report — issue #1, labelled bug, unassigned, no comments.
Starting it also writes .pome/twin-status.json in the folder you ran it from, holding that same URL and bearer as rest_url and auth_token. Everything below reads the twin’s address out of that file rather than asking you to copy a 187-character token out of a wrapped terminal. It is one file per folder, so a second twin started here replaces it.
One token opens a twin: POME_AUTH_TOKEN. It is the bearer on every call, REST and MCP alike, and twin start printed it on the line after the URL. The POME_GMAIL_TOKEN and POME_LINEAR_TOKEN lines are that same token again under a twin-named alias, and a github_pat_… or sk_test_… served inside a twin is data in the world, not a way into it.
A local twin has no proxy in front of it, so a wrong bearer gets you the vendor’s own refusal. GitHub answers 401 Bad credentials, and that is the twin reproducing GitHub, not Pome reporting an error.Hosted is where that changes. pome sandbox create puts a routing proxy in front, and a bad bearer there comes back as an opaque404 No twin pod for this session. So a 404 on a sandbox you have just created is almost always the wrong bearer rather than a dead sandbox.
2

Paste this

Hand your coding agent the matching prompt as it is, from the folder you started the twin in. The prompts name .pome/twin-status.json rather than a $POME_GITHUB_REST_URL, because nothing expands a shell variable inside a chat message — a prompt that reads the file works whatever port the twin took.Every prompt has the same shape: read the world, do one real piece of work in it, then read the result back through the twin rather than from memory of what was sent. That last step is the one that matters, and it is the one agents skip.
3

Read the tape

Your agent has just told you what it did. Here is the twin’s account of the same run, written down as it happened by the other party — the one thing on this page your agent did not produce. Read it yourself, in a terminal in the folder you started the twin from: the first two lines take the address out of the status file, so any fresh terminal there works. Recorded paths carry the /s/standalone prefix.
Five rows, in the order they happened: it looked, it wrote twice, it checked. Here is the second row cut to five fields with jq '.[1] | {method, status, tool, state_mutation, fidelity}' — the full row also records the request and response bodies, latency and a state_delta:
The twin stamps its action vocabulary on the row whether the call came over REST or MCP, so the same work reads the same either way. state_mutation: true means the call landed — a refused write reads false. No tool on the assignees row: only a short list of GitHub actions is stamped by name today.
Ctrl-C stops the twin. Start it again and the world is back to the state it declares, which is what makes anything you just saw repeatable instead of an anecdote.

What you could assert here

Nothing here was graded, but the tape and final state you just read are exactly what a graded check reads. You would not have to write the checks either: each twin declares its own, and pome checks <twin> prints them locally and for free with what each one compares. Write a task is where the grammar lives. Two per twin:
  • github.tool-was-called catches an agent that reports triaging the bug without ever writing the comment. It reads the tape, so doing nothing fails rather than scoring free points.
  • github.no-new-issues catches an agent that “handles” the report by opening a second issue. It compares issue numbers, so a duplicate carrying the same title is still caught.

How real is this twin?

That is worth asking before you trust anything you just read. Every day a run compares the twin’s responses against captures of the real vendor API and publishes the result surface by surface. Some surfaces are ruled permanently unverified, this page’s GET /v1/balance among them, and a ruling is published with its reason rather than quietly dropped from the count. Take the numbers from status.pome.sh rather than from here: it carries the live row per twin, with match counts, ruled divergences by id, and how old each baseline is. Which surfaces are shape-only is under Digital twins.

Now grade it

The tape you just read is the input to a score. Turning it into one adds two things: criteria you declare up front, and an agent under test that never sees them. The graded capstone walks through exactly that against a local GitHub twin.

The graded capstone

The same twins, now an exam: a sealed agent under test, a deliberate failing score, and one sentence of prompt that turns it green.