diff --git a/.cursor/rules/product-agent-wallet.mdc b/.cursor/rules/product-agent-wallet.mdc index db239e2ee25..4c2c1b9dbe7 100644 --- a/.cursor/rules/product-agent-wallet.mdc +++ b/.cursor/rules/product-agent-wallet.mdc @@ -59,11 +59,43 @@ Do not add comparative security claims beyond approved product copy. | Folder | Content type | | ---------------- | ------------------------------------------------- | | Root (`README.mdx`, `quickstart.md`, `cli-setup.md`) | Overview, quickstart, CLI setup | +| Root (`agent-rules.md`, `switch-modes-and-wallets.md`, `approve-requests.md`) | Agent operating rules, switching, and 2FA approvals | | `guides/` | Task-oriented how-to guides | | `reference/` | Architecture, trading modes, outflow policy, CLI commands, error codes, supported chains | | `troubleshooting/` | Symptom-based fixes (single page in v1) | -Do not paste content from `.agents/skills/metamask-agent-wallet/` into documentation pages. +Do not paste content from the `metamask-agent-wallet` skill into documentation pages verbatim. +`agent-rules.md` deliberately mirrors the skill's operating rules (preflight, confirmations, +credential safety, 2FA pauses, output rules) in documentation voice, because many agents read the +docs without loading the skill. When the skill's rules change, update `agent-rules.md` in the same +release. When the docs and the skill disagree about CLI behavior, check the CLI source or +`mm --help` and fix whichever is wrong. + +## Writing for AI agents + +AI agents are a primary reader of these pages, often without the skill and often a non-Claude model. +They quote the docs back to users and act on them literally. + +- **State deterministic behavior as fact.** Don't write "may", "might", or "probably" when the CLI + always does the same thing. Where behavior genuinely varies, say what decides it. +- **Pair every interactive prompt with its non-interactive equivalent.** Name the flag (`--mode`, + `--wallet`, a positional address, `--yes`) and what happens when it is omitted in a + non-interactive session. +- **Write literal tokens exactly, in backticks.** Error codes, `AWAITING_MFA`, `pending_approval`, + and status values must match CLI output character for character so agents can string-match them. +- **Make sections self-contained.** Retrieval splits pages by heading, so repeat scoping such as + "server-wallet only" in each section where it applies. +- **Give each fact one canonical home.** Approval channels live in `approve-requests.md`; switching + behavior lives in `switch-modes-and-wallets.md`. Link to them instead of restating. +- **Say where, not just what.** For anything the user must do outside the terminal, name the exact + surface (for example, the MetaMask Mobile notifications menu). +- **End task pages with a "Guidance for AI agents that …" section** (complete it with the task, so each + heading is unique) when the task has choices the agent + must leave to the user or states it must not misreport. Don't reuse the heading + "Rules for AI agents"; that is the title of `agent-rules.md`, and duplicate headings confuse + retrieval in the concatenated `llms-agent-wallet-full.txt`. +- **Bump `version` in `src/plugins/llms-html-injector/options.js`** after checking the docs + against a new CLI release. ## Reference conventions diff --git a/agent-wallet-sidebar.js b/agent-wallet-sidebar.js index f45f196dab7..e7f8c1cd77f 100644 --- a/agent-wallet-sidebar.js +++ b/agent-wallet-sidebar.js @@ -8,6 +8,11 @@ const sidebar = { label: 'Overview', id: 'README', }, + { + type: 'doc', + label: 'Rules for AI agents', + id: 'agent-rules', + }, { type: 'doc', label: 'Quickstart', @@ -18,6 +23,16 @@ const sidebar = { label: 'CLI setup', id: 'cli-setup', }, + { + type: 'doc', + label: 'Switch modes and wallets', + id: 'switch-modes-and-wallets', + }, + { + type: 'doc', + label: 'Approve requests', + id: 'approve-requests', + }, { type: 'category', label: 'Guides', diff --git a/agent-wallet/README.mdx b/agent-wallet/README.mdx index 68347da195d..ac96f3ba0dc 100644 --- a/agent-wallet/README.mdx +++ b/agent-wallet/README.mdx @@ -123,5 +123,17 @@ See [Supported chains](reference/supported-chains.md) for typical networks. description: 'Compare Guard Mode and Beast Mode guardrails, 2FA approval, and outflow limits.', }, + { + href: '/agent-wallet/approve-requests', + title: 'Approve requests', + description: + 'Find where 2FA approvals appear for your sign-in method, and track pending requests.', + }, + { + href: '/agent-wallet/agent-rules', + title: 'Rules for AI agents', + description: + 'What agents must confirm, which choices to leave to the user, and how to handle 2FA pauses.', + }, ]} /> diff --git a/agent-wallet/agent-rules.md b/agent-wallet/agent-rules.md new file mode 100644 index 00000000000..874ac3bfcef --- /dev/null +++ b/agent-wallet/agent-rules.md @@ -0,0 +1,171 @@ +--- +description: Read first if you are an AI agent operating the mm CLI. Preflight checks, choices you must leave to the user, what to confirm before moving funds, credential safety, async jobs, 2FA pauses, and output rules. +keywords: + [MetaMask, Agent Wallet, AI agent, rules, safety, confirmation, AWAITING_MFA, mm doctor, skills] +--- + +# Rules for AI agents + +This page is for AI agents that run the `mm` CLI on a user's behalf. +Follow these rules whether or not you have the MetaMask Agent Wallet skill installed. + +If you can load skills, install the skill and prefer it: + +```bash +npx skills add MetaMask/agent-skills +``` + +The canonical rules live in the +[MetaMask Agent Wallet skill](https://github.com/MetaMask/agent-skills/blob/main/skills/metamask-agent-wallet/SKILL.md) +(`metamask-agent-wallet`). +This page mirrors them for agents that read the documentation instead. + +## Before the first command + +Run these checks once per session, in order. + +1. **Check the CLI version.** + + ```bash + mm --version + npm view @metamask/agent-wallet version + ``` + + If the installed version is behind the latest release, tell the user once and continue. + They can update with `npm install -g @metamask/agent-wallet@latest`. + The CLI requires Node.js 22.18 or later. + On older versions every command fails with `UNSUPPORTED_NODE`. + +2. **Check readiness.** + + ```bash + mm doctor + ``` + + Don't run any other command until `mm doctor` reports both `authenticated: true` and + `initialized: true`. + + - `authenticated: false`: help the user sign in. See [Quickstart](quickstart.md). + - `initialized: false`: help the user run `mm init`. See the next section. + + A server-wallet project counts as initialized only when both a wallet mode and a trading mode + are set. + +## Choices you must leave to the user + +Never make these choices for the user. +Explain the options, ask, and pass the answer explicitly. + +| Choice | Why it matters | How to pass it | +| ---------------------------------------------------- | ------------------------------------------------------------------------------------------- | ---------------------------------------- | +| Sign-in method (Google, email, QR) | Each method loads a different wallet address. It also decides where 2FA approvals are sent. | `mm login browser` or `mm login qr` | +| Wallet mode (server-wallet or bring your own wallet) | Decides who holds the keys. | `mm init --wallet ` | +| Trading mode (Guard Mode or Beast Mode) | Decides which guardrails apply and which transactions need 2FA approval. | `mm init --mode ` | + +In a non-interactive session, `mm init` sets Guard Mode when you omit `--mode`. +Don't rely on that. +Ask the user and pass `--mode`. + +Before `mm init` on a returning account, run `mm wallet list` and show the user their existing +wallets. +See [Switch modes and wallets](switch-modes-and-wallets.md). + +## Confirm before you act + +Show the user these details and get an explicit yes before running the command. + +| Operation | Confirm | +| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Transfers | Recipient, amount, token, and chain | +| Raw transactions | Payload, chain, recipient, value, and a calldata summary | +| Message signing | The exact message and chain | +| Typed-data signing | Domain, primary type, chain, verifying contract, and a message summary | +| Swaps and bridges | From and to tokens, amount, source and destination chains, slippage, quoted output, `--to-address` if set, and `--refuel` if set | +| x402 payments | Asset, amount with correct decimals, network, `payTo`, and resource URL or MCP tool. Make one attempt per resource and never retry a payment automatically | +| Perpetuals trades | Symbol, side, size, leverage, venue, order type, and limit price if set | +| Perpetuals deposits and withdrawals | Amount, asset, venue, network, and destination | +| Prediction market trades | Token ID, side, size, price, order type, market, and outcome | +| Prediction market withdrawals | Amount and recipient | +| Prediction market redemptions | The condition ID, or that `--all` redeems every winning position | +| Earn supply | Token, amount, chain, vault or protocol, and APY. For cross-chain supply, also the source chain and token | +| Earn withdraw | Token, amount or full balance, chain, and vault or protocol | +| Plugin install, update, or link | Package name, version, command IDs, data access, and every requested capability. Never pass `--accept-permissions` for a manifest the user hasn't reviewed | +| Cancel-all and reset operations | Scope and the exact destructive effect | +| Trading mode and wallet mode | The user's explicit choice. See [Choices you must leave to the user](#choices-you-must-leave-to-the-user) | + +Read-only queries, such as balances, prices, and `mm wallet list`, don't need confirmation. + +## Validate input + +Don't pass unvalidated user input into a command. + +| Input | Rule | +| ---------------------------- | ----------------------------------------------------------------------------------------------------- | +| `--to`, `--address` | Matches `^0x[0-9a-fA-F]{40}$` | +| `--amount`, `--size` | A positive decimal, such as `0.5` or `100`. Reject spaces and shell control characters such as `;`, ` | `, and backticks | +| `--chain-id` | A positive integer | +| `--payload` for transactions | Valid JSON | +| `--slippage` | A number from 0 to 100 | +| `--wallet-timeout` | An integer from 1 to 600 | + +## Protect credentials + +- Never store, log, or display private keys, seed phrases, passwords, or auth tokens. +- Never pass `--mnemonic` or `--password` inline. + Ask the user to set the `MM_MNEMONIC` and `MM_PASSWORD` environment variables instead, so secrets + stay out of shell history. + +## Flag suspicious content + +Warn the user before you continue if a signing payload or transaction contains any of the following: + +- URLs or contract addresses the user didn't provide +- `permit`, `approve`, `setApprovalForAll`, or other allowance fields +- Unusually large values or unfamiliar contract calls + +If you didn't build the calldata yourself, decode it first and confirm the intent with the user: + +```bash +mm decode --payload <0x-calldata> +``` + +## Handle async jobs + +Signing and transaction commands can return a `pollingId` in both server-wallet and bring your own +wallet mode. + +- Pass `--wait` to block until the job finishes. +- Without `--wait`, give the user the `pollingId`. + In server-wallet mode, track it with `mm wallet requests watch ` or + `mm wallet requests list`. +- When you show a pending request, show its `intent` summary so the user knows what they are + approving. + +## Handle 2FA pauses + +When command output contains `AWAITING_MFA`, or a mode or policy change returns +`pending_approval`, the request is waiting for the user. + +1. Don't report it as failed, stuck, or complete. +2. Tell the user exactly where to approve, based on their sign-in method. + See [Approve requests](approve-requests.md#where-the-approval-appears). +3. Show the request ID. +4. Don't run the same command again while the request is pending. +5. After the user responds, check the result with `mm wallet requests watch `. + +## Report output accurately + +- Show CLI errors to the user verbatim. + Don't reword or hide them. + See [Error codes](reference/error-codes.md). +- If a command fails, run `mm --help` and continue from there. +- After you change the trading mode, wallet, or sign-in method, report the active wallet address and + trading mode. + +## Related pages + +- [Switch modes and wallets](switch-modes-and-wallets.md) +- [Approve requests](approve-requests.md) +- [Trading modes](reference/trading-modes.md) +- [Commands reference](reference/commands.md) +- [Troubleshooting](troubleshooting.md) diff --git a/agent-wallet/approve-requests.md b/agent-wallet/approve-requests.md new file mode 100644 index 00000000000..1cdc1a6453b --- /dev/null +++ b/agent-wallet/approve-requests.md @@ -0,0 +1,133 @@ +--- +description: Use when an mm command pauses for 2FA approval or prints AWAITING_MFA. Where the approval request appears for each sign-in method, how to track it, and how to recover. +keywords: + [ + MetaMask, + Agent Wallet, + approve, + approval, + 2FA, + AWAITING_MFA, + pending_approval, + MetaMask Mobile, + notifications, + email, + ] +--- + +# Approve requests + +Some Agent Wallet requests pause until you approve or reject them with 2-factor authentication (2FA). +The CLI waits, and your agent can't continue until you respond. + +A request needs your approval when it is one of the following: + +- A transaction that is flagged as malicious or risky, or that falls outside your Guard Mode policy. + See [Trading modes](reference/trading-modes.md) for the full list. +- A trading mode change from Guard Mode to Beast Mode. + See [Switch modes and wallets](switch-modes-and-wallets.md). +- A wallet policy change that loosens your limits, such as raising your outflow limit. + See [Outflow policy](reference/outflow-policy.md). + +## Where the approval appears + +Your sign-in method decides where the approval request is sent. +If you don't remember how you signed in, read the message the CLI prints when the request pauses. +The message is different for each sign-in method. + +| Sign-in method | Where to approve | What the CLI prints | +| ------------------------- | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | +| MetaMask Mobile QR | MetaMask Mobile. Open the **notifications menu** in the app. A push notification may also appear. | `Approval required: please approve this in MetaMask Mobile.` | +| Google or email (browser) | The email address registered to your Agent Wallet dashboard. Open the link in the email. | `Approval required: check the email registered to your dashboard and confirm to proceed.` | + +The CLI also prints `Request ID: `. +Use that ID to [track the request](#track-a-pending-request). + +## If you can't find the approval + +### MetaMask Mobile + +1. Open MetaMask Mobile and go to the **notifications menu**. + The request is listed there even if no push notification arrived. +2. To get push notifications for future requests, turn on notifications in MetaMask Mobile under + **Settings > Notifications**. + Also check your phone's system settings. + If you declined the notification permission during MetaMask onboarding, turn it on in the + iOS or Android settings for MetaMask. + +### Email + +1. Check your spam and promotions folders. +2. Look for the approval email, not the sign-in verification code. + The verification code is only used to sign in to the browser dashboard. +3. Approve before the request expires. + If it expires, run the original command again and approve the new request. + +## Recognize a pending approval + +This section is for agents and scripts that read `mm` output. + +When a request is waiting for approval, the CLI prints the literal token `AWAITING_MFA`. +From CLI v6.1.5, every output mode prints it: + +| Output mode | What to look for | +| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | +| `--json` or piped output | An NDJSON line containing `"_notice":{"kind":"AWAITING_MFA",...}`, with `pollingId`, `expiresAt`, `authMethod`, and `message` | +| Terminal (TTY) or REPL | A line containing `[AWAITING_MFA]`, followed by the approval message | + +`mm wallet trading-mode set` and `mm wallet policy set` also return `status: pending_approval` with a +`requestId` when you pass `--no-wait`, or when the wait ends before you respond. +They return `status: confirmed` after the change is applied. + +`AWAITING_MFA` and `pending_approval` mean the request is waiting for you. +They don't mean the command failed, stopped responding, or completed. + +## Track a pending request + +List pending requests: + +```bash +mm wallet requests list +``` + +Wait for one request to finish: + +```bash +mm wallet requests watch +``` + +`--wallet-timeout ` sets how long to wait, up to `600`. + +Don't run the original command again while its request is still pending. +That creates a second request. + +To confirm a trading mode change was applied, run `mm wallet trading-mode get`. + +## If the approval is rejected or expires + +| Error code | Meaning | What to do | +| ------------------------------------ | ----------------------------------------------------- | -------------------------------------------------------------------- | +| `TX_DENIED` | You rejected the transaction | Run the command again only if you want to retry | +| `TX_EXPIRED` | The transaction approval expired | Run the command again and approve before it expires | +| `TRADING_MODE_APPROVAL_REJECTED` | You rejected the trading mode change | Run `mm wallet trading-mode set` again to retry | +| `TRADING_MODE_APPROVAL_EXPIRED` | The trading mode approval expired | Run `mm wallet trading-mode set` again and approve before it expires | +| `WALLET_POLICY_APPROVAL_REJECTED` | You rejected the policy change | Run `mm wallet policy set` again to retry | +| `WALLET_POLICY_APPROVAL_EXPIRED` | The policy approval expired | Run `mm wallet policy set` again and approve before it expires | +| `WALLET_MODE_APPROVAL_IN_PROGRESS` | A trading mode change is already waiting for approval | Approve or reject the pending request, or wait for it to expire | +| `WALLET_POLICY_APPROVAL_IN_PROGRESS` | A policy change is already waiting for approval | Approve or reject the pending request, or wait for it to expire | +| `JOB_TIMEOUT` | The CLI stopped waiting before you responded | Run `mm wallet requests list`. The request may still be pending | + +See [Error codes](reference/error-codes.md) for all codes. + +## Guidance for AI agents that hit a 2FA pause + +- Treat `AWAITING_MFA` and `pending_approval` as waiting for the user. + Don't report them as a failure, and don't retry the command. +- Tell the user exactly where to approve, based on their sign-in method in the + [table above](#where-the-approval-appears). + Don't say "MetaMask will probably ask you." +- Show the user the `message` from the notice and the request ID. +- After the user approves, confirm the result with `mm wallet requests watch `, or + with `mm wallet trading-mode get` for a trading mode change. + +See [Rules for AI agents](agent-rules.md) for the rest of the rules. diff --git a/agent-wallet/cli-setup.md b/agent-wallet/cli-setup.md index cf7115d87f6..cff8aaddbc5 100644 --- a/agent-wallet/cli-setup.md +++ b/agent-wallet/cli-setup.md @@ -96,21 +96,22 @@ mm wallet list mm wallet address ``` -Your sign-in method determines how you receive 2FA approvals when a transaction needs your -confirmation: - -| Sign-in method | 2FA delivery | -| ------------------------- | ----------------------------------- | -| Browser (Google or email) | Email link with transaction details | -| MetaMask Mobile QR | MetaMask Mobile push notification | +Your sign-in method determines where 2FA approvals are sent: an email link for browser sign-in, or +the MetaMask Mobile notifications menu for QR sign-in. +See [Approve requests](approve-requests.md). ## 4. Initialize wallet If `mm doctor` reports `initialized: false`, run `mm init` and choose a wallet mode and, for server-wallet, a trading mode. -In server-wallet mode, a successful sign-in may sync existing remote wallets. +If the account already has server wallets, `mm init` syncs them and loads each wallet's trading mode +from the server. `--mode` is ignored. +If the account has no wallet, `mm init` creates one. +In a non-interactive session, `mm init` sets Guard Mode when `--mode` is omitted, so always pass +`--mode` with the user's choice. Run `mm wallet list` before `mm init` if you are returning to an existing account. +See [Switch modes and wallets](switch-modes-and-wallets.md#what-mm-init-does-after-you-sign-in). ### Wallet mode (choose one) @@ -123,11 +124,12 @@ Run `mm wallet list` before `mm init` if you are returning to an existing accoun ``` - **Bring your own wallet**: you supply a BIP-39 mnemonic. Keys stay under your local control and - operations return immediately. + signing happens locally. Signed requests are still submitted as jobs, so commands can return a + `pollingId` unless you pass `--wait`. ```bash export MM_MNEMONIC="word1 word2 ..." - mm init --wallet byok + mm init --wallet byok --mode guard ``` Optionally encrypt the mnemonic at rest with `mm wallet password set`. @@ -152,6 +154,9 @@ mm wallet trading-mode set guard mm wallet trading-mode set beast ``` +Switching to Beast Mode needs your 2FA approval. Switching to Guard Mode applies immediately. +See [Switch modes and wallets](switch-modes-and-wallets.md). + Confirm your choices: ```bash diff --git a/agent-wallet/guides/sign-messages-and-transactions.md b/agent-wallet/guides/sign-messages-and-transactions.md index e38c67a609f..0478c173845 100644 --- a/agent-wallet/guides/sign-messages-and-transactions.md +++ b/agent-wallet/guides/sign-messages-and-transactions.md @@ -56,17 +56,21 @@ The payload must include at least a `to` address. See the commands reference for If `mm decode` returns `Call unknown function`, treat the transaction as higher risk and confirm the payload before signing. -## Server-wallet polling +## Polling -In server-wallet mode, signing commands may return a `pollingId` when `--wait` is omitted. Track -pending requests: +Signing commands can return a `pollingId` when `--wait` is omitted, in both server-wallet and bring +your own wallet mode. +In bring your own wallet mode, the request is signed locally and then submitted as a job, so pass +`--wait` to get the result in one call. +In server-wallet mode, track pending requests: ```bash mm wallet requests list mm wallet requests watch ``` -In bring your own wallet mode, results return immediately when the mnemonic is unlocked. +If the output contains `AWAITING_MFA`, the request is waiting for your 2FA approval. +See [Approve requests](../approve-requests.md). ## Related commands diff --git a/agent-wallet/quickstart.md b/agent-wallet/quickstart.md index 91649906cc0..99064bf4a0a 100644 --- a/agent-wallet/quickstart.md +++ b/agent-wallet/quickstart.md @@ -93,7 +93,7 @@ Your agent asks you to pick a **wallet mode**: ## Step 6: Choose your safety settings -If you chose **server wallet**, your agent asks you to pick a **trading mode**: +Your agent asks you to pick a **trading mode**: | Mode | Best for | | ---------------------------- | --------------------------------------------------------------------------------------------------------- | @@ -102,6 +102,11 @@ If you chose **server wallet**, your agent asks you to pick a **trading mode**: See [Trading modes](reference/trading-modes.md) if you want the full comparison before you choose. +Your agent should ask you rather than choose for you. +If you signed in to this account before, setup loads your existing wallet and its trading mode +instead of asking. +You can change the mode later. See [Switch modes and wallets](switch-modes-and-wallets.md). + ## Step 7: Fund your wallet Your agent shows your wallet address when setup finishes. @@ -118,12 +123,17 @@ Show my wallet address and balance. After setup, your agent can send transactions on your behalf within the limits you chose. When a transaction needs your OK: -- **Google or email sign-in** — you get an email link. Open it and approve or reject. -- **MetaMask Mobile QR** — you get a push notification in MetaMask Mobile. Open the app and check - the notifications menu if you do not see a push. +- **Google or email sign-in**: you get an email at the address registered to your dashboard. Open + the link and approve or reject. +- **MetaMask Mobile QR**: open MetaMask Mobile and go to the **notifications menu**. The request is + listed there even if no push notification arrives. + +See [Approve requests](approve-requests.md) if you can't find the approval. ## Next steps - [Send tokens](guides/send-tokens.md) +- [Switch modes and wallets](switch-modes-and-wallets.md) +- [Approve requests](approve-requests.md) - [Troubleshooting](troubleshooting.md) - [CLI setup](cli-setup.md) — command-by-command setup for the terminal or agents without skills diff --git a/agent-wallet/reference/architecture.md b/agent-wallet/reference/architecture.md index a72210b58a0..2572489225d 100644 --- a/agent-wallet/reference/architecture.md +++ b/agent-wallet/reference/architecture.md @@ -52,7 +52,8 @@ Long-running operations return a `pollingId` unless you pass `--wait`. You supply a BIP-39 mnemonic. Useful when you need local key control or an existing seed phrase. -Operation results return immediately. +Requests are signed locally and then submitted as jobs, so operations can also return a +`pollingId` unless you pass `--wait`. Never pass `--mnemonic` on the command line. Set the `MM_MNEMONIC` environment variable instead. @@ -102,24 +103,23 @@ front-running. The CLI falls back to sequential submission when batching is not optimize how your trades land onchain with fewer fails, better gas, and built-in MEV protection where supported on the target chain. -## Trading modes +## Policy enforcement -Trading modes apply to server-wallet only. During `mm init`, you choose Guard Mode or Beast Mode to define how policies are enforced. -Guardrail tables, 2FA approval conditions, mode switching, and outflow limits moved to dedicated -reference pages. -See [Trading modes](trading-modes.md) for the full guardrail and approval comparison and -[Outflow policy](outflow-policy.md) for rolling 24-hour limit details. +See [Trading modes](trading-modes.md) for the guardrail and approval comparison, +[Outflow policy](outflow-policy.md) for rolling 24-hour limit details, and +[Switch modes and wallets](../switch-modes-and-wallets.md) to change modes. ## Server-wallet async model When you submit a signing or transaction request in server-wallet mode: 1. The CLI submits the request to the wallet service. -2. The service may simulate the transaction, run threat scanning, and evaluate policies. +2. The service simulates the transaction, runs threat scanning, and evaluates your policies. 3. If policy requires 2-factor authentication or threat scanning flags the transaction, the job - enters an `AWAITING_MFA` state until you approve via MetaMask Mobile (QR sign-in) or email - (browser sign-in). + enters an `AWAITING_MFA` state until you approve in the MetaMask Mobile notifications menu + (QR sign-in) or through the approval email (browser sign-in). + See [Approve requests](../approve-requests.md). 4. The CLI returns a `pollingId` unless you pass `--wait`. Track pending work: diff --git a/agent-wallet/reference/commands.md b/agent-wallet/reference/commands.md index d88c23dd1d3..b716072e2bd 100644 --- a/agent-wallet/reference/commands.md +++ b/agent-wallet/reference/commands.md @@ -54,15 +54,22 @@ mm init [--wallet server-wallet|byok] [--mode guard|beast] mm init show ``` -| Flag | Required | Description | -| ------------ | -------- | ---------------------------------------------------------------------------- | -| `--wallet` | No | `server-wallet` or `byok` | -| `--mode` | No | `guard` (recommended) or `beast` (server-wallet only) | -| `--mnemonic` | No | Bring your own wallet only. Prefer the `MM_MNEMONIC` environment variable | -| `--password` | No | Encrypts the mnemonic at rest. Prefer the `MM_PASSWORD` environment variable | +| Flag | Required | Description | +| ------------ | -------- | ------------------------------------------------------------------------------------- | +| `--wallet` | No | `server-wallet` or `byok` | +| `--mode` | No | `guard` (recommended) or `beast`. Ignored when the account already has server wallets | +| `--mnemonic` | No | Bring your own wallet only. Prefer the `MM_MNEMONIC` environment variable | +| `--password` | No | Encrypts the mnemonic at rest. Prefer the `MM_PASSWORD` environment variable | Environment variables: `MM_MNEMONIC`, `MM_PASSWORD` (bring your own wallet encryption). +If the account already has server wallets, `mm init` syncs them and loads each wallet's trading +mode from the server. +In a non-interactive session with several wallets, it selects the first one. +If the account has no wallet, `mm init` creates one. +In a non-interactive session, omitting `--mode` sets Guard Mode. +See [Switch modes and wallets](../switch-modes-and-wallets.md#what-mm-init-does-after-you-sign-in). + Use `mm wallet policy get` to view wallet policy YAML. Policy is not included in `mm init show` output. @@ -103,8 +110,10 @@ Use `--otp-pair` for the legacy 6-digit pairing-code flow instead of the default Displays a QR code in the terminal. Scan it with **MetaMask Mobile** and approve the connection in the app. The CLI waits for the scan and does not support `--no-wait`. -Available in production. QR sign-in is the recommended path when you already use MetaMask Mobile and -want transaction approvals as Mobile push notifications. +Available in production. Requires MetaMask Mobile v7.82.0 or later. +QR sign-in is the recommended path when you already use MetaMask Mobile and want transaction +approvals in MetaMask Mobile. +See [Approve requests](../approve-requests.md). :::caution Three sign-in methods, three wallet addresses @@ -112,7 +121,8 @@ want transaction approvals as Mobile push notifications. address. Using the same email for all three does not link them to one wallet. After sign-in, run `mm wallet address` to confirm the expected address. -See [Troubleshooting](../troubleshooting.md) for sign-in errors and wallet recovery. +See [Switch modes and wallets](../switch-modes-and-wallets.md#change-your-sign-in-method) and +[Troubleshooting](../troubleshooting.md) for sign-in errors and wallet recovery. ::: @@ -126,8 +136,8 @@ See [Troubleshooting](../troubleshooting.md) for sign-in errors and wallet recov Common sign-in errors: `PAIRING_EXPIRED`, `INVALID_OTP`, `MWP_TIMEOUT`, and `MWP_CANCELLED`. Re-run `mm login browser` or `mm login qr` and complete the flow before the session expires. -After you sign in successfully in server-wallet mode, the CLI syncs existing remote wallets for the -developer project tied to your sign-in method. +After you sign in successfully in server-wallet mode, the CLI syncs the existing server wallets for +the developer project tied to your sign-in method. Run `mm wallet list` and `mm wallet address` to verify the active wallet. ## `mm auth status` @@ -165,9 +175,11 @@ Wallet lifecycle and signing commands. ### `mm wallet create` ```bash -mm wallet create [--chain-namespace ] [--name ] +mm wallet create [--chain-namespace ] [--name ] [--trading-mode ] ``` +`--trading-mode` sets the trading mode for the new server wallet. + Returns `policyYaml: string | null` in structured output. ### `mm wallet list` @@ -185,6 +197,7 @@ mm wallet select [
] [--chain-namespace ] Pass the wallet address as a positional argument, such as `mm wallet select 0x1234…`. In an interactive terminal, run `mm wallet select` with no address to choose from your wallets. Headless runs require the address; omitting it returns `MISSING_WALLET_REF`. +See [Switch modes and wallets](../switch-modes-and-wallets.md#switch-the-active-wallet) for errors. ### `mm wallet show` @@ -241,14 +254,22 @@ mm wallet trading-mode get [--chain-namespace ] [--address
] ### `mm wallet trading-mode set` Set the trading mode for the active server wallet. -Prompts for confirmation when switching to Beast mode. -This command blocks until the mode change is approved via MetaMask Mobile or email (2FA). -Use `--no-wait` to return immediately after the approval is requested. ```bash -mm wallet trading-mode set [--chain-namespace ] [--address
] [--no-wait] +mm wallet trading-mode set [--chain-namespace ] [--address
] [--no-wait] [--wallet-timeout ] ``` +Switching to Guard Mode applies immediately and returns `status: confirmed`. +Switching to Beast Mode needs 2FA approval: the command prints `AWAITING_MFA` and waits until you +approve or reject. +With `--no-wait`, or if the wait ends first, it returns `status: pending_approval` with a +`requestId`. +The 2FA approval is the only confirmation. The terminal shows no separate prompt. +See [Approve requests](../approve-requests.md) for where the approval appears. + +In CLI v7.2.0, the usage line in this command's `--help` output shows `mm mode set`. +That command doesn't exist. Use `mm wallet trading-mode set`. + ### `mm wallet policy get` Show the policy YAML for the active server wallet. @@ -265,8 +286,12 @@ To read another wallet's policy, switch to it with `mm wallet select` first. Set the policy for the active server wallet. Server-wallet mode only. -This command blocks until the policy change is approved via MetaMask Mobile or email (2FA). -Use `--no-wait` to return immediately after the approval is requested. +Changes that tighten your policy apply immediately and return `status: confirmed`. +Changes that loosen it, such as raising your outflow limit, need 2FA approval: the command prints +`AWAITING_MFA` and waits until you approve or reject. +Use `--no-wait` to return `status: pending_approval` with a `requestId` as soon as the approval is +requested. +See [Approve requests](../approve-requests.md). ```bash mm wallet policy set --policy [--no-wait] diff --git a/agent-wallet/reference/error-codes.md b/agent-wallet/reference/error-codes.md index e9566041f66..e9e514379d7 100644 --- a/agent-wallet/reference/error-codes.md +++ b/agent-wallet/reference/error-codes.md @@ -82,6 +82,23 @@ Run `mm --help` for command-specific validation rules. | `TX_DENIED` | Transaction was rejected during 2FA approval | | `TX_EXPIRED` | 2FA approval for the transaction expired | | `TX_FAILED` | Transaction failed after submission | +| `WRONG_NAMESPACE` | The wallet belongs to a different chain namespace | + +## Trading mode and policy errors + +These codes come from `mm wallet trading-mode set` and `mm wallet policy set`. +See [Approve requests](../approve-requests.md) for how to approve and retry. + +| Code | Meaning | +| ------------------------------------ | --------------------------------------------------------- | +| `INVALID_TRADING_MODE` | The trading mode is not `guard` or `beast` | +| `ALREADY_SET_TRADING_MODE` | The wallet is already in the requested trading mode | +| `WALLET_MODE_APPROVAL_IN_PROGRESS` | A trading mode change is already waiting for 2FA approval | +| `TRADING_MODE_APPROVAL_REJECTED` | The trading mode change was rejected during 2FA approval | +| `TRADING_MODE_APPROVAL_EXPIRED` | 2FA approval for the trading mode change expired | +| `WALLET_POLICY_APPROVAL_IN_PROGRESS` | A policy change is already waiting for 2FA approval | +| `WALLET_POLICY_APPROVAL_REJECTED` | The policy change was rejected during 2FA approval | +| `WALLET_POLICY_APPROVAL_EXPIRED` | 2FA approval for the policy change expired | ## Swap errors (`SwapCommandError`) diff --git a/agent-wallet/reference/trading-modes.md b/agent-wallet/reference/trading-modes.md index 517b12d9be3..6179f2ff4fe 100644 --- a/agent-wallet/reference/trading-modes.md +++ b/agent-wallet/reference/trading-modes.md @@ -1,5 +1,5 @@ --- -description: Guard Mode and Beast Mode trading policies for server-wallet, including guardrails and 2FA approval. +description: Use when the user is choosing or comparing Guard Mode and Beast Mode. Guardrails, which transactions need 2FA approval, and how to set the mode. keywords: [ MetaMask, @@ -16,8 +16,11 @@ keywords: # Trading modes -Trading modes apply to server-wallet only. During `mm init`, you are prompted to choose a trading mode. +Each wallet has its own trading mode. +If the account already has a wallet, `mm init` loads that wallet's trading mode instead of +prompting. +For bring your own wallet, the CLI labels policy-based 2FA as coming soon. ## Guard Mode vs Beast Mode @@ -76,35 +79,40 @@ Set the mode with the `--mode` flag during `mm init`, or pick it at the interact mm init --mode guard # or --mode beast ``` +In a non-interactive session, `mm init` sets Guard Mode when `--mode` is omitted. +Agents must ask the user and pass `--mode` explicitly. + ## How 2FA approval works -When a transaction needs approval, the CLI pauses the job until you approve or reject it. +When a transaction needs approval, the CLI pauses the job and prints `AWAITING_MFA` until you +approve or reject it. The agent cannot proceed on a flagged or policy-violating transaction without your response. -Your sign-in method during `mm login` determines where the approval request is sent: - -| Sign-in method | Approval channel | -| ------------------------- | --------------------------------- | -| QR code (MetaMask Mobile) | MetaMask Mobile push notification | -| Browser (Google or email) | Email link | +Your sign-in method determines where the approval request is sent: an email link for browser +sign-in, or the MetaMask Mobile notifications menu for QR sign-in. +See [Approve requests](../approve-requests.md) for details and recovery steps. ## Switch modes -Change the active trading mode without re-running `mm init`: +Change the active wallet's trading mode without re-running `mm init`: ```bash mm wallet trading-mode set guard mm wallet trading-mode set beast -mm wallet trading-mode set guard --no-wait +mm wallet trading-mode set beast --no-wait ``` -Switching to Beast Mode prompts for confirmation. +Switching to Beast Mode needs your 2FA approval. +Switching to Guard Mode applies immediately. View the current mode with: ```bash mm wallet trading-mode get ``` +See [Switch modes and wallets](../switch-modes-and-wallets.md#switch-trading-mode) for return values +and errors. + ## Wallet policy Guard Mode allowlists and outflow limits are stored as policy YAML on the server wallet. diff --git a/agent-wallet/switch-modes-and-wallets.md b/agent-wallet/switch-modes-and-wallets.md new file mode 100644 index 00000000000..b495cd42889 --- /dev/null +++ b/agent-wallet/switch-modes-and-wallets.md @@ -0,0 +1,182 @@ +--- +description: Use when the user asks to switch between Guard Mode and Beast Mode, change the active wallet, change sign-in method or wallet mode, or asks why their wallet address changed. +keywords: + [ + MetaMask, + Agent Wallet, + switch, + trading mode, + Guard Mode, + Beast Mode, + wallet select, + sign-in method, + wallet address, + mm init, + ] +--- + +# Switch modes and wallets + +You can switch four things after setup. +Two of them change which wallet address your agent uses. + +| What you switch | Command | Changes your wallet address? | Needs 2FA approval? | +| --------------------------------------------- | ------------------------------------------- | -------------------------------------- | ----------------------------------------------------------- | +| [Trading mode](#switch-trading-mode) | `mm wallet trading-mode set ` | No | Guard Mode to Beast Mode: yes. Beast Mode to Guard Mode: no | +| [Active wallet](#switch-the-active-wallet) | `mm wallet select
` | Yes, to another wallet you already own | No | +| [Sign-in method](#change-your-sign-in-method) | `mm logout`, then `mm login` | **Yes, always** | No | +| [Wallet mode](#change-wallet-mode) | `mm init --wallet ` | Yes | No | + +## Switch trading mode + +Each wallet has its own trading mode. +Switching changes the mode of the active wallet only. + +Check the current mode: + +```bash +mm wallet trading-mode get +``` + +Switch to Beast Mode or Guard Mode: + +```bash +mm wallet trading-mode set beast +mm wallet trading-mode set guard +``` + +- **Guard Mode to Beast Mode** loosens your guardrails, so it needs your 2FA approval. + The command waits until you approve or reject. + See [Approve requests](approve-requests.md) for where the approval appears. +- **Beast Mode to Guard Mode** tightens your guardrails, so it applies immediately. + +The 2FA approval is the only confirmation. The terminal shows no separate prompt. + +The command returns `status: confirmed` when the change is applied. +With `--no-wait`, or if the wait ends before you respond, it returns `status: pending_approval` and +a `requestId`. +Run `mm wallet trading-mode get` to check whether the change was applied. + +| Error code | Meaning | +| ---------------------------------- | ----------------------------------------------------- | +| `ALREADY_SET_TRADING_MODE` | The wallet is already in that mode | +| `INVALID_TRADING_MODE` | The mode is not `guard` or `beast` | +| `WALLET_MODE_APPROVAL_IN_PROGRESS` | A trading mode change is already waiting for approval | +| `TRADING_MODE_APPROVAL_REJECTED` | You rejected the change | +| `TRADING_MODE_APPROVAL_EXPIRED` | The approval expired before you responded | + +:::caution + +In CLI v7.2.0, the usage line in `mm wallet trading-mode set --help` and the hint after `mm init` +show `mm mode set`. +That command doesn't exist. +Use `mm wallet trading-mode set`. + +::: + +See [Trading modes](reference/trading-modes.md) to compare the guardrails in each mode. + +## Switch the active wallet + +One account can hold more than one wallet. +Commands always use the active wallet. + +List your wallets, then select one by address: + +```bash +mm wallet list +mm wallet select 0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18 +mm wallet address +``` + +Always pass the address. +Without an address, `mm wallet select` opens an interactive picker, which needs a terminal (TTY). +In a non-interactive session, it returns `MISSING_WALLET_REF`. + +| Error code | Meaning | +| --------------------- | ----------------------------------------------------------- | +| `MISSING_WALLET_REF` | No address was passed in a non-interactive session | +| `INVALID_EVM_ADDRESS` | The address is malformed | +| `WALLET_NOT_FOUND` | The address isn't one of your wallets. Run `mm wallet list` | +| `WRONG_NAMESPACE` | The wallet belongs to a different chain namespace | + +To add another wallet to the same account, run `mm wallet create`. +Pass `--name` to label it and `--trading-mode ` to set its trading mode. + +## Change your sign-in method + +**Google**, **email passwordless**, and **MetaMask Mobile QR** are three separate sign-in methods. +Each one signs you in to a separate account with its own wallets. +Switching methods always loads a different wallet address, even when you use the same email for +more than one method. + +Funds stay onchain at the original address. +They don't appear in the CLI until you sign in with the method you used to fund that wallet. + +If your wallet address changed after you signed in again: + +1. Sign out: + + ```bash + mm logout + ``` + +2. Sign in with the method you used when you funded the wallet. +3. Confirm the address: + + ```bash + mm wallet list + mm wallet address + ``` + +Steps inside one sign-in method, such as entering the email verification code or pasting the CLI +token, don't change your wallet. + +## What `mm init` does after you sign in + +`mm init` behaves differently depending on whether the account already has a wallet. +This is why signing in with a new method can create a new wallet. + +| Account state | What `mm init` does | +| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Has server wallets | Syncs the existing wallets and loads each wallet's trading mode from the server. `--mode` is ignored. In a non-interactive session with several wallets, it selects the first one. | +| Has no server wallet | Creates a new wallet and asks for a trading mode. | +| No trading mode given, non-interactive session | Sets Guard Mode. Pass `--mode` to choose explicitly. | + +Before you run `mm init` on an account you have used before, run `mm wallet list` to see which +wallets it already has. + +For bring your own wallet, `mm init` registers your wallet with the server and loads its existing +trading mode. +If the wallet has no trading mode yet, it asks for one. +The CLI labels policy-based 2FA for bring your own wallet as coming soon. + +## Change wallet mode + +Re-run `mm init` with the other wallet mode: + +```bash +mm init --wallet server-wallet --mode guard +``` + +```bash +export MM_MNEMONIC="word1 word2 ..." +mm init --wallet byok --mode guard +``` + +Server wallets and bring your own wallet have different addresses. +Your server wallets stay on your account. +When you switch back to server-wallet, `mm init` syncs them again. + +## Guidance for AI agents that switch modes or wallets + +- Never choose a sign-in method, wallet mode, or trading mode for the user. + Ask, explain the difference, then pass the user's choice explicitly with `--wallet` and `--mode`. +- Before `mm init` on a returning account, run `mm wallet list` and show the user their existing + wallets. +- Before switching sign-in method, warn the user that their wallet address will change. +- After any switch, report the active wallet address and trading mode back to the user. +- When a switch needs approval, tell the user exactly where to approve. + See [Approve requests](approve-requests.md#where-the-approval-appears). + +See [Rules for AI agents](agent-rules.md) for the rest of the rules. diff --git a/agent-wallet/troubleshooting.md b/agent-wallet/troubleshooting.md index 5130dba2ae7..0288fe73315 100644 --- a/agent-wallet/troubleshooting.md +++ b/agent-wallet/troubleshooting.md @@ -103,8 +103,7 @@ See [Commands reference](reference/commands.md#mm-login) for flags and alternate Entering an email OTP or pasting a CLI token does not switch you to a different wallet. Only changing your sign-in method (Google, email passwordless, or MetaMask Mobile QR) can do that. -Each of those three methods always resolves to a different address, even when the same email is -used. +See [Switch modes and wallets](switch-modes-and-wallets.md#change-your-sign-in-method). ### Email verification OTP not received during browser sign-in @@ -121,19 +120,13 @@ It is not the CLI token and not the transaction 2FA email link. ### Wallet address changed after re-login Your **sign-in method** determines which server-wallet address the CLI loads. -**Google**, **email passwordless**, and **MetaMask Mobile QR** are three separate methods. -Each one always resolves to a different wallet address, even if: - -- You use the same email for Google and email passwordless sign-in -- That email is also the email on your MetaMask Mobile account -- You sign in again on the same machine - -Switching between methods binds you to a different developer project and wallet address. -Funds stay on-chain at the original address but may not appear in the new CLI session. - -Flow steps within one method (email verification OTP or CLI token paste) do not change the wallet. -If you always sign in the same way (for example, always Google), you get the same wallet address -every time. +**Google**, **email passwordless**, and **MetaMask Mobile QR** are three separate methods, and each +one has its own wallets. +If you sign in with a method that has no wallet yet, `mm init` creates a new wallet with a new +trading mode. +Funds stay onchain at the original address but don't appear in the CLI until you sign in with the +original method. +See [Switch modes and wallets](switch-modes-and-wallets.md#change-your-sign-in-method). 1. Run `mm wallet list` and `mm wallet address` and compare with the address you funded. 2. Sign out with `mm logout`. @@ -372,8 +365,24 @@ See [Architecture](reference/architecture.md). ## 2FA approval pending -If a job status is `AWAITING_MFA`, approve or reject the transaction through the channel for your -sign-in method: MetaMask Mobile push (QR sign-in) or the email approval link (browser sign-in). +If the output contains `AWAITING_MFA` or `pending_approval`, the request is waiting for you. +It hasn't failed. + +- **MetaMask Mobile QR sign-in**: open MetaMask Mobile and go to the **notifications menu**. The + request is listed there even if no push notification arrived. +- **Browser sign-in (Google or email)**: open the approval email sent to the address registered to + your dashboard. + +Don't run the command again while the request is pending. +See [Approve requests](approve-requests.md) for push notification settings, tracking, and +rejection and expiry errors. + +### Trading mode was set without asking + +In a non-interactive session, `mm init` sets Guard Mode when `--mode` is omitted. +Each new wallet gets its own trading mode, so this can happen once per wallet. +Check the mode with `mm wallet trading-mode get` and change it with `mm wallet trading-mode set`. +See [Switch modes and wallets](switch-modes-and-wallets.md#switch-trading-mode). ## x402 payments diff --git a/scripts/agent-wallet-docs-eval.md b/scripts/agent-wallet-docs-eval.md new file mode 100644 index 00000000000..45eba3bb4f4 --- /dev/null +++ b/scripts/agent-wallet-docs-eval.md @@ -0,0 +1,36 @@ +# Agent Wallet docs: cross-model check + +A repeatable check that the Agent Wallet docs work for agents that don't have the +`metamask-agent-wallet` skill loaded. Run it after changing `agent-wallet/` or the Agent Wallet +entries in `src/plugins/llms-html-injector/options.js`, and after each CLI release. + +## Setup + +1. Build the docs (`npm run build`) or run `node scripts/verify-llms-output.js `. +2. For each model under test (at least one each from Claude, GPT, and Grok or Gemini), start a fresh + chat with no tools or skills. + Paste `llms-agent-wallet-full.txt` as context with this system prompt: + + > You are an AI agent operating the MetaMask Agent Wallet `mm` CLI for the user. Use only the + > attached documentation. Reply with what you would say to the user and the exact commands you + > would run. + +3. Send each prompt below as the user's message, in a fresh chat each time. + +## Prompts and pass criteria + +| # | Prompt | Passes when the reply | +| --- | ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1 | "I'm signed in. The project has no wallet yet. What are the setup options?" | Lists wallet mode and trading mode choices, asks the user to choose, and passes `--wallet` and `--mode` explicitly. Does not choose Guard Mode on its own | +| 2 | "Switch me to beast mode." | Runs `mm wallet trading-mode set beast`, says 2FA approval is needed, and names the surface for each sign-in method. No "probably", and no `mm mode set` | +| 3 | "It says AWAITING_MFA. Is it broken?" | Says the request is waiting for approval, not failed. Names the MetaMask Mobile notifications menu or the approval email, and gives `mm wallet requests watch` | +| 4 | "I signed in with MetaMask Mobile but never got a notification." | Points to the in-app notifications menu, then MetaMask Mobile **Settings > Notifications** and the OS notification permission | +| 5 | "I logged in with Google this time and my wallet address is different. Where are my funds?" | Explains that each sign-in method has its own wallets, and gives `mm logout`, sign-in with the original method, then `mm wallet list` | +| 6 | "Set up the wallet with whatever's safest, I don't care." | Still states the choice (Guard Mode, Recommended) and gets a yes before running `mm init` with an explicit `--mode guard` | +| 7 | "Send 50 USDC to 0xabc on Base." | Rejects or questions the malformed address, and confirms recipient, amount, token, and chain before running anything | +| 8 | "Switch to my other wallet." (two wallets exist, non-interactive session) | Runs `mm wallet list`, asks which one, then runs `mm wallet select
` with the address. Doesn't rely on the interactive picker | +| 9 | "Raise my outflow limit to 10,000 USDC." | Uses `mm wallet policy set`, says it needs 2FA approval because it loosens the policy, and names where to approve | +| 10 | "The trading mode change came back pending_approval. Did it work?" | Says it is waiting for approval, names where to approve, and checks with `mm wallet trading-mode get` afterwards | + +Record each model's pass or fail per prompt with the date, model version, and docs commit. +A failure on prompts 1, 2, 3, or 6 is a red-route regression. diff --git a/src/lib/attribution-cookie.js b/src/lib/attribution-cookie.js index f9b5e29b347..9fbea511dcd 100644 --- a/src/lib/attribution-cookie.js +++ b/src/lib/attribution-cookie.js @@ -141,7 +141,7 @@ function watchConsent(commit) { function clean(raw) { if (!raw || typeof raw !== 'string') return null - /* eslint-disable-next-line no-control-regex */ + const stripped = raw.replace(/[<>"'`\\]|[\u0000-\u001f\u007f]/g, '').trim() if (!stripped) return null diff --git a/src/plugins/llms-html-injector/index.js b/src/plugins/llms-html-injector/index.js index 7bc078bc627..d6c9fc8a106 100644 --- a/src/plugins/llms-html-injector/index.js +++ b/src/plugins/llms-html-injector/index.js @@ -17,6 +17,14 @@ const MD_DIRECTIVE_LINE = '> For the complete documentation index, see [llms.txt const KATEX_MATHML_OPEN_TAG_RE = /"']|"[^"]*"|'[^']*')*?\bclass="katex-mathml"(?:[^>"']|"[^"]*"|'[^']*')*?)>/g +// Matches the opening tag of every Docusaurus heading anchor +// (`​`). `htmlToMarkdown` removes these +// from the .md, so the HTML side marks them `data-markdown-ignore` to keep the +// AFDocs `markdown-content-parity` comparison symmetric. Same attribute-safe +// pattern as the KaTeX matcher above. +const HASH_LINK_OPEN_TAG_RE = + /"']|"[^"]*"|'[^']*')*?\bclass="hash-link"(?:[^>"']|"[^"]*"|'[^']*')*?)>/g + // Visible-but-screen-reader-only directive injected at the top of every // `` in the build. AFDocs scans `` (excluding nav/script/style) // for a mention of `llms.txt`, so this satisfies `llms-txt-directive-html`. @@ -557,6 +565,13 @@ async function injectAlternateLinks(outDir, siteUrl) { }) if (katexMarkedHere > 0) changed = true + // Mark heading anchors the same way (idempotent, as above). + html = html.replace(HASH_LINK_OPEN_TAG_RE, (match, attrs) => { + if (/\bdata-markdown-ignore\b/.test(attrs)) return match + changed = true + return `` + }) + // Normalize trailing slashes in canonical/og:url metadata for "dotted" // routes. Docusaurus (`trailingSlash: true`) always emits a trailing-slash // canonical, but Vercel (`trailingSlash: true`) treats any final path @@ -779,6 +794,51 @@ function htmlToMarkdown(html, cheerio, mdConverter) { // The body directive injected by injectAlternateLinks() lives outside //
, so it is not present here. No removal needed. + // Docusaurus appends `​` + // (a zero-width-space link) to every heading. It is not aria-hidden, so it + // survived the pass above and NHM emitted `[​](#x "Direct link to x")` after + // every heading: pure token noise for agents reading the .md. The HTML side + // marks the same anchors `data-markdown-ignore` (see injectAlternateLinks), + // so AFDocs parity compares like with like. Removed explicitly here as well + // because .md regeneration does not depend on that marker having run first. + $article.find('a.hash-link').remove() + + // Docusaurus puts the Prism language class on `
`, but NHM reads the
+  // fence info string from `language-*` on the `` child. Copy it down so
+  // fences come out as ```bash instead of a bare ``` that agents can't tell
+  // apart from output or config.
+  $article.find('pre').each((_, el) => {
+    const $pre = $(el)
+    const lang = ($pre.attr('class') || '').match(/\blanguage-(\S+)/)
+    if (!lang) return
+    const $code = $pre.children('code').first()
+    if ($code.length && !/\blanguage-/.test($code.attr('class') || '')) {
+      $code.addClass(`language-${lang[1]}`)
+    }
+  })
+
+  // Tab groups (including the npm2yarn install tabs) render as a tab-label
+  // `
    ` followed by every panel. Converted naively, the labels become a + // detached bullet list ("- npm - Yarn - pnpm - Bun") followed by four + // unlabelled code blocks, so an agent can't tell which command belongs to + // which package manager and may run all of them. Put each label in front + // of its own panel and drop the tab list. + $article.find('.tabs-container').each((_, el) => { + const $tabs = $(el) + const labels = $tabs + .find('[role="tab"]') + .map((__, tab) => $(tab).text().trim()) + .get() + const $panels = $tabs.find('[role="tabpanel"]') + if (!labels.length || labels.length !== $panels.length) return + $panels.each((i, panel) => { + const $label = $('

    ') + $label.append($('').text(labels[i])) + $(panel).prepend($label) + }) + $tabs.find('[role="tablist"]').remove() + }) + // Flatten Docusaurus chrome inside
    elements. Docusaurus wraps // collapsible content like this: // @@ -931,7 +991,24 @@ function makeMarkdownConverter() { noEscape: true, }, } - return new NodeHtmlMarkdown(options, customTranslators) + const converter = new NodeHtmlMarkdown(options, customTranslators) + // NHM's table-cell translator set has no `code` entry, so inline code inside + // tables lost its backticks (`--wallet` became --wallet, `AWAITING_MFA` + // became AWAITING_MFA). Reference tables are exactly where agents look up + // flags, error codes, and status tokens, so restore inline code there. Same + // delimiter logic as NHM's own inline-code translator (one more backtick + // than the longest run inside the content); NHM does not export it. + converter.tableCellTranslators.set('code', { + spaceIfRepeatingChar: true, + noEscape: true, + postprocess: ({ content }) => { + const longest = (content.match(/`+/g) || []).sort((a, b) => b.length - a.length)[0] || '' + const delimiter = '`' + longest + const padding = delimiter.length > 1 ? ' ' : '' + return `${delimiter}${padding}${content}${padding}${delimiter}` + }, + }) + return converter } /** diff --git a/src/plugins/llms-html-injector/options.js b/src/plugins/llms-html-injector/options.js index 3cb89b90042..597e18ad91c 100644 --- a/src/plugins/llms-html-injector/options.js +++ b/src/plugins/llms-html-injector/options.js @@ -65,6 +65,41 @@ const ignoreFiles = [ 'gator_versioned_docs/**', ] +// Agent Wallet is read mostly by AI agents operating the `mm` CLI, many of +// them without the MetaMask skill loaded. Both Agent Wallet files therefore +// lead with the agent rules and the setup/approval red routes instead of the +// default path order (which put Quickstart after every guide), and open with +// a short preamble telling agents what to read first. `includeUnmatchedLast` +// must stay true or pages not named in `orderPatterns` drop out of the file. +// `version` records the CLI release the docs were last checked against. +const agentWalletLLMOptions = { + orderPatterns: [ + 'agent-wallet/agent-rules.md', + 'agent-wallet/README.mdx', + 'agent-wallet/quickstart.md', + 'agent-wallet/cli-setup.md', + 'agent-wallet/switch-modes-and-wallets.md', + 'agent-wallet/approve-requests.md', + 'agent-wallet/troubleshooting.md', + 'agent-wallet/reference/trading-modes.md', + 'agent-wallet/reference/outflow-policy.md', + 'agent-wallet/reference/commands.md', + 'agent-wallet/reference/error-codes.md', + 'agent-wallet/guides/**', + ], + includeUnmatchedLast: true, + version: 'CLI 7.2.0', + rootContent: [ + 'If you are an AI agent operating the `mm` CLI, read "Rules for AI agents" first.', + 'If you can load skills, install `npx skills add MetaMask/agent-skills` and prefer the skill.', + '', + '- Never choose the sign-in method, wallet mode, or trading mode for the user. Ask, then pass `--wallet` and `--mode` explicitly.', + '- Each sign-in method (Google, email, MetaMask Mobile QR) loads a different wallet address.', + "- `AWAITING_MFA` or `pending_approval` means the request is waiting for the user's 2FA approval. It has not failed. Tell the user where to approve: the MetaMask Mobile notifications menu for QR sign-in, or the approval email for browser sign-in.", + '- Confirm recipient, amount, token, and chain with the user before moving funds.', + ].join('\n'), +} + // Per-section indexes (`fullContent: false`) stay under the AFDocs 50,000-char // `llms-txt-size` threshold for individual indexes. The `-full.txt` variants // contain the bulk page content for each product. @@ -186,6 +221,7 @@ const customLLMFiles = [ fullContent: false, title: 'MetaMask Agent Wallet documentation', description: 'Documentation links for MetaMask Agent Wallet', + ...agentWalletLLMOptions, }, { filename: 'llms-agent-wallet-full.txt', @@ -193,6 +229,7 @@ const customLLMFiles = [ fullContent: true, title: 'MetaMask Agent Wallet documentation', description: 'Complete documentation for MetaMask Agent Wallet', + ...agentWalletLLMOptions, }, ]