rea-agents 1.1.0 → 1.3.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 (103) hide show
  1. package/README.md +94 -28
  2. package/bridge/hopper_bridge.py +161 -12
  3. package/dist/application/AnalysisSnapshotCache.js +131 -0
  4. package/dist/application/AnalysisSnapshotFiles.js +31 -0
  5. package/dist/application/ArtifactInventory.js +84 -44
  6. package/dist/application/AuthorizedArtifactInventory.js +16 -0
  7. package/dist/application/BinarySession.js +66 -36
  8. package/dist/application/BinarySessionPort.js +1 -0
  9. package/dist/application/BoundedJsonFiles.js +109 -0
  10. package/dist/application/CommandShimReplay.js +136 -0
  11. package/dist/application/CrossVersionInventory.js +98 -0
  12. package/dist/application/CrossVersionInvestigation.js +295 -0
  13. package/dist/application/DirectAnalysis.js +115 -22
  14. package/dist/application/Doctor.js +30 -1
  15. package/dist/application/EvidenceBundleFiles.js +16 -101
  16. package/dist/application/EvidenceLedger.js +3 -2
  17. package/dist/application/InvestigationProviders.js +48 -0
  18. package/dist/application/InvestigationWorkspaceStore.js +214 -0
  19. package/dist/application/LinuxHopper.js +72 -48
  20. package/dist/application/ProcessCaptureAuthority.js +25 -0
  21. package/dist/application/ProcessCaptureCapability.js +23 -0
  22. package/dist/application/ProcessCaptureError.js +17 -0
  23. package/dist/application/ProcessCaptureLifecycle.js +287 -0
  24. package/dist/application/ProcessCheckpoints.js +129 -0
  25. package/dist/application/ProcessCli.js +128 -0
  26. package/dist/application/ProcessEvidence.js +38 -0
  27. package/dist/application/ProcessHarness.js +252 -272
  28. package/dist/application/ProcessNormalization.js +10 -1
  29. package/dist/application/ProcessOwnership.js +39 -1
  30. package/dist/application/ProcessSampling.js +39 -23
  31. package/dist/application/ReferenceSourceImportEntries.js +18 -3
  32. package/dist/application/ReferenceSourceImportTypes.js +32 -0
  33. package/dist/application/Setup.js +44 -96
  34. package/dist/application/SetupClients.js +19 -0
  35. package/dist/application/SetupInstallFailure.js +53 -0
  36. package/dist/application/SetupPlan.js +31 -0
  37. package/dist/application/SetupSkill.js +44 -0
  38. package/dist/application/TerminalRenderer.js +92 -0
  39. package/dist/application/Uninstall.js +33 -23
  40. package/dist/application/UnknownEvidence.js +33 -0
  41. package/dist/application/Upgrade.js +1 -1
  42. package/dist/application/runtime.js +2 -2
  43. package/dist/artifacts/ArtifactProvider.js +20 -11
  44. package/dist/artifacts/ArtifactReader.js +3 -1
  45. package/dist/artifacts/AsarArtifactReader.js +8 -1
  46. package/dist/artifacts/DirectoryArtifactReader.js +1 -0
  47. package/dist/artifacts/MachOSliceArtifactReader.js +1 -0
  48. package/dist/artifacts/NativeDmgArtifactReader.js +151 -0
  49. package/dist/artifacts/ZipArtifactReader.js +1 -0
  50. package/dist/cli.js +57 -32
  51. package/dist/cliEvidenceCommands.js +11 -12
  52. package/dist/cliInvestigationCommands.js +86 -0
  53. package/dist/cliOutput.js +41 -0
  54. package/dist/cliProcessCommands.js +29 -0
  55. package/dist/config.js +41 -24
  56. package/dist/contracts/artifactToolContracts.js +1 -0
  57. package/dist/contracts/investigationExamples.js +3 -3
  58. package/dist/contracts/processCaptureExample.js +50 -7
  59. package/dist/contracts/promptContracts.js +256 -0
  60. package/dist/contracts/sessionLifecycleInputs.js +11 -0
  61. package/dist/contracts/toolContractTypes.js +1 -0
  62. package/dist/contracts/toolContracts.js +13 -8
  63. package/dist/contracts/toolOutputSchemas.js +33 -4
  64. package/dist/domain/analysisSnapshot.js +149 -0
  65. package/dist/domain/changedBehavior.js +32 -9
  66. package/dist/domain/errors.js +186 -39
  67. package/dist/domain/evidence.js +4 -2
  68. package/dist/domain/evidenceBundle.js +28 -0
  69. package/dist/domain/hopperStartupFailure.js +55 -0
  70. package/dist/domain/investigationWorkspace.js +214 -0
  71. package/dist/domain/jsonValue.js +2 -0
  72. package/dist/domain/nativeInspection.js +3 -2
  73. package/dist/domain/processCapture.js +100 -293
  74. package/dist/domain/processCaptureValidation.js +124 -0
  75. package/dist/domain/processComparison.js +177 -32
  76. package/dist/domain/processScenario.js +370 -0
  77. package/dist/domain/reconstructionVerification.js +3 -3
  78. package/dist/domain/staticRuntimeCorrelation.js +3 -2
  79. package/dist/hopper/BridgeLauncher.js +47 -20
  80. package/dist/hopper/HopperClient.js +17 -2
  81. package/dist/hopper/HopperProvider.js +1 -0
  82. package/dist/identity.js +1 -0
  83. package/dist/main.js +47 -24
  84. package/dist/server/createServer.js +2 -0
  85. package/dist/server/promptCompletion.js +144 -0
  86. package/dist/server/registerEnhancedTools.js +2 -6
  87. package/dist/server/registerEvidenceTools.js +2 -8
  88. package/dist/server/registerFunctionComparisonTool.js +1 -1
  89. package/dist/server/registerInvestigationTools.js +31 -11
  90. package/dist/server/registerOfficialTools.js +6 -13
  91. package/dist/server/registerProcessComparisonTool.js +28 -14
  92. package/dist/server/registerPrompts.js +67 -0
  93. package/dist/server/registerSessionStatusTool.js +11 -0
  94. package/dist/server/registerSessionTools.js +55 -43
  95. package/dist/server/sessionEvidence.js +2 -8
  96. package/dist/server/sessionToolPolicies.js +2 -48
  97. package/dist/server/toolResult.js +7 -3
  98. package/install.sh +11 -11
  99. package/package.json +9 -3
  100. package/scripts/hopper-demo-x11.py +349 -0
  101. package/scripts/prepare-node-pty.mjs +35 -0
  102. package/scripts/rea.mjs +6 -3
  103. package/skills/rea-analysis/SKILL.md +27 -5
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # REA: Reverse Engineer Anything
6
6
 
7
- ### One CLI and MCP server for coding agents to reverse engineer anything
7
+ ### One CLI and MCP server for agents to reverse engineer anything
8
8
 
9
9
  **See a feature you like. Understand how it works, down to the binary level.**
10
10
 
@@ -24,7 +24,7 @@
24
24
 
25
25
  ---
26
26
 
27
- See a feature in an app that you want in your own product? Give the app to your coding agent—even without its source code. With REA, the agent can investigate the feature, explain how it works, show its evidence, and build a version adapted to your stack and requirements.
27
+ See a feature in an app that you want in your own product? Give the app to your agent—even without its source code. With REA, the agent can investigate the feature, explain how it works, show its evidence, and build a version adapted to your stack and requirements.
28
28
 
29
29
  REA gives agents one consistent way to investigate software. Today that includes deep native analysis through Hopper, complete function dossiers, reproducible Evidence v2 records, and controlled process capture. The longer-term toolkit extends the same agent workflow to packaged apps, JavaScript bundles, websites, APIs, protocols, mobile artifacts, firmware, runtime behavior, and differences between versions.
30
30
 
@@ -73,7 +73,7 @@ REA shows how it reached its conclusions. It does not claim to recover original
73
73
  | | |
74
74
  | ------------------------ | ------------------------------------------------------------------------------------ |
75
75
  | **Built for agents** | Ask what an app does and let your agent inspect it instead of guessing. |
76
- | **CLI and MCP** | Run the same reverse-engineering capabilities from your terminal or coding agent. |
76
+ | **CLI and MCP** | Run the same reverse-engineering capabilities from your terminal or agent. |
77
77
  | **Complexity handled** | REA installs and manages the reverse-engineering tools behind the scenes. |
78
78
  | **From insight to code** | Understand a feature, then build your own version in the same coding session. |
79
79
  | **Local by design** | Analysis runs on your Mac. REA does not upload the app to a hosted analysis service. |
@@ -88,7 +88,7 @@ npm install --global rea-agents
88
88
  rea setup
89
89
  ```
90
90
 
91
- Installing the CLI does not update Homebrew, Node.js, npm, Hopper, or coding-agent configuration. `rea setup` detects what is already present, prints every proposed change, and asks before applying it.
91
+ Installing the CLI does not update Homebrew, Node.js, npm, Hopper, or agent configuration. `rea setup` detects what is already present, prints every proposed change, and asks before applying it.
92
92
 
93
93
  REA detects Claude Code, Claude Desktop, Codex, Cursor, Gemini CLI, Windsurf, and Devin. Registrations are additive, backup-first, and read back after writing. You can safely rerun setup.
94
94
 
@@ -100,7 +100,7 @@ curl -fsSL https://raw.githubusercontent.com/morluto/rea/main/install.sh | bash
100
100
 
101
101
  Pass installer options after `bash -s --`, for example `--dry-run`, `--no-setup`, or `--version 1.0.0`. The curl wrapper never installs prerequisites or configures integrations itself. See [Installation and setup](docs/installation.md) for its exact mutation boundary.
102
102
 
103
- ### With a coding agent — recommended
103
+ ### With an agent — recommended
104
104
 
105
105
  ```bash
106
106
  npx skills add morluto/rea
@@ -108,7 +108,7 @@ npx skills add morluto/rea
108
108
 
109
109
  Ask your agent to set up REA. It will check your Mac, explain anything it needs to install, ask for approval, and guide you through system prompts. After setup, restart the agent if it asks you to load the full REA toolset.
110
110
 
111
- Review the setup plan, approve it if appropriate, complete Hopper's one-time activation when prompted, then describe the app or feature you want to understand.
111
+ Review the setup plan, approve it if appropriate, then describe the app or feature you want to understand. Hopper can run in its free demo mode; if it shows a first-run prompt, choose the demo or enter an existing license.
112
112
 
113
113
  ### From Terminal — no installation
114
114
 
@@ -118,7 +118,7 @@ npx -y rea-agents doctor
118
118
  npx -y rea-agents analyze /Applications/Notes.app
119
119
  ```
120
120
 
121
- Review the setup plan before confirming it. Restart a configured coding agent so it loads REA.
121
+ Review the setup plan before confirming it. Restart a configured agent so it loads REA.
122
122
 
123
123
  ### From Terminal — install the `rea` command
124
124
 
@@ -157,13 +157,13 @@ If something is not working, run:
157
157
  npx -y rea-agents doctor
158
158
  ```
159
159
 
160
- `rea doctor --json` is read-only and distinguishes unsupported hosts, missing dependencies, a missing local analysis engine, configuration drift, and healthy checks. Fresh-install activation is reported by setup because Hopper does not expose a reliable noninteractive activation probe.
160
+ `rea doctor --json` is read-only and distinguishes unsupported hosts, missing dependencies, a missing local analysis engine, configuration drift, and healthy checks. Paid-license activation is optional: on Linux, REA runs the supported Hopper demo build on a private Xvfb display and selects Hopper's offered demo mode for each analysis session.
161
161
 
162
162
  ### Linux installation and troubleshooting
163
163
 
164
- On macOS, approved setup downloads Hopper's official DMG, verifies it, and installs the app into `~/Applications` without Homebrew or administrator privileges. It opens Hopper once for activation; no manual drag-and-drop is required.
164
+ On macOS, approved setup downloads Hopper's official DMG, verifies it, and installs the app into `~/Applications` without Homebrew or administrator privileges. Hopper may show its demo or license prompt when first opened; no manual drag-and-drop is required.
165
165
 
166
- On Ubuntu 24.04+, Fedora 41+, and 64-bit Arch Linux, approved setup downloads the matching official Hopper package, restricts downloads to Hopper's public origin, verifies the published size and checksum, and invokes `apt-get`, `dnf`, or `pacman`. When REA is not already running as root, `pkexec` presents the system authorization prompt. REA never invokes `sudo`.
166
+ On Ubuntu 24.04+, Fedora 41+, and 64-bit Arch Linux, approved setup downloads the pinned official Hopper 6.4.2 package, restricts downloads to Hopper's public origin, verifies the published size and checksum, and invokes `apt-get`, `dnf`, or `pacman` to install Hopper and the Xvfb, Python, X11, and XTEST packages used by demo sessions. When REA is not already running as root, `pkexec` presents the system authorization prompt. REA never invokes `sudo`. Demo sessions run on an isolated 1280×1024 Xvfb display. REA verifies the exact supported Hopper binary, its owned process ancestry, the expected dialog geometry, and bridge state before selecting `Try the Demo`; any mismatch fails closed.
167
167
 
168
168
  The normal Linux launcher is `/opt/hopper/bin/Hopper`. If Hopper was installed elsewhere:
169
169
 
@@ -178,7 +178,7 @@ If doctor reports a missing analysis engine even though the file exists, inspect
178
178
  ldd /opt/hopper/bin/Hopper | grep 'not found'
179
179
  ```
180
180
 
181
- Install the missing distribution packages and rerun `rea setup`. Hopper is a desktop application: real analysis requires an active `DISPLAY` or `WAYLAND_DISPLAY`, plus one-time license activation. The curl installer places the `rea` command in `~/.local/bin` on Linux; add that directory to future shell `PATH` values if it is not already present.
181
+ Install the missing distribution packages and rerun `rea setup`. Linux demo automation requires `Xvfb`, Python 3, `libX11.so.6`, and `libXtst.so.6`; approved setup installs those direct runtime dependencies and does not interact with the user's desktop display. Hopper's free demo supports analysis with vendor-defined limits, and a paid license is optional. The curl installer places the `rea` command in `~/.local/bin` on Linux; add that directory to future shell `PATH` values if it is not already present.
182
182
 
183
183
  REA defaults `HOPPER_LAUNCHER_PATH` to `/Applications/Hopper Disassembler.app/Contents/MacOS/hopper` on macOS and `/opt/hopper/bin/Hopper` on Linux. Explicit configuration always takes precedence.
184
184
 
@@ -191,24 +191,40 @@ rea uninstall --purge-data # also removes only ~/.rea/cache and ~/.rea/state
191
191
 
192
192
  Uninstall preserves Hopper, Node.js, evidence, captures, external evidence roots, unrelated skills, and other MCP servers. It refuses malformed client configuration and never follows purge-data symlinks.
193
193
 
194
- ### CLI or coding agent?
194
+ ### CLI or agent?
195
195
 
196
- | If you want to… | Use |
197
- | --------------------------------------------------------- | -------------------------------------------------------------- |
198
- | Ask an agent to investigate an app and build a feature | Install the skill, then talk to your agent |
199
- | Inspect or decompile one part of an app from the Terminal | `rea analyze` or `rea decompile` |
200
- | Validate, canonicalize, or compare Evidence v2 bundles | `rea evidence-import`, `rea evidence-export`, or `rea compare` |
201
- | Import source as historical reference | `rea import-reference-source` |
196
+ | If you want to… | Use |
197
+ | --------------------------------------------------------------- | ------------------------------------------------------------------------- |
198
+ | Ask an agent to investigate an app and build a feature | Install the skill, then talk to your agent |
199
+ | Inspect or decompile one part of an app from the Terminal | `rea analyze` or `rea decompile` |
200
+ | Validate, canonicalize, or compare Evidence v2 bundles | `rea evidence-import`, `rea evidence-export`, or `rea compare` |
201
+ | Run or resume a persistent two-version artifact analysis | `rea investigate-versions` |
202
+ | Reuse immutable analysis results without relaunching a provider | Pass `--snapshot /approved/path/analysis.json` to a deep-analysis command |
203
+ | Import source as historical reference | `rea import-reference-source` |
204
+ | Capture or compare controlled process behavior | `rea capture-process` or `rea compare-process-captures` |
202
205
 
203
206
  Filesystem evidence commands and MCP file tools are disabled until the operator approves absolute roots:
204
207
 
205
208
  ```bash
206
209
  export REA_EVIDENCE_ROOTS_JSON='["/absolute/path/to/evidence"]'
210
+ export REA_INVESTIGATION_INPUT_ROOTS_JSON='["/absolute/path/to/releases"]'
207
211
  rea evidence-import /absolute/path/to/evidence/bundle.json
208
212
  rea evidence-export /absolute/path/to/evidence/bundle.json /absolute/path/to/evidence/canonical.json
209
213
  rea compare /absolute/path/to/evidence/left.json /absolute/path/to/evidence/right.json
214
+ rea investigate-versions /absolute/path/to/releases/v1 /absolute/path/to/releases/v2 /absolute/path/to/evidence/releases.json --yes --workspace-name releases
210
215
  ```
211
216
 
217
+ `investigate-versions` inventories both versions, checkpoints their observed
218
+ Evidence, derives an artifact comparison, and records a changed-behavior report.
219
+ Both input paths must resolve beneath `REA_INVESTIGATION_INPUT_ROOTS_JSON`;
220
+ workspace files remain independently restricted by `REA_EVIDENCE_ROOTS_JSON`.
221
+ The workspace uses deterministic content identities and monotonic CAS-linked
222
+ revisions, so the same request resumes an interrupted run or reuses a completed
223
+ run without replacing earlier investigations. It currently compares static
224
+ artifact structure only; it does not execute either version, and its report
225
+ keeps every difference labeled as a behavior candidate. See
226
+ [Persistent investigation workspaces](docs/investigation-workspaces.md).
227
+
212
228
  Historical source import requires a separate allowlist and never treats source as current behavioral authority:
213
229
 
214
230
  ```bash
@@ -218,6 +234,30 @@ rea import-reference-source /absolute/path/to/source
218
234
 
219
235
  Exports never replace an existing file unless `--overwrite` is explicit. Imports are size/depth bounded, validate every Evidence v2 ID and manifest, and never execute bundle content.
220
236
 
237
+ Provider-neutral analysis snapshots persist successful, immutable REA calls and
238
+ their Evidence v2 records. They are exact caches rather than Hopper databases:
239
+ REA reuses an entry only when the binary digest, format, architecture, operation
240
+ parameters, loader arguments, and provider identity match. Custom Hopper loader
241
+ overrides disable snapshots because their provider configuration cannot be
242
+ replayed safely. Cursor-dependent and mutating calls are never cached. Snapshot
243
+ files can contain proprietary analysis results and local
244
+ paths, so REA keeps them local, writes them with owner-only permissions, and
245
+ requires a separate approved root:
246
+
247
+ ```bash
248
+ export REA_ANALYSIS_SNAPSHOT_ROOTS_JSON='["/absolute/path/to/analysis"]'
249
+ rea analyze /absolute/path/to/app --snapshot /absolute/path/to/analysis/app.json
250
+ # The same exact query can now be answered from the snapshot.
251
+ rea analyze /absolute/path/to/app --snapshot /absolute/path/to/analysis/app.json
252
+ ```
253
+
254
+ Exact CLI evidence replays happen before any provider starts. In MCP sessions,
255
+ pass `snapshot_path` to `open_binary` to import a snapshot atomically while
256
+ opening its matching target; MCP providers may still start before a cached call
257
+ is replayed. Pass `snapshot_path` and, when required, `overwrite: true` to
258
+ `close_binary` to save atomically before Hopper resources are released. If the
259
+ save fails, REA deliberately leaves the session open.
260
+
221
261
  ## One prompt, a full investigation
222
262
 
223
263
  ```text
@@ -245,7 +285,7 @@ REA handles the app analysis in steps 1–5. The agent performs step 6 with its
245
285
  - Reconstruct an app's authentication, storage, update, or networking flow.
246
286
  - Recover enough structure to document an undocumented format or interface.
247
287
  - Trace a suspicious behavior from a string or symbol to the code that implements it.
248
- - Compare implementation paths across two app versions by switching targets in one session.
288
+ - Run, checkpoint, resume, and reuse a content-addressed artifact investigation across two versions.
249
289
  - Turn recovered behavior into product features, tests, migration notes, ports, or interoperable replacements.
250
290
  - Analyze Swift and Objective-C metadata without manually untangling every mangled symbol.
251
291
  - Leave names, comments, and bookmarks in Hopper so human and agent analysis reinforce each other.
@@ -267,12 +307,13 @@ The public interface describes what the agent is trying to learn. Providers deci
267
307
  REA is already useful for native application investigation on macOS:
268
308
 
269
309
  - Open Mach-O, ELF, PE, `.app`, ZIP, APK, IPA, ASAR, plist, JavaScript, source-map, and Hopper database targets.
270
- - Traverse content-addressed artifact graphs without extraction; materialize only approved occurrences into absent output roots.
310
+ - Traverse content-addressed artifact graphs without extraction; on macOS, read-only DMG traversal additionally requires `native_mount_approved: true` and `REA_ARTIFACT_NATIVE_MOUNT_ENABLED=true`. Materialize only approved occurrences into absent output roots.
271
311
  - Build bounded function dossiers with pseudocode, assembly, CFG edges, comments, calls, references, strings, and names.
272
312
  - Search and trace features across symbols, strings, metadata, references, and call paths.
273
313
  - Record every successful result as deterministic Evidence v2 with artifact and provider identity, confidence, authority, limitations, and locations.
274
314
  - Export and import evidence bundles across sessions.
275
- - Capture approved PTY scenarios, child processes, filesystem changes, and loopback HTTP/WebSocket exchanges, then compare normalized captures.
315
+ - Persist automatic cross-version artifact runs as canonical, lock-protected workspaces with tamper-evident revision commitments.
316
+ - Capture approved PTY scenarios as Process Capture v4 Evidence, including committed run manifests, raw and rendered terminal frames, scripted interactions, descendant settlement, named filesystem checkpoints, deterministic command shims, and loopback HTTP/WebSocket exchanges.
276
317
  - Compare complete artifact inventories by stable path, content, metadata, and relations; incomplete evidence never implies equivalence.
277
318
  - Compare explicit function dossiers across text, calls, references, strings, and address-normalized CFG topology with per-facet unknowns.
278
319
  - Compare canonical Evidence bundles by exact membership, explicit observation pairs, and residual-unknown histories without turning omissions into behavioral absence.
@@ -282,6 +323,7 @@ REA is already useful for native application investigation on macOS:
282
323
  - Verify finite behavioral and structural reconstruction specifications with pass, fail, and unknown kept distinct.
283
324
  - Track residual unknowns through immutable CAS revisions, evidence-qualified resolution, contradictions, probes, and validated dependency relationships.
284
325
  - With explicit `unknown_registry_approved: true`, record bounded trace/capture residuals, typed provider unavailability, and capture disagreements automatically.
326
+ - Start six [guided MCP workflows](docs/mcp-prompts.md) with live, session-aware completion for documents, procedures, providers, evidence, captures, artifact IDs, and active unknowns.
285
327
 
286
328
  Hopper is the first provider, not the boundary of the project. Some current workflows still require Hopper and macOS; every evidence record identifies the provider and limitations behind its result.
287
329
 
@@ -296,15 +338,15 @@ REA is growing into a toolkit for understanding software across static artifacts
296
338
  5. **Runtime observation** — approval-gated LLDB, Frida, system logs, process and filesystem observers, and native API tracing.
297
339
  6. **More static-analysis providers** — native platform utilities first, followed by Ghidra, IDA/Hex-Rays, Binary Ninja, Rizin, LIEF, and other engines behind provider-neutral capabilities.
298
340
  7. **More targets and platforms** — Windows-native providers and ConPTY verification, Linux parity, websites and APIs, mobile artifacts, firmware, document formats, and other software-defined systems.
299
- 8. **Differential reconstruction** — compare artifacts, functions, bundles, protocols, UIs, and process captures; track residual unknowns; verify a reconstruction against observed behavior.
341
+ 8. **Differential reconstruction expansion** — add automatic function matching, protocol/UI comparison, controlled replay, residual-unknown planning, and reconstruction verification to persistent version runs.
300
342
 
301
343
  Roadmap items describe direction, not shipped support. New providers must produce the same evidence and safety metadata as existing capabilities before they become part of the public workflow. Once REA has multiple optional toolchains, setup can become capability-selective; the consent rules for that future work are recorded in the [installation roadmap](docs/roadmap.md).
302
344
 
303
345
  See the [static-analysis provider evaluation](docs/provider-evaluation.md) for the current research matrix and admission gate.
304
346
 
305
- ## Using REA with other coding agents
347
+ ## Using REA with other agents
306
348
 
307
- Setup currently configures Claude Desktop and Cursor automatically. Any coding agent that supports local MCP servers can use REA with the configuration below.
349
+ Setup currently configures Claude Desktop and Cursor automatically. Any agent that supports local MCP servers can use REA with the configuration below.
308
350
 
309
351
  ### Manual MCP configuration
310
352
 
@@ -319,11 +361,16 @@ Setup currently configures Claude Desktop and Cursor automatically. Any coding a
319
361
  }
320
362
  ```
321
363
 
364
+ MCP clients that support prompts can also discover six ordered investigation
365
+ workflows through `prompts/list`. Their optional identifier arguments use the
366
+ current session for bounded `completion/complete` suggestions; see
367
+ [Guided MCP prompts and completion](docs/mcp-prompts.md).
368
+
322
369
  ## How it works
323
370
 
324
371
  ```mermaid
325
372
  flowchart LR
326
- Agent["Coding agent"] --> REA["REA<br/>CLI + MCP"]
373
+ Agent["Agent"] --> REA["REA<br/>CLI + MCP"]
327
374
  Terminal --> REA
328
375
  REA --> Workspace["Investigation workspace<br/>evidence + artifacts + captures"]
329
376
  Workspace --> Router["Capability router"]
@@ -338,7 +385,7 @@ flowchart LR
338
385
  Artifact --> Target
339
386
  ```
340
387
 
341
- The CLI and MCP server use the same application workflows and evidence contracts. A provider declares which capabilities it supports and the side effects those capabilities may have. Terminal commands are short-lived; an MCP session can retain an active target and evidence ledger across an investigation.
388
+ The CLI and MCP server use the same application workflows and evidence contracts. A provider declares which capabilities it supports and the side effects those capabilities may have. Terminal commands are short-lived; an MCP session can retain an active target and evidence ledger across an investigation. Approved persistent workspaces keep canonical Evidence and resumable run checkpoints across both process and session lifetimes.
342
389
 
343
390
  ## CLI
344
391
 
@@ -353,6 +400,7 @@ npx -y rea-agents function /Applications/Notes.app 0x1000
353
400
  npx -y rea-agents xrefs /Applications/Notes.app 0x1000
354
401
  npx -y rea-agents trace /Applications/Notes.app "offline"
355
402
  npx -y rea-agents compare /absolute/path/to/left-evidence.json /absolute/path/to/right-evidence.json
403
+ npx -y rea-agents investigate-versions /path/to/v1 /path/to/v2 /absolute/path/to/evidence/releases.json --yes
356
404
  npx -y rea-agents capabilities
357
405
  npx -y rea-agents providers
358
406
  ```
@@ -389,10 +437,28 @@ environment allowlist in `REA_PROCESS_ALLOWED_ENV_JSON`. Because the current PTY
389
437
  adapter uses host networking, it also requires
390
438
  `REA_PROCESS_ALLOW_EXTERNAL_NETWORK=true`.
391
439
 
440
+ Capture a scenario or compare two saved Process Capture v4 Evidence records:
441
+
442
+ ```bash
443
+ rea capture-process ./scenario.json > authority.json
444
+ rea capture-process ./reconstruction.json > reconstruction.json
445
+ rea compare-process-captures authority.json reconstruction.json
446
+ ```
447
+
448
+ The comparison reports each observed dimension separately and identifies the
449
+ first terminal, interaction, exit, filesystem, protocol, process, or shim
450
+ divergence. See [Process Capture v4](docs/process-capture.md) for scenario
451
+ fields, command-shim replay, checkpoint triggers, limits, and safety behavior.
452
+
392
453
  If the native PTY backend is unavailable, install Xcode command-line tools and
393
454
  run `npm run rebuild:native`. Linux source builds require Python, `make`, and a
394
455
  C++ toolchain. Compatible packaged binaries do not require this rebuild.
395
456
 
457
+ ASAR inventory verifies Electron integrity metadata for both archive entries
458
+ and `.asar.unpacked` companion files. Integrity failures identify the logical
459
+ path, declared and calculated SHA-256 values, and whether the entry was
460
+ unpacked; REA does not silently accept the mismatched artifact.
461
+
396
462
  ## Security model
397
463
 
398
464
  REA does not provide a hosted analysis service. Hopper communication uses an authenticated private local socket. Dynamic capabilities are disabled by default and require both operator policy and explicit per-call approval. REA is not a security sandbox: providers and launched targets run with the current user's permissions, and each capability reports its side effects and limitations. Report vulnerabilities through the private process in [SECURITY.md](SECURITY.md).
@@ -423,7 +489,7 @@ No. Setup can install Hopper for you, but Hopper remains separate software with
423
489
  <details>
424
490
  <summary><strong>Does REA upload the app?</strong></summary>
425
491
 
426
- REA has no hosted analysis service. Current providers analyze artifacts and capture behavior locally. Your coding agent or model provider may have its own data policy, so review that separately.
492
+ REA has no hosted analysis service. Current providers analyze artifacts and capture behavior locally. Your agent or model provider may have its own data policy, so review that separately.
427
493
 
428
494
  </details>
429
495
 
@@ -437,7 +503,7 @@ No decompiler can guarantee the original source. REA gives an agent pseudocode,
437
503
  <details>
438
504
  <summary><strong>Which agents can use REA?</strong></summary>
439
505
 
440
- Any coding agent that can run a local MCP server can use the manual configuration. Setup currently detects and configures Claude Desktop and Cursor automatically.
506
+ Any agent that can run a local MCP server can use the manual configuration. Setup currently detects and configures Claude Desktop and Cursor automatically.
441
507
 
442
508
  </details>
443
509
 
@@ -20,6 +20,22 @@ MAX_SEARCH_PATTERN_LENGTH = 256
20
20
  MAX_SEARCH_VALUE_LENGTH = 4096
21
21
 
22
22
 
23
+ def _session_document():
24
+ """Find only the document opened for this authenticated REA session."""
25
+ target = os.path.realpath(REA_TARGET_PATH)
26
+ for document in Document.getAllDocuments():
27
+ paths = (document.getExecutableFilePath(), document.getDatabaseFilePath())
28
+ for path in paths:
29
+ if path and os.path.realpath(path) == target:
30
+ return document
31
+ return None
32
+
33
+
34
+ MAX_REGEX_BACKTRACKING_PATHS = 10000
35
+ MAX_REGEX_CANDIDATE_LENGTH = 4096
36
+ MAX_REGEX_SEARCH_WORK_UNITS = 1000000
37
+
38
+
23
39
  def _hex(value):
24
40
  return "0x%x" % value
25
41
 
@@ -216,33 +232,150 @@ def _search_inventory(document, kind):
216
232
  return inventory
217
233
 
218
234
 
235
+ def _checked_regex_paths(left, right, operation):
236
+ """Apply one path-count operation without crossing the static work budget."""
237
+ if operation == "add":
238
+ exceeded = left > MAX_REGEX_BACKTRACKING_PATHS - right
239
+ result = left + right
240
+ else:
241
+ exceeded = right != 0 and left > MAX_REGEX_BACKTRACKING_PATHS // right
242
+ result = left * right
243
+ if exceeded or result > MAX_REGEX_BACKTRACKING_PATHS:
244
+ raise ValueError(
245
+ "Regex exceeds the %d-path backtracking budget"
246
+ % MAX_REGEX_BACKTRACKING_PATHS
247
+ )
248
+ return result
249
+
250
+
251
+ def _repeat_regex_paths(child_paths, minimum, maximum):
252
+ """Count every bounded repetition path, including alternative child paths."""
253
+ paths = 0
254
+ repeated_paths = 1
255
+ for count in range(maximum + 1):
256
+ if count >= minimum:
257
+ paths = _checked_regex_paths(paths, repeated_paths, "add")
258
+ if count < maximum:
259
+ repeated_paths = _checked_regex_paths(
260
+ repeated_paths, child_paths, "multiply"
261
+ )
262
+ return paths
263
+
264
+
265
+ def _validate_regex_class(items):
266
+ """Accept only constant-time character-class operations."""
267
+ allowed = {
268
+ sre_parse.CATEGORY,
269
+ sre_parse.LITERAL,
270
+ sre_parse.NEGATE,
271
+ sre_parse.RANGE,
272
+ }
273
+ if any(operation not in allowed for operation, _ in items):
274
+ raise ValueError("Regex operation is not supported by the bounded matcher")
275
+
276
+
219
277
  def _validate_regex_node(node, inside_repeat=False):
220
- """Reject regex structures with disproportionate or non-local evaluation cost."""
278
+ """Return capped path and step bounds for Python regex evaluation."""
279
+ leaf_operations = {
280
+ sre_parse.ANY,
281
+ sre_parse.AT,
282
+ sre_parse.CATEGORY,
283
+ sre_parse.LITERAL,
284
+ sre_parse.NOT_LITERAL,
285
+ }
221
286
  forbidden = {
222
287
  sre_parse.ASSERT,
223
288
  sre_parse.ASSERT_NOT,
224
289
  sre_parse.GROUPREF,
225
290
  sre_parse.GROUPREF_EXISTS,
226
291
  }
292
+ for name in ("GROUPREF_IGNORE", "GROUPREF_LOC_IGNORE", "GROUPREF_UNI_IGNORE"):
293
+ operation = getattr(sre_parse, name, None)
294
+ if operation is not None:
295
+ forbidden.add(operation)
227
296
  repeat_tokens = {sre_parse.MAX_REPEAT, sre_parse.MIN_REPEAT}
228
297
  possessive = getattr(sre_parse, "POSSESSIVE_REPEAT", None)
229
298
  if possessive is not None:
230
299
  repeat_tokens.add(possessive)
300
+ atomic = getattr(sre_parse, "ATOMIC_GROUP", None)
301
+
302
+ paths = 1
303
+ steps = 0
231
304
  for operation, argument in node:
232
305
  if operation in forbidden:
233
306
  raise ValueError("Regex lookarounds and backreferences are not supported")
234
- if operation in repeat_tokens:
307
+ if operation in leaf_operations:
308
+ operation_paths = 1
309
+ operation_steps = 1
310
+ elif operation == sre_parse.IN:
311
+ _validate_regex_class(argument)
312
+ operation_paths = 1
313
+ operation_steps = 1
314
+ elif operation in repeat_tokens:
235
315
  if inside_repeat:
236
316
  raise ValueError("Nested regex repetitions are not supported")
237
317
  minimum, maximum, child = argument
238
318
  if maximum == sre_parse.MAXREPEAT or maximum > 1000:
239
- raise ValueError("Unbounded or excessive regex repetitions are not supported")
240
- _validate_regex_node(child, True)
319
+ raise ValueError(
320
+ "Unbounded or excessive regex repetitions are not supported"
321
+ )
322
+ child_paths, child_steps = _validate_regex_node(child, True)
323
+ operation_paths = _repeat_regex_paths(
324
+ child_paths, minimum, maximum
325
+ )
326
+ operation_steps = maximum * child_steps
241
327
  elif operation == sre_parse.SUBPATTERN:
242
- _validate_regex_node(argument[-1], inside_repeat)
328
+ operation_paths, operation_steps = _validate_regex_node(
329
+ argument[-1], inside_repeat
330
+ )
243
331
  elif operation == sre_parse.BRANCH:
332
+ operation_paths = 0
333
+ operation_steps = 0
244
334
  for branch in argument[1]:
245
- _validate_regex_node(branch, inside_repeat)
335
+ branch_paths, branch_steps = _validate_regex_node(
336
+ branch, inside_repeat
337
+ )
338
+ operation_paths = _checked_regex_paths(
339
+ operation_paths,
340
+ branch_paths,
341
+ "add",
342
+ )
343
+ operation_steps = max(operation_steps, branch_steps)
344
+ elif atomic is not None and operation == atomic:
345
+ operation_paths, operation_steps = _validate_regex_node(
346
+ argument, inside_repeat
347
+ )
348
+ else:
349
+ raise ValueError("Regex operation is not supported by the bounded matcher")
350
+ paths = _checked_regex_paths(paths, operation_paths, "multiply")
351
+ steps += operation_steps
352
+ return paths, steps
353
+
354
+
355
+ def _bounded_regex_matcher(expression, backtracking_paths, steps_per_path):
356
+ """Create a matcher with per-candidate and cumulative work bounds."""
357
+ remaining_work = MAX_REGEX_SEARCH_WORK_UNITS
358
+ work_per_character = backtracking_paths * max(steps_per_path, 1)
359
+
360
+ def matches(value):
361
+ nonlocal remaining_work
362
+ if not isinstance(value, str):
363
+ raise ValueError("Regex candidates must be strings")
364
+ if len(value) > MAX_REGEX_CANDIDATE_LENGTH:
365
+ raise ValueError(
366
+ "Regex candidate exceeds the %d-character safety limit"
367
+ % MAX_REGEX_CANDIDATE_LENGTH
368
+ )
369
+ required_work = work_per_character * max(len(value), 1)
370
+ if required_work > remaining_work:
371
+ raise ValueError(
372
+ "Regex search exceeds the %d-unit work budget"
373
+ % MAX_REGEX_SEARCH_WORK_UNITS
374
+ )
375
+ remaining_work -= required_work
376
+ return expression.search(value) is not None
377
+
378
+ return matches
246
379
 
247
380
 
248
381
  def _search_page(document, kind, params):
@@ -268,11 +401,13 @@ def _search_page(document, kind, params):
268
401
  else:
269
402
  try:
270
403
  parsed = sre_parse.parse(pattern)
271
- _validate_regex_node(parsed)
404
+ backtracking_paths, steps_per_path = _validate_regex_node(parsed)
272
405
  expression = re.compile(pattern, 0 if case_sensitive else re.IGNORECASE)
273
- except re.error as error:
406
+ except (re.error, OverflowError) as error:
274
407
  raise ValueError("Invalid regex pattern") from error
275
- matches = lambda value: expression.search(value) is not None
408
+ matches = _bounded_regex_matcher(
409
+ expression, backtracking_paths, steps_per_path
410
+ )
276
411
 
277
412
  selected = []
278
413
  total = 0
@@ -494,7 +629,21 @@ def _dispatch(method, params):
494
629
  if method == "health":
495
630
  return {"name": "REA Hopper bridge", "version": "1.0.0", "run_id": REA_RUN_ID}
496
631
  if method == "shutdown":
497
- return {"shutdown": True}
632
+ document = _session_document()
633
+ if document is None:
634
+ return {"shutdown": True, "analysis_stopped": True, "document_closed": True}
635
+ if document.backgroundProcessActive():
636
+ document.requestBackgroundProcessStop()
637
+ if document.backgroundProcessActive():
638
+ document.waitForBackgroundProcessToEnd()
639
+ analysis_stopped = not document.backgroundProcessActive()
640
+ document.closeDocument()
641
+ document_closed = _session_document() is None
642
+ return {
643
+ "shutdown": True,
644
+ "analysis_stopped": analysis_stopped,
645
+ "document_closed": document_closed,
646
+ }
498
647
  if method == "list_documents":
499
648
  return [document.getDocumentName() for document in Document.getAllDocuments()]
500
649
  if method == "current_document":
@@ -604,9 +753,9 @@ def _dispatch(method, params):
604
753
  if method == "procedure_pseudo_code":
605
754
  return procedure.decompile()
606
755
  if method == "procedure_callers":
607
- return [_procedure_name(item) for item in procedure.getAllCallerProcedures()]
756
+ return sorted((_hex(item.getEntryPoint()) for item in procedure.getAllCallerProcedures()), key=lambda value: int(value, 16))
608
757
  if method == "procedure_callees":
609
- return [_procedure_name(item) for item in procedure.getAllCalleeProcedures()]
758
+ return sorted((_hex(item.getEntryPoint()) for item in procedure.getAllCalleeProcedures()), key=lambda value: int(value, 16))
610
759
  if method == "procedure_info":
611
760
  blocks = list(procedure.basicBlockIterator())
612
761
  length = sum(max(0, block.getEndingAddress() - block.getStartingAddress()) for block in blocks)