Pull Request Screenshots and Video for React Native and Expo, Recorded by Your AI Agent
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.mp4is the clean H.264 replay of the verified flow, on iOS or Android.states/*.jpgholds a screenshot of each verified state in the order it was reached, so you get stills without scrubbing the video.snapshots/*.jsonholds the structured UI snapshot behind each verified state: the elements, their roles and labels, and on-screen bounds.run.jsonis 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.
- Reproduce. The agent calls
ceraph_start, opens checkout withscreen_open_url(myapp://checkout), fills the form withscreen_type_into_field, and sees inceraph_snapshotthat the button is still disabled. - Fix and verify. The agent finds the validation bug and edits the code, then runs the form again, and this time
screen_tap_and_verifytaps "Place order" and confirms the order confirmation screen appears.rn_get_errorsis clean. - Record. The agent calls
ceraph_record_runwith the verified path: open checkout, fill the card, tap "Place order", reach confirmation. - Draft the PR. The agent writes the description from
run.jsonand 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.