Skip to main content
Every digital twin simulates a slice of its upstream API, not the whole thing. GitHub alone exposes hundreds of REST routes; building all of them would spend fidelity budget on routes agents never call. We pick the slice deliberately, using the same rubric across every twin.

The three heat tiers

We sort every upstream endpoint into one of three tiers, ranked by how often an autonomous agent actually reaches for it. This is the same heat axis (hot / warm / cold) that each twin’s FIDELITY.md carries in its Heat column, and that packages/sdk/ENDPOINT-TIERS.md defines the rubric for.
  • Hot path — the endpoint sits on a task an agent routinely performs against this API: collecting a payment, triaging an issue, posting a message to a channel. If a hot-path endpoint were shallow, an eval run against the twin would silently diverge from what happens against the real service — the failure mode we care most about avoiding. A twin implements its hot path with full behavior: state changes, side effects, and error semantics that match the live service, backed by tests.
  • Warm path — adjacent to a hot path: a context read, an occasional cleanup step, or a real chain that’s too long or too rare to justify full behavioral modeling yet. A warm-path call never fails loudly by surprise, but you shouldn’t build an agent that depends on its side effects. A twin implements its warm path so the response shape matches the live service, without necessarily reproducing every stateful consequence.
  • Cold path — not plausibly on an autonomous agent’s task chain: browser redirect flows, admin and enterprise surfaces, or anything outside a twin’s product scope. A twin does not implement its cold path at all. Calling a cold-path route returns a loud, structured error instead of a silent 200 — see what happens if you call an unimplemented endpoint.
We decide which band an endpoint falls in the same way for every twin: enumerate the tasks agents actually run against that API, then cross-check against the upstream vendor’s own default-enabled agent tooling where one exists. Endpoints on a real task chain are hot even if a vendor’s tooling doesn’t expose them; the task chain wins disagreements.

This is a different axis from fidelity tiers

Each twin ships a FIDELITY.md in the pome-sh/digital-twins repo that classifies every implemented endpoint into a fidelity tier — semantic, shape, or unsupported — describing how faithfully that endpoint’s behavior reproduces the real service. Heat and fidelity tier answer different questions and should not be read as two names for the same thing: They correlate — a hot-path endpoint is expected to reach semantic fidelity, a warm-path endpoint shape, a cold-path endpoint stays unsupported — but the words aren’t interchangeable. In particular, cold is not a synonym for unsupported: cold describes an endpoint we chose not to model because agents don’t plausibly need it, while unsupported describes the measured fidelity of an endpoint today, whatever its heat. A warm-path endpoint can also be unsupported while work is in flight, and that’s tracked as a gap, not a scope decision. Each twin’s own page carries that reading, surface by surface, under What you can rely onGitHub, Stripe, Slack, Gmail, Linear. Those sections are generated from the FIDELITY.md and fidelity.inventory.json above, at a pinned commit, so they cannot drift from the twin they describe.

How much of each API is covered

The five twins declare 115 MCP tools and 263 REST and GraphQL surfaces between them. That total is arithmetic on the same per-twin declarations each twin page renders, and a CI gate fails the moment this page and those pages stop agreeing — so it moves when a twin ships surface area instead of quietly going stale. The breakdown by state is on each twin’s own page, rendered from that twin’s declaration rather than written down beside it. status.pome.sh answers the other half, and it is a different number: not what the twins declare, but what the daily comparison against the real service found — how many surfaces matched, which drifted, and which are ruled exceptions with the reason published in full. Both halves of that fraction move, the denominator when a twin adds surface area and the numerator when anything drifts or is ruled, so it is linked here rather than copied.

Calling something outside the hot or warm path

If your agent calls a cold-path (or not-yet-implemented) endpoint, the twin returns a loud 501 instead of a silent success. Each twin mimics the error shape of the upstream it emulates, so the unsupported signal lives in different places:
  • GitHub nests it under a _twin namespace. This body is what the twin returns today, verbatim:
  • Slack carries the same _twin block inside its own Web API envelope, {"ok": false, "error": "unsupported_endpoint"} — there is no message body.
  • Stripe nests fidelity and supported_surfaces on its native error object instead of _twin.
  • Linear puts a top-level fidelity field alongside its GraphQL-style errors array, with no _twin namespace — that is its catch-all for unroutable paths. A GraphQL field outside its schema is refused earlier, as a plain GraphQL validation error with HTTP 400.
  • Gmail mirrors Google’s UNIMPLEMENTED error shape and carries no fidelity marker or supported_surfaces list at all.
Don’t hardcode a check against _twin.fidelity === "unsupported" — it only holds for the GitHub and Slack twins. Check the twin’s own 501 shape (each twin’s FIDELITY.md documents it) or key off the HTTP status code — 501 everywhere except Linear’s out-of-schema GraphQL fields, which answer 400 — and treat it the way you’d treat a real 404 on a route that doesn’t exist: don’t retry into it. If the endpoint you need isn’t covered, file it against the twin’s repo (pome-sh/digital-twins) with the route or MCP tool name and the task you’re trying to run — that’s exactly the input we use to move an endpoint onto a warm or hot path, or to raise an existing one’s fidelity tier.