Skip to main content
A deterministic, in-process simulation of the GitHub REST API. It covers issues, pull requests, comments, labels, repositories, combined commit status, and the parts of the search API that agents tend to reach for. Each instance starts from a task seed and resets between runs, so the same task produces the same state every time.

By use case

The twin’s surface is large enough that a prose summary can’t tell you whether your specific workflow is covered. These are the use cases agents actually exercise against it, each naming the tools and routes involved. For whether the fidelity check is currently passing and how recently it ran, see status.pome.sh.

Triage an incoming issue

Read the issue, apply the right label, assign an owner, and leave a comment explaining the call. MCP: get_issue, list_issue_labels, add_issue_labels, remove_issue_label, add_assignees, add_issue_comment. REST: GET /repos/:owner/:repo/issues/:number, POST .../labels, DELETE .../labels/:name, POST .../assignees, POST .../comments.

Review a pull request

Pull the diff and file list, read existing review threads, and leave a review or inline comment. MCP: get_pull_request, get_pull_request_diff, get_pull_request_files, get_pull_request_reviews, create_pull_request_review, create_pull_request_review_comment, add_reply_to_pull_request_comment. REST: GET .../pulls/:number/*, GET .../pulls/:number/commits, POST .../pulls/:number/comments. get_pull_request_diff (and its REST face, GET .../pulls/:number/diff) is shape-tier — the diff body is a simplified placeholder, not a real line-by-line diff. Don’t assert on diff hunk contents yet.

Merge a PR and check CI status

Read the combined commit status or check runs before merging, and post a status back. MCP: get_pull_request_status, get_combined_status_for_ref, create_commit_status, create_check_run, list_check_runs_for_ref, merge_pull_request, update_pull_request_branch. REST: POST /repos/:owner/:repo/statuses/:sha, GET .../commits/:ref/status, POST .../check-runs.

Manage labels and milestones

Create the taxonomy a repo needs, then move issues through it. MCP: list_repository_labels, create_label, list_milestones, create_milestone, update_milestone, delete_milestone. REST: GET/POST /repos/:owner/:repo/labels, GET/POST/PATCH/DELETE .../milestones.

Search across a repo

Find the issue, PR, commit, or file a task is actually about instead of walking every list. MCP: search_code, search_issues, search_commits, search_users, search_repositories. REST: GET /search/*.

Work with branches and commits

Cut a branch, push a fix, and compare it against a base. MCP: create_branch, list_branches, get_branch, delete_branch, push_files, create_or_update_file, delete_file, list_commits, get_commit, compare_commits. REST: POST .../git/refs, GET/PUT/DELETE .../contents/*, GET .../compare/:basehead. compare_commits and GET .../compare/:basehead are shape-tier — the comparison walks first-parent ancestry only, not the full merge graph a real diff-across-branches comparison would.

Publish releases and tags

Cut a release once a milestone’s work lands. MCP: list_releases, get_latest_release, get_release_by_tag, create_release, list_tags, get_tag. REST: GET/POST /repos/:owner/:repo/releases, GET .../releases/latest, GET .../tags.

What’s out of scope

GitHub Actions execution, billing, Copilot APIs, and real OAuth flows. The twin hands out a static token; if you need real OAuth, run against GitHub directly.

Fidelity

Every surface above is tiered — semantic (a full behavioral contract, checked by an automated weekly capture), shape (the response shape matches but values aren’t asserted — see get_pull_request_diff and compare_commits below, which are both shape-tier: PR diffs are simplified placeholders and the compare walks first-parent ancestry only), or unsupported (a loud 501 instead of a faked success). Only part of the semantic surface is captured by the weekly check today; the rest is rolling out. The GitHub row on status.pome.sh shows whether the check is passing and how recently it last ran — it does not list individual surfaces, so check the tiers above before you rely on a specific tool or route in a task.

Quickstart

That task boots the GitHub twin, hands your agent a token and base URL, and scores the agent’s output once it finishes. No GitHub account and no network round-trips.

Point your agent at it

For interactive development without a full task run, start the standalone twin:
The command prints env-var lines you can paste into your agent’s environment:
POME_GITHUB_REST_URL is the REST root. POME_GITHUB_MCP_URL is the MCP transport endpoint. POME_AUTH_TOKEN is a short-lived JWT that authenticates every request on the session. The twin speaks the GitHub REST shape. Point any existing GitHub client at POME_GITHUB_REST_URL and the same code path runs. To check whether it is alive, use the unauthenticated root health endpoint:
The session path /s/standalone/healthz requires the JWT and returns 401 without it.

Reset between runs

Removes the local SQLite database under .pome/github.db. The next pome twin start github reseeds from the fixture.

Task seed shape

GitHub tasks use a flat seed block with repositories:
Set twins: ["github"] in the task’s ## Config block.

Example tasks

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

Catalog

00-default-seed.md is a reference seed for hosted runs that do not define their own. It is not runnable — pome tasks github and --copy skip it.

Run one

Or let the coach pick and run a matching task for you — the pome-suggest-tasks and pome-run-task skills, installed by the Quickstart.