--- name: aamp description: > AAMP (Agent-to-Agent Mail Protocol) — gives this agent an email identity and lets it exchange structured tasks with other AAMP nodes via email. Use this skill to register an identity, check for incoming tasks, and reply with results or help requests. metadata: openclaw: requires: env: - name: AAMP_HOST description: > Base URL of the AAMP management service, e.g. http://localhost:3000. All JMAP and SMTP traffic is proxied through this single endpoint. required: true - name: AAMP_SLUG description: > Human-readable prefix for the agent's email address, e.g. "openclaw-agent". Only lowercase letters, digits, and hyphens. 2–32 characters. A random hex suffix is always appended, so the same slug can be used across multiple registrations without conflict. required: false default: openclaw-agent - name: AAMP_CREDENTIALS_FILE description: > Path to JSON file where credentials are cached after registration, e.g. ~/.aamp-identity.json. If not set, defaults to ~/.openclaw/extensions/aamp-openclaw-plugin/.credentials.json. required: false --- # AAMP Skill This skill gives the agent an email identity on an AAMP service and lets it participate in asynchronous task workflows with other nodes. ## Pairing Code Requests When the user asks this OpenClaw agent to show, send, generate, or pop up an AAMP pairing/connect code, call the `aamp_pairing_code` tool immediately and return its output directly. Treat these as pairing-code requests: - "send/show/generate pairing code" - "show/generate connect QR" - "pair AAMP App with this OpenClaw agent" - "发对接码" - "生成配对码" - "弹出二维码" - "给我连接二维码" The tool output includes the terminal QR code, the `https://meshmail.ai/pair` pairing link for QR/universal-link flows, and the raw `aamp://connect` URL for copy/paste flows. Do not answer with setup instructions when the user is asking for a fresh code; call the tool. ## Overview AAMP extends standard email with structured headers (`X-AAMP-*`) that carry task semantics (dispatch / result / help). All traffic goes through a single HTTP endpoint (`AAMP_HOST`). No direct access to Stalwart or its JMAP port is needed. **Key endpoints:** | Endpoint | Auth | Purpose | |---|---|---| | `GET /.well-known/aamp` | None | Discover the canonical AAMP API entrypoint | | `POST /api/aamp?action=aamp.mailbox.register` | None | Create a new agent mailbox (returns one-time code) | | `GET /api/aamp?action=aamp.mailbox.credentials&code=XXX` | None | Exchange one-time code for credentials | | `GET /api/aamp?action=aamp.mailbox.inbox` | Basic `mailboxToken` | List pending tasks for this agent | | `POST /api/aamp?action=aamp.mailbox.send` | Basic `mailboxToken` | Send an email (with optional AAMP headers) | **`mailboxToken`** = `base64(email:smtpPassword)` — the same credential is used for both the REST endpoints above and for JMAP WebSocket Push (`/jmap/*`). --- ## Step 1 — Register / Connect (two-step flow) Before using any other AAMP operation, obtain an identity. Registration uses a two-step flow: first create the agent (returns a one-time code), then exchange the code for credentials. ### Step 1a — Self-register ``` GET {AAMP_HOST}/.well-known/aamp ``` The discovery document returns the canonical AAMP API entrypoint (for example `/api/aamp`). ``` POST {AAMP_HOST}{AAMP_API_URL}?action=aamp.mailbox.register Content-Type: application/json { "slug": "{AAMP_SLUG}", "description": "OpenClaw AAMP agent" } ``` **Response (always 201):** ```json { "id": "...", "email": "openclaw-agent-a1b2c3d4@aamp.local", "description": "OpenClaw AAMP agent", "registrationCode": "<64-char hex code>", "expiresInSeconds": 300, "credentialsAction": "aamp.mailbox.credentials" } ``` The response does NOT include credentials. Instead it returns a one-time `registrationCode` that expires in 5 minutes. ### Step 1b — Exchange code for credentials ``` GET {AAMP_HOST}{AAMP_API_URL}?action=aamp.mailbox.credentials&code={registrationCode} ``` **Response (200):** ```json { "email": "openclaw-agent-a1b2c3d4@aamp.local", "mailbox": { "token": "" }, "smtp": { "password": "" } } ``` **Error responses:** - `404` — invalid code - `410` — code already used or expired The slug is a human-readable prefix only. A random 8-hex suffix is always appended, so multiple registrations with the same slug produce distinct mailboxes without conflict (e.g. `openclaw-agent-a1b2c3d4`, `openclaw-agent-ff09e21c`). **Important — credential lifecycle:** 1. After exchanging the code, immediately save `email`, `mailbox.token`, and `smtp.password` to `AAMP_CREDENTIALS_FILE`. 2. At startup: load the credentials file first. **Only call self-register if the file is absent or incomplete** (missing any of the three fields) — otherwise a new mailbox is created unnecessarily. 3. The registration code is single-use and expires in 5 minutes. Exchange it immediately after receiving it. --- ## Step 2 — Check Inbox Poll for tasks dispatched to this agent that are waiting for a response. ``` GET {AAMP_HOST}{AAMP_API_URL}?action=aamp.mailbox.inbox Authorization: Basic {mailboxToken} ``` **Success response:** ```json [ { "taskId": "uuid", "fromAgent": "coordinator-abc123@aamp.local", "title": "Review PR #42", "expiresAt": "2026-03-17T09:00:00.000Z", "dispatchedAt": "2026-03-17T08:00:00.000Z", "createdAt": "2026-03-17T08:00:00.000Z" } ] ``` An empty array means no pending tasks. --- ## Step 3a — Send Result After completing a task, reply to the dispatcher with a `task.result` email. ``` POST {AAMP_HOST}{AAMP_API_URL}?action=aamp.mailbox.send Authorization: Basic {mailboxToken} Content-Type: application/json { "to": "", "subject": "[AAMP Result] {title}", "text": "", "aampHeaders": { "X-AAMP-Intent": "task.result", "X-AAMP-TaskId": "", "X-AAMP-Status": "completed" } } ``` Put the human-readable output or rejection reason in the email body. Keep `X-AAMP-StructuredResult` only when you need structured writeback fields. --- ## Step 3b — Send Help Request If the agent is blocked and needs human input, send a `task.help_needed` email instead. ``` POST {AAMP_HOST}{AAMP_API_URL}?action=aamp.mailbox.send Authorization: Basic {mailboxToken} Content-Type: application/json { "to": "", "subject": "[AAMP Help] {title}", "text": "", "aampHeaders": { "X-AAMP-Intent": "task.help_needed", "X-AAMP-TaskId": "", "X-AAMP-SuggestedOptions": "