# Contributing

Keep `mm-harness` thin: put each change in the layer that owns it and validate
both the machine contract and the visible human result.

## Ownership

```text
bin/mm-harness
  -> src/                         typed CLI and product decisions
  -> @farmslot/agent-runtime     checklist state
  -> @farmslot/handoff           scrubbed learning capture/share
  -> @farmslot/recipe-harness    generic execution, UI transports, evidence
  -> @farmslot/protocol          schemas
  -> adapters/                   focused host/browser/device leaves
  -> library/                    MetaMask actions and recipes
  -> MetaMask checkout           product under test
```

| Layer | Owns |
|---|---|
| `@farmslot/protocol` | recipe and evidence schemas |
| `@farmslot/agent-runtime` | task-local checklist state and terminal contracts |
| `@farmslot/handoff` | learning assembly, scrubbing, validation, approval, and publication |
| `@farmslot/recipe-harness` | generic execution, recovery, traces, artifacts, `ui.*` |
| `mm-harness` | MetaMask runtime control, diagnostics, durable domain actions |
| skills/checklists | task workflow and proof expectations |
| product checkout | app behavior and explicit debug hooks |

Generic bootstrap, trust, receipts, and recovery belong upstream. MetaMask
platform behavior and risk classification belong here. Ticket assertions stay
task-local.

`mm-harness checklist` is only the MetaMask-facing dispatch layer. Terminal
marks stage learnings through Handoff; sharing always requires a separate
explicit `--share` call.

## Repository map

| Path | Responsibility |
|---|---|
| `bin/mm-harness` | only public executable |
| `src/commands/` | command behavior |
| `src/adapters/` | typed platform decisions and `AdapterSurface` |
| `adapters/<platform>/` | focused shell/Node host operations |
| `adapters/<platform>/inject*` | assemble the checkout overlay from shipped adapter/library files |
| `library/actions/` | executable MetaMask action adapters |
| `library/recipes/` | reusable parameterized behavior and proofs |
| `library/manifests/` | declared capability surface |
| `scripts/` | build/validation tooling and shipped completion/human-QA helpers |

All TypeScript lives under `src/`. Use `.mjs` for direct no-build Node leaves,
`.cjs` only for required CommonJS contexts, and shell only for host/device
commands. Decisions belong in TypeScript; a leaf performs one operation and
exits.

## Adapter surface

Commands resolve shared platform behavior through
`src/adapters/surface.ts`. Extend `AdapterSurface` only when all platforms need
the concept, implement all three adapters, and let Core report headless/N/A
explicitly. Do not add command-local platform ladders for surface-owned behavior.

Each checkout owns:

```text
temp/recipe/runtime/   ports, processes, fixture, logs, runtime identity
temp/recipe/harness/   installed runtime overlay
```

Profiles, devices, ports, watchers, and evidence paths must resolve from that
checkout so slots remain isolated.

## Actions and adapters

Official `ui.*` behavior comes from the generic runtime. MetaMask-specific
actions are manifest-declared modules under:

```text
library/actions/<platform>/<domain>/<name>.mjs
library/actions/shared/<domain>/<name>.mjs
```

Configured libraries use the same structure. An adapter receives a JSON input
path, writes JSON to its `outputPath` or stdout, returns redacted trace-safe
output, and performs only the declared operation. It must not execute another
recipe graph.

The input path is argv 1 and `METAMASK_RECIPE_ADAPTER_INPUT`. Its document is:

```json
{
  "schemaVersion": 1,
  "platform": "mobile|extension|core",
  "action": "metamask.example.action",
  "node": {},
  "context": {
    "nodeId": "step-id",
    "projectRoot": "/path/to/checkout",
    "artifactsDir": "/path/to/run/artifacts"
  },
  "outputPath": "/temporary/output.json"
}
```

Write JSON to `outputPath` (also `METAMASK_RECIPE_ADAPTER_OUTPUT`) or stdout.
Write evidence under `context.artifactsDir` and return relative artifact paths.
`METAMASK_RECIPE_LIVE_ADAPTER_DIR` is the explicit task-local implementation
root; configured libraries are the durable sharing mechanism.

Add a bundled action only when it is reusable, typed, stable, reduces inference
or risk, and has a real postcondition. Otherwise use a team library or task-local
recipe. Follow [Recipes](RECIPES.md) and [Security](SECURITY.md).

## CLI contract

- Human mode is contextual, colored only in a TTY, and teaches one exact next
  action on failure.
- `--json` stdout is one stable document with no decoration.
- Long work acknowledges intent before blocking and streams child output.
- Lifecycle commands are checkout-scoped and idempotent.
- `doctor` is read-only; `doctor --fix` repairs without launching.
- No command may fabricate platform support or readiness.

When adding a command, register its behavior and human metadata, then add a
contract test. When a flag reaches a host leaf, both the typed composer and leaf
parser must accept it. Before renaming or removing a public flag, injected file,
or wrapper, verify real callers and retain compatibility only when one exists.

## Change gates

```bash
yarn test:unit
yarn test:coverage
yarn check
bash tests/contract/run.sh
```

Runtime changes also require real affected-platform QA and a packed installation
test. Update `CHANGELOG.md` under `Unreleased` for user-visible behavior.

Docs describe only current behavior. History belongs in the changelog and Git;
do not add handovers, audits, speculative roadmaps, or duplicate command guides
under `docs/`.
