ProductIntegrationsPricingFAQFeedbackX
All posts

Pull Request Screenshots and Video for React Native and Expo, Recorded by Your AI Agent

Ike Studios LLC

A pull request for a mobile app asks the reviewer to take something on faith. The diff shows what changed in the code; it doesn't show the checkout button actually working on a phone. Reviewers need visual evidence: pull request screenshots or a quick PR video of the change running. When an AI coding agent wrote the change, the gap is wider: the agent says it's done, and the reviewer has no visual evidence that the change ever ran.

Ceraph closes that gap at the source. It's an MCP server that lets your AI coding agent drive and test your React Native or Expo app on real devices, simulators, and emulators. Once the agent has verified a change in the running app, it records that verified path as a clean screen recording plus a screenshot of each verified state. That is the visual evidence a reviewer needs for a mobile app pull request review, and the agent produces it as part of the same task that wrote the code.

Verify first, then record

Screen recording for code review only helps when the recording shows a path that actually works. Ceraph keeps verifying and recording as two separate steps.

Verify. The agent brings the app up with ceraph_start, reads the screen with ceraph_snapshot, and drives the flow with the screen_* tools: tap, type, swipe, deep-link. It snapshots again after each action and reads anything the app threw from rn_get_errors. This is where the agent explores, hits the bug, fixes it, and tries again.

Record. Once the path works, the agent calls ceraph_record_run. It replays the verified path without model pauses: no dead air while the agent thinks, no exploratory detours, no debugging retries. Each recorded checkpoint must match a screen state the agent already observed during verification, so a replay that doesn't reach a state it already verified is marked failed in run.json.

For a change that's purely visual and static, like a new color or a reworded label, a recording adds nothing. In that case the agent verifies the settled screen with screen_screenshot and ceraph_snapshot, and passes saveTo so the same screenshot is written to a PNG in your project, ready to attach to the PR.

What you get

Each recorded run writes its evidence to .ceraph/recorded-runs/<run-id>/, a directory that ceraph init adds to your .gitignore, so evidence stays out of your commits:

  • recording.mp4 is the clean H.264 replay of the verified flow, on iOS or Android.
  • states/*.jpg holds a screenshot of each verified state in the order it was reached, so you get stills without scrubbing the video.
  • snapshots/*.json holds the structured UI snapshot behind each verified state: the elements, their roles and labels, and on-screen bounds.
  • run.json is a manifest with the run's title, every replayed step in order, and each verified state with its evidence. Values the agent typed into fields are recorded only by length, so a password used during the run is not written to the manifest.

The recording captures the screen only. It doesn't capture or verify audio.

The manifest is also the agent's source for the PR description. Its ordered steps and verified states become the "How it was tested" section, written from what actually ran rather than from memory.

Getting the evidence into the pull request

GitHub CLI v2.99.0 added a repeatable --attach flag to gh pr create, gh pr edit, and gh pr comment. It uploads local images and video and embeds them in the body. So an AI agent opening a pull request can post the evidence itself. It writes the body, references the files, and attaches them in one command. Attach only runs whose run.json status is succeeded:

gh pr create \
  --title "Fix: Place order button stays disabled after card entry" \
  --body-file pr-body.md \
  --attach .ceraph/recorded-runs/<run-id>/recording.mp4 \
  --attach .ceraph/recorded-runs/<run-id>/states/<confirmation-state>.jpg

A few GitHub rules apply. Attaching requires push access to the repository. Videos are limited to 10 MB on Free-plan repositories and 100 MB on paid plans, so keep recorded runs focused on the flow under review. Attached files the body doesn't reference are appended to the end of it, and a video renders as an inline player only when its reference is alone in its paragraph. On an older gh, or when you'd rather choose the clips yourself, drag recording.mp4 and the state screenshots into the PR from .ceraph/recorded-runs/.

A walkthrough: fixing a checkout bug

Say a user reports that the "Place order" button stays disabled after they enter a valid card. You ask your agent to fix it and open a PR with evidence.

  1. Reproduce. The agent calls ceraph_start, opens checkout with screen_open_url (myapp://checkout), fills the form with screen_type_into_field, and sees in ceraph_snapshot that the button is still disabled.
  2. Fix and verify. The agent finds the validation bug and edits the code, then runs the form again, and this time screen_tap_and_verify taps "Place order" and confirms the order confirmation screen appears. rn_get_errors is clean.
  3. Record. The agent calls ceraph_record_run with the verified path: open checkout, fill the card, tap "Place order", reach confirmation.
  4. Draft the PR. The agent writes the description from run.json and attaches the evidence:
## Fix: Place order stays disabled after valid card entry

Card validation rejected 16-digit numbers that contained spaces, so the
form never became valid.

### How it was tested (iPhone 16 Simulator, verified run)
1. Opened `myapp://checkout`
2. Entered shipping address and card `4242 4242 4242 4242`
3. Tapped "Place order"
4. Order confirmation screen appeared, no runtime errors

The body doesn't reference the media, so gh appends the attached recording and confirmation screenshot to the end of the description.

The reviewer opens the PR and watches the fix work on a real runtime before reading the diff.

Before and after screenshots

If a reviewer wants before and after screenshots, ask the agent for both. It records the broken flow with ceraph_record_run before it edits anything, then records the fixed flow afterward. Both runs write states/*.jpg files, so the PR can carry the pair.

Where this fits

The loop is the same one described in Expo E2E testing with an AI coding agent: bring the app up, observe, act, observe. The recording is that loop's output in a form a reviewer can watch.

Ready to give your pull requests visual evidence? Get started here.