Skip to main content
About 5 minutes. You start a private mailbox holding one unanswered customer email, your own coding agent replies to it and files it, and you read the twin’s own record of every call it made — including what the recorder keeps about a sent message and what it deliberately throws away.
A digital twin is not a mock. It is a stateful service that answers the same REST and MCP calls as gmail.googleapis.com, boots from a declared starting state, records every request, and never reaches Google. No mailbox is connected and no OAuth consent is asked for, because there is no real account behind it to consent to: the hosted twin holds no Google credential, ever.

Before you start

  • A Pome account. pome login opens the browser sign-in and creates one if you do not have it. No credit card.
  • Your own coding agent — Claude Code, Cursor, anything that can run a shell command and read JSON back.
  • Node 18+ for npx, plus curl and jq for the transcripts below. Your agent can read the raw JSON without jq; it is here to keep the blocks short.
Nothing else. No Google account, no ANTHROPIC_API_KEY, no model inference paid for by Pome: your agent is both the operator and the actor. It drives Pome, and it is the thing that acts on the twin.
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 support-triage capstone, where the agent under test is sealed off from the criteria that judge it.

Paste this

Hand this to your coding agent as-is. It names the twin’s own Gmail surface and the boundary it must not cross.
One token opens a sandbox: POME_AUTH_TOKEN. It is the bearer on every call to the twin, REST and MCP alike. On most twins the secrets file also carries a provider-shaped token — POME_GITHUB_TOKEN=github_pat_…, POME_STRIPE_API_KEY=sk_test_… — and that one is not the bearer; it is what the twin serves inside the sandbox. The linear twin ships none at all. Send that provider-shaped token as the bearer, or send no bearer at all, and the proxy answers an opaque 404 readingNo twin pod for this session. So a 404 on a sandbox you just created is almost always the wrong bearer rather than a dead sandbox.

The world

sandbox create boots a Gmail twin from its declared starting state and hands back the URLs that reach it. It also writes the connection secrets to .pome-sandbox.env at mode 0600, and says so on stderr.
That empty provider_credentials is not an omission — it is the point. There is no upstream Gmail credential to hand you, so the twin serves its own mailbox and nothing you do here can reach a real one.
The world is one mailbox with four threads, two of them unread:
One of those two is a customer waiting on an answer. Read it:
Unread, unanswered, and the same every time you create this sandbox — which is what makes anything you observe next reproducible. Now the reply. Gmail takes a whole RFC822 message, base64url-encoded, in raw:
Read the thread back through the twin’s own surface — not out of the response your agent already holds:
This is the thing worth noticing. The reply joined Alice’s thread rather than starting a fourth one, and msg_support lost UNREAD and gained a label — read back through two different routes. SENT now holds two messages, not one: the mailbox started with a sent reply on the build thread, so two is the number that means “replied exactly once”, and that is the number a check has to assert. Stop the sandbox and all of it is gone.

Read the tape

Every call above was recorded by the twin as it happened. This is the part neither a mock nor a test mailbox gives you: an account of the run written by the service, not by the agent.
Each row carries more than the request line:
You should see:
  • Seven rows, in the order they happened. Read top to bottom and the triage is legible without asking the agent what it did: it looked, it read the inquiry, it replied, it filed, it checked twice.
  • mut=true on exactly the two writes. state_mutation means the call landed — a write the twin refuses reads false, not true. Send the same message with no From header and you get a 400 with mut=false beside it.
  • tool=null on every row. Unlike the GitHub twin, this one stamps no action vocabulary; calls are identified by method and path.
  • fid=semantic. These surfaces carry a full behavioural contract, not a response shape with placeholder values.
Now the part that is specific to mail. Ask the recorder what it kept about the message you just sent:
Two things there are worth a second look. bodyOmitted: true — the API served you that body a moment ago, but the recorded state keeps a SHA-256 and a byte count in its place, so the evidence a grader reads can prove which message was sent without holding what it said. And sentAt is 2026-07-20T00:00:01.000Z, one second past the mailbox’s own clock rather than the wall clock you ran this at: the twin advances a logical clock per write, so running this twice gives you the same timestamp and the same hash. When you are done, stop the sandbox to free the slot — it also expires on its own 30 minutes after it was created:

What you could assert here

Nothing on this page was graded, but a tape and a final state are exactly what a graded check reads. The Gmail twin already declares these — no authoring required, and list_checks on the Pome MCP prints the full set with what each one actually compares: Pointers, not a task. Turning them into a graded exam is the capstone below, and Write a task is where the grammar lives.

How real is this twin?

Every surface you called above is compared against a captured response from the real Gmail API, re-run daily and published. The Gmail row on status.pome.sh carries the current count of twin responses that match, names every divergence we have ruled on by id, and states how old the captured baseline is. Nobody has to take our word for the fidelity, including us — a twin that drifts turns that row red. Which surfaces are covered, and which are shape-only, is on the Gmail twin reference.

Next: the one graded lesson

The support-triage capstone

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

Gmail twin reference

Every route and MCP tool the twin serves, by use case, with its fidelity tier.

Write a task

Turn the checks above into a graded exam for your own agent.

pome sandbox

Create, list and stop sandboxes — including multi-twin ones.