Skip to main content
A deterministic, resettable, in-process simulation of Linear’s GraphQL API. It reproduces the same query/mutation shapes and error semantics as Linear without touching the live service. Each instance starts from a scenario seed and resets between runs, so the same scenario produces the same state every time. Unlike the REST-shaped twins, it speaks GraphQL at /graphql.

What it covers

  • A Linear GraphQL API at /graphql, plus OAuth routes (/oauth/authorize, /oauth/token, /oauth/revoke)
  • Queries: viewer, organization, users/user, teams/team, workflowStates, issues/issue, comments/comment, issueLabels/issueLabel, projects/project, cycles/cycle, webhooks, agentSessions
  • Mutations: issueCreate, issueUpdate, issueDelete, issueArchive/issueUnarchive, commentCreate/commentUpdate/commentDelete, issueLabelCreate/issueLabelUpdate/issueLabelDelete, issueAddLabel/issueRemoveLabel, webhookCreate/webhookDelete, agentSession* mutations, and agentActivityCreate
  • A curated 22-tool MCP subset of the official Linear MCP (see below); save_* tools are upserts
  • Personal-token and OAuth flows for official-client parity

MCP tools

list_issues, get_issue, save_issue, list_comments, save_comment, delete_comment, list_teams, get_team, list_users, get_user, list_issue_statuses, get_issue_status, list_issue_labels, create_issue_label, list_projects, get_project, save_project, list_cycles, search_documentation, list_documents, get_document, save_document.

What it does not cover

MCP families outside the 22 tools above — initiatives, milestones, releases, attachments, git diffs / PR review, status updates, agent skills, and list_project_labels. Some implemented tools omit real params (for example, save_issue omits milestone and dueDate over MCP, and save_document omits initiative parents). The rest of the GraphQL schema returns a loud unsupported/501. There is no external webhook delivery beyond logged attempts, and no live Linear network calls.
GraphQL still exposes issueCreate/issueUpdate for SDK parity, even though the MCP surface uses save_issue.

Quickstart

That scenario boots the twin in-process, seeds a workspace, and scores the run once your agent exits.

Point your agent at it

For interactive development without a full scenario run, start the standalone twin:
The command prints env-var lines you can paste into your agent’s environment:
POME_LINEAR_REST_URL is the GraphQL root — the twin exposes it at /graphql. POME_LINEAR_MCP_URL is the MCP transport endpoint. POME_AUTH_TOKEN is the Pome session JWT, and POME_LINEAR_TOKEN is an alias of it. The default local user is admin@pome-twin.test, and the seed also provisions a personal token lin_test_admin. The twin accepts the Pome session JWT, seeded Linear tokens, or lin_pome_* provider tokens as bearers. Since it speaks GraphQL, point requests at /graphql with a query in the body:
To check whether the twin is alive, use the unauthenticated root health endpoint:

Reset between runs

Clears local twin state. The next pome twin start linear reseeds from the fixture.

Scenario seed shape

Linear scenarios use a seed block with organization, users, teams, labels, projects, cycles, issues, comments, documents, and (optionally) oauthApps, tokens, and webhooks. Each team carries its own states list, and issue state refers to one of those state ids:
An issue’s priority is 0-4, and a team state’s type is one of backlog, unstarted, started, completed, or canceled. Set twins: ["linear"] in the scenario’s ## Config block.

Example scenarios

Ready-made examples you can run or copy to see the twin in action:

Catalog

There is also a cross-twin handoff scenario, 26-github-linear-handoff.md, cataloged under GitHub.

Run one

Or let /pome-test pick matching scenarios automatically. See /test-with-pome.