@deeeed/metamask-harness 0.2.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.
- package/CHANGELOG.md +161 -0
- package/README.md +140 -0
- package/bin/mm-harness +99 -0
- package/docs/CHEATSHEET.md +61 -0
- package/docs/CLI-SPEC.md +915 -0
- package/docs/MENTAL-MODEL.md +295 -0
- package/docs/architecture.md +367 -0
- package/docs/extension-runtime-commands.md +60 -0
- package/docs/harness-cli.md +43 -0
- package/docs/live-adapter-contract.md +188 -0
- package/docs/package-boundaries.md +47 -0
- package/docs/perps-flow-catalog.md +235 -0
- package/docs/recipe-libraries.md +95 -0
- package/docs/runtime-file-conventions.md +36 -0
- package/library/actions/core/perps/_controller.mjs +727 -0
- package/library/actions/core/perps/assert_orders.mjs +53 -0
- package/library/actions/core/perps/assert_positions.mjs +52 -0
- package/library/actions/core/perps/close_orders.mjs +97 -0
- package/library/actions/core/perps/close_positions.mjs +118 -0
- package/library/actions/core/perps/ensure_orders.mjs +40 -0
- package/library/actions/core/perps/ensure_positions.mjs +37 -0
- package/library/actions/core/perps/place_order.mjs +201 -0
- package/library/actions/core/perps/read_account.mjs +30 -0
- package/library/actions/core/perps/read_orders.mjs +27 -0
- package/library/actions/core/perps/read_positions.mjs +27 -0
- package/library/actions/core/perps/start_state.mjs +92 -0
- package/library/actions/core/perps/teardown_state.mjs +86 -0
- package/library/actions/extension/perps/assert_orders.mjs +11 -0
- package/library/actions/extension/perps/assert_positions.mjs +11 -0
- package/library/actions/extension/perps/close_orders.mjs +8 -0
- package/library/actions/extension/perps/close_positions.mjs +8 -0
- package/library/actions/extension/perps/ensure_orders.mjs +4 -0
- package/library/actions/extension/perps/ensure_positions.mjs +4 -0
- package/library/actions/extension/perps/perps.mjs +730 -0
- package/library/actions/extension/perps/place_order.mjs +7 -0
- package/library/actions/extension/perps/read_orders.mjs +4 -0
- package/library/actions/extension/perps/read_positions.mjs +3 -0
- package/library/actions/extension/platform/cdp.mjs +541 -0
- package/library/actions/extension/ui/navigate.mjs +44 -0
- package/library/actions/extension/wallet/ensure_unlocked.mjs +36 -0
- package/library/actions/extension/wallet/read_state.mjs +27 -0
- package/library/actions/extension/wallet/select_account.mjs +48 -0
- package/library/actions/extension/wallet/setup.mjs +35 -0
- package/library/actions/mobile/app-overlay/app/dev-tools/AgenticService/AgentStepHud.tsx.patch +185 -0
- package/library/actions/mobile/app-overlay/app/dev-tools/AgenticService/AgenticService.ts.patch +1662 -0
- package/library/actions/mobile/bridge-runtime/cdp-bridge.cjs +686 -0
- package/library/actions/mobile/bridge-runtime/lib/cdp-eval.cjs +110 -0
- package/library/actions/mobile/bridge-runtime/lib/config.cjs +39 -0
- package/library/actions/mobile/bridge-runtime/lib/issue-capture.cjs +446 -0
- package/library/actions/mobile/bridge-runtime/lib/target-discovery.cjs +204 -0
- package/library/actions/mobile/bridge-runtime/lib/ws-client.cjs +108 -0
- package/library/actions/mobile/bridge-runtime/setup-wallet.sh +442 -0
- package/library/actions/mobile/perps/assert_orders.mjs +11 -0
- package/library/actions/mobile/perps/assert_positions.mjs +11 -0
- package/library/actions/mobile/perps/close_orders.mjs +8 -0
- package/library/actions/mobile/perps/close_positions.mjs +8 -0
- package/library/actions/mobile/perps/ensure_orders.mjs +4 -0
- package/library/actions/mobile/perps/ensure_positions.mjs +4 -0
- package/library/actions/mobile/perps/perps.mjs +709 -0
- package/library/actions/mobile/perps/place_order.mjs +7 -0
- package/library/actions/mobile/perps/read_orders.mjs +4 -0
- package/library/actions/mobile/perps/read_positions.mjs +3 -0
- package/library/actions/mobile/platform/bridge.mjs +283 -0
- package/library/actions/mobile/ui/navigate.mjs +38 -0
- package/library/actions/mobile/wallet/ensure_unlocked.mjs +107 -0
- package/library/actions/mobile/wallet/home.mjs +35 -0
- package/library/actions/mobile/wallet/read_state.mjs +40 -0
- package/library/actions/mobile/wallet/select_account.mjs +48 -0
- package/library/actions/mobile/wallet/setup.mjs +220 -0
- package/library/flows/perps.flows.json +64 -0
- package/library/library.json +7 -0
- package/library/manifests/core.action-manifest.json +1282 -0
- package/library/manifests/extension.action-manifest.json +1749 -0
- package/library/manifests/mobile.action-manifest.json +1753 -0
- package/library/recipes/action-validation.extension.recipe.json +417 -0
- package/library/recipes/action-validation.mobile.recipe.json +422 -0
- package/library/recipes/order-lifecycle.core.recipe.json +78 -0
- package/library/recipes/perps-lifecycle.recipe.json +194 -0
- package/library/recipes/read-markets.core.recipe.json +38 -0
- package/library/recipes/smoke.extension.recipe.json +31 -0
- package/library/recipes/smoke.mobile.recipe.json +31 -0
- package/library/recipes/trading-lifecycle.core.recipe.json +76 -0
- package/orchestration/compat-overlays/README.md +19 -0
- package/orchestration/compat-overlays/mobile/README.md +13 -0
- package/orchestration/compat-overlays/mobile/rn81-message-event-source.patch +42 -0
- package/orchestration/core/cleanup.sh +37 -0
- package/orchestration/core/inject.sh +154 -0
- package/orchestration/doctor.mjs +72 -0
- package/orchestration/extension/cleanup.mjs +60 -0
- package/orchestration/extension/console-tail.mjs +228 -0
- package/orchestration/extension/ensure-browser.sh +416 -0
- package/orchestration/extension/ensure-ready.ts +185 -0
- package/orchestration/extension/extension-id.ts +107 -0
- package/orchestration/extension/inject.mjs +266 -0
- package/orchestration/extension/launch-browser.cjs +216 -0
- package/orchestration/extension/launch.sh +175 -0
- package/orchestration/extension/live.sh +320 -0
- package/orchestration/extension/pin-remote-flags.cjs +45 -0
- package/orchestration/extension/readiness.mjs +414 -0
- package/orchestration/extension/refresh-build.sh +190 -0
- package/orchestration/extension/runtime-decision.ts +445 -0
- package/orchestration/extension/runtime.ts +407 -0
- package/orchestration/extension/seed-fixture.sh +177 -0
- package/orchestration/extension/sidepanel-toggle.sh +291 -0
- package/orchestration/extension/snapshot-dist.sh +84 -0
- package/orchestration/extension/start-watch.sh +339 -0
- package/orchestration/extension/wallet-fixture-state.cjs +1086 -0
- package/orchestration/lib/activate-repo-node.sh +144 -0
- package/orchestration/lib/cli-color.mjs +84 -0
- package/orchestration/lib/cli-commands.mjs +243 -0
- package/orchestration/lib/cli-home.mjs +354 -0
- package/orchestration/lib/cli-ux.sh +252 -0
- package/orchestration/lib/cli-version.mjs +123 -0
- package/orchestration/lib/ensure-runner-deps.sh +56 -0
- package/orchestration/lib/harness-path.sh +55 -0
- package/orchestration/lib/hash-helpers.sh +44 -0
- package/orchestration/lib/json-field.sh +23 -0
- package/orchestration/lib/log-tui.mjs +304 -0
- package/orchestration/lib/open-debug.mjs +317 -0
- package/orchestration/lib/path-defaults.json +4 -0
- package/orchestration/lib/progress.mjs +107 -0
- package/orchestration/lib/recipe-paths.mjs +26 -0
- package/orchestration/lib/resolve-farmslot-ports.sh +144 -0
- package/orchestration/manifest.json +358 -0
- package/orchestration/mobile/cleanup.sh +192 -0
- package/orchestration/mobile/deps-markers.ts +21 -0
- package/orchestration/mobile/inject.sh +681 -0
- package/orchestration/mobile/launch.sh +137 -0
- package/orchestration/mobile/live.sh +125 -0
- package/orchestration/mobile/runtime-decision.ts +292 -0
- package/orchestration/porcelain/metamask-recipe +99 -0
- package/orchestration/porcelain/mm-recipe +1591 -0
- package/orchestration/porcelain/mme-recipe +1181 -0
- package/package.json +59 -0
- package/runner/extension/verify.sh +511 -0
- package/runner/mobile/verify.sh +501 -0
- package/runner/src/adapters.ts +601 -0
- package/runner/src/cli.ts +1820 -0
- package/runner/src/commands/debug.ts +44 -0
- package/runner/src/commands/fixtures.ts +99 -0
- package/runner/src/commands/launch.ts +397 -0
- package/runner/src/commands/logs.ts +60 -0
- package/runner/src/commands/shared.ts +138 -0
- package/runner/src/completions-cache.ts +86 -0
- package/runner/src/doctor.ts +203 -0
- package/runner/src/harness.ts +516 -0
- package/runner/src/heal-bounds.ts +179 -0
- package/runner/src/index.ts +6 -0
- package/runner/src/live-adapter-contract.ts +274 -0
- package/runner/src/manifest.ts +47 -0
- package/runner/src/mm-harness-cli.ts +488 -0
- package/runner/src/paths.ts +198 -0
- package/runner/src/recording-target.ts +147 -0
- package/runner/src/run-recording.ts +329 -0
- package/runner/src/runner.ts +108 -0
- package/runner/src/types.ts +57 -0
- package/scripts/completions.sh +125 -0
- package/scripts/install-completions.sh +62 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
# MetaMask Recipe Runner Architecture
|
|
2
|
+
|
|
3
|
+
This repo is the MetaMask-specific adapter layer for Recipe Protocol v1. It is
|
|
4
|
+
not the protocol engine, not a skills repo, not a slot farm, and not product
|
|
5
|
+
code. Its job is to publish reviewable MetaMask capabilities and run them
|
|
6
|
+
against a local Mobile or Extension checkout without committing harness runtime
|
|
7
|
+
into that checkout.
|
|
8
|
+
|
|
9
|
+
The core model is standalone: install or check out this runner, point it at a
|
|
10
|
+
MetaMask checkout, and run `mm-harness`. Farm/slot orchestration is only a
|
|
11
|
+
way to scale the same loop across many checkouts, machines, ports, and agents;
|
|
12
|
+
it is not required to understand or use the runner.
|
|
13
|
+
|
|
14
|
+
## TL;DR
|
|
15
|
+
|
|
16
|
+
The four questions that come up whenever this repo needs explaining.
|
|
17
|
+
|
|
18
|
+
**Responsibility split.** This runner owns the logic; skills and farms are a
|
|
19
|
+
minimum overlay that call its CLI. Rule of thumb: if a skill's shell script is
|
|
20
|
+
doing more than parsing flags and calling `mm-harness`, that logic
|
|
21
|
+
belongs in this runner instead. Concrete example in flight: the
|
|
22
|
+
`recipe-harness` skill currently locates and execs runner internals in
|
|
23
|
+
hundreds of lines of bash (resolve runner source, dispatch to
|
|
24
|
+
`orchestration/<platform>/{inject,cleanup}.{sh,mjs}` — `.sh` for Mobile/Core,
|
|
25
|
+
`.mjs` for Extension); the fix is a
|
|
26
|
+
[`mm-harness <install|verify|cleanup|live>`](harness-cli.md) command here, so the
|
|
27
|
+
skill thins to a few lines that call it. Same pattern applies to every other
|
|
28
|
+
`recipe-*` skill over time.
|
|
29
|
+
|
|
30
|
+
**Language policy — bash vs ts vs mjs vs cjs.** Current mix: 65 `.sh`, 62
|
|
31
|
+
`.mjs`, 17 `.ts`, 9 `.cjs` (excluding `node_modules`).
|
|
32
|
+
|
|
33
|
+
| Extension | Where | Use for | Why |
|
|
34
|
+
|---|---|---|---|
|
|
35
|
+
| `.ts` | `runner/src/**` | CLI parsing, manifests, adapter binding, runtime decisions — typed/testable/shared logic | Compiled and typed; the maintainable core that everything else should grow into |
|
|
36
|
+
| `.mjs` | `library/actions/**`, `orchestration/**`, `scripts/**` | Standalone action adapters and injected runtime helpers | Run-anywhere with zero build step, whether invoked from a published package or a raw checkout |
|
|
37
|
+
| `.cjs` | scattered, quarantined | Compatibility islands: portable `require()` from shell, bridge code for older runtime contexts | Only when the runtime context makes ESM brittle — not a default choice |
|
|
38
|
+
| `.sh` | `bin/`, `orchestration/{mobile,extension,core}/`, `runner/{mobile,extension}/`, `orchestration/lib/` | Thin OS/device glue at the edge: `simctl`, `adb`, Chrome process flags, git-exclude, filesystem setup | Must run before/without Node business logic; never recipe graph execution or MetaMask domain semantics |
|
|
39
|
+
|
|
40
|
+
The mix is bash-heavy today because sandbox setup crosses OS/device boundaries
|
|
41
|
+
(see "Why there are shell scripts" below) — that is current reality, not the
|
|
42
|
+
target ratio. The direction is less bash over time: when a shell helper starts
|
|
43
|
+
accumulating domain behavior, move it into `.ts` or a focused `.mjs` adapter
|
|
44
|
+
(see [Runtime File Conventions](runtime-file-conventions.md) for the full
|
|
45
|
+
rule).
|
|
46
|
+
|
|
47
|
+
**Packaging — one package, not several.** This stays one npm package while the
|
|
48
|
+
runtime API is still moving; see [Package Boundaries](package-boundaries.md)
|
|
49
|
+
for the full rationale. Splitting now would force every wrapper (skills,
|
|
50
|
+
farmslot) to pin two coordinated versions before the boundary between "recipe
|
|
51
|
+
execution" and "runtime lifecycle" has stabilized — coordination cost for no
|
|
52
|
+
current benefit. Split when the runtime CLI contract is stable, all wrappers
|
|
53
|
+
call it exclusively (no copied adapter scripts), and the two areas have gone
|
|
54
|
+
several releases without a change that touches both.
|
|
55
|
+
|
|
56
|
+
## Layer map (front door → engine → schema)
|
|
57
|
+
|
|
58
|
+
The whole stack is three layers with a strictly one-way dependency. `mm-harness`
|
|
59
|
+
is the MetaMask-facing **front door**; underneath it the runner is a thin
|
|
60
|
+
**adapter layer** over a fat generic **engine** (`@farmslot/recipe-harness`) and
|
|
61
|
+
**schema** (`@farmslot/protocol`). The runner never re-implements engine logic —
|
|
62
|
+
it imports it.
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
mm-harness (the one bin — no per-platform binaries) ← front door: one verb vocabulary
|
|
66
|
+
│ launch · logs · debug · fixtures (daily loop) · run/flows/doctor/actions/manifest (prove)
|
|
67
|
+
│ install/verify/cleanup/live (runtime overlay lifecycle)
|
|
68
|
+
▼
|
|
69
|
+
metamask-recipe-runner (MetaMask ADAPTER layer) ← this repo
|
|
70
|
+
│ MetaMask action manifests, metamask.* live adapters, Mobile/Extension
|
|
71
|
+
│ runtime overlay install, runtime health/decision probes
|
|
72
|
+
▼
|
|
73
|
+
@farmslot/recipe-harness (GENERIC engine) ← npm dependency
|
|
74
|
+
│ recipe graph execution, official ui.* transports, RecordingTarget
|
|
75
|
+
│ evidence framework, runtime modules, generic run/flows/validate CLI
|
|
76
|
+
▼
|
|
77
|
+
@farmslot/protocol (GENERIC schema) ← npm dependency
|
|
78
|
+
│ Recipe v1 schema, action-manifest document, artifact contract
|
|
79
|
+
▼
|
|
80
|
+
MetaMask app under test
|
|
81
|
+
│ local debug runtime only; product source should not own runner logic
|
|
82
|
+
▼
|
|
83
|
+
summary.json · trace.json · artifact-manifest.json · screenshots/logs
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Dependency direction is one-way and provable.** The runner *depends on*
|
|
87
|
+
`@farmslot/recipe-harness` + `@farmslot/protocol` (see `package.json`), and
|
|
88
|
+
`runner/src/**` *imports* the generic contracts rather than forking them:
|
|
89
|
+
|
|
90
|
+
- `runner/src/cli.ts` imports `RecipeRunResult` from `@farmslot/recipe-harness`
|
|
91
|
+
and delegates library `flows` to the harness CLI (`importRecipeHarnessCli`).
|
|
92
|
+
- `runner/src/runner.ts` wires `metamask.*` adapters INTO the farmslot
|
|
93
|
+
`RecipeRunner`; it does not implement graph execution.
|
|
94
|
+
- `runner/src/manifest.ts` loads *MetaMask* manifests typed by the *farmslot*
|
|
95
|
+
protocol document type.
|
|
96
|
+
- `runner/src/recording-target.ts` is a MetaMask provider over the farmslot
|
|
97
|
+
`RecordingTarget` contract.
|
|
98
|
+
|
|
99
|
+
**The invariant both repos assert:** farmslot stays MetaMask-free; the runner
|
|
100
|
+
never re-implements engine logic, only binds to it. Decision lens for placing any
|
|
101
|
+
new capability: *would a non-MetaMask project reuse this unchanged?* → yes =
|
|
102
|
+
generic (farmslot); encodes MetaMask app knowledge = runner.
|
|
103
|
+
|
|
104
|
+
> Note on naming: "harness" refers to the tool (`mm-harness`) and the generic
|
|
105
|
+
> engine package (`@farmslot/recipe-harness`). The per-checkout files the tool
|
|
106
|
+
> installs into a target are the **runtime overlay** (`install`/`verify`/
|
|
107
|
+
> `cleanup`/`live`), never "the harness" — see [harness-cli.md](harness-cli.md).
|
|
108
|
+
|
|
109
|
+
## One-minute model
|
|
110
|
+
|
|
111
|
+
```text
|
|
112
|
+
human CLI / optional skill wrapper
|
|
113
|
+
│ resolve + invoke
|
|
114
|
+
▼
|
|
115
|
+
metamask-recipe-runner
|
|
116
|
+
│ MetaMask action manifests, live adapters, runtime overlay install, runtime probes
|
|
117
|
+
▼
|
|
118
|
+
Recipe harness package
|
|
119
|
+
│ generic graph execution, official ui.* transports, traces, artifacts
|
|
120
|
+
▼
|
|
121
|
+
Recipe protocol package
|
|
122
|
+
│ Recipe v1 schema, manifest contract, artifact contract
|
|
123
|
+
▼
|
|
124
|
+
MetaMask app under test
|
|
125
|
+
│ local debug runtime only; product source should not own runner logic
|
|
126
|
+
▼
|
|
127
|
+
summary.json · trace.json · artifact-manifest.json · screenshots/logs
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Dependency direction is one-way. Wrappers call the runner; the runner calls the
|
|
131
|
+
shared harness/protocol packages; product apps are only driven at runtime.
|
|
132
|
+
|
|
133
|
+
## Package shape
|
|
134
|
+
|
|
135
|
+
This repo remains one npm package for now, but it has two internal areas: recipe execution and runtime lifecycle. See [Package Boundaries](package-boundaries.md) for the stability policy and why we are not splitting packages yet.
|
|
136
|
+
|
|
137
|
+
## The two subsystems
|
|
138
|
+
|
|
139
|
+
This repo has two intentionally different kinds of code. Keeping them separate
|
|
140
|
+
is the main way to understand the repository.
|
|
141
|
+
|
|
142
|
+
| Subsystem | Question it answers | Primary files | Should contain | Should not contain |
|
|
143
|
+
|---|---|---|---|---|
|
|
144
|
+
| Recipe capability/execution | “What can a MetaMask recipe do, and how does a node execute?” | `library/manifests/`, `library/recipes/`, `runner/src/runner.ts`, `runner/src/adapters.ts`, `runner/src/live-adapter-contract.ts`, `library/actions/` | action manifests, domain actions, UI transport binding, adapter outputs, proof semantics | Metro startup, Chrome process flags, simulator boot, git-exclude/rsync cleanup |
|
|
145
|
+
| Runtime lifecycle / sandbox helpers | “How do I give an agent an isolated app session that is ready to inspect or run recipes?” | `bin/mm-recipe`, `bin/mme-recipe`, `orchestration/{mobile,extension,core}/`, `runner/{mobile,extension}/`, `orchestration/lib/` | install/sync harness, start/reuse Metro or Chrome, prewarm bundles, open Extension full-screen or popup-style, prepare dedicated profiles/fixtures, check build/runtime health, cleanup local files | new recipe schema, graph traversal, MetaMask business semantics, task-specific proof logic |
|
|
146
|
+
|
|
147
|
+
When reviewing a change, first decide which subsystem it touches. Recipe changes
|
|
148
|
+
should be validated against manifests and action artifacts. Runtime lifecycle changes should be validated by install/launch/live/verify
|
|
149
|
+
behavior on a real checkout. Some commands cross the boundary, but they should
|
|
150
|
+
do so by delegating: sandbox helpers get the runtime ready, then
|
|
151
|
+
`mm-harness run` executes the recipe.
|
|
152
|
+
|
|
153
|
+
## Ownership boundaries
|
|
154
|
+
|
|
155
|
+
| Layer | Owns | Must not own |
|
|
156
|
+
|---|---|---|
|
|
157
|
+
| Human CLI / optional wrapper | Target selection, runner invocation, evidence handoff | Copied adapter scripts, recipe graph execution, product runtime logic |
|
|
158
|
+
| This runner | MetaMask action manifests, `metamask.*` adapters, Mobile/Extension harness install, runtime health/decision commands | Shared Recipe v1 schema, generic `ui.*` semantics, task-specific acceptance criteria |
|
|
159
|
+
| `Recipe harness package` | Recipe graph execution, standard core/ui adapters, trace/summary/artifact writing | MetaMask wallet/Perps behavior |
|
|
160
|
+
| `Recipe protocol package` | Recipe/manifest/artifact schemas | Runtime control or product-specific actions |
|
|
161
|
+
| Product checkout | App code and debug hooks exposed by the app | Harness scripts, runner copy, skills, private workflow logic |
|
|
162
|
+
|
|
163
|
+
Rule of thumb: if code describes **what MetaMask can do**, it belongs here. If it
|
|
164
|
+
describes **how Recipe v1 works**, it belongs in the shared protocol/runtime packages. If it
|
|
165
|
+
describes **how an agent should work**, it belongs in skills.
|
|
166
|
+
|
|
167
|
+
## Key files and directories
|
|
168
|
+
|
|
169
|
+
| Path | Responsibility |
|
|
170
|
+
|---|---|
|
|
171
|
+
| `bin/metamask-recipe` | Public binary. Dispatches to typed CLI and platform convenience commands. |
|
|
172
|
+
| `bin/mm-recipe` | Mobile convenience/runtime UX: start/reuse Metro, prewarm bundle, launch app, query bridge, setup wallet, screenshot. |
|
|
173
|
+
| `bin/mme-recipe` | Extension convenience/runtime UX: install, health, decision, ready, watch/refresh/reopen, run recipes. |
|
|
174
|
+
| `runner/src/cli.ts` | Typed command handlers: manifests, actions, doctor, runtime health/decision/launch, `run`, self-test. |
|
|
175
|
+
| `runner/src/runner.ts` | Creates the Recipe runner by combining shared core/ui adapters with MetaMask live adapters. Enables the Recipe HUD metadata. |
|
|
176
|
+
| `runner/src/adapters.ts` | MetaMask adapter binding and `ui.*` transport selection for Mobile vs Extension. Refuses static placeholders for live-only proof actions. |
|
|
177
|
+
| `runner/src/live-adapter-contract.ts` | Script adapter contract and lookup rules for `library/actions/<platform>/<domain>/*.mjs`. |
|
|
178
|
+
| `library/manifests/*.action-manifest.json` | Reviewable capability contract. A recipe may only call declared actions. |
|
|
179
|
+
| `library/actions/mobile/` | Mobile action implementations. Talks to the runner bridge and app-exposed `globalThis.__AGENTIC__` hooks. |
|
|
180
|
+
| `library/actions/extension/` | Extension action implementations. Talks to Chrome/extension pages over CDP. |
|
|
181
|
+
| `orchestration/mobile/inject.sh` | Installs/syncs the Mobile runtime overlay under the configured harness root and protects cleanup/git-exclude behavior. |
|
|
182
|
+
| `orchestration/extension/inject.mjs` | Installs/syncs Extension runtime helpers under the configured harness root. |
|
|
183
|
+
| `orchestration/mobile/` + `runner/mobile/` | Runner-owned Mobile launch/live/inject/cleanup and verify helpers copied into installed harnesses. |
|
|
184
|
+
| `orchestration/extension/` + `runner/extension/` | Runner-owned Extension launch/live/watch/windows/wallet-state/readiness helpers (orchestration) and verify (recipe) copied into installed harnesses. |
|
|
185
|
+
| `orchestration/lib/path-defaults.json` | Single source for default `recipeHarnessRoot` and `recipeRuntimeDir`. |
|
|
186
|
+
| `orchestration/lib/harness-path.sh`, `orchestration/lib/recipe-paths.mjs`, `runner/src/paths.ts` | Shell, standalone Node, and TypeScript accessors for those defaults plus validation. |
|
|
187
|
+
| `library/recipes/` | Reusable smoke/action-validation recipes only. Task-specific proof recipes stay task-local. |
|
|
188
|
+
| `library/library.json`, `library/flows/` | Canonical recipe library: minimal, stable flows recipes can `call`. Personal/team libraries shadow it by default — see [Recipe Libraries](recipe-libraries.md). |
|
|
189
|
+
| `docs/` | Runner architecture, contracts, and operational conventions. |
|
|
190
|
+
|
|
191
|
+
## Runtime paths and installed harnesses
|
|
192
|
+
|
|
193
|
+
Defaults are centralized in `orchestration/lib/path-defaults.json`:
|
|
194
|
+
|
|
195
|
+
```json
|
|
196
|
+
{
|
|
197
|
+
"recipeHarnessRoot": "temp/recipe/harness",
|
|
198
|
+
"recipeRuntimeDir": "temp/recipe/runtime"
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
All shell, standalone Node, and TypeScript code must read these through the
|
|
203
|
+
shared helpers instead of hardcoding defaults. Environment overrides are allowed
|
|
204
|
+
through `RECIPE_HARNESS_ROOT` and `RECIPE_RUNTIME_DIR`, but they must stay safe
|
|
205
|
+
relative paths.
|
|
206
|
+
|
|
207
|
+
Install commands write a small runtime package into the target checkout:
|
|
208
|
+
|
|
209
|
+
```text
|
|
210
|
+
<target>/<recipeHarnessRoot>/<adapter>/
|
|
211
|
+
manifest.json installed source/revision/cleanup metadata
|
|
212
|
+
action-manifest.json snapshot of the adapter manifest
|
|
213
|
+
runner/bin/metamask-recipe delegate back to the resolved runner source
|
|
214
|
+
runner/recipes/ reusable recipe snapshot
|
|
215
|
+
scripts/ adapter runtime helpers copied from this repo
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
The installed harness exists so a running slot has stable helper paths even when
|
|
219
|
+
called from skills, orchestration hooks, or a human shell. The source of truth remains
|
|
220
|
+
this runner.
|
|
221
|
+
|
|
222
|
+
## Recipe execution vs sandbox lifecycle
|
|
223
|
+
|
|
224
|
+
`mm-harness run <recipe.json> --adapter ...` is the recipe path. It creates
|
|
225
|
+
a shared Recipe runner (`runner/src/runner.ts`), validates the recipe against the
|
|
226
|
+
manifest, executes nodes, and writes artifacts. If a bug is about action fields,
|
|
227
|
+
trace output, adapter semantics, or whether a recipe proves a claim, start in
|
|
228
|
+
`library/manifests/`, `runner/src/`, `library/actions/`, and `library/recipes/`.
|
|
229
|
+
|
|
230
|
+
`prepare`, `launch`, `live`, `verify`, `status`, `decision`, and `ready` are
|
|
231
|
+
sandbox lifecycle paths. They give the agent a reproducible local app session:
|
|
232
|
+
Mobile with Metro/dev-client/simulator and the bridge online; Extension with an
|
|
233
|
+
isolated browser profile, unpacked extension loaded, and a known home/popup-style
|
|
234
|
+
UI target. If a bug is about Metro, bundle prewarm, simulator launch, Chrome CDP,
|
|
235
|
+
Extension full-screen vs popup presentation, build freshness, wallet fixture
|
|
236
|
+
placement, git-exclude, or cleanup, start in `bin/mm-recipe`, `bin/mme-recipe`,
|
|
237
|
+
`orchestration/{mobile,extension,core}/` and `runner/{mobile,extension}/`.
|
|
238
|
+
|
|
239
|
+
Do not put recipe graph traversal into shell scripts. Shell scripts may prepare
|
|
240
|
+
or inspect the sandboxed runtime, then delegate graph execution to
|
|
241
|
+
`mm-harness run`.
|
|
242
|
+
|
|
243
|
+
## HUD vs bridge vs product hooks
|
|
244
|
+
|
|
245
|
+
These names are easy to mix up; they are different concerns.
|
|
246
|
+
|
|
247
|
+
| Term | What it is | Why it exists |
|
|
248
|
+
|---|---|---|
|
|
249
|
+
| Recipe HUD | A visual overlay driven by Recipe runner metadata (`intent`, current node, status). | Makes screenshots/videos explain what the recipe is doing without exposing secrets. |
|
|
250
|
+
| Mobile bridge | Runner-side CDP/Hermes bridge process under `library/actions/mobile/bridge-runtime/`. | Lets the runner call app-exposed commands, read state, press UI targets, and capture status from React Native. |
|
|
251
|
+
| `globalThis.__AGENTIC__` | Development-only in-app command surface exposed by the Mobile overlay/patch. | Gives the bridge a stable API for route/status/wallet/UI operations when the app lacks a built-in automation API. |
|
|
252
|
+
| Extension CDP hooks | Chrome DevTools Protocol access to extension pages/background state hooks. | Lets the runner inspect/drive the unpacked Extension without patching product source. |
|
|
253
|
+
|
|
254
|
+
The HUD does not control the app. The bridge/CDP control the app. The HUD only
|
|
255
|
+
renders proof context.
|
|
256
|
+
|
|
257
|
+
## Mobile runtime shape
|
|
258
|
+
|
|
259
|
+
Mobile has the most moving parts because React Native does not expose a browser
|
|
260
|
+
DOM by default.
|
|
261
|
+
|
|
262
|
+
```text
|
|
263
|
+
mm-recipe / orchestration/mobile/*.sh
|
|
264
|
+
│ starts/reuses Metro, prewarms bundle, launches iOS/Android dev client
|
|
265
|
+
▼
|
|
266
|
+
library/actions/mobile/bridge-runtime/cdp-bridge.cjs
|
|
267
|
+
│ connects to Hermes / RN debug runtime
|
|
268
|
+
▼
|
|
269
|
+
globalThis.__AGENTIC__ inside the app
|
|
270
|
+
│ route/status/wallet/ui commands + optional HUD rendering
|
|
271
|
+
▼
|
|
272
|
+
library/actions/mobile/{wallet,perps,ui,platform}/*.mjs
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Ideally the app would expose a product-owned debug automation surface directly,
|
|
276
|
+
so the runner would not need to patch or inject Mobile client files at all. The
|
|
277
|
+
current injection exists as a compatibility bridge: it lets recipes run against
|
|
278
|
+
older Mobile versions, historical PR branches, and eval/replay runs that do not yet include that
|
|
279
|
+
client-side automation surface.
|
|
280
|
+
|
|
281
|
+
The Mobile injection currently may touch development-only product files on older
|
|
282
|
+
checkouts to install the `AgenticService`, navigation hook, and HUD mount. That
|
|
283
|
+
is the fragile compatibility path, not the desired long-term product contract.
|
|
284
|
+
Those product patches are local runtime state: never commit them to MetaMask
|
|
285
|
+
Mobile. The runner also installs ignored helper files under
|
|
286
|
+
`temp/recipe/harness/mobile`.
|
|
287
|
+
|
|
288
|
+
Mobile `ensure_*` actions must be idempotent: if the wallet is already unlocked,
|
|
289
|
+
`metamask.wallet.ensure_unlocked` should report success or converge cheaply, not
|
|
290
|
+
fail because the starting state differed.
|
|
291
|
+
|
|
292
|
+
## Extension runtime shape
|
|
293
|
+
|
|
294
|
+
Extension does not need an in-product source patch. The runner works through an
|
|
295
|
+
unpacked `dist/chrome` build and Chrome CDP.
|
|
296
|
+
|
|
297
|
+
```text
|
|
298
|
+
mme-recipe / orchestration/extension/*.sh
|
|
299
|
+
│ checks dist freshness, build health, fixture/profile state
|
|
300
|
+
▼
|
|
301
|
+
Chrome for Testing with --load-extension=<runtime-dist>
|
|
302
|
+
│ CDP target discovery + deterministic extension id
|
|
303
|
+
▼
|
|
304
|
+
library/actions/extension/{wallet,perps,ui,platform}/*.mjs
|
|
305
|
+
│ extension page/background hooks and UI events
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
`runtime-launch --start-watch` is the clean-build path. Without `--start-watch`,
|
|
309
|
+
verify can prove the existing runtime is reachable but may fail `dist-freshness`
|
|
310
|
+
if `dist/chrome` does not match `HEAD`. That failure is intentional: it prevents
|
|
311
|
+
silently proving stale product code.
|
|
312
|
+
|
|
313
|
+
## Why there are shell scripts
|
|
314
|
+
|
|
315
|
+
The shell scripts are large because sandbox setup crosses OS/device boundaries:
|
|
316
|
+
`simctl`, `adb`, Metro, Watchman, Chrome process flags, isolated browser
|
|
317
|
+
profiles, git exclude files, symlink safety checks, and cleanup all live outside
|
|
318
|
+
Node's typed domain logic. Their purpose is to give an agent a reliable app
|
|
319
|
+
session, not to define recipe semantics.
|
|
320
|
+
|
|
321
|
+
Allowed in shell:
|
|
322
|
+
|
|
323
|
+
- parsing CLI flags for lifecycle commands;
|
|
324
|
+
- calling OS/device tools;
|
|
325
|
+
- copying/removing installed harness files;
|
|
326
|
+
- starting/stopping/reusing local dev servers;
|
|
327
|
+
- writing small runtime summaries from command results.
|
|
328
|
+
|
|
329
|
+
Not allowed in shell:
|
|
330
|
+
|
|
331
|
+
- Recipe v1 graph execution;
|
|
332
|
+
- MetaMask domain semantics that can live in `runner/src/**/*.ts` or `library/actions/**/*.mjs`;
|
|
333
|
+
- duplicated action manifest logic;
|
|
334
|
+
- product-specific business decisions beyond runtime boot/health checks.
|
|
335
|
+
|
|
336
|
+
When a shell helper starts accumulating domain behavior, move that behavior into
|
|
337
|
+
TypeScript or a focused `.mjs` adapter and keep shell as the launcher.
|
|
338
|
+
|
|
339
|
+
## Adding or changing capabilities
|
|
340
|
+
|
|
341
|
+
1. Add/adjust the shared capability in both Mobile and Extension manifests when
|
|
342
|
+
the concept exists on both platforms.
|
|
343
|
+
2. Implement durable behavior under `library/actions/<platform>/<domain>/`.
|
|
344
|
+
3. Keep parameterized actions instead of multiplying action names.
|
|
345
|
+
4. Ensure every `ensure_*` action proves a postcondition.
|
|
346
|
+
5. Use official `ui.*` actions and screenshot claims for visible acceptance
|
|
347
|
+
criteria; do not add task-specific `metamask.*` actions for exact copy,
|
|
348
|
+
styling, ticket IDs, or one-off selectors.
|
|
349
|
+
6. Update smoke/action-validation recipes only when the capability is reusable.
|
|
350
|
+
|
|
351
|
+
## Standalone use first; farm later
|
|
352
|
+
|
|
353
|
+
This runner should make sense without any slot farm:
|
|
354
|
+
|
|
355
|
+
1. choose a local MetaMask Mobile or Extension checkout;
|
|
356
|
+
2. run `mm-harness launch <platform>` (or `mm-harness install` for the overlay only);
|
|
357
|
+
3. run `mm-harness doctor` (or the advanced `runtime-health`);
|
|
358
|
+
4. run `mm-harness run <recipe.json> --adapter <platform> --artifacts-dir <dir>`.
|
|
359
|
+
|
|
360
|
+
Skills are optional workflow wrappers around that same CLI. A wrapper may resolve
|
|
361
|
+
the runner source and package evidence, but it should dispatch `install`,
|
|
362
|
+
`launch`, `live`, `verify`, and `cleanup` to this repo or to the installed
|
|
363
|
+
harness helper. It should not carry Mobile or Extension adapter scripts.
|
|
364
|
+
|
|
365
|
+
Farm/slot orchestration belongs one layer outside this runner. It can scale the
|
|
366
|
+
standalone loop by choosing checkouts, machines, ports, simulators, and agents,
|
|
367
|
+
but it should not change the runner contract or copy runner implementation.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Extension runtime lifecycle (internal notes)
|
|
2
|
+
|
|
3
|
+
Internal implementation notes for the MetaMask Extension runtime lifecycle — the
|
|
4
|
+
self-healing path that gets a checkout from "installed" to "a live, verified
|
|
5
|
+
extension under CDP control". These are **not** a public command surface: the
|
|
6
|
+
probes below are internal functions, composed for you by the daily-loop commands
|
|
7
|
+
(`launch --verify`) and the readiness commands (`doctor --fix`, `verify`). The
|
|
8
|
+
public surface is defined in [CLI-SPEC.md](CLI-SPEC.md); this file explains what
|
|
9
|
+
happens underneath.
|
|
10
|
+
|
|
11
|
+
The runner is the source of truth for Extension harness injection, readiness
|
|
12
|
+
decisions, extension-id resolution, and live CDP health checks.
|
|
13
|
+
|
|
14
|
+
## Public entry points
|
|
15
|
+
|
|
16
|
+
- **`install`** writes the Extension runtime overlay under the configured harness
|
|
17
|
+
root. CI/agents run it explicitly; the daily-loop commands auto-ensure it.
|
|
18
|
+
- **`verify`** confirms the overlay is present and healthy — a live CDP health
|
|
19
|
+
probe when a runtime is reachable, no launch.
|
|
20
|
+
- **`launch --verify`** installs the overlay if missing, launches/attaches the
|
|
21
|
+
extension, and polls CDP until the runtime is ready.
|
|
22
|
+
- **`doctor` / `doctor --fix`** report readiness and (with `--fix`) run the
|
|
23
|
+
healing steps below WITHOUT starting the app.
|
|
24
|
+
|
|
25
|
+
## Internal lifecycle stages
|
|
26
|
+
|
|
27
|
+
The healing path composes these internal functions in order. Each is idempotent
|
|
28
|
+
and reports the cheapest next action, so the composed path converges rather than
|
|
29
|
+
rebuilding from scratch.
|
|
30
|
+
|
|
31
|
+
### Extension-id resolution
|
|
32
|
+
|
|
33
|
+
Resolves the deterministic unpacked extension id from
|
|
34
|
+
`dist/chrome/manifest.json`, and can verify it against a live CDP target. Every
|
|
35
|
+
later stage keys off this id, so it runs first.
|
|
36
|
+
|
|
37
|
+
### Readiness decision
|
|
38
|
+
|
|
39
|
+
Inspects the checkout + live browser and returns the cheapest next action:
|
|
40
|
+
`install`, `build`, `relaunch`, or `ready`, plus the concrete `actions[]` to
|
|
41
|
+
execute. The healing path branches on this decision instead of always launching.
|
|
42
|
+
|
|
43
|
+
### Runtime launch
|
|
44
|
+
|
|
45
|
+
Launches Chrome with the installed harness helper, seeds the wallet fixture, and
|
|
46
|
+
runs live smoke verification. Two tiers: reuse the existing dist (quick relaunch),
|
|
47
|
+
or the clean-build path — clear the webpack cache, start the harness-owned
|
|
48
|
+
watcher, wait for a clean compile, then launch and verify.
|
|
49
|
+
|
|
50
|
+
### Convergence
|
|
51
|
+
|
|
52
|
+
Converges the live browser to exactly one healthy `home.html` tab (closing
|
|
53
|
+
strays, reopening if needed) and confirms it with the health probe. This is the
|
|
54
|
+
step that makes "launch" deterministic across a messy pre-existing browser state.
|
|
55
|
+
|
|
56
|
+
### Health probe
|
|
57
|
+
|
|
58
|
+
Read-only liveness probe for the running extension over CDP. Used both as the
|
|
59
|
+
final gate of the convergence step and standalone by `verify` to answer "is the
|
|
60
|
+
runtime healthy right now?" without mutating anything.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# `mm-harness` — Command Reference
|
|
2
|
+
|
|
3
|
+
> This page is a pointer. The full, authoritative command contract lives in
|
|
4
|
+
> [CLI-SPEC.md](CLI-SPEC.md); the before→after overview is in
|
|
5
|
+
> [MENTAL-MODEL.md](MENTAL-MODEL.md). This file exists only so links to
|
|
6
|
+
> `harness-cli.md` keep resolving.
|
|
7
|
+
|
|
8
|
+
`mm-harness` is the MetaMask recipe harness — the single front door for launching
|
|
9
|
+
the app, proving behavior, and managing the per-checkout **runtime overlay**. It
|
|
10
|
+
is the only bin: platform (`mobile | extension | core`) is auto-detected from the
|
|
11
|
+
checkout, a positional target forces it (`mm-harness launch ios`), and depth lives
|
|
12
|
+
in flags (`--json`, ports, build tiers), never in extra command names.
|
|
13
|
+
|
|
14
|
+
Naming: **"harness" is the tool** (`mm-harness`) and the generic engine package
|
|
15
|
+
(`@farmslot/recipe-harness`). The files the tool installs into a target checkout
|
|
16
|
+
are the **runtime overlay** — never "the harness".
|
|
17
|
+
|
|
18
|
+
## Command surface (all shipped)
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
DAILY LOOP launch · logs · debug · fixtures what a teammate runs many times a day
|
|
22
|
+
DISCOVER actions · call · flows compose recipes from the vocabulary + flow library
|
|
23
|
+
PROVE run · doctor run recipes, check readiness
|
|
24
|
+
RUNTIME OVERLAY install · verify · cleanup install/verify/clean the per-checkout overlay
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Grammar: `mm-harness <command> [target] [flags]`. `--json` is the agent contract on
|
|
28
|
+
every command; the bare command is the human happy path.
|
|
29
|
+
|
|
30
|
+
- `run` validates first, then executes; `run --plan` validates and prints the plan
|
|
31
|
+
without touching a device.
|
|
32
|
+
- `call <action>` runs one action from the adapter vocabulary through the same
|
|
33
|
+
engine path `run` uses.
|
|
34
|
+
- `doctor` is read-only; `doctor --fix` runs the self-healing steps (overlay
|
|
35
|
+
auto-ensure; never a fixture reseed) without launching the app and reports
|
|
36
|
+
`fixed[]` / `failed[]`.
|
|
37
|
+
- `flows` lists the recipe library (bare = `flows list`); `flows promote` keeps a
|
|
38
|
+
proven flow.
|
|
39
|
+
- `install` / `verify` / `cleanup` manage the runtime overlay; the DAILY LOOP
|
|
40
|
+
commands auto-ensure it.
|
|
41
|
+
|
|
42
|
+
For flags, exit-code taxonomy, `--json` shapes, and per-command detail, see
|
|
43
|
+
[CLI-SPEC.md](CLI-SPEC.md).
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# Live Adapter Contract
|
|
2
|
+
|
|
3
|
+
The MetaMask runner implements Recipe Protocol v1 through the shared recipe
|
|
4
|
+
harness package. Project-specific live behavior is supplied by
|
|
5
|
+
manifest-declared action adapters.
|
|
6
|
+
|
|
7
|
+
Official `ui.*` semantics are implemented by
|
|
8
|
+
`createStandardUiAdapters({ transport })` plus shared CDP/React Native base
|
|
9
|
+
transports. The MetaMask runner supplies only tiny runtime bindings that point
|
|
10
|
+
those base transports at the Extension CDP page or Mobile React Native bridge.
|
|
11
|
+
MetaMask-specific actions remain separate manifest-declared live adapters.
|
|
12
|
+
|
|
13
|
+
For actions that must prove real product behavior, especially `metamask.perps.*`, static placeholders are refused by default. A live adapter script must exist in one of these locations. Domain-grouped paths are preferred so code ownership stays obvious:
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
$METAMASK_RECIPE_LIVE_ADAPTER_DIR/<platform>/<domain>/<action-local-name>.mjs
|
|
17
|
+
$METAMASK_RECIPE_LIVE_ADAPTER_DIR/shared/<domain>/<action-local-name>.mjs
|
|
18
|
+
<runner>/library/actions/<platform>/<domain>/<action-local-name>.mjs
|
|
19
|
+
<runner>/library/actions/shared/<domain>/<action-local-name>.mjs
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Legacy external `.js` adapters are still resolved for compatibility, and `.sh` remains available for edge orchestration. New committed adapter code should use grouped `.mjs` modules. Fully-qualified flat filenames are still searched after grouped paths, but new adapter code should use grouped modules. Do not add `ui.*` files here; official UI actions go through shared base transports. Examples:
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
library/actions/extension/perps/ensure_positions.mjs
|
|
26
|
+
library/actions/extension/perps/close_positions.mjs
|
|
27
|
+
library/actions/extension/perps/close_orders.mjs
|
|
28
|
+
library/actions/mobile/perps/place_order.mjs
|
|
29
|
+
library/actions/mobile/wallet/ensure_unlocked.mjs
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The runner invokes the script with one argument: a JSON input file path. The same path is also available as `METAMASK_RECIPE_ADAPTER_INPUT`. The script must write JSON to `outputPath` from the input document, or print JSON to stdout.
|
|
33
|
+
|
|
34
|
+
Input shape:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"schemaVersion": 1,
|
|
39
|
+
"platform": "mobile|extension",
|
|
40
|
+
"action": "metamask.perps.ensure_positions",
|
|
41
|
+
"node": {},
|
|
42
|
+
"context": {
|
|
43
|
+
"nodeId": "ensure-clean",
|
|
44
|
+
"projectRoot": "/path/to/product",
|
|
45
|
+
"artifactsDir": "/path/to/artifacts"
|
|
46
|
+
},
|
|
47
|
+
"outputPath": "/tmp/.../output.json"
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Output shape is action-specific, but must be redacted and suitable for `trace.json`. If the adapter captures evidence files, write them under `context.artifactsDir` and return relative artifact paths for the runner adapter to index in a follow-up implementation.
|
|
52
|
+
|
|
53
|
+
Proof rule: live adapters must drive real supported app/API paths. They must not write directly into UI state, DOM state, React/Redux/MobX state, local storage, controller internals, or any mid-recipe state that fabricates the proof condition.
|
|
54
|
+
|
|
55
|
+
## Controller/API calls vs visible UI proof
|
|
56
|
+
|
|
57
|
+
Recipe authors should choose the layer based on what must be proven:
|
|
58
|
+
|
|
59
|
+
| Need | Use | Rule |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| Fast reproducible setup/teardown before or after the proof window | `metamask.*` domain actions such as `start_state`, `ensure_positions`, `close_orders` | May use supported product/controller APIs, but must read/assert the final state. |
|
|
62
|
+
| Read-only state proof | `metamask.*.read_*` or `metamask.*.assert_*` | Must return redacted live state in trace output. |
|
|
63
|
+
| Human-visible acceptance criterion | official `ui.*` actions | Drive the actual visible path: press/tap, input/keypad, scroll into view, screenshot. Do not replace it with a controller call. |
|
|
64
|
+
| Ticket-specific visual detail | task-local recipe assertions/evidence | Do not add a reusable action only for one ticket. |
|
|
65
|
+
|
|
66
|
+
## Shared action-surface boundaries
|
|
67
|
+
|
|
68
|
+
The manifest is a durable capability contract, not a place to encode one
|
|
69
|
+
ticket's acceptance criteria. Do not add shared `metamask.*` actions for ticket
|
|
70
|
+
IDs, POCs, exact test IDs, exact copy, styling, placement, or other one-off UI
|
|
71
|
+
proof needs.
|
|
72
|
+
|
|
73
|
+
Use:
|
|
74
|
+
|
|
75
|
+
- official `ui.*` actions for reusable presence, input, scroll, and screenshot
|
|
76
|
+
behavior;
|
|
77
|
+
- screenshot `claims` for visual, copy, and layout proof;
|
|
78
|
+
- task-local composed flows under the task artifact directory when a ticket
|
|
79
|
+
needs a reusable helper for that ticket only;
|
|
80
|
+
- safe direct CDP/controller calls for read/assert or supported setup paths,
|
|
81
|
+
never state fabrication.
|
|
82
|
+
|
|
83
|
+
Add or keep a shared action only when it represents a durable parameterized
|
|
84
|
+
domain capability useful across many tasks, such as `metamask.perps.start_state`,
|
|
85
|
+
`metamask.perps.place_order`, `metamask.perps.close_positions`, or
|
|
86
|
+
`metamask.perps.assert_positions`.
|
|
87
|
+
|
|
88
|
+
`ui.scroll` is part of the current executable contract and action-validation must
|
|
89
|
+
prove both normal scrolling and `scroll_into_view` before screenshot capture.
|
|
90
|
+
`ui.gesture` is intentionally not advertised yet; drag/swipe proof must wait
|
|
91
|
+
until the shared runtime and this runner expose and validate that action on both
|
|
92
|
+
platforms.
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
## Flow catalog follow-up
|
|
97
|
+
|
|
98
|
+
Action adapters fulfill one manifest-declared operation. Production recipes should also be able to call domain flow catalogs that compose these operations into idempotent `ensure_*` start states. These flows are owned by this runner/domain layer, not by shared runtime packages or wrapper glue.
|
|
99
|
+
|
|
100
|
+
For Perps, recipes should use the runner-provided `metamask.perps.start_state({ network, provider, page, market, positions, orders })` and `metamask.perps.teardown_state(...)` actions as the default reproducibility boundary. These actions compose primitive bulk operations such as `close_positions({ mode: "all" })` and `close_orders({ mode: "all" })` instead of multiplying one-off cleanup actions.
|
|
101
|
+
|
|
102
|
+
## Built-in Extension live adapters
|
|
103
|
+
|
|
104
|
+
The first Extension adapter set is bundled under `library/actions/extension/` and talks directly to the Chrome extension page target over CDP. It does not execute a second recipe graph. The v1 runner still owns workflow traversal; each script only fulfills one manifest-declared action.
|
|
105
|
+
|
|
106
|
+
Runtime input:
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
node.cdp_port | CDP_PORT | RECIPE_CDP_PORT
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Optional autolaunch input for existing Extension builds:
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
METAMASK_RECIPE_EXTENSION_AUTOLAUNCH=1
|
|
116
|
+
METAMASK_RECIPE_EXTENSION_LAUNCH_EXISTING_DIST=1
|
|
117
|
+
node.launch_existing_dist=true
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
When enabled, the adapter reuses the requested CDP port if a compatible extension target exists; otherwise it launches Chrome from the target checkout's existing `dist/chrome` without rebuilding the product. The runtime copy, profile, logs, and `runtime.json` are written under `context.artifactsDir/extension-runtime/`.
|
|
121
|
+
|
|
122
|
+
CLI equivalent:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
mm-harness run <recipe.json> --adapter extension --cdp-port 6664 --launch-existing-dist --artifacts-dir <dir>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The CLI maps `--cdp-port` to `CDP_PORT`/`RECIPE_CDP_PORT` and maps `--launch-existing-dist` to `METAMASK_RECIPE_EXTENSION_AUTOLAUNCH=1` for the duration of the recipe run.
|
|
129
|
+
|
|
130
|
+
Currently implemented Extension actions:
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
ui.navigate # extension: page alias or hash/path/url
|
|
134
|
+
metamask.perps.read_positions
|
|
135
|
+
metamask.perps.read_orders
|
|
136
|
+
metamask.perps.close_positions # primitive bulk close selected positions
|
|
137
|
+
metamask.perps.close_orders # primitive bulk cancel selected orders
|
|
138
|
+
metamask.perps.place_order
|
|
139
|
+
metamask.perps.assert_positions
|
|
140
|
+
metamask.perps.assert_orders
|
|
141
|
+
metamask.perps.ensure_positions # high-level read/close/place/assert wrapper
|
|
142
|
+
metamask.perps.ensure_orders # high-level read/cancel/assert wrapper
|
|
143
|
+
ui.press
|
|
144
|
+
ui.scroll
|
|
145
|
+
ui.wait_for
|
|
146
|
+
ui.screenshot
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Navigation supports a small discoverable `page` alias set (`home`, `perps`, `perps-market`) plus raw extension hash/url fallback. Check the action manifest before hardcoding routes.
|
|
150
|
+
|
|
151
|
+
Task-specific UI styling checks, such as one ticket proving a banner color or placement, must not be implemented as reusable `metamask.perps.*` actions. Use official `ui.wait_for` for reusable presence/absence checks plus screenshot/task-local validation evidence for that ticket.
|
|
152
|
+
|
|
153
|
+
Read-only position checks use `stateHooks.submitRequestToBackground('perpsGetPositions', [{ skipCache: true }])`. State-changing actions prefer UI interaction through CDP mouse/keyboard events. Bulk cleanup primitives may call product background APIs such as `perpsClosePositions` or `perpsCancelOrders` when the UI control is unavailable; this is a supported app/API path, not direct state mutation. Adapters must not mutate Redux/React state, DOM state, local storage, or controller internals to fabricate proof.
|
|
154
|
+
|
|
155
|
+
## Built-in Mobile live adapters
|
|
156
|
+
|
|
157
|
+
The Mobile adapter is bundled under `library/actions/mobile/`. Its CDP bridge, wallet setup, target discovery, and screenshot helpers run from the runner runtime; the Mobile checkout must not own harness control scripts. The app still needs a development-only in-app bridge/HUD overlay when a historical checkout does not expose the required `globalThis.__AGENTIC__` hooks.
|
|
158
|
+
|
|
159
|
+
Runtime input:
|
|
160
|
+
|
|
161
|
+
```text
|
|
162
|
+
node.watcher_port | node.metro_port | node.cdp_port | WATCHER_PORT | CDP_PORT | RECIPE_CDP_PORT
|
|
163
|
+
node.simulator | node.ios_simulator | IOS_SIMULATOR
|
|
164
|
+
node.android_device | ANDROID_DEVICE
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Currently implemented Mobile actions:
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
ui.navigate # mobile: page alias or route/screen + params
|
|
171
|
+
metamask.perps.read_positions
|
|
172
|
+
metamask.perps.read_orders
|
|
173
|
+
metamask.perps.close_positions # primitive bulk close selected positions
|
|
174
|
+
metamask.perps.close_orders # primitive bulk cancel selected orders
|
|
175
|
+
metamask.perps.place_order
|
|
176
|
+
metamask.perps.assert_positions
|
|
177
|
+
metamask.perps.assert_orders
|
|
178
|
+
metamask.perps.ensure_positions # high-level read/close/place/assert wrapper
|
|
179
|
+
metamask.perps.ensure_orders # high-level read/cancel/assert wrapper
|
|
180
|
+
ui.press
|
|
181
|
+
ui.scroll
|
|
182
|
+
ui.wait_for
|
|
183
|
+
ui.screenshot
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Navigation supports a small discoverable `page` alias set (`home`, `perps`, `perps-market`) plus raw React Navigation route/params fallback. Check the action manifest before hardcoding routes.
|
|
187
|
+
|
|
188
|
+
Read-only position checks use `Engine.context.PerpsController.getPositions()` through Hermes CDP. State-changing Perps actions use supported controller APIs (`placeOrder`, `closePositions`) through the same app bridge rather than mutating Redux/React/local storage. UI actions delegate to existing bridge capabilities such as `press-test-id` and `scroll-view`. Screenshot capture uses `xcrun simctl io <simulator> screenshot` for iOS simulator proof.
|