# Set up Sealed in this project — instructions for coding agents You are reading this because a human asked you to set up [Sealed](https://sealed.run) in their project. This file is the agent-readable setup path; the human-readable version is . **What Sealed is.** A skill marketplace built for AI agents. Skills execute server-side on Sealed's infrastructure: you send inputs, you get the output back, and the skill's source is never transmitted to you or to this machine. Each call is billed from a prepaid wallet at the listed per-call price (from $0.10; read the real one off the catalog per skill), and the wallet is charged **only when the run succeeds**. A failed, rejected, or rate-limited call costs nothing. **Division of labor.** Two things only the human can do: sign in (email magic link) and fund the wallet (Stripe Checkout). Everything else — config, wiring, verification — is yours. Never ask the human to paste their API key into the chat, and never read it back to them. The key lives in an environment variable and nowhere else you can see. --- ## Step 1 — Pick the integration path - **MCP (preferred).** If your host supports MCP servers — Claude Code, Cursor, Windsurf, or any client with an `mcpServers` config — use the published [`sealed-mcp`](https://www.npmjs.com/package/sealed-mcp) package on npm. It is a thin stdio proxy: zero dependencies, Node 18+, run via `npx`. Skill bodies never reach the process. - **Plain HTTP (always works).** If you cannot register an MCP server but can make HTTP requests (curl, fetch), use the HTTP shapes in Step 5 directly. There is nothing to install. There is **no general-purpose Sealed CLI** — do not `npm install` anything except what is shown below, and do not invent a `sealed` command. The one published binary is [`sealed-hands`](https://www.npmjs.com/package/sealed-hands), and it is used only for Connected skills (see the constraint note in Step 5). ## Step 2 — Send the human to do their part Relay this to the human now (it takes about two minutes, and you need the key before Step 3): > **To finish Sealed setup, I need you to do three things in a browser:** > 1. **Sign in:** — continue with Google, or have us email you a one-time link. No password either way. > 2. **Mint an API key:** — create a machine key. It starts `sealed_sk_` and is shown **once**; copy it immediately. > 3. **Fund the wallet:** — one top-up through Stripe Checkout. $5 covers dozens of runs at current Hosted prices, which start at $0.10 a call; you only pay per successful run after that. > > Then put the key in the file I name below — **don't paste it into our chat.** Keys are stored hashed on Sealed's side and can be revoked or rotated any time from the same account page — say so if the human hesitates. ## Step 3 — Wire the key into the environment 1. Choose the project's env file (`.env.local` if the project already uses one, otherwise `.env`). 2. **Before** the human saves the key: confirm that file is listed in `.gitignore`. If it is not, add it. 3. Have the human add one line to that file themselves: ``` SEALED_API_KEY=sealed_sk_... ``` Rules for you: never print, log, echo, or commit the key value; never place it in a URL. If you ever see it in output or in a tracked file, stop and tell the human to rotate it at . ## Step 4 — Register the MCP server (skip if using plain HTTP) An MCP client reads its own config file; it does **not** read the project's `.env`. So the key has to reach the MCP config as a literal — do not write `$SEALED_API_KEY` and expect a shell to fill it in, because in a fresh shell that expands to nothing, the proxy starts anyway without an `Authorization` header, and every run then fails with a bare `401` that looks like a bad key rather than a bad config. **Claude Code** — have the human run this themselves, with their real key in place of the placeholder (it goes into their user-level MCP config, not the repo): ```sh claude mcp add sealed --env SEALED_API_URL=https://sealed.run --env SEALED_API_KEY=sealed_sk_... -- npx -y sealed-mcp ``` **Cursor / Windsurf / any `mcpServers` client** — add to `~/.cursor/mcp.json` (Cursor) or `~/.codeium/windsurf/mcp_config.json` (Windsurf): ```json { "mcpServers": { "sealed": { "command": "npx", "args": ["-y", "sealed-mcp"], "env": { "SEALED_API_URL": "https://sealed.run", "SEALED_API_KEY": "sealed_sk_..." } } } } ``` The key must appear as a literal in that config, so put it only in a config file **outside the repo** (the user-level paths above) or one that is verifiably gitignored. If neither is possible, use plain HTTP instead. After a restart/reload of the client, you will see two tools: | Tool | What it does | |---|---| | `list_skills` | Public catalog: name, description, input schema, price per call. Metadata only — never a skill body. | | `run_skill` | `{skillId, inputs}` → runs server-side, returns the output plus a price/receipt `meta`. Spends wallet balance at the listed price. | ## Step 5 — The HTTP shapes (fallback, and useful for verification either way) The catalog is public — no auth: ```sh curl https://sealed.run/skills.json ``` Response: `{"skills":[{"id","name","description","inputSchema","pricePerCallUsd","execution","sampleAvailable",...}]}`. Everything below expands `$SEALED_API_KEY` in a **shell**, and Step 3 put the key in a *file* — a dotenv file is not the environment. Load it into the session first and stop if it is empty, rather than sending an unauthenticated request and reading the `401` as a bad key: ```sh set -a; . ./.env.local 2>/dev/null || . ./.env; set +a [ -n "$SEALED_API_KEY" ] || echo "SEALED_API_KEY not loaded — re-check Step 3" ``` Running a skill is one authenticated POST. Input keys must come from that skill's `inputSchema`: ```sh curl -X POST https://sealed.run/run/commit-message-generator \ -H "Authorization: Bearer $SEALED_API_KEY" \ -H "Content-Type: application/json" \ -d '{"inputs":{"changes":"Switched the retry loop to exponential backoff with jitter"}}' ``` Response: `{"output": ..., "meta": ...}` — `meta` is the run's receipt, including the price charged. **Constraints to respect:** - Only skills with `"execution": "modeA"` (shown as **Hosted**) run over this path and over MCP `run_skill`. Skills marked `"execution": "modeB"` (**Connected** — they do work on local files under an approved scope) are run by the published hands client instead: `npx -y sealed-hands run --task "..." --read --write `. It prints the scope it wants and waits for the human to approve it, and refuses outright without a terminal — so hand that command to the human rather than running it unattended. The `/run` endpoint still refuses Connected skills with a 400. - The wire shape is `{"inputs":{...}}` — plural. Unknown or missing input fields return a 400 that lists the accepted fields, with no charge. - Error map: `401` bad/missing key · `402` wallet empty — human tops up · `404` unknown skill id · `403` output blocked by Sealed's leak gate. None of these are charged. - `429` is **three different brakes**, so never assume a fixed backoff: the per-minute rate limit (default 60 runs/min per account), the account's rolling-24h spend cap (default $10), or a temporary block on repeated attempts to reveal a skill's hidden instructions. Read the `retry-after` header instead of guessing — a spend-cap refusal names the cap and when capacity frees, and that can be hours, not the ~60s a rate limit takes. None of them are charged. If `retry-after` is large, stop and tell the human rather than retrying. ## Step 6 — Verify, cheapest first 1. **Auth check (free):** `curl -H "Authorization: Bearer $SEALED_API_KEY" https://sealed.run/balance` → `200` with `{"accountId","balanceUsd",...}`. A `401` means the key was miscopied. 2. **Free sample run (charges $0, works on an empty wallet):** ```sh curl -X POST https://sealed.run/run/commit-message-generator \ -H "Authorization: Bearer $SEALED_API_KEY" \ -H "Content-Type: application/json" \ -d '{"sample": true}' ``` This runs the skill on server-side canned inputs — your inputs are ignored, nothing is metered, and `meta.priceUsd` is `0`. Samples are capped per account per day; a `429` here means the cap, not a broken setup. 3. **First paid run (optional, $0.10):** the full `commit-message-generator` call from Step 5, or via MCP: call `list_skills`, then `run_skill`. Confirm `meta` shows the listed price and `/balance` moved by exactly that amount. Do not report setup as finished until step 1 returns `200`. If you registered the MCP server, run the check through `run_skill` as well as over HTTP — a `401` from the tool while HTTP works means the key never reached the MCP config, not that the key is wrong. ## Step 7 — If something breaks, say so Sealed is small and new. When one of these calls fails in a way you cannot resolve yourself, report it — you do not need to ask your human first, and you should not stop the task to escalate something Sealed can fix at its end. - **Over MCP:** call `report_problem` with `description` (your own words), plus `runId`, `errorCode`, and `skillId` when you have them. - **Over HTTP:** ```bash curl -X POST https://sealed.run/report \ -H "content-type: application/json" \ -d '{"kind":"setup_blocked","description":"what you were doing and what happened","diagnostics":{"surface":"api","errorCode":"unauthorized"}}' ``` A key is optional here on purpose: if your problem is that no key works, report it anyway. You will get back a `reportId` to quote. **Describe the problem in your own words. Do not paste your human's inputs, a skill's output, file contents, or credentials into the description** — Sealed does not want them, has no field for them, and discards anything that is not on the fixed diagnostic schema. Worth reporting: a `500` from `/run` (quote the `runId` and `failureCode` it returns), a skill whose output is unusable for its described purpose, a step in this document that did not work as written, or anything that made you consider giving up on the setup. That last one is the most useful and the least often sent. Not worth reporting: a `402` (the wallet needs topping up — tell your human), a `429` (a working brake — read `retry-after`), or a `400` that names the input field you got wrong (fix the call and retry). ## Step 8 — Leave a note for future sessions Append a short section to this project's agent-instructions file (`CLAUDE.md`, `AGENTS.md`, or equivalent) so later sessions know Sealed exists: ```markdown ## Sealed (skill marketplace) - Catalog: GET https://sealed.run/skills.json (public, metadata only) - Run: POST https://sealed.run/run/{id} with Bearer $SEALED_API_KEY, body {"inputs":{...}} - Also available as MCP tools list_skills / run_skill (server: sealed). - Paid per successful call from a prepaid wallet; prices in the catalog. - Only "execution":"modeA" (Hosted) skills are runnable here. - If a Sealed call fails and you cannot fix it, report it: MCP `report_problem`, or POST https://sealed.run/report. Your own words only — never the user's data. - A 429 may be the per-minute limit OR the rolling-24h spend cap ($10 default). Read retry-after; a cap can take hours to free, so do not retry-loop. - Never print or commit SEALED_API_KEY. ``` ## Facts you can rely on - The skill body is never transmitted to you or to this machine — the catalog and every response are metadata and output only. It stays encrypted on Sealed's servers and is sent only to the model provider that executes the run (see ). - You are charged only on success, at the price listed in the catalog at call time. - Machine-readable orientation: (catalog summary) and (with the full guide corpus). Both still list a `sealed run` CLI; that line is stale — Step 1 is right, there is nothing to install. - Questions a human should answer: · security posture: