For agents: sign in and deploy
How a coding agent signs in to wirl, deploys a first app, and what to do when wirl refuses a request.
An agent cannot create a wirl account: sign-in is Google, the company's Google Workspace domain is the organisation, and a person approves every agent in the browser.
Commands here run as written, except a word in <angle brackets>: replace it, with the app's name for <your-app>, the address the person gave you for <their-email> (never one you made up), and so on. npx fetches the CLI from npm the first time and needs Node 22.13 or later (in a terminal, npm first asks "Ok to proceed? (y)": answer y).
1. Check#
Run npx wirl whoami, or call wirl_whoami over MCP. Signed in, it prints scope: full or scope: deploy and one line for each organisation you belong to: go to step 4. Signed out, the CLI says "Not signed in.": go to step 2. To see which account, run npx wirl whoami --json: it adds email. If that is the wrong person, have the right one approve a new npx wirl login; a WIRL_TOKEN in the environment wins over the saved sign-in until it is unset.
The hosted MCP server and the CLI sign in separately. The hosted wirl_deploy and wirl_preview hand back a command for the CLI to run, so check the CLI too before you deploy. The local MCP server (npx -y @wirl/mcp) uses the CLI's sign-in.
2. Sign in#
Sign in the way that fits where you run. Never print, paste or save a token anywhere: not in a message, a file or a log. The CLI keeps its sign-in in ~/.config/wirl/credentials.json; leave that file alone. A hosted MCP sign-in does not sign in the CLI, so deploying through it needs npx wirl login too.
- Claude Code. Run
claude mcp add --transport http wirl https://app.wirl.dev/mcp.claude mcp addonly saves the server's configuration. Then sign in: run/mcpinside Claude Code and follow the steps in the browser, or runclaude mcp login wirlin a terminal. If you will need to share, ask the person to tick the full-access box on the consent page (step 3). - Any shell.
npx wirl loginprints a link and a code for the person to approve in their browser: show them both. It then waits for the approval and saves the sign-in; the code expires after 10 minutes. Run it where you can read its first lines while it waits (in the background, if your shell tool returns only when a command ends). If you will need to share, ask the person to tick full access on the approval page (step 3). - CI. The person creates a token on the Connect an agent page, https://app.wirl.dev/settings/tokens, and puts it in the job's secrets as
WIRL_TOKEN; it is shown once, and no token can make another. AWIRL_TOKENin the environment is used before the saved sign-in.
3. Access#
The person decides how much an agent may do. npx wirl login gives build-and-update access unless the person ticks full access on the approval page. On the MCP consent page the box "Also give it full access" is that choice: the person ticks it or leaves it. A token made for CI has deploy access unless the person picks "can do everything".
- Deploy access deploys, previews, reads logs, rolls back and pulls.
- Full access also shares an app, changes who can open it, deletes, restores, moves or transfers it, manages connections and members, creates organisations and revokes tokens.
- No token makes an app public: a person does that on the app's Access page.
With deploy access, a request that needs full access is refused with a 403 whose sentence names the page where the person does it: show them that page.
4. First app#
Before you write the app, read The contract: the module's shape, env.DB, migrations written one statement a line, and who is asking. When the folder's name is not the app's, npx wirl init <folder> --server --app <your-app> names the app.
| Step | CLI | MCP tool |
|---|---|---|
| Start a folder | npx wirl init <your-app> --server, then cd <your-app> |
none: it writes files on this machine |
| Try it here | npx wirl dev |
none |
| Preview it: never live, its own address and database | npx wirl preview |
wirl_preview |
| See what the preview answers | npx wirl fetch / --preview <preview-name> |
wirl_preview_fetch |
| Deploy it | npx wirl deploy |
wirl_deploy |
| Share it, with an address the person gave you | npx wirl share <their-email> |
wirl_share, with full access |
Run each command inside the app's folder. A folder you already have needs no init: a deploy takes the app from its wirl.json, else from the folder's name, and makes the app if it is new; if that name is already an app you can deploy to, it updates that app, so run npx wirl apps first when unsure. It prints the URL and who can open it. npx wirl dev keeps running until stopped: start it in the background, read its output for the address, and stop it when you are done. The hosted wirl_deploy and wirl_preview cannot read your files, so they hand back the command to run in a terminal; the local MCP server uploads for itself. If a command names several organisations and asks which, ask the person, then pass --org <slug>.
5. When wirl refuses#
Read the sentence first: it says what happened and usually what to do. The CLI commands on this page and the MCP tools print the sentence and its hint, and usually not the status, the code or the Retry-After header: those are the API's, and the table gives them so you can match a sentence. Wait as long as the sentence says (a minute, 30 seconds, or at least N seconds in the hint of migrations_rate_limited); if it gives no time, wait a minute. Then send the same request again, once, and do not retry in a loop; if it is refused again, tell the person what the sentence says. A program that calls the API itself reads Retry-After: a number of seconds.
| API status | What you see | What to do |
|---|---|---|
401 |
Not signed in. with no sign-in at all; Not signed in, or this token cannot do that. for a 401, or a 403 with no sentence of its own. The API's 401 says unauthenticated, the hosted MCP server's unauthorized. |
Sign in (step 2). If you just did, this token cannot do that: tell the person. On the local MCP server, call wirl_login. |
403 |
insufficient_scope: This token can deploy, but not <action>. Do it at <page>, or connect again with a full token. |
Stop and show the person that page. If they want you to do it, they connect you again with full access: the box ticked on the consent page or the approval page, or "can do everything" for a CI token (step 3). |
404 |
not_found: Not found, or you do not have access to it: app "<app>" in organisation "<org>". |
wirl answers the same for an app that is not there and one the person cannot open, so do not try other names to find out which. Check the name, --org and --app, and what npx wirl apps or wirl_list_apps lists. |
409 |
migration_needs_approval: <file> <what it does> on the live database. A person approves it at <page>, then deploy again; nothing was applied. With several files, <n> destructive files wait for a person before they change the live database: ... and each file's page. |
Show the person that page, or each file's page, and deploy again once they say they approved. Never type the file's name or send a confirmation yourself. |
409 |
slug_taken: An app named <name> already exists in this organisation; choose another name. Or, for an app that was deleted, An app named <name> was deleted on <date>; its data is kept until <date>. and the way back. |
Choose another name. A deleted app comes back only if the person asks for it: ask before you run npx wirl apps restore <name>. |
409 |
migrations_busy: a sentence about applies of migrations under way, ending Try again in a minute; nothing was applied. (or Try again after that; nothing was applied.), and a Retry-After. |
Wait as long as the sentence says, then deploy again. |
409 |
preview_busy: A preview named <name> is being deployed right now. Try again in a moment. Or too_many_previews: This app already has <n> previews. Delete the oldest first: wirl preview --delete <name>. |
For the first, wait a moment. For the second, ask the person before you delete a preview you did not make: npx wirl previews lists them. |
413 |
too_large: Bundle is larger than 100MB. or The body is over 1 MiB, the most wirl reads of a request other than a deploy's or a preview's upload, so the request was refused. Or manifest_too_large: wirl.json is larger than 262144 bytes. |
Send less. For a deploy, leave out what the app does not serve, or list it in .wirlignore (Limits). |
429 |
rate_limited: Too many attempts. Try again shortly. or a sentence saying what ran out. migrations_rate_limited: This org is too close to the database calls wirl allows one org in five minutes for another apply to start. Try again in a minute; nothing was applied. Each with a Retry-After. npx wirl login says Could not start sign-in (429). |
Wait as long as the sentence says, or a minute when it says none, as Too many attempts. Try again shortly. and npx wirl login do. Then try again once, and do not retry in a loop; if it is refused again, tell the person. |
502 |
app_answers_full or answers_full: npx wirl egress lists it as 502 app_answers_full for an outgoing call of the app: the vendor answered, but wirl could not hold the answer. The vendor may have acted on the call: send it again only if repeating it is safe. No Retry-After. |
This is the app's own outgoing call, not your request to wirl. Send it again only if repeating the call is safe. |
503 |
too_many_uploads: ... nothing changed. Send it again once one of them has finished. (or ... once the other has finished.) uploads_busy: ... nothing changed. Send it again in 30 seconds. database_unavailable: The control plane could not get a database connection, so nothing was changed. Try again in a few seconds. Each with a Retry-After. |
For too_many_uploads, wait for your other deploy or preview to finish. For the others, wait as long as the sentence says. Then send the same request again. If the sentence says part of it may have been made (so this request did not finish, and part of it may have been made. Check the app before you send it again.), check with npx wirl versions or wirl_list_versions first. |
Any other refusal comes with a sentence, a code or at least a status: read it before you send the request again.
6. Where to go next#
- Quickstart: connect an agent, build, run, deploy and share.
- wirl.json and the CLI: every key and every command.
- The contract: what runs on wirl, and what waits for a person before it changes live data.
- Limits: the sizes, counts and waits wirl holds uploads, calls and migrations to.
- Connections and keys: what a
deploytoken and afulltoken cover. - llms-full.txt: every page of this site as one Markdown file.