Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# MetaMask Agent CLI Skills

SKILLs for the MetaMask Agent CLI (`@metamask/agentic-cli` v3.0.0). These skills enable AI agents to authenticate, manage wallets, swap tokens, bridge across chains, trade perpetual futures, and more using the MetaMask Agent CLI.
SKILLs for the MetaMask Agent CLI (`@metamask/agentic-cli` v4.0.0). These skills enable AI agents to authenticate, manage wallets, swap tokens, bridge across chains, trade perpetual futures, and more using the MetaMask Agent CLI.

## Skills

Expand Down
14 changes: 7 additions & 7 deletions skills/metamask-agent-wallet/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ description: Use when the user asks anything about blockchain wallets, transacti
license: MIT
metadata:
author: metamask
version: "4.1.0"
cliVersion: "3.0.0"
version: "5.0.0"
cliVersion: "4.0.0"
---

# MetaMask Agentic CLI Skill
Expand Down Expand Up @@ -155,7 +155,7 @@ Run these checks before the first CLI operation in a session, in order.

### 1. Version compatibility

This skill is written for `@metamask/agentic-cli` **v3.0.0** (see `cliVersion` in the frontmatter). Check the installed version:
This skill is written for `@metamask/agentic-cli` **v4.0.0** (see `cliVersion` in the frontmatter). Check the installed version:

```bash
mm --version
Expand All @@ -169,7 +169,7 @@ npm view @metamask/agentic-cli version

If the installed `major.minor` differs from the pinned `cliVersion`, or the installed version is behind the latest release, warn the user once and continue:

> Version mismatch: installed CLI `<installed>`, this skill is pinned to `3.0.0`, latest release is `<latest>`. Command syntax in this skill may be inaccurate until they are aligned. Update the CLI with `npm install -g @metamask/agentic-cli@latest`, then re-install the skills with `npx skills add metaMask/agent-skills`.
> Version mismatch: installed CLI `<installed>`, this skill is pinned to `4.0.0`, latest release is `<latest>`. Command syntax in this skill may be inaccurate until they are aligned. Update the CLI with `npm install -g @metamask/agentic-cli@latest`, then re-install the skills with `npx skills add metaMask/agent-skills`.

Run this check once per session. Do not block operations on it.

Expand Down Expand Up @@ -262,15 +262,15 @@ Flag to the user before proceeding if a signing payload or transaction contains:

When raw calldata is unfamiliar or was not constructed by you, run `mm decode --payload <0x-calldata>` first and confirm the decoded intent with the user before signing or sending. See [decode.md](references/decode.md).

## Server Wallet Async Model
## Async Model

In server-wallet mode, signing and transaction commands return a `pollingId` instead of an immediate result. Handle this consistently:
In both server-wallet and BYOK mode, signing and transaction commands go through a job-polling loop and return a `pollingId`. Handle this consistently:

1. Prefer `--wait` to block until complete.
2. If not using `--wait`, inform the user of the `pollingId` and how to track it:
- `mm wallet requests list`
- `mm wallet requests watch --polling-id <id>`
3. In BYOK mode, results are returned immediately. If the mnemonic is password-encrypted, the user must set `MM_PASSWORD` environment variable to unlock it for the operation.
3. In BYOK mode, the local key signs locally but the operation still produces a pending job and a `pollingId`. If the mnemonic is password-encrypted, the user must set `MM_PASSWORD` environment variable to unlock it for the operation.

Transfers, swaps, perps, predict orders, and predict withdraws attach a human-readable `intent` summary to their wallet request (e.g. `Transfer 0.5 ETH to 0x...`, `Withdraw 10 pUSD to 0x...`). When surfacing a pending request from `wallet requests list` or `wallet requests watch`, show the `intent` summary so the user can confirm what they are approving.

Expand Down
31 changes: 19 additions & 12 deletions skills/metamask-agent-wallet/references/auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ mm init [--wallet <mode>] [--mode <mode>] [--mnemonic <phrase>] [--password <pas
| Name | Required | Description |
| --- | --- | --- |
| `--wallet` | No | Wallet mode: `server-wallet` or `byok` |
| `--mode` | No | Trading mode: `guard` or `beast` (server-wallet only) |
| `--mode` | No | Trading mode: `guard` or `beast` |
| `--mnemonic` | No | BIP-39 mnemonic phrase for BYOK wallet. Never pass inline. Set `MM_MNEMONIC` env var instead. |
| `--password` | No | Password to encrypt the BYOK mnemonic at rest. Never pass inline. Set `MM_PASSWORD` env var instead. If omitted in interactive mode, the CLI prompts. If omitted in non-interactive mode, mnemonic is stored unencrypted. |

Expand All @@ -27,16 +27,17 @@ mm init [--wallet <mode>] [--mode <mode>] [--mnemonic <phrase>] [--password <pas
mm init
mm init --wallet server-wallet --mode beast
export MM_MNEMONIC="word1 word2 ..."
mm init --wallet byok
mm init --wallet byok --mode guard

export MM_MNEMONIC="word1 word2 ..."
export MM_PASSWORD="mypassword"
mm init --wallet byok
mm init --wallet byok --mode guard
```

### Note

- In server-wallet mode, if the account already has a remote EVM wallet, `mm init` syncs it and loads the existing trading mode instead of prompting for a new trading mode or creating a wallet. Use `mm wallet policy get` to view the wallet policy.
- In BYOK mode, `mm init` registers the wallet server-side and prompts for trading mode (`guard` or `beast`). If a trading mode is already set server-side, it is loaded without prompting. The `--mode` flag skips the prompt in non-interactive/scripted use.

## `init show` Command

Expand Down Expand Up @@ -86,7 +87,7 @@ mm login --token "cliToken:cliRefreshToken"
### Note

- If already authenticated, the CLI returns `ALREADY_AUTHENTICATED`. Run `mm logout` first, then log in again.
- `mm login qr` (scan with MetaMask Mobile) is available on non-production builds (dev/uat). On production it returns `COMING_SOON`; use browser sign-in instead.
- `mm login qr` (scan with MetaMask Mobile) is available on all environments, including production.
- Pairing codes tolerate `-` and whitespace separators (e.g. `608-225` is equivalent to `608225`).
- Use `mm login browser --no-wait` for non-interactive/CI flows. The command prints a sign-in URL; the user completes login in the browser (Google or Email). Bare `mm login --no-wait` fails without a TTY because no method is selected.
- `--no-wait` is not supported with QR login. Complete authentication later with `mm login --token`.
Expand Down Expand Up @@ -115,22 +116,25 @@ mm auth status --toon

## `logout` Command

Sign out and clear auth credentials plus local init state, wallet selection, and stored BYOK mnemonic.
Sign out and clear auth credentials plus local init state, wallet selection, and stored BYOK mnemonic. Prompts for confirmation before signing out.

### Syntax

```bash
mm logout
mm logout [--yes]
```

### Supported Flags

This command does not support flags.
| Name | Required | Description |
| --- | --- | --- |
| `--yes` | No | Skip the confirmation prompt (for non-interactive/scripted use) |

### Example

```bash
mm logout
mm logout --yes
```

## `config get` Command
Expand Down Expand Up @@ -204,22 +208,25 @@ mm config set format toon

## `reset` Command

Clear the local CLI session entirely, including auth credentials, wallet state, mnemonic, swap quotes, and persisted config.
Clear the local CLI session entirely, including auth credentials, wallet state, mnemonic, swap quotes, and persisted config. Prompts for confirmation before resetting.

### Syntax

```bash
mm reset
mm reset [--yes]
```

### Supported Flags

This command does not support flags.
| Name | Required | Description |
| --- | --- | --- |
| `--yes` | No | Skip the confirmation prompt (for non-interactive/scripted use) |

### Example

```bash
mm reset
mm reset --yes
```

## `wallet password set` Command
Expand Down Expand Up @@ -296,5 +303,5 @@ mm wallet password remove --current "mypassword"

| Mode | Behavior |
| --- | --- |
| `server-wallet` | Keys hosted by MetaMask infrastructure. Signing and transaction operations may return async job handles. |
| `byok` | Bring your own local mnemonic. Operation results are returned immediately. If the mnemonic is encrypted with a password, the CLI requires `--password` or interactive prompt to unlock before any operation that needs the private key. |
| `server-wallet` | Keys hosted by MetaMask infrastructure. Signing and transaction operations return async job handles with a `pollingId`. |
| `byok` | Bring your own local mnemonic. Keys are held locally and signing is done on-device, but operations still go through a job-polling loop and return a `pollingId`. If the mnemonic is encrypted with a password, the CLI requires `MM_PASSWORD` to unlock before any operation that needs the private key. |
2 changes: 1 addition & 1 deletion skills/metamask-agent-wallet/references/wallet.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mm wallet create [--chain-namespace <namespace>] [--name <name>] [--trading-mode
| --- | --- | --- |
| `--chain-namespace` | No | Wallet chain namespace: `evm` (EIP-155) (allowed: `evm`) |
| `--name` | No | Display name for the wallet |
| `--trading-mode` | No | `guard` enforces outflow/whitelist policies and blocks malicious transactions. `beast` skips policy checks but still blocks malicious transactions. Only applies to server-wallet mode (allowed: `guard`, `beast`) |
| `--trading-mode` | No | `guard` enforces outflow/whitelist policies and blocks malicious transactions. `beast` skips policy checks but still blocks malicious transactions (allowed: `guard`, `beast`) |
| `--password` | No | Password to unlock the BYOK mnemonic (BYOK mode only) [env: `MM_PASSWORD`] |

### Example
Expand Down
22 changes: 12 additions & 10 deletions skills/metamask-agent-wallet/workflows/aave-borrow.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@ Use this workflow to borrow assets from Aave V3 against supplied collateral.

## Resolve chain and addresses

If the user doesn't specify a chain, ask. Look up the pool address:

| Chain | Chain ID | Pool address |
| --- | --- | --- |
| Ethereum | 1 | `0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2` |
| Polygon | 137 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Arbitrum | 42161 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Optimism | 10 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Avalanche | 43114 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Base | 8453 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
If the user doesn't specify a chain, ask. Fetch the available markets for the chain from the Aave API to get pool addresses:

```bash
curl -s -X POST https://api.v3.aave.com/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"{ markets(request: { chainIds: [<CHAIN_ID>] }) { address reserves { underlyingToken { symbol } } } }"}'
```

Each entry in the response is a separate Aave V3 market. Extract `address` from each — this is the pool contract address.

- If one market is returned, use its `address` as `<POOL_ADDRESS>`.
- If multiple markets are returned, present them to the user (showing the `address` and up to 5 representative token symbols from `reserves[].underlyingToken.symbol`) and ask which market they want to interact with.

## Check collateral

Expand Down
22 changes: 12 additions & 10 deletions skills/metamask-agent-wallet/workflows/aave-collateral.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@ Use this workflow to enable or disable an asset as collateral on Aave V3.

## Resolve chain and addresses

If the user doesn't specify a chain, ask. Look up the pool address:

| Chain | Chain ID | Pool address |
| --- | --- | --- |
| Ethereum | 1 | `0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2` |
| Polygon | 137 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Arbitrum | 42161 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Optimism | 10 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Avalanche | 43114 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Base | 8453 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
If the user doesn't specify a chain, ask. Fetch the available markets for the chain from the Aave API to get pool addresses:

```bash
curl -s -X POST https://api.v3.aave.com/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"{ markets(request: { chainIds: [<CHAIN_ID>] }) { address reserves { underlyingToken { symbol } } } }"}'
```

Each entry in the response is a separate Aave V3 market. Extract `address` from each — this is the pool contract address.

- If one market is returned, use its `address` as `<POOL_ADDRESS>`.
- If multiple markets are returned, present them to the user (showing the `address` and up to 5 representative token symbols from `reserves[].underlyingToken.symbol`) and ask which market they want to interact with.

## Check status

Expand Down
17 changes: 5 additions & 12 deletions skills/metamask-agent-wallet/workflows/aave-markets.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,23 @@ Use this workflow to discover available Aave V3 tokens, supply/borrow rates, and

## Resolve chain

If the user doesn't specify a chain, ask. Aave V3 is deployed on these chains:

| Chain | Chain ID |
| --- | --- |
| Ethereum | 1 |
| Polygon | 137 |
| Arbitrum | 42161 |
| Optimism | 10 |
| Avalanche | 43114 |
| Base | 8453 |
If the user doesn't specify a chain, ask.

## Query available markets

```bash
curl -s -X POST https://api.v3.aave.com/graphql \
-H 'Content-Type: application/json' \
-d '{
"query": "{ markets(request: { chainIds: [<CHAIN_ID>] }) { reserves { underlyingToken { symbol decimals } supplyInfo { apy { formatted } } borrowInfo { apy { formatted } availableLiquidity { amount { value } usd } borrowCapReached } isFrozen isPaused } } }"
"query": "{ markets(request: { chainIds: [<CHAIN_ID>] }) { address reserves { underlyingToken { symbol decimals } supplyInfo { apy { formatted } } borrowInfo { apy { formatted } availableLiquidity { amount { value } usd } borrowCapReached } isFrozen isPaused } } }"
}'
```

The response returns one entry per market. Each entry has an `address` (the pool contract address) and a `reserves` array.

## Present results

Filter out reserves where `isFrozen` or `isPaused` is `true`. For each active reserve, show:
Group reserves by market `address`. Within each market, filter out reserves where `isFrozen` or `isPaused` is `true`. For each active reserve, show:

- Token symbol and decimals (`underlyingToken.symbol`, `underlyingToken.decimals`)
- Supply APY (`supplyInfo.apy.formatted`)
Expand Down
23 changes: 11 additions & 12 deletions skills/metamask-agent-wallet/workflows/aave-positions.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,29 @@ Get the wallet address:
mm wallet address
```

If the user doesn't specify a chain, ask. Aave V3 is deployed on these chains:
If the user doesn't specify a chain, ask. Fetch all markets for the chain to get pool addresses:

| Chain | Chain ID | Pool address |
| --- | --- | --- |
| Ethereum | 1 | `0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2` |
| Polygon | 137 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Arbitrum | 42161 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Optimism | 10 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Avalanche | 43114 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Base | 8453 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
```bash
curl -s -X POST https://api.v3.aave.com/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"{ markets(request: { chainIds: [<CHAIN_ID>] }) { address } }"}'
```

Collect all returned `address` values as `<POOL_ADDRESSES>`.

## Query positions

Query supply and borrow positions in a single request:
Query supply and borrow positions across all markets in a single request. Build the `markets` array from all addresses returned above:

```bash
curl -s -X POST https://api.v3.aave.com/graphql \
-H 'Content-Type: application/json' \
-d '{
"query": "{ userSupplies(request: { markets: [{ address: \"<POOL_ADDRESS>\", chainId: <CHAIN_ID> }], user: \"<WALLET_ADDRESS>\" }) { currency { symbol decimals } balance { amount { value } usd } apy { formatted } isCollateral } userBorrows(request: { markets: [{ address: \"<POOL_ADDRESS>\", chainId: <CHAIN_ID> }], user: \"<WALLET_ADDRESS>\" }) { currency { symbol decimals } debt { amount { value } usd } apy { formatted } } }"
"query": "{ userSupplies(request: { markets: [{ address: \"<POOL_ADDRESS_1>\", chainId: <CHAIN_ID> }, { address: \"<POOL_ADDRESS_2>\", chainId: <CHAIN_ID> }], user: \"<WALLET_ADDRESS>\" }) { currency { symbol decimals } balance { amount { value } usd } apy { formatted } isCollateral marketAddress } userBorrows(request: { markets: [{ address: \"<POOL_ADDRESS_1>\", chainId: <CHAIN_ID> }, { address: \"<POOL_ADDRESS_2>\", chainId: <CHAIN_ID> }], user: \"<WALLET_ADDRESS>\" }) { currency { symbol decimals } debt { amount { value } usd } apy { formatted } marketAddress } }"
}'
```

The response contains both `userSupplies` and `userBorrows` arrays.
Include one `{ address, chainId }` entry per market returned by the previous query. The response contains both `userSupplies` and `userBorrows` arrays spanning all markets.

## Health factor preview

Expand Down
22 changes: 12 additions & 10 deletions skills/metamask-agent-wallet/workflows/aave-repay.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@ Use this workflow to repay borrowed assets on Aave V3.

## Resolve chain and addresses

If the user doesn't specify a chain, ask. Look up the pool address:

| Chain | Chain ID | Pool address |
| --- | --- | --- |
| Ethereum | 1 | `0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2` |
| Polygon | 137 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Arbitrum | 42161 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Optimism | 10 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Avalanche | 43114 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Base | 8453 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
If the user doesn't specify a chain, ask. Fetch the available markets for the chain from the Aave API to get pool addresses:

```bash
curl -s -X POST https://api.v3.aave.com/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"{ markets(request: { chainIds: [<CHAIN_ID>] }) { address reserves { underlyingToken { symbol } } } }"}'
```

Each entry in the response is a separate Aave V3 market. Extract `address` from each — this is the pool contract address.

- If one market is returned, use its `address` as `<POOL_ADDRESS>`.
- If multiple markets are returned, present them to the user (showing the `address` and up to 5 representative token symbols from `reserves[].underlyingToken.symbol`) and ask which market they want to interact with.

## Check debt

Expand Down
22 changes: 12 additions & 10 deletions skills/metamask-agent-wallet/workflows/aave-supply.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@ Use this workflow to supply (deposit) assets into Aave V3 and earn interest.

## Resolve chain and addresses

If the user doesn't specify a chain, ask. Look up the pool address:

| Chain | Chain ID | Pool address |
| --- | --- | --- |
| Ethereum | 1 | `0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2` |
| Polygon | 137 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Arbitrum | 42161 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Optimism | 10 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Avalanche | 43114 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
| Base | 8453 | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` |
If the user doesn't specify a chain, ask. Fetch the available markets for the chain from the Aave API to get pool addresses:

```bash
curl -s -X POST https://api.v3.aave.com/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"{ markets(request: { chainIds: [<CHAIN_ID>] }) { address reserves { underlyingToken { symbol } } } }"}'
```

Each entry in the response is a separate Aave V3 market. Extract `address` from each — this is the pool contract address.

- If one market is returned, use its `address` as `<POOL_ADDRESS>`.
- If multiple markets are returned, present them to the user (showing the `address` and up to 5 representative token symbols from `reserves[].underlyingToken.symbol`) and ask which market they want to interact with.

Resolve the asset's contract address on the target chain. If the user provides a symbol instead of an address, run `mm token list search --query <SYMBOL> --chain <CHAIN_ID>`.

Expand Down
Loading