recipes
Customization

Make it your team's harness

The harness ships an execution standard and a deliberately small bundled library. Everything that is specific to what you work on — the journeys, the assertions, the checklists, the review knowledge — lives in a library you own and point the harness at. MetaMask Perps is the worked example on this page.

per team per engineer one env var

The harness supplies the execution standard; your library supplies the domain. A team shares one library. An engineer can add their own on top. Neither requires a change to the harness.

What lives where

LayerOwnsDoes not own
mm-harness Launch, typed actions, graph execution, screenshots, video, traces, and artifact contracts. Anything specific to one team's domain.
Your library Reusable setup, journeys, assertions, cleanup, platform variants, and checklist templates. Wallet credentials, generated evidence, or product source.
Product checkout The real Extension, Mobile, or Core code and runtime being proved. A substitute test implementation.

Point the harness at a library

One environment variable does it. The Perps library is private, so start by asking its owners for access — a clone failure means your GitHub account does not have it yet.

$ git clone git@github.com:MetaMask/experimental-metamask-recipe-perps.git \
    "$HOME/shared-library/metamask-recipe-perps"
$ export RECIPE_LIBRARY_PATH="perps=$HOME/shared-library/metamask-recipe-perps"
$ mm-harness run --list

name=path gives the source its alias; without one the directory name is used. Separate several libraries with : — order is precedence, first wins:

$ export RECIPE_LIBRARY_PATH="mine=$HOME/my-recipes:perps=$HOME/shared-library/metamask-recipe-perps"

Use --library name=/path for a single command instead — useful when a tool shell loses an exported variable. Resolution follows your library order, then the bundled MetaMask library.

Your own library, with no configuration

A directory at ~/.farmslot/recipe-library is picked up automatically as personal when you set no library at all. It is a fallback, not an addition: as soon as RECIPE_LIBRARY_PATH or --library is set, only those sources are used. List it explicitly to keep both.

Discovery is adapter-aware

The list shows only recipes runnable in the current product checkout. A recipe marked [perps] came from that library; [metamask] means it ships with the harness. Read the selected platform variant with --describe before running it.

What a team library actually holds

Every path below is real, from the Perps library. Copy the shape, not the contents — it is the reference structure for a MetaMask team building its own.

manifests/extension.action-manifest.json     types the actions you add
actions/extension/perps/                     domain actions the product needs
recipes/mobile/perps/                        per-adapter journeys
recipes/extension/perps/
recipes/core/perps/
checklists/dev/                              your own Recipe Cook checklist templates
checklists/fix-bug/
docs/                                        the knowledge: authoring rules,
                                             performance evidence, analytics

The docs/ and checklists/ directories are the part teams underestimate. They are how a team's hard-won conventions — how performance evidence is gathered here, which analytics events matter, what a finished task looks like — stop living in one engineer's head.

Review knowledge lives with the skills

One team surface sits outside the recipe library: the static antipattern packs the PR QA review reads, which ship with the skills as references/antipatterns/<repo>/<pack>.md. Today there is a perps pack for Mobile, Extension, and Core, and a Mobile-only unit-vs-cv pack. A pack is advisory: it never changes an acceptance-criterion verdict.

Your first live proof

Complete the walkthrough first so the app, device, and wallet fixture are ready. With RECIPE_LIBRARY_PATH exported, the library's recipes are just names.

Extension or Mobile

$ mm-harness run perps.open-market --describe
$ mm-harness run perps.open-market network=testnet market=BTC --plan
$ mm-harness run perps.open-market network=testnet market=BTC \
    --record-video=full-run --artifacts-dir ./perps-open-market-evidence

Core

$ mm-harness run perps.snapshot-market --describe
$ mm-harness run perps.snapshot-market network=testnet market=BTC \
    --artifacts-dir ./perps-market-evidence

A passing run writes summary.json, per-node results in trace.json, and an artifact manifest beside screenshots or video. Visual review surfaces can render those same recipe-derived artifacts without changing the proof graph.

What the Perps team put in theirs

A sample of the library's recipes, as an idea of the granularity that works: small, parameterized, composed rather than duplicated.

ClaimRecipePlatforms
Reach a live market detail screenperps.open-marketMobile, Extension
Read positions and ordersperps.snapshot-marketMobile, Extension, Core
Place, assert, and clean up an orderperps.prove-orderMobile, Extension, Core
Manage or close a positionperps.manage-positionMobile, Extension, Core
Prove real MetaMetrics emissionsperps.analytics-lifecycleMobile, Extension
Measure the open-market journeyperps.performance-open-marketMobile, Extension
Exercise edit-order contractsperps.prove-edit-orderCore
Mutation boundary

Always run --describe and --plan before a state-changing recipe. The library defaults to testnet and cleans up testnet state. Never turn an onboarding proof into a mainnet mutation; mainnet operations require the recipe's explicit real-funds confirmation.

Starting your team's library

  1. Create a repository with the directory shape above. It holds no accounts, fixtures, credentials, or generated evidence.
  2. Parameterize stable choices such as market, side, order type, and network.
  3. Compose existing setup, assertion, and cleanup recipes before adding a new top-level recipe.
  4. Add a platform variant only when the products genuinely differ.
  5. If a locator or screen assertion fails, classify it first. Intentional product change may mean small recipe drift; otherwise preserve the failure and fix the product, runtime, or harness layer that owns it.
  6. Re-run every caller after a shared node changes and attach the fresh evidence.

Keep it small. Compose or repair the closest recipe before creating another one — a library that grows a scenario per ticket stops being maintainable faster than the product does.