# Preference Gates — Contract

One file per key in this directory — `ls preference-gates/*.md` is the
authoritative key list. Skills load this contract + only the gates they
actually fire.

Default allowed values: `always` / `never` / `ask`. Per-key overrides are noted
in their own file: `defaultExecutionMode` (`local` / `remote` / `ask`),
`autoE2ETest` (`always` / `ask`), and `watcherLifetime` (`1d` / `7d` / `never`).

## Resolution

`SessionStart` injects a `Muggle Test Preferences` line (`key=value` pairs) from
`~/.muggle-ai/preferences.json`. Preferences are user-level — there is no
per-project layer. The line carries every key, already resolved against the
shipped defaults in `${CLAUDE_PLUGIN_ROOT}/config/preference-defaults.json`, so a
key is never absent.

## Gate behavior

- `always` → take the pro-action, then **always** print the silent footer.
- `never` → take the skip-action, then **always** print the silent footer.
- `ask` → run Picker 1 (per-key file) → Picker 2 (below).

`defaultExecutionMode` uses `local`/`remote` instead of `always`/`never`.

## Silent footer (mandatory whenever a prompt is skipped)

Whenever a gate resolves to a non-`ask` value and skips its picker, the footer
below is **required** — every gate, every time, no exceptions. It tells the
user **what happened**, **why it was silent**, and **how to change it**. The
`preference-gates-lint` test enforces that this contract exists; omitting the
footer when a gate fires is a bug. Two lines:

```
✓ <silent action from per-key file>
  (Skipped the prompt — `<key>` is set to `<value>`. Change: `/muggle-preferences <key>`.)
```

Concrete example (gate `autoLogin = always`):

```
✓ Continuing as foo@bar.com
  (Skipped the prompt — `autoLogin` is set to `always`. Change: `/muggle-preferences autoLogin`.)
```

## Picker 2 — shared template

Header `Remember this choice?`. Question: `"Always <restate Picker 1 choice in
plain language> from now on, without asking?"`. Never put the raw key or
`=` in the user-visible text.

- `Yes, always` (sub: `You can change this later in muggle preferences.`) → `muggle-local-preferences-set` with the value Picker 1 mapped to.
- `Just this once` (sub: `I'll ask again next time.`) → don't save.

A few keys override this template (their per-key file says how).

**Saved value MUST match the Picker 1 choice.** Saving the opposite of
what the user picked is a bug.

## `/muggle-preferences <key>` (re-prompt)

Run Picker 1 only, save immediately, skip Picker 2.
