@swmansion/argent 0.28.1-next.9 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/agents/argent-environment-inspector.md +7 -7
  2. package/agents/references/quality-control-checklist.md +14 -14
  3. package/assets/manifest.json +2 -2
  4. package/bin/argent-android-devtools-0.3.0.apk +0 -0
  5. package/bin/darwin/ax-service +0 -0
  6. package/bin/darwin/simulator-server +0 -0
  7. package/bin/darwin/tvos-ax-service +0 -0
  8. package/bin/darwin/tvos-hid-daemon +0 -0
  9. package/bin/linux/simulator-server +0 -0
  10. package/bin/linux-arm64/simulator-server +0 -0
  11. package/bin/tcp/ax-service +0 -0
  12. package/bin/win32/simulator-server.exe +0 -0
  13. package/dist/cli-cmds.mjs +4 -1
  14. package/dist/client.d.ts +18 -0
  15. package/dist/client.js +3 -0
  16. package/dist/installer.mjs +9 -2
  17. package/dist/mcp-server.mjs +13 -1
  18. package/dist/tool-args.generated.d.ts +87 -77
  19. package/dist/tool-server.cjs +947 -370
  20. package/dylibs/libArgentInjectionBootstrap.dylib +0 -0
  21. package/dylibs/libKeyboardPatch.dylib +0 -0
  22. package/dylibs/libNativeDevtoolsIos.dylib +0 -0
  23. package/dylibs/tcp/libArgentInjectionBootstrap.dylib +0 -0
  24. package/dylibs/tcp/libKeyboardPatch.dylib +0 -0
  25. package/dylibs/tcp/libNativeDevtoolsIos.dylib +0 -0
  26. package/dylibs/tvos/libArgentInjectionBootstrap.dylib +0 -0
  27. package/dylibs/tvos/libKeyboardPatch.dylib +0 -0
  28. package/dylibs/tvos/libNativeDevtoolsIos.dylib +0 -0
  29. package/package.json +1 -1
  30. package/rules/argent.md +16 -16
  31. package/skills/argent-android-emulator-setup/SKILL.md +9 -9
  32. package/skills/argent-create-flow/references/flow-yaml.md +11 -11
  33. package/skills/argent-create-flow/references/live-authoring.md +11 -11
  34. package/skills/argent-create-flow/references/reliability-and-recovery.md +13 -13
  35. package/skills/argent-device-interact/SKILL.md +47 -47
  36. package/skills/argent-device-interact/references/chromium.md +1 -1
  37. package/skills/argent-device-interact/references/gesture-examples.md +7 -7
  38. package/skills/argent-device-interact/references/secrets.md +6 -6
  39. package/skills/argent-lens/SKILL.md +21 -21
  40. package/skills/argent-metro-debugger/SKILL.md +24 -24
  41. package/skills/argent-metro-debugger/references/failure-scenarios.md +11 -11
  42. package/skills/argent-metro-debugger/references/source-maps.md +4 -4
  43. package/skills/argent-native-profiler/SKILL.md +13 -13
  44. package/skills/argent-qa-flows/SKILL.md +3 -3
  45. package/skills/argent-react-native-app-workflow/SKILL.md +18 -18
  46. package/skills/argent-react-native-optimization/SKILL.md +12 -12
  47. package/skills/argent-react-native-optimization/references/fix-reference.md +10 -10
  48. package/skills/argent-react-native-optimization/references/lint-rules.md +1 -1
  49. package/skills/argent-react-native-profiler/SKILL.md +25 -25
  50. package/skills/argent-react-native-profiler/references/diagnostic-tools.md +19 -19
  51. package/skills/argent-screen-recording/SKILL.md +14 -14
  52. package/skills/argent-test-ui-flow/SKILL.md +9 -9
  53. package/skills/argent-tv-interact/SKILL.md +19 -19
  54. package/bin/argent-android-devtools-0.2.0.apk +0 -0
@@ -1,14 +1,14 @@
1
1
  # Failure Scenarios: Recovery Steps
2
2
 
3
- When a debugger tool fails, use **`debugger-status`** first to diagnose. Note: `debugger-status` and `debugger-log-registry` do **not** fail when the debugger is simply unreachable — they return `{ status: "not_connected", reason, detail, guidance }` (the `detail` field carries the same error text other tools throw). Do not retry the same failing tool repeatedly without following the recovery steps.
3
+ When a debugger tool fails, use **`debugger-status`** first to diagnose. Note: `debugger-status` and `debugger-log-registry` do **not** fail when the debugger is simply unreachable: they return `{ status: "not_connected", reason, detail, guidance }` (the `detail` field carries the same error text other tools throw). Do not retry the same failing tool repeatedly without following the recovery steps.
4
4
 
5
- | Scenario | Error or situation | What to do |
6
- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
7
- | **Metro not running** | Error (or `not_connected` `detail`) contains: `Metro at port 8081 is not running (got: ...)` | `debugger-status` / `debugger-log-registry` return `{ status: "not_connected", reason: "metro_not_running", guidance }` here instead of erroring; other debugger tools still throw. **Start Metro yourself** unless the user asked you not to: scan the workspace configuration and run the appropriate command to start Metro in the background (by default `npx react-native start` or `npx expo start`). Wait for Metro to be ready, then retry `debugger-connect` or `debugger-status` once — not in a loop. If you cannot determine the project root, ask the user. A non-Metro server occupying the port lands here too — the `got:` text shows what answered. |
8
- | **No source locations** | `projectRoot` is `""` and source lookups report no file:line | Not a failure. Legacy Metro (RN 0.72 and older, e.g. Vega) sends no `X-React-Native-Project-Root` header, so paths cannot be resolved against a project root. `debugger-evaluate`, console logs and the network inspector work regardless — do not restart Metro to "fix" it. |
9
- | **App not connected** | Error (or `not_connected` `detail`) contains: `Metro at port 8081 has no CDP targets — is a React Native app connected?` | `debugger-status` / `debugger-log-registry` return `{ status: "not_connected", reason: "no_app_connected", guidance }` here instead of erroring; other debugger tools still throw. 1) Confirm the app is running on the device. 2) Use `restart-app` with the app's device id and bundleId to relaunch so it connects to Metro. 3) Wait a few seconds for the bundle to load. 4) Retry `debugger-status` once. Do **not** use `debugger-reload-metro` to fix this — it also requires at least one target. |
10
- | **Wrong device id** | `debugger-status` / `debugger-log-registry` return `reason: "device_mismatch"`, or `debugger-connect` fails with `DEBUGGER_TARGET_DEVICE_MISMATCH` | The `device_id` matches no debugger target on this Metro. Re-target with the `logicalDeviceId` listed in the `detail` / error message, or give the device its own Metro port. Do not retry with the same `device_id` — the result will not change. |
11
- | **Stale connection** | `debugger-status` returns `reason: "stale_connection"` | The cached debugger connection was no longer open; `debugger-status` has already discarded it. Use `restart-app` if the app is not running, then call `debugger-connect` — the next call reconnects fresh. |
12
- | **Reconnecting** | `debugger-status` / `debugger-log-registry` return `reason: "reconnecting"` | A reconnect is in flight — the previous connection was just torn down, or (Chromium) a tab switch is in progress. Transient: wait a moment and retry once. Do **not** restart the app for this. |
13
- | **Runtime unresponsive** | `reason: "runtime_unresponsive"`, or another debugger tool fails with `DEBUGGER_CDP_REQUEST_TIMEOUT` | Follow the `guidance` / error text — it explains the state and the recovery. Each attempt waits out the full CDP timeout, so never retry in a loop. |
14
- | **Was connected, then tool fails** | Any debugger tool fails with a connection or disconnect error after it was working | The app may have crashed or been closed. Use `restart-app` to relaunch the app, then call `debugger-connect` again to pick up the fresh `logicalDeviceId` (may change for booted-fresh simulators), and use that new `device_id` on all subsequent calls. |
5
+ | Scenario | Error or situation | What to do |
6
+ | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
7
+ | **Metro not running** | Error (or `not_connected` `detail`) contains: `Metro at port 8081 is not running (got: ...)` | `debugger-status` / `debugger-log-registry` return `{ status: "not_connected", reason: "metro_not_running", guidance }` here instead of erroring; other debugger tools still throw. **Start Metro yourself** unless the user asked you not to: scan the workspace configuration and run the appropriate command to start Metro in the background (by default `npx react-native start` or `npx expo start`). Wait for Metro to be ready, then retry `debugger-connect` or `debugger-status` once, not in a loop. If you cannot determine the project root, ask the user. A non-Metro server occupying the port lands here too; the `got:` text shows what answered. |
8
+ | **No source locations** | `projectRoot` is `""` and source lookups report no file:line | Not a failure. Legacy Metro (RN 0.72 and older, e.g. Vega) sends no `X-React-Native-Project-Root` header, so paths cannot be resolved against a project root. `debugger-evaluate`, console logs and the network inspector work regardless; do not restart Metro to "fix" it. |
9
+ | **App not connected** | Error (or `not_connected` `detail`) contains: `Metro at port 8081 has no CDP targets — is a React Native app connected?` | `debugger-status` / `debugger-log-registry` return `{ status: "not_connected", reason: "no_app_connected", guidance }` here instead of erroring; other debugger tools still throw. 1) Confirm the app is running on the device. 2) Use `restart-app` with the app's device id and bundleId to relaunch so it connects to Metro. 3) Wait a few seconds for the bundle to load. 4) Retry `debugger-status` once. Do **not** use `debugger-reload-metro` to fix this; it also requires at least one target. |
10
+ | **Wrong device id** | `debugger-status` / `debugger-log-registry` return `reason: "device_mismatch"`, or `debugger-connect` fails with `DEBUGGER_TARGET_DEVICE_MISMATCH` | The `device_id` matches no debugger target on this Metro. Re-target with the `logicalDeviceId` listed in the `detail` / error message, or give the device its own Metro port. Do not retry with the same `device_id`; the result will not change. |
11
+ | **Stale connection** | `debugger-status` returns `reason: "stale_connection"` | The cached debugger connection was no longer open; `debugger-status` has already discarded it. Use `restart-app` if the app is not running, then call `debugger-connect`; the next call reconnects fresh. |
12
+ | **Reconnecting** | `debugger-status` / `debugger-log-registry` return `reason: "reconnecting"` | A reconnect is in flight: the previous connection was just torn down, or (Chromium) a tab switch is in progress. Transient: wait a moment and retry once. Do **not** restart the app for this. |
13
+ | **Runtime unresponsive** | `reason: "runtime_unresponsive"`, or another debugger tool fails with `DEBUGGER_CDP_REQUEST_TIMEOUT` | Follow the `guidance` / error text; it explains the state and the recovery. Each attempt waits out the full CDP timeout, so never retry in a loop. |
14
+ | **Was connected, then tool fails** | Any debugger tool fails with a connection or disconnect error after it was working | The app may have crashed or been closed. Use `restart-app` to relaunch the app, then call `debugger-connect` again to pick up the fresh `logicalDeviceId` (may change for booted-fresh simulators), and use that new `device_id` on all subsequent calls. |
@@ -2,9 +2,9 @@
2
2
 
3
3
  `debugger-inspect-element` tries to resolve each component in the hierarchy to its source file and line. It uses a fallback chain:
4
4
 
5
- 1. **`_debugStack`** (React fiber property) — a stack trace string from the bundled code. When available, the tool symbolicates it via Metro's `/symbolicate` endpoint to resolve to the original source file, then reads a code fragment from disk. Set `resolveSourceMaps: false` to skip symbolication and return raw bundled locations instead.
6
- 2. **`_debugSource`** (React fiber property) — contains `{ fileName, lineNumber, columnNumber }` pointing directly to the original source file. No symbolication needed. The tool reads the code fragment from disk automatically.
7
- 3. **Neither available** — the tool returns the component hierarchy with `source: null` and `code: null` for all items. The hierarchy (component names) is still useful.
5
+ 1. **`_debugStack`** (React fiber property): a stack trace string from the bundled code. When available, the tool symbolicates it via Metro's `/symbolicate` endpoint to resolve to the original source file, then reads a code fragment from disk. Set `resolveSourceMaps: false` to skip symbolication and return raw bundled locations instead.
6
+ 2. **`_debugSource`** (React fiber property): contains `{ fileName, lineNumber, columnNumber }` pointing directly to the original source file. No symbolication needed. The tool reads the code fragment from disk automatically.
7
+ 3. **Neither available**: the tool returns the component hierarchy with `source: null` and `code: null` for all items. The hierarchy (component names) is still useful.
8
8
 
9
9
  ## When Source Info Is Missing
10
10
 
@@ -24,4 +24,4 @@ module.exports = function (api) {
24
24
  };
25
25
  ```
26
26
 
27
- After adding the plugin, restart Metro (`npx react-native start --reset-cache` or `npx expo start --clear`) and reload the app. No extra `npm install` needed — the plugin ships with `babel-preset-expo` and `@babel/preset-env`.
27
+ After adding the plugin, restart Metro (`npx react-native start --reset-cache` or `npx expo start --clear`) and reload the app. No extra `npm install` needed; the plugin ships with `babel-preset-expo` and `@babel/preset-env`.
@@ -5,11 +5,11 @@ description: Native profiling for CPU hotspots, UI hangs, memory issues. iOS via
5
5
 
6
6
  ## 1. Tools
7
7
 
8
- - `native-profiler-start` — start profiling on a booted device. iOS: xctrace recording for CPU, hangs, and leaks.
9
- - `native-profiler-stop` — stop the profiler and export trace data to timestamped XML files.
10
- - `native-profiler-analyze` — parse exported trace data and return a structured bottleneck payload.
11
- - `profiler-stack-query` — drill into parsed data: hang stacks, function callers, thread breakdown, leak details.
12
- - `profiler-load` — list and reload previous trace sessions from disk for re-investigation.
8
+ - `native-profiler-start`: start profiling on a booted device. iOS: xctrace recording for CPU, hangs, and leaks.
9
+ - `native-profiler-stop`: stop the profiler and export trace data to timestamped XML files.
10
+ - `native-profiler-analyze`: parse exported trace data and return a structured bottleneck payload.
11
+ - `profiler-stack-query`: drill into parsed data: hang stacks, function callers, thread breakdown, leak details.
12
+ - `profiler-load`: list and reload previous trace sessions from disk for re-investigation.
13
13
  - Physical iPhone: not supported; use a simulator.
14
14
 
15
15
  ---
@@ -28,7 +28,7 @@ After `native-profiler-analyze` surfaces findings, use `profiler-stack-query` to
28
28
  - **Hang detected** → `profiler-stack-query` mode=`hang_stacks` for full native call chains → mode=`function_callers` for the suspected function → read native source.
29
29
  - **CPU hotspot** → `profiler-stack-query` mode=`thread_breakdown` for per-thread distribution → mode=`function_callers` for the dominant function.
30
30
  - **Memory leak** → `profiler-stack-query` mode=`leak_stacks` filtered by `object_type` for responsible frames and libraries.
31
- - iOS: if leaks come back unattributed (responsible frame `<Call stack limit reached>`), re-run `native-profiler-start` with `malloc_stack_logging: true`. This cold-launches the app with Malloc Stack Logging so leaks carry a real allocation backtrace (responsible frame + library). It restarts the app and adds overhead, so use it only when you need leak attribution — not for CPU/hang passes.
31
+ - iOS: if leaks come back unattributed (responsible frame `<Call stack limit reached>`), re-run `native-profiler-start` with `malloc_stack_logging: true`. This cold-launches the app with Malloc Stack Logging so leaks carry a real allocation backtrace (responsible frame + library). It restarts the app and adds overhead, so use it only when you need leak attribution, not for CPU/hang passes.
32
32
 
33
33
  After presenting findings, ask the user whether to investigate further, implement fixes, or stop. After applying fixes, always re-profile the same scenario and compare with `profiler-load`. Report honestly whether the target metric improved, regressed, or stayed flat. If the fix showed no net benefit or introduced regressions elsewhere, say so and reconsider.
34
34
 
@@ -40,12 +40,12 @@ After presenting findings, ask the user whether to investigate further, implemen
40
40
 
41
41
  ## 4. Workflow
42
42
 
43
- **Complete all steps in order — do not break mid-flow.**
43
+ **Complete all steps in order; do not break mid-flow.**
44
44
 
45
45
  ### Step 0: Ensure the target app is running
46
46
 
47
47
  The `native-profiler-start` tool **auto-detects** the running app on the device.
48
- You do not need to derive `app_process` manually — just make sure the app is launched.
48
+ You do not need to derive `app_process` manually; just make sure the app is launched.
49
49
 
50
50
  1. If the app is already running on the device, skip to Step 1 (do not pass `app_process`).
51
51
  2. If the app is not running, use `launch-app` with the correct bundle ID first.
@@ -60,7 +60,7 @@ Let the user interact with the app or drive interaction via simulator tools (see
60
60
 
61
61
  ### Step 2: Stop and export
62
62
 
63
- Call `native-profiler-stop` with `device_id`. iOS sends SIGINT to xctrace, waits for trace packaging, and exports CPU, hangs, and leaks data to XML — check `exportDiagnostics` for any export warnings. Android sends SIGTERM to the on-device perfetto daemon, polls `/proc/<pid>` until it exits, then `adb pull`s the `.pftrace` to the host.
63
+ Call `native-profiler-stop` with `device_id`. iOS sends SIGINT to xctrace, waits for trace packaging, and exports CPU, hangs, and leaks data to XML; check `exportDiagnostics` for any export warnings. Android sends SIGTERM to the on-device perfetto daemon, polls `/proc/<pid>` until it exits, then `adb pull`s the `.pftrace` to the host.
64
64
 
65
65
  ### Step 3: Analyze
66
66
 
@@ -68,7 +68,7 @@ Call `native-profiler-analyze` with `device_id`. Returns a markdown report with
68
68
 
69
69
  ### Step 4: Present findings and ask about next steps
70
70
 
71
- Present a concise summary of the key findings. Then follow the "After analysis" guideline — ask whether to investigate further with query tools, implement fixes, or stop.
71
+ Present a concise summary of the key findings. Then follow the "After analysis" guideline: ask whether to investigate further with query tools, implement fixes, or stop.
72
72
 
73
73
  ### Step 5: Drill-down investigation
74
74
 
@@ -89,13 +89,13 @@ To revisit a previous trace:
89
89
  Bottlenecks are categorized by severity:
90
90
 
91
91
  - **RED**: CPU functions taking >15% of total time, all UI hangs, and **attributed** memory leaks (those with a resolved responsible frame). These require immediate attention.
92
- - **YELLOW**: CPU functions taking 3-15% of total time, and **unattributed** memory leaks (`<Call stack limit reached>`, no library — see the memory-leaks caveat below). Worth investigating but may be acceptable.
92
+ - **YELLOW**: CPU functions taking 3-15% of total time, and **unattributed** memory leaks (`<Call stack limit reached>`, no library; see the memory-leaks caveat below). Worth investigating but may be acceptable.
93
93
 
94
94
  Each bottleneck type indicates a different class of problem:
95
95
 
96
96
  - **CPU hotspots**: Native functions consuming excessive CPU time. Look for tight loops, expensive computations, or redundant work.
97
97
  - **UI hangs**: Main thread blocked long enough to cause visible jank or unresponsiveness. Often caused by synchronous I/O, heavy layout passes, or lock contention.
98
- - **Memory leaks**: Objects allocated but never freed. Common causes include retain cycles, unclosed resources, or forgotten observers. Argent records via `xctrace --attach`, which has no malloc-stack history, so on the simulator most leaks come back **unattributed** (`<Call stack limit reached>`, no library) and are dominated by benign system allocations — these are reported as a low-confidence YELLOW summary, not confirmed RED leaks. For attributed stacks, capture with malloc stack logging enabled at launch.
98
+ - **Memory leaks**: Objects allocated but never freed. Common causes include retain cycles, unclosed resources, or forgotten observers. Argent records via `xctrace --attach`, which has no malloc-stack history, so on the simulator most leaks come back **unattributed** (`<Call stack limit reached>`, no library) and are dominated by benign system allocations; these are reported as a low-confidence YELLOW summary, not confirmed RED leaks. For attributed stacks, capture with malloc stack logging enabled at launch.
99
99
 
100
100
  ---
101
101
 
@@ -103,6 +103,6 @@ Each bottleneck type indicates a different class of problem:
103
103
 
104
104
  - **Simulator vs device**: Simulator profiling reflects host Mac performance, not real device hardware. Use device profiling for accurate CPU timings and memory behavior.
105
105
  - **xctrace availability (iOS)**: Requires Xcode command-line tools installed. Verify with `xcrun xctrace version`.
106
- - **Profiler overhead**: xctrace instrumentation adds CPU load. If `JSLexer`, `JSONEmitter`, or Hermes runtime internals dominate the JS thread in CPU hotspot results, those reflect profiler overhead — not app work. Discount those entries when evaluating findings.
106
+ - **Profiler overhead**: xctrace instrumentation adds CPU load. If `JSLexer`, `JSONEmitter`, or Hermes runtime internals dominate the JS thread in CPU hotspot results, those reflect profiler overhead, not app work. Discount those entries when evaluating findings.
107
107
  - **Run-to-run variance**: Small fluctuations in CPU percentages between runs are normal. Treat only consistent directional changes (across 2+ runs or >15% delta) as actionable signal.
108
108
  - **Live data variability**: If the app fetches live API data, different responses between runs change rendering workload independently of code changes. Note when data-dependent screens show variance.
@@ -106,9 +106,9 @@ After the last edit and audit, set the streak to zero:
106
106
 
107
107
  1. Choose one runner for both passes. Use `flow-execute` locally or `argent flow run <name> --platform <platform>` for CI. Switching runners resets the streak.
108
108
  2. Seed, review, and freeze snapshot baselines. Baseline updates do not count as passes.
109
- 3. Before mobile pass 1, recycle Argent services for this flow's device: two warm passes are correlated evidence, because a fixed timing margin can pass twice simply because environment speed did not change. Scope `stop-all-simulator-servers` to `devices: [<device>]`. Never omit the scope — a bare call is the machine-wide sweep, and step 7 restarts this proof often enough to reap every other agent's devices repeatedly. Use the MCP call for `flow-execute`, or `argent run stop-all-simulator-servers --devices <device>` from the standalone runner's install. The reset must not change app or account data. For Chromium, let the runner boot the declared app and omit `device`. Vega owns no recyclable Argent services, so the teardown is a no-op there and both passes are warm.
110
- 4. Run from the flow's launch and setup without baseline-update mode. Count a pass only when `ok: true` and every acceptance check executed. A false `when:` can skip optional setup only. An errored step does not advance the streak, and the count mixes two kinds — read each reason. One that could not run (an unreadable tree under `idle`, an unresolvable `run:` target) is environment: fix it and rerun. **A failed `launch:` also scores `errored`, and it is a verdict about the app** — an app that no longer installs or starts is the regression this test exists to catch, so report it instead of rerunning.
111
- 5. Resolve every passing-step warning before completion. Also resolve recorded-wait warnings from `flow-finish-recording`. Follow [Live waits and checks](../argent-create-flow/references/live-authoring.md#live-waits-and-checks). For runner warnings, `await: { idle: true }` raises [six different warnings](../argent-create-flow/references/flow-yaml.md#idle-readiness), so read which one it is first. Two say the screen was moving. One says the wait ran out mid-hold and needs a larger `timeout:`. One says the tree stayed empty. One — **settled on the UI tree alone** — says the hierarchy did hold still and only the screenshot pairs were missing, so inspect the capture path rather than the app's rendering. One says the step ended with no evidence either way. Inspect the screen, disclose the cause, and verify that surrounding acceptance checks use stable elements rather than stillness. A [selector-less gesture](../argent-create-flow/references/flow-yaml.md#directives) — a coordinate `tap`/`long-press`/`swipe`, or a `pinch`/`rotate` with no `on:` — warns in a different shape: a tree-source outage left it unsettled, so it dispatched blind and the green says only that the gesture was sent. Restore the tree source, usually by relaunching the app so the instrumentation loads, and rerun. Accepting that warning needs an app that serves no tree, which cannot satisfy this contract anyway.
109
+ 3. Before mobile pass 1, recycle Argent services for this flow's device: two warm passes are correlated evidence, because a fixed timing margin can pass twice simply because environment speed did not change. Scope `stop-all-simulator-servers` to `devices: [<device>]`. Never omit the scope: a bare call is the machine-wide sweep, and step 7 restarts this proof often enough to reap every other agent's devices repeatedly. Use the MCP call for `flow-execute`, or `argent run stop-all-simulator-servers --devices <device>` from the standalone runner's install. The reset must not change app or account data. For Chromium, let the runner boot the declared app and omit `device`. Vega owns no recyclable Argent services, so the teardown is a no-op there and both passes are warm.
110
+ 4. Run from the flow's launch and setup without baseline-update mode. Count a pass only when `ok: true` and every acceptance check executed. A false `when:` can skip optional setup only. An errored step does not advance the streak, and the count mixes two kinds: read each reason. One that could not run (an unreadable tree under `idle`, an unresolvable `run:` target) is environment: fix it and rerun. **A failed `launch:` also scores `errored`, and it is a verdict about the app**; an app that no longer installs or starts is the regression this test exists to catch, so report it instead of rerunning.
111
+ 5. Resolve every passing-step warning before completion. Also resolve recorded-wait warnings from `flow-finish-recording`. Follow [Live waits and checks](../argent-create-flow/references/live-authoring.md#live-waits-and-checks). For runner warnings, `await: { idle: true }` raises [six different warnings](../argent-create-flow/references/flow-yaml.md#idle-readiness), so read which one it is first. Two say the screen was moving. One says the wait ran out mid-hold and needs a larger `timeout:`. One says the tree stayed empty. One, **settled on the UI tree alone**, says the hierarchy did hold still and only the screenshot pairs were missing, so inspect the capture path rather than the app's rendering. One says the step ended with no evidence either way. Inspect the screen, disclose the cause, and verify that surrounding acceptance checks use stable elements rather than stillness. A [selector-less gesture](../argent-create-flow/references/flow-yaml.md#directives) (a coordinate `tap`/`long-press`/`swipe`, or a `pinch`/`rotate` with no `on:`) warns in a different shape: a tree-source outage left it unsettled, so it dispatched blind and the green says only that the gesture was sent. Restore the tree source, usually by relaunching the app so the instrumentation loads, and rerun. Accepting that warning needs an app that serves no tree, which cannot satisfy this contract anyway.
112
112
  6. Run the same YAML again immediately with the same runner. Do not manually reset app or account data.
113
113
  7. Reset the streak after any failure, edit, re-recording, baseline update, or state-changing manual recovery. Repair through `argent-create-flow`, audit again, and restart with fresh services.
114
114
 
@@ -7,13 +7,13 @@ Physical iPhone (`kind: "device"`): Metro debugging and profiling tools reject i
7
7
 
8
8
  ## 1. Starting the React Native App
9
9
 
10
- ### 1.1 Explore Configuration (MANDATORY — Do This First)
10
+ ### 1.1 Explore Configuration (MANDATORY: Do This First)
11
11
 
12
12
  **Before running commands**, read the project's build and run configuration from the `argent-environment-inspector` subagent result.
13
13
 
14
14
  Do NOT default to `npx react-native start` or `npx react-native run-ios` without first checking for custom scripts and workflows.
15
15
 
16
- **Manual fallback** (if neither the agent nor the tool is available): read ALL `package.json` scripts — look for custom scripts like `start:local`, `start:dev`, `ios`, `build:ios`, flavors, etc. Custom scripts take priority over default commands. Also check `metro.config.js` for non-default port or watchFolders. For iOS builds, prefer opening `.xcworkspace` over `.xcodeproj` (CocoaPods generates the workspace).
16
+ **Manual fallback** (if neither the agent nor the tool is available): read ALL `package.json` scripts: look for custom scripts like `start:local`, `start:dev`, `ios`, `build:ios`, flavors, etc. Custom scripts take priority over default commands. Also check `metro.config.js` for non-default port or watchFolders. For iOS builds, prefer opening `.xcworkspace` over `.xcodeproj` (CocoaPods generates the workspace).
17
17
 
18
18
  **If the project structure is convoluted, ask the user before proceeding.**
19
19
 
@@ -37,7 +37,7 @@ Do NOT default to `npx react-native start` or `npx react-native run-ios` without
37
37
 
38
38
  Optional: `npx react-native start --reset-cache` if cache issues are suspected.
39
39
 
40
- 1. **Verify Metro is ready**: use the `debugger-status` tool. It returns a `status` result instead of erroring: `status: "connected"` or `status: "not_connected"` with `reason: "no_app_connected"` both mean Metro is up (the app just hasn't attached yet); `reason: "metro_not_running"` means Metro is not reachable — follow the result's `guidance`.
40
+ 1. **Verify Metro is ready**: use the `debugger-status` tool. It returns a `status` result instead of erroring: `status: "connected"` or `status: "not_connected"` with `reason: "no_app_connected"` both mean Metro is up (the app just hasn't attached yet); `reason: "metro_not_running"` means Metro is not reachable; follow the result's `guidance`.
41
41
 
42
42
  1. **Projects with flavors or custom configs**: Use project-specific start script if present (e.g. `npm run start:local`), and start Metro **before** running the app.
43
43
 
@@ -47,7 +47,7 @@ In a **separate** terminal (Metro keeps running in the first):
47
47
 
48
48
  **Use the project's custom build/run script if one exists** (e.g. `npm run ios`, `npm run android`, `yarn ios:debug`). Only fall back to the defaults below if no custom scripts are defined.
49
49
 
50
- **Pass the target device explicitly** — derive it from `list-devices` (see `<device_selection_rule>`):
50
+ **Pass the target device explicitly**: derive it from `list-devices` (see `<device_selection_rule>`):
51
51
 
52
52
  ```bash
53
53
  npx react-native run-ios --simulator="<name>" # iOS (or --udid <UDID>)
@@ -78,7 +78,7 @@ lsof -i :PORT
78
78
  - **No output** → Port free; safe to start Metro.
79
79
  - **Output with PID** → Another process is using the port.
80
80
 
81
- Use the `debugger-status` tool to check whether the process on that port is actually a Metro server — it returns a structured result, not an error. `status: "connected"` or `reason: "no_app_connected"` → the process is Metro. `reason: "metro_not_running"` while `lsof` shows a listener → the port is occupied by something that is **not** Metro; the result's `detail` field shows what the process answered (`Metro at port ... is not running (got: ...)`). In that case ask the user whether you may kill the process.
81
+ Use the `debugger-status` tool to check whether the process on that port is actually a Metro server: it returns a structured result, not an error. `status: "connected"` or `reason: "no_app_connected"` → the process is Metro. `reason: "metro_not_running"` while `lsof` shows a listener → the port is occupied by something that is **not** Metro; the result's `detail` field shows what the process answered (`Metro at port ... is not running (got: ...)`). In that case ask the user whether you may kill the process.
82
82
 
83
83
  To kill a Metro process, use the `stop-metro` tool (requires user confirmation).
84
84
 
@@ -87,7 +87,7 @@ To kill a Metro process, use the `stop-metro` tool (requires user confirmation).
87
87
  - **App must point at the same host/port as the running Metro.** Default: same machine, port 8081.
88
88
  - **iOS Simulator:** By default uses localhost; no extra config needed for same-machine Metro.
89
89
 
90
- **Verify Metro is reachable:** use the `debugger-status` tool. `reason: "metro_not_running"` means Metro did not answer on that port — start it (§2.1); `"no_app_connected"` means Metro answered but the app has not attached (§2.3). Any other reason: follow the result's `guidance` (it does not by itself prove Metro is up).
90
+ **Verify Metro is reachable:** use the `debugger-status` tool. `reason: "metro_not_running"` means Metro did not answer on that port: start it (§2.1); `"no_app_connected"` means Metro answered but the app has not attached (§2.3). Any other reason: follow the result's `guidance` (it does not by itself prove Metro is up).
91
91
 
92
92
  ### 2.3 Reload the App (Ensure New Bundle)
93
93
 
@@ -139,17 +139,17 @@ Once you discover the correct build/run workflow for a project, **save it to pro
139
139
 
140
140
  ### 3.5 Device Control
141
141
 
142
- | Action | Tool / Command |
143
- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
144
- | List devices | `list-devices` tool (iOS + Android) |
145
- | Boot an iOS simulator | `boot-device` tool with `udid` |
146
- | Boot an Android emulator | `boot-device` tool with `avdName` |
147
- | Launch an app | `launch-app` tool (pass device id + bundle id / package name) |
148
- | Restart an app | `restart-app` tool (pass device id + bundle id / package name) |
149
- | Open a URL / deep link | `open-url` tool (pass device id + URL) |
150
- | Rotate device | `rotate` tool |
151
- | Stop simulator server | `stop-simulator-server` tool (iOS UDID or Android serial — one device) |
152
- | Stop all simulator servers | `stop-all-simulator-servers` tool — pass `devices: [...]` to scope the teardown to this session's devices (an unscoped call also tears down other agents' devices; use it only for a machine-wide cleanup) |
142
+ | Action | Tool / Command |
143
+ | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
144
+ | List devices | `list-devices` tool (iOS + Android) |
145
+ | Boot an iOS simulator | `boot-device` tool with `udid` |
146
+ | Boot an Android emulator | `boot-device` tool with `avdName` |
147
+ | Launch an app | `launch-app` tool (pass device id + bundle id / package name) |
148
+ | Restart an app | `restart-app` tool (pass device id + bundle id / package name) |
149
+ | Open a URL / deep link | `open-url` tool (pass device id + URL) |
150
+ | Rotate device | `rotate` tool |
151
+ | Stop simulator server | `stop-simulator-server` tool (iOS UDID or Android serial, one device) |
152
+ | Stop all simulator servers | `stop-all-simulator-servers` tool: pass `devices: [...]` to scope the teardown to this session's devices (an unscoped call also tears down other agents' devices; use it only for a machine-wide cleanup) |
153
153
 
154
154
  For full simulator setup workflow, refer to the `argent-ios-simulator-setup` skill.
155
155
 
@@ -161,7 +161,7 @@ For full simulator setup workflow, refer to the `argent-ios-simulator-setup` ski
161
161
 
162
162
  | Problem type | Tool / Where to look |
163
163
  | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
164
- | **JavaScript errors / logs** | Use `debugger-log-registry` to get a summary and log file path, then `Grep` to search. If it returns `status: "not_connected"`, no log file is returned — follow its `guidance` to reconnect first. |
164
+ | **JavaScript errors / logs** | Use `debugger-log-registry` to get a summary and log file path, then `Grep` to search. If it returns `status: "not_connected"`, no log file is returned; follow its `guidance` to reconnect first. |
165
165
  | **React component hierarchy** | Use `debugger-component-tree` tool for a text tree, or `debugger-inspect-element` at specific logical pixel coordinates (not normalized 0-1). |
166
166
  | **Visual state of the app** | Use `screenshot` tool to capture the current screen, but prefer `describe` or `debugger-component-tree` for actual navigation and target discovery. If a permission prompt or system-owned modal overlay is not exposed reliably, then fall back to `screenshot`. |
167
167
  | **Evaluate JS in the app** | Use `debugger-evaluate` tool to run JavaScript in the app's runtime. |
@@ -6,16 +6,16 @@ description: Optimizes a React Native app by profiling first to find real bottle
6
6
  ## Rules
7
7
 
8
8
  - Do not apply shotgun optimizations. Measure first, define what "good enough" looks like (target metric + threshold), fix the top offender, re-measure honestly.
9
- - **Quick scan** — `react-profiler-renders` for a live render count table. Identifies hot components instantly.
10
- - **Deep measure** — load `argent-react-native-profiler` skill. `react-profiler-start` → interact → `react-profiler-stop` → `react-profiler-analyze`.
11
- - **Inspect** — `react-profiler-component-source` per finding. `react-profiler-fiber-tree` to trace component ancestry and render cost.
9
+ - **Quick scan**: `react-profiler-renders` for a live render count table. Identifies hot components instantly.
10
+ - **Deep measure**: load `argent-react-native-profiler` skill. `react-profiler-start` → interact → `react-profiler-stop` → `react-profiler-analyze`.
11
+ - **Inspect**: `react-profiler-component-source` per finding. `react-profiler-fiber-tree` to trace component ancestry and render cost.
12
12
  - **Verify correctness** - before fixing, recollect information from steps above and make a logical conclusion whether the approach is worth undertaking.
13
- - **Fix** — apply one fix. Validate with `debugger-evaluate` before committing.
14
- - **Re-measure** — report whether the target metric improved, regressed, or stayed flat. Check for regressions in other areas. If no net benefit or unacceptable tradeoffs, revert.
13
+ - **Fix**: apply one fix. Validate with `debugger-evaluate` before committing.
14
+ - **Re-measure**: report whether the target metric improved, regressed, or stayed flat. Check for regressions in other areas. If no net benefit or unacceptable tradeoffs, revert.
15
15
  - **Profile for discovery, not only verification.** Use the profiler to find issues static analysis missed, not only to confirm fixes.
16
- - **One fix per cycle for architectural changes.** Mechanical batch fixes (inline styles, index keys) can be grouped — re-profile once after the batch. When the measurement involves device interaction, record it as a flow (`argent-create-flow` skill) before the first run so all subsequent cycles replay identical steps.
16
+ - **One fix per cycle for architectural changes.** Mechanical batch fixes (inline styles, index keys) can be grouped; re-profile once after the batch. When the measurement involves device interaction, record it as a flow (`argent-create-flow` skill) before the first run so all subsequent cycles replay identical steps.
17
17
  - **React Compiler**: if `react-profiler-analyze` reports `reactCompilerEnabled: true`, do NOT propose `useCallback`/`useMemo`/`React.memo` unless you confirmed compiler bail-out via `react-profiler-fiber-tree` (absent `useMemoCache`).
18
- - **Sub-agents**: Phases 1–2 dispatch sub-agents — one per file for lint results, one per checklist item for semantic. Sub-agents CANNOT touch the device - all profiling and E2E verification must happen in the main agent.
18
+ - **Sub-agents**: Phases 1–2 dispatch sub-agents: one per file for lint results, one per checklist item for semantic. Sub-agents CANNOT touch the device - all profiling and E2E verification must happen in the main agent.
19
19
 
20
20
  ## Pipeline
21
21
 
@@ -25,20 +25,20 @@ Copy this checklist into your TODO list:
25
25
 
26
26
  ```
27
27
  Optimization Progress:
28
- - [ ] Phase 1: Lint sweep (deterministic — catch mechanical issues without a running app)
29
- - [ ] Phase 2: Semantic sweep (judgment — memoization, lists, animations, etc.)
28
+ - [ ] Phase 1: Lint sweep (deterministic: catch mechanical issues without a running app)
29
+ - [ ] Phase 2: Semantic sweep (judgment: memoization, lists, animations, etc.)
30
30
  - [ ] Phase 3: Baseline profile (find real bottlenecks, fix top offenders)
31
31
  - [ ] Phase 4: Verify no regressions (crashes, errors, red screens)
32
32
  ```
33
33
 
34
34
  ### Phase 1: Lint sweep
35
35
 
36
- Run ESLint once at the project root with a comprehensive RN performance ruleset. Dispatch sub-agents to fix results — one per file.
36
+ Run ESLint once at the project root with a comprehensive RN performance ruleset. Dispatch sub-agents to fix results: one per file.
37
37
  See [references/lint-rules.md](references/lint-rules.md) for ruleset and procedure.
38
38
 
39
39
  ### Phase 2: Semantic sweep
40
40
 
41
- Review each area requiring judgment — memoization, list rendering, animations, async patterns, effect cleanup, state hygiene, context architecture. Dispatch one sub-agent per checklist item.
41
+ Review each area requiring judgment: memoization, list rendering, animations, async patterns, effect cleanup, state hygiene, context architecture. Dispatch one sub-agent per checklist item.
42
42
  See [references/semantic-checklist.md](references/semantic-checklist.md) for full checklist.
43
43
 
44
44
  ### Phase 3: Visual profiling
@@ -51,7 +51,7 @@ See [references/semantic-checklist.md](references/semantic-checklist.md) for ful
51
51
 
52
52
  ### Phase 4: Verify no regressions
53
53
 
54
- Navigate every screen and UI flow within scope, confirm each renders without errors. If no scope was specified, verify the entire app — cover all reachable screens via `argent-device-interact`. Use `debugger-log-registry` to check for runtime errors (if it returns `status: "not_connected"` there is no log file — follow its `guidance` to reconnect first) and take screenshots to check for red/yellow error screens. Check for regressions introduced by fixes (e.g., fewer re-renders but higher CPU, or new jank in a different screen). Main agent only.
54
+ Navigate every screen and UI flow within scope, confirm each renders without errors. If no scope was specified, verify the entire app: cover all reachable screens via `argent-device-interact`. Use `debugger-log-registry` to check for runtime errors (if it returns `status: "not_connected"` there is no log file; follow its `guidance` to reconnect first) and take screenshots to check for red/yellow error screens. Check for regressions introduced by fixes (e.g., fewer re-renders but higher CPU, or new jank in a different screen). Main agent only.
55
55
 
56
56
  ## App-wide optimization
57
57
 
@@ -2,13 +2,13 @@
2
2
 
3
3
  Match profiler findings and semantic sweep results to concrete fixes.
4
4
 
5
- | Finding | Fix | Detail |
6
- | -------------------------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
7
- | Re-renders with same props | `React.memo(Comp)` | **Skip if React Compiler active** — `react-profiler-analyze` reports compiler status per component |
8
- | Expensive recomputation / unstable callbacks | `useMemo(fn, [deps])` / `useCallback(fn, [deps])` | `useCallback` must pair with `React.memo` on child — alone it has no effect |
9
- | Inline objects/arrays in JSX | `StyleSheet.create()` / module-level const | New reference every render breaks shallow equality |
10
- | List jank | `removeClippedSubviews`, `maxToRenderPerBatch`, `windowSize`, `getItemLayout` | Or migrate to `@shopify/flash-list` with `estimatedItemSize` |
11
- | JS-thread animation jank | `useNativeDriver: true` or `react-native-reanimated` | `useNativeDriver` only works for `transform` and `opacity` properties |
12
- | Heavy work during transitions | `InteractionManager.runAfterInteractions()` | Defers execution until active animations complete |
13
- | Slow startup | Hermes + inline requires in `metro.config.js` | Lazy `require()` defers loading heavy modules until first use |
14
- | Redundant, heavy, or n+1 network calls | `view-network-logs` → `view-network-request-details` | Batch, debounce, or cache at the data layer |
5
+ | Finding | Fix | Detail |
6
+ | -------------------------------------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
7
+ | Re-renders with same props | `React.memo(Comp)` | **Skip if React Compiler active**: `react-profiler-analyze` reports compiler status per component |
8
+ | Expensive recomputation / unstable callbacks | `useMemo(fn, [deps])` / `useCallback(fn, [deps])` | `useCallback` must pair with `React.memo` on child; alone it has no effect |
9
+ | Inline objects/arrays in JSX | `StyleSheet.create()` / module-level const | New reference every render breaks shallow equality |
10
+ | List jank | `removeClippedSubviews`, `maxToRenderPerBatch`, `windowSize`, `getItemLayout` | Or migrate to `@shopify/flash-list` with `estimatedItemSize` |
11
+ | JS-thread animation jank | `useNativeDriver: true` or `react-native-reanimated` | `useNativeDriver` only works for `transform` and `opacity` properties |
12
+ | Heavy work during transitions | `InteractionManager.runAfterInteractions()` | Defers execution until active animations complete |
13
+ | Slow startup | Hermes + inline requires in `metro.config.js` | Lazy `require()` defers loading heavy modules until first use |
14
+ | Redundant, heavy, or n+1 network calls | `view-network-logs` → `view-network-request-details` | Batch, debounce, or cache at the data layer |
@@ -51,5 +51,5 @@ Install missing plugins before running: `npm install --save-dev eslint-plugin-re
51
51
  1. Check if the project has an existing ESLint config.
52
52
  2a. If yes, extend it with missing rules from above.
53
53
  2b. If no config, create a temporary `.eslintrc.json` with all rules above.
54
- 2. Run: `npx eslint --format json <src_dir>` — replace `<src_dir>` with the project's JS/TS source root (check `package.json` scripts or look for `src/`, `app/`, `lib/`)
54
+ 2. Run: `npx eslint --format json <src_dir>`; replace `<src_dir>` with the project's JS/TS source root (check `package.json` scripts or look for `src/`, `app/`, `lib/`)
55
55
  3. Parse output into: `file:line -> rule -> message`.
@@ -46,11 +46,11 @@ Follow these rules throughout the profiling workflow:
46
46
 
47
47
  After presenting the analysis report, always ask the user what they want to do next. Present these options:
48
48
 
49
- 1. **Investigate further** — drill down into specific findings using query tools (CPU call trees, commit cascades, hang stacks, etc.) to identify root causes with confidence before making changes.
50
- 2. **Implement fixes** — apply changes based on the current findings, then re-profile to measure whether the metric changed (improved, regressed, or stayed flat).
51
- 3. **Done for now** — accept the report as-is.
49
+ 1. **Investigate further**: drill down into specific findings using query tools (CPU call trees, commit cascades, hang stacks, etc.) to identify root causes with confidence before making changes.
50
+ 2. **Implement fixes**: apply changes based on the current findings, then re-profile to measure whether the metric changed (improved, regressed, or stayed flat).
51
+ 3. **Done for now**: accept the report as-is.
52
52
 
53
- Do NOT silently move on after the report. The report is the starting point, not the end — query tools exist specifically to let you dig deeper into anything the report flags.
53
+ Do NOT silently move on after the report. The report is the starting point, not the end; query tools exist specifically to let you dig deeper into anything the report flags.
54
54
 
55
55
  ### During investigation: use query tools proactively
56
56
 
@@ -76,36 +76,36 @@ When profiling requires a specific interaction sequence (scroll a list, navigate
76
76
 
77
77
  ## 4. Standard Profiling Workflow
78
78
 
79
- **Complete all steps in order — do not break mid-flow.**
79
+ **Complete all steps in order; do not break mid-flow.**
80
80
 
81
81
  ### Step 1: Start profiling
82
82
 
83
- Mind the react-native and ios-native profiler selection mentioned above when starting the session and start the tools. **Save `startedAtEpochMs` from the response** — you will need it for annotation offsets. Every subsequent profiler/query call in this session must use the same `device_id`. Before beginning, define lightweight success criteria with the user: which metric matters most (e.g., `totalRenderMs`, specific commit duration, render count for a component) and what threshold would be meaningful. This anchors later evaluation. On success:
83
+ Mind the react-native and ios-native profiler selection mentioned above when starting the session and start the tools. **Save `startedAtEpochMs` from the response**: you will need it for annotation offsets. Every subsequent profiler/query call in this session must use the same `device_id`. Before beginning, define lightweight success criteria with the user: which metric matters most (e.g., `totalRenderMs`, specific commit duration, render count for a component) and what threshold would be meaningful. This anchors later evaluation. On success:
84
84
 
85
85
  - if user asked you to perform the profiling, determine how to profile yourself using tools described in `argent-device-interact` skill.
86
- - if the user stated they wish to perform the interaction themselves — suggest what interaction to perform (e.g. "scroll the list", "switch tabs") and wait for their reply.
86
+ - if the user stated they wish to perform the interaction themselves, suggest what interaction to perform (e.g. "scroll the list", "switch tabs") and wait for their reply.
87
87
  If you received information about **existing profiling session** being owned by another agent:
88
88
  - if session is marked as "stale", you may overtake it without prompting the user for allowance
89
89
  - if session is NOT "stale" - before taking action and terminating the other session, **stop and ask user what you should do**, explaining the situation.
90
90
 
91
91
  #### Annotate every interaction
92
92
 
93
- After each `gesture-tap` or `gesture-swipe` call, record an annotation using the returned `timestampMs`. Compute `offsetMs = timestampMs - startedAtEpochMs`. Do this for _every_ interaction — including back-navigation swipes, not just the primary action. Pass all collected annotations to `react-profiler-analyze` in Step 3.
93
+ After each `gesture-tap` or `gesture-swipe` call, record an annotation using the returned `timestampMs`. Compute `offsetMs = timestampMs - startedAtEpochMs`. Do this for _every_ interaction, including back-navigation swipes, not just the primary action. Pass all collected annotations to `react-profiler-analyze` in Step 3.
94
94
 
95
95
  ### Step 2: Stop and collect
96
96
 
97
97
  Call `react-profiler-stop` **and** `native-profiler-stop` in parallel. Only skip `native-profiler-stop` if you did not start it in Step 1. Note `duration_ms` and `fiber_renders_captured`.
98
- If `fiber_renders_captured: 0`, warn the user — React commit data may be missing.
98
+ If `fiber_renders_captured: 0`, warn the user: React commit data may be missing.
99
99
 
100
100
  ### Step 3: Analyze
101
101
 
102
- Call `react-profiler-analyze` with `port`, `device_id`, `project_root`, `platform`, and `rn_version`. The report includes metadata such as `reactCompilerEnabled`, `strictModeEnabled`, and `buildMode` — check these in the returned markdown report.
102
+ Call `react-profiler-analyze` with `port`, `device_id`, `project_root`, `platform`, and `rn_version`. The report includes metadata such as `reactCompilerEnabled`, `strictModeEnabled`, and `buildMode`; check these in the returned markdown report.
103
103
 
104
- If you performed interactions using `gesture-tap`/`gesture-swipe`, pass `annotations` to mark when each action occurred. Each annotation's `offsetMs` must be computed as `tapTimestampMs - startedAtEpochMs`, where `tapTimestampMs` is the `timestampMs` returned by the gesture-tap/gesture-swipe tool and `startedAtEpochMs` was returned by `react-profiler-start`. Do **not** use `Date.now()` for this calculation — only server-side timestamps from the tool return values.
104
+ If you performed interactions using `gesture-tap`/`gesture-swipe`, pass `annotations` to mark when each action occurred. Each annotation's `offsetMs` must be computed as `tapTimestampMs - startedAtEpochMs`, where `tapTimestampMs` is the `timestampMs` returned by the gesture-tap/gesture-swipe tool and `startedAtEpochMs` was returned by `react-profiler-start`. Do **not** use `Date.now()` for this calculation; only server-side timestamps from the tool return values.
105
105
 
106
- If dual profiling, also call `native-profiler-analyze`, then **you must** call `profiler-combined-report` for the cross-correlated view — do not skip this step when both profilers ran; the combined report surfaces correlations that individual reports miss.
106
+ If dual profiling, also call `native-profiler-analyze`, then **you must** call `profiler-combined-report` for the cross-correlated view; do not skip this step when both profilers ran; the combined report surfaces correlations that individual reports miss.
107
107
 
108
- The analyze report includes **CPU hotspots per commit** — showing exactly which JS functions ran during each slow React commit. Raw data is saved to disk automatically for later reload.
108
+ The analyze report includes **CPU hotspots per commit**, showing exactly which JS functions ran during each slow React commit. Raw data is saved to disk automatically for later reload.
109
109
 
110
110
  ### Step 4: Assess results
111
111
 
@@ -113,18 +113,18 @@ Analyze whether the results give you a proper image of what is wrong with the ap
113
113
 
114
114
  ### Step 5: Present findings and ask about next steps
115
115
 
116
- Present a concise summary of the key findings - present whether possibilities for improvement exist and how performing further actions could affect performance. Then follow the "After analysis" guideline — ask whether to investigate further, implement fixes (if available), or stop.
116
+ Present a concise summary of the key findings - present whether possibilities for improvement exist and how performing further actions could affect performance. Then follow the "After analysis" guideline: ask whether to investigate further, implement fixes (if available), or stop.
117
117
 
118
118
  ### Step 6: Drill-down investigation (iterative)
119
119
 
120
120
  Based on findings from the report, use query tools to investigate deeper:
121
121
 
122
- - **Slow component?** -> `profiler-cpu-query` mode=`component_cpu` component_name=`AppNavigator` — shows what JS functions ran during that component's commits.
123
- - **Want to see the call tree?** -> `profiler-cpu-query` mode=`call_tree` function_name=`expensiveFunction` — shows callers and callees.
124
- - **What happened during a time window?** -> `profiler-commit-query` mode=`by_time_range` — lists all commits in a range.
125
- - **Full commit detail?** -> `profiler-commit-query` mode=`by_index` commit_index=38 — all components, props changes, parent cascade.
126
- - **Who triggered whom?** -> `profiler-commit-query` mode=`cascade_tree` — visual parent-child cascade.
127
- - **iOS hang details?** -> `profiler-stack-query` mode=`hang_stacks` — native call stacks during a hang.
122
+ - **Slow component?** -> `profiler-cpu-query` mode=`component_cpu` component_name=`AppNavigator`: shows what JS functions ran during that component's commits.
123
+ - **Want to see the call tree?** -> `profiler-cpu-query` mode=`call_tree` function_name=`expensiveFunction`: shows callers and callees.
124
+ - **What happened during a time window?** -> `profiler-commit-query` mode=`by_time_range`: lists all commits in a range.
125
+ - **Full commit detail?** -> `profiler-commit-query` mode=`by_index` commit_index=38: all components, props changes, parent cascade.
126
+ - **Who triggered whom?** -> `profiler-commit-query` mode=`cascade_tree`: visual parent-child cascade.
127
+ - **iOS hang details?** -> `profiler-stack-query` mode=`hang_stacks`: native call stacks during a hang.
128
128
 
129
129
  Repeat as needed until you identify the root cause function and file, referring to step 4 for honest evaluation. After each round of investigation, ask the user if they want to continue digging or move to fixing.
130
130
 
@@ -135,7 +135,7 @@ If you profiled multiple scenarios and need to revisit earlier data:
135
135
  1. Call `profiler-load` mode=`list` to see all saved sessions with timestamps (the list now also shows Runtime / Device / Metro bundle columns to help identify the right session).
136
136
  2. Call `profiler-load` mode=`load_react` session_id=`<timestamp>` device_id=`<UDID>` to reload React data. `device_id` scopes the reload into the `port:device_id` cache slot.
137
137
  3. Call `profiler-load` mode=`load_native` session_id=`<timestamp>` device_id=`<UDID>` to reload native profiler data.
138
- 4. Query tools now operate on the reloaded session data — **pass the same `device_id` you loaded with**, otherwise they will miss the cache.
138
+ 4. Query tools now operate on the reloaded session data; **pass the same `device_id` you loaded with**, otherwise they will miss the cache.
139
139
 
140
140
  This is useful for before/after comparisons: profile, fix, re-profile, then reload the original session to compare metrics side by side.
141
141
 
@@ -153,14 +153,14 @@ If the user stated that they do not wish for changes, present the profiling repo
153
153
 
154
154
  ## 5. Important Caveats
155
155
 
156
- - **Dev mode inflation**: `buildMode: "dev"` renders are ~3x slower than production. Prioritize high `normalizedRenderCount` — it scales to prod.
157
- - **Re-run after fixes**: Always re-profile after changes. Report honestly whether the metric improved, regressed, or stayed flat — do not assume improvement.
156
+ - **Dev mode inflation**: `buildMode: "dev"` renders are ~3x slower than production. Prioritize high `normalizedRenderCount`; it scales to prod.
157
+ - **Re-run after fixes**: Always re-profile after changes. Report honestly whether the metric improved, regressed, or stayed flat; do not assume improvement.
158
158
  - **`excluded` is informational**: Components in `animatedSubtrees` and `recyclerChildren` re-render by design.
159
159
  - **Strict Mode**: Double-invokes renders. The pipeline halves `normalizedRenderCount` automatically when detected.
160
- - **Debugger connection**: If interrupted, started profiling also closes. Before attempting recovery, call `react-profiler-status` — it tells you whether the session is `active`, `taken_over`, `stopped`, or `no_react_runtime`, so you can decide whether to stop, restart, or reconnect first.
160
+ - **Debugger connection**: If interrupted, started profiling also closes. Before attempting recovery, call `react-profiler-status`: it tells you whether the session is `active`, `taken_over`, `stopped`, or `no_react_runtime`, so you can decide whether to stop, restart, or reconnect first.
161
161
  - **Confounders to watch for**:
162
162
  - Live API data may differ between runs (different payload sizes, content counts), which shifts render counts and durations independently of your fix. Note when data-dependent components show variance.
163
- - Profiler overhead inflates CPU measurements. If iOS Instruments shows `JSLexer`, `JSONEmitter`, or Hermes internals dominating the JS thread, that reflects profiler instrumentation cost — not app work. Discount those entries.
163
+ - Profiler overhead inflates CPU measurements. If iOS Instruments shows `JSLexer`, `JSONEmitter`, or Hermes internals dominating the JS thread, that reflects profiler instrumentation cost, not app work. Discount those entries.
164
164
  - Runs are not perfectly reproducible. Small variations (under ~10-15%) in commit duration may be noise; only treat consistent, directional changes as signal.
165
165
 
166
166
  For standalone diagnostic tools (live render stats, fiber tree, CPU summary), see `references/diagnostic-tools.md`.