From rn-dev-agent
Executes 8-phase pipeline for React Native/Expo feature development: discovery, codebase exploration, clarifying questions, architecture, implementation, live verification, quality review, and E2E proof.
npx claudepluginhub lykhoyda/rn-dev-agent --plugin rn-dev-agentThis skill uses the workspace's default tool permissions.
You are helping a developer implement a new feature in a React Native app.
Suggests manual /compact at logical task boundaries in long Claude Code sessions and multi-phase tasks to avoid arbitrary auto-compaction losses.
Share bugs, ideas, or general feedback.
You are helping a developer implement a new feature in a React Native app. Follow this systematic approach: understand the codebase deeply, ask about all ambiguities, design an elegant architecture, implement, verify live on the simulator, review quality, and produce E2E proof with screenshots.
Goal: Understand what needs to be built.
Actions:
Evaluator: If dev/evaluator.md exists in the plugin root, initialize report — record feature name, slug, start time per dev/evaluator.md Phase 1.
Goal: Understand relevant existing code and patterns.
Actions:
rn-code-explorer agents in parallel. Each should:
Evaluator: If dev/evaluator.md exists in the plugin root, log agent launches and files identified per dev/evaluator.md Phase 2.
Goal: Fill in all gaps before designing.
CRITICAL: This is the most important phase. DO NOT SKIP.
Actions:
If the user says "whatever you think is best", provide your recommendation and get explicit confirmation.
Evaluator: If dev/evaluator.md exists in the plugin root, log question counts per dev/evaluator.md Phase 3.
Goal: Design the implementation approach.
Actions:
rn-code-architect agents with the feature spec, explorer
findings, and user answers. Ask for a complete blueprint including the
mandatory Verification Parameters and E2E Proof Flow sections.Rules consulted block listing rule
IDs from skills/rn-best-practices/rules.index.json derived from the
feature's keyword set.[CRITICAL|HIGH] <rule-id> one per line.Evaluator: If dev/evaluator.md exists in the plugin root, log agent launches and blueprint completeness per dev/evaluator.md Phase 4.
Goal: Build the feature.
Actions:
__DEV__ Zustand exposure (if Zustand project)requiresFullReload is true: call cdp_reload(full=true) and wait
for reconnectionEvaluator: If dev/evaluator.md exists in the plugin root, log files changed, reload type, and cdp_reload result per dev/evaluator.md Phase 5.
Goal: Prove the feature works on the running simulator/emulator.
This is what separates rn-feature-dev from generic feature development. After implementation, verify the feature live using CDP tools and screenshots.
Actions:
Run this verification sequence in order. Stop and fix if any step fails.
Before ANY verification, confirm the environment is functional.
Call cdp_status. If it fails to connect:
xcrun simctl, adb, or xcodebuild as substitutes for
CDP tools. These bypass the plugin's connection management and error
recovery, and produce a degraded experience.npx expo start
or npx react-native start) and the app is loaded on a simulator."/rn-dev-agent:check-env to diagnose missing dependencies."cdp_connect(platform="ios"))Only proceed to Step 0 after cdp_status returns ok: true.
First, verify the simulator is running and CDP is connected:
device_list to check for booted simulators/emulatorsrn-ensure-running <platform>cdp_status to confirm connection/rn-dev-agent:setup to verify all dependencies are installed.
Do not skip verification without user consent.cdp_status to confirm CDP connection before proceeding.Then, ensure a device session is open for device_* tools:
4. Check if /tmp/rn-dev-agent-session.json exists (via bash cat).
If absent or stale (older than 30 minutes), open a fresh session:
device_snapshot(action="open", platform="<platform from cdp_status>")
Auto-detect appId — the tool resolves it from app.json if omitted.
This enables device_screenshot, device_find, device_press, and
device_scroll for the rest of the verification and proof phases.
NEVER skip this step — without a session, all device_* calls fail
and verification falls back to bash commands, defeating the plugin's
purpose.
Then, if the blueprint's entryRoute is not "none", navigate to the feature
screen using cdp_navigate or cdp_evaluate:
cdp_navigate(screen="<screen>", params={...})
Or if cdp_navigate is unavailable:
cdp_evaluate(expression="globalThis.__NAV_REF__?.navigate('<screen>', <params>)")
If navigation ref is not available, use device_deeplink as a last resort:
device_deeplink(url="<entryRoute from blueprint>")
After navigation, call cdp_navigation_state to confirm you are on the
correct screen. Wait 1-2 seconds for the screen to settle.
First, clear the error buffer to establish a baseline:
cdp_error_log(clear=true)
Then capture the current screen state:
device_screenshot(path="/tmp/rn-feature-verify.jpg")
Call cdp_status. Gate on:
metro.running = truecdp.connected = trueapp.dev = true (not false)app.hasRedBox = falseapp.isPaused = falseapp.errorCount = 0If app.dev is false: CDP is connected to the wrong JS context (common in
RN 0.76+ Bridgeless mode with multiple Hermes targets). Call
cdp_reload(full=true) to force reconnection — the target selection now
probes __DEV__ on each candidate. If still false after reload, ask the
user to restart Metro.
If isPaused is true: call cdp_reload(full=true) to recover, then
restart Phase 5.5 from Step 0.
If RedBox is showing: read cdp_error_log, fix the error in source,
save, wait for Fast Refresh, then restart Phase 5.5 from Step 0.
Call cdp_component_tree(filter="<primaryComponent from blueprint>", depth=3).
Gate on:
If the component is not found, call cdp_navigation_state to check if you
are on the wrong screen before diagnosing a render issue.
If the blueprint specifies interactive elements (buttons, pressables, inputs), exercise at least ONE primary interaction to verify the feature works end-to-end, not just renders:
device_find(text="<button text>", action="click") or
device_press(ref="@<ref>") to trigger the main user action.
Fallback: cdp_interact(testID="<testID>", action="press") if agent-device unavailabledevice_snapshot to verify UI changed)cdp_store_state to confirmcdp_navigation_state to confirmcdp_error_log for handler errorsThis step proves the feature is functional, not just rendered. Skip only if the feature has no interactive elements (e.g., display-only screens).
If the blueprint's storeQueryPath is not "none":
Call cdp_store_state(path="<storeQueryPath from blueprint>").
Gate on:
__agent_error key in the responseSkip this step if the feature has no store involvement.
Call cdp_error_log. Gate on:
If new errors are present: read the stack trace, fix the source, save, wait for Fast Refresh, then restart Phase 5.5 from Step 0.
Maximum 3 fix-and-retry loops before escalating to the user with a full state dump.
Present results as a table (use the actual screenshot path for the platform):
| Check | Result | Evidence |
|---|---|---|
| Navigation (cdp_navigation_state) | PASS/SKIP | current route |
| Screenshot | PASS/FAIL | actual file path |
| Health (cdp_status) | PASS/FAIL | errorCount, hasRedBox, isPaused |
| Component (cdp_component_tree) | PASS/FAIL | component found, props summary |
| Interaction (device_find/device_press) | PASS/FAIL/SKIP | action + side effect verified |
| State (cdp_store_state) | PASS/FAIL/SKIP | state shape summary |
| Errors (cdp_error_log) | PASS/FAIL | error count since baseline |
Gate: All checks must be PASS (or SKIP where not applicable) before proceeding to Phase 6.
If both iOS and Android are available, run this check BEFORE marking verification as complete. This catches platform-specific rendering failures (e.g., missing icon fonts, layout differences, invisible elements).
| Element | testID | iOS | Android |
|---|---|---|---|
| Like icon | feed-like-1 | visible | visible/MISSING |
| Like count | feed-like-count-1 | "1" | "1" |
| Avatar image | profile-avatar-image | visible | visible/MISSING |
docs/BUGS.md and note it in the verification report.
Verification can proceed with the working platform, but the MISSING
elements must be documented and the Android column in the results log
must show the actual status, not a false "PASS".Never mark a platform as "PASS" if UI elements are invisible or missing. A screen that loads without crashing but has missing icons is a FAIL, not a PASS.
Evaluator: If dev/evaluator.md exists in the plugin root, log every CDP tool call, recovery action, and fix-retry loop per dev/evaluator.md Phase 5.5.
Goal: Ensure code is clean, correct, and follows RN conventions.
Actions:
rn-code-reviewer agents in parallel:
__DEV__ guards on debug code, Zustand
exposure, selector memoization. Scope: [list of files changed]"node scripts/check-vercel-rules.mjs --changed --format hook -- <changed file paths>
rn-code-reviewer Pass 4 also runs an index-driven lookup, but this
standalone check is faster (~50ms) and catches the 3 deterministic rules
even when the reviewer agent skips Pass 4.node scripts/check-vercel-rules.mjs --ci.Evaluator: If dev/evaluator.md exists in the plugin root, log agent launches, findings, and re-verification per dev/evaluator.md Phase 6. If re-verification ran, log as Phase 5.5-retry.
Goal: Document what was accomplished.
Actions:
Evaluator: If dev/evaluator.md exists in the plugin root, finalize and write the evaluation report per dev/evaluator.md Phase 7. Append high-confidence bugs to docs/BUGS.md.
Goal: Produce a permanent proof artifact showing the feature works end-to-end, with screenshots of each step of the user flow.
CRITICAL: This phase executes the E2E Proof Flow designed by the architect in Phase 4 — step by step, mechanically. Do NOT improvise the flow, skip steps, or simplify the sequence. The architect (Opus) designed this flow with full feature context. Your job is to execute it faithfully and capture the evidence.
The output is a docs/proof/<feature-slug>/ directory with numbered screenshots
and a PROOF.md summary.
Actions:
mkdir -p docs/proof/<feature-slug>
Use the feature slug from Phase 1 (e.g., s4-notification-snooze, profile-edit-modal).
Rule. The video must capture a known-good replay of the feature, NOT the LLM figuring out how to navigate. Recording during discovery produces multi-minute videos full of dead-ends, wrong screens, and "let me check the testID" pauses — nobody wants that in a PR. Discovery is cheap; re-recording is expensive.
Protocol — perform every step BEFORE pressing record:
device_* / cdp_* calls to walk every row of the blueprint table from
start to end. Verify each interaction lands and each assertion holds.<test-app>/.rn-agent/actions/<feature-slug>.yaml. Two authoring paths:
maestro_generate(name="<feature-slug>", steps=[...], appId="...") —
structured-step authoring; the MCP tool writes the YAML but does NOT
emit the M7 metadata header.cdp_record_test_generate(format="maestro") — converts the recorder
buffer (started via cdp_record_test_start during rehearsal) into
YAML text returned in the response; the MCP tool schema does not
forward the M7 fields, so the header is not auto-populated.
In both cases, the agent MUST then read the file (or capture the
returned text) and PREPEND the 5-key M7 metadata header by hand
(id, intent, tags, mutates, status) — see
skills/rn-testing/SKILL.md § "Reusable Action Metadata Schema".${VAR} placeholders, use the Bash CLI (which supports -e
substitution):
maestro-runner --platform <ios|android> test \
<test-app>/.rn-agent/actions/<feature-slug>.yaml \
-e KEY=VALUE
For env-free flows, the MCP tool also works:
maestro_run(flowPath="<test-app>/.rn-agent/actions/<feature-slug>.yaml").
The replay must pass end-to-end without a single failure.cdp_navigation_state and cdp_store_state. Do NOT loop indefinitely.Maestro-inexpressible carve-out. If the flow genuinely cannot be
expressed in Maestro (custom gestures, native-module side-effects,
Reanimated proof captures via cdp_set_shared_value, JS-introspection
mid-flow), the rehearsal walk itself via device_* / cdp_* becomes the
artifact. Document the specific Maestro primitive that is missing in
PROOF.md "Deviations" — naming the inexpressibility is mandatory; without
it you must keep trying to express the flow.
Hard gate. Do not proceed to Step 1.5 until either step 4 passes cleanly OR the inexpressibility carve-out has been written into PROOF.md. If you catch yourself thinking "I'll just record while I work out the last step," stop — that's the failure mode this gate exists to prevent.
Pre-recording readiness (GH #8, #9):
cdp_status — auto-detects and dismisses the Dev Client picker if
an agent-device session is open (GH #9). If warning returned, retry.cdp_navigation_state — verify a valid route (not Dev Client picker).
If still stuck, ask the user to select the Metro server.cdp_dev_settings(action="disableDevMenu") — suppress dev menu popups
during recording.Then start recording:
# Detect platform
PLATFORM="ios" # or "android" based on booted devices
# Start recording
rn-record-proof start $PLATFORM docs/proof/<feature-slug>/flow-$PLATFORM.mp4
If recording fails to start (no simulator, permissions), log a warning and continue — video is a nice-to-have, not a gate. Screenshots remain primary.
Preferred path: replay the Maestro flow generated in Step 1.4. With recording running, invoke the rehearsed flow.
For flows with ${VAR} placeholders (need env substitution):
maestro-runner --platform <ios|android> test \
<test-app>/.rn-agent/actions/<feature-slug>.yaml \
-e KEY=VALUE
For env-free flows, use the MCP tool:
maestro_run(flowPath="<test-app>/.rn-agent/actions/<feature-slug>.yaml")(The MCP maestro_run tool schema accepts flowPath, inlineYaml,
platform, appId, timeoutMs — there is no -e env-var pass-through.
For substitution you need the maestro-runner CLI via Bash.)
Either path produces a deterministic, hesitation-free recording. The LLM
is NOT in the loop during the actual replay — Maestro drives the device
at native speed. While the flow runs, take numbered screenshots at meaningful state
changes via device_screenshot(path="docs/proof/<feature-slug>/<NN-stepname>.jpg").
Flow assertion failure during recording = stop and re-rehearse. A
failure here means the flow drifted between rehearsal and recording (timing,
state, leftover residue from a mutates: true flow). Stop the recording,
rebase to a clean app state, redo Step 1.4. Do not "fix it on camera."
Fallback: only when Maestro cannot express the flow — custom gestures,
native-module side-effects, Reanimated proof captures via
cdp_set_shared_value, or anything that needs JS-level introspection
mid-flow. In that case, execute the rehearsed sequence step-by-step using
the same device_* / cdp_* calls you ran in Step 1.4. Every action must
be one you already executed cleanly during rehearsal — do NOT debug,
explore, or improvise on camera.
For each meaningful state change (whether driven by Maestro or by the fallback path), capture:
device_screenshot(path="docs/proof/<feature-slug>/<filename>")cdp_store_state value matchescdp_navigation_stateStop the background video recording:
rn-record-proof stop
Attempt GIF conversion for inline PR display:
rn-record-proof convert-gif \
docs/proof/<feature-slug>/flow-$PLATFORM.mp4 \
docs/proof/<feature-slug>/flow-$PLATFORM.gif
If ffmpeg is not available, skip GIF conversion — the raw .mp4 is still useful.
Create docs/proof/<feature-slug>/PROOF.md with this structure:
# <Feature Name> — E2E Proof
**Date:** <YYYY-MM-DD>
**Device:** <device name> (<OS version>, Simulator/Emulator)
**Method:** CDP interactions + screenshots (flow designed by architect in Phase 4)
## Flow
| Step | Screenshot | Action | Verification |
|------|-----------|--------|--------------|
| 1 | 01-initial.jpg | Navigate to <screen> | Route confirmed via cdp_navigation_state |
| 2 | 02-action.jpg | <interaction description> | <state or visual confirmation> |
| 3 | 03-result.jpg | <interaction description> | <state or visual confirmation> |
## Key State Snapshots
- After step 2: `store.path = <value>`
- After step 3: `store.path = <value>`
## Deviations from Plan
List any steps where the actual result differed from the architect's expected
state, or any steps that required retries. If none, write "None — all steps
matched the architect's E2E Proof Flow."
## Files
- `01-initial.jpg` — <description>
- `02-action.jpg` — <description>
- `03-result.jpg` — <description>
Before presenting proof to the user, verify the recording and screenshots actually show the expected feature. This prevents presenting invalid proof.
Validation checklist:
ls -la docs/proof/<feature-slug>/flow-*.mp4 2>/dev/null
cdp_component_tree or cdp_navigation_state that the app is on the
expected screen with expected data visible.cdp_error_log and confirm no
new errors appeared during the proof flow.If validation fails: report what went wrong and ask the user if they want to re-record. Do NOT present invalid proof as complete.
rn-generate-pr-body docs/proof/<feature-slug>/
This produces docs/proof/<feature-slug>/PR-BODY.md — a ready-to-paste PR
description with embedded screenshots, video upload placeholders, device
info, and a files-changed summary.
Mark all todos complete. The feature is done — implemented, verified, reviewed, and proven with screenshots and video.
Gate: PROOF.md exists, contains screenshots for ALL steps in the architect's E2E Proof Flow, all state assertions match, and PR-BODY.md is generated. If screenshot capture fails (e.g., no simulator), log the failure in PROOF.md and note it in the Phase 7 summary. If a state assertion doesn't match, this is a bug — fix it before completing.
npx expo start or npx react-native start)if (__DEV__) global.__ZUSTAND_STORES__ = { ... } in app entrygit checkout, git stash,
git reset. Agents read and verify, they don't manage branches.expo_ensure_running.sh is
attempted in Phase 5.5 Step 0. If that fails, ask the user to boot it.
Verification can be skipped with explicit user consent, but must be noted
in the Phase 7 summary.cdp_error_log, fix source, reload,
restart Phase 5.5.cdp_status which auto-connects. If that
fails, check Metro is running (curl http://localhost:8081/status).cdp_reload(full=true) to resume.Each phase has shortcuts agents reach for. Don't.
| Excuse | Reality |
|---|---|
| "I read the explorer's report — skip reading the actual files" | Explorer reports are summaries. Read 2-3 key files the explorer flagged before designing. |
| "The blueprint is detailed enough — implement directly, skip questions" | Phase 3 (Questions) catches the 5 assumptions that would waste 2 hours of rework. Ask them. |
| "Phase 5.5 verification is slow — skip it and trust the review" | Code review ≠ runtime verification. A component can look correct and render wrong. cdp_component_tree + cdp_store_state takes 10 seconds. |
| "I tested iOS — Android works the same" | Wrong ~40% of the time. Keyboard, permissions, back button, text input, safe-area all differ. cross_platform_verify is mandatory unless explicitly single-platform. |
| "Phase 6 found 1 issue — ship it" | Review agents already filter by confidence. If ONE flags an issue, read it fully. |
| "Phase 8 (E2E Proof) is just for PR theater" | Proof flows become the permanent Maestro test file. Skip them and you pay in manual testing every sprint. |
| "I'll record while I figure out the flow — saves a pass" | The video then shows you stuck on a wrong testID for 90 seconds. Rehearsal (Step 1.4) is the cheap pass; re-recording is the expensive one. Discovery happens off camera, replay happens on camera. |
cdp_error_log to confirm zero new errorsrn-record-proof start before the Step 1.4 rehearsal flow has replayed clean (via maestro-runner CLI or maestro_run)device_* exploratory calls during recording to "find the right testID"device_* / cdp_* fallback path in Phase 8 Step 2 without naming the specific Maestro primitive that cannot express the step in PROOF.md "Deviations"cdp_status before Phase 5.5 startsmaestro-runner CLI for env-substituted flows or maestro_run MCP tool for env-free flows) when expressible, step-by-step device_* / cdp_* only when Maestro genuinely cannot capture it AND the inexpressibility is documented in PROOF.md Deviationsmaestro_run replays the generated flow cleanly BEFORE starting any video recordingxcrun simctl or adb for app interaction (use MCP tools)xcrun simctl io screenshot or bash for screenshots — use device_screenshot(path=...) exclusivelysleep N for settling — use device_snapshot to verify UI state change insteadconsole.log calls and leave them in committed codecdp_error_log showing new errorsrn-record-proof start while still discovering testIDs, navigation paths, or state shapes — recording is for verified replay, not explorationcdp_status returns ok:true at end of Phase 5.5 and Phase 8cdp_error_log shows 0 new errors at end of Phase 8docs/proof/<feature>/PROOF.md written with the architect's steps and actual resultscross_platform_verify run OR single-platform noted in Phase 7 summary