Docs / CLI

CLI

Install the hosted CLI, ship with aft deploy — no login — then manage claimed sites after aft login: rename, secrets, visibility, rollback, update.

Install

Installs a native binary — no Node.js required. Puts aft in ~/.local/bin.

curl -fsSL https://aft.page/install | sh
aft --help

If aft is not found, add export PATH="$HOME/.local/bin:$PATH" and reopen the terminal.

The CLI checks for a newer version once a day and nudges you if you're behind — see Troubleshooting if you'd rather turn that off.

Ship (no login)

Only shipping is anonymous. aft deploy and aft init don't need an account. Same durable URL you'd get from Drop or MCP.

# Plain HTML — folder with index.html
aft deploy

# Vite / React / Vue — build first; CLI auto-picks dist/
npm run build
aft deploy

# Or point at the output folder directly
aft deploy dist
aft deploy out     # Next static export

On first deploy in a project root, the CLI writes aft.json (slug from package.json's name, or the folder name) if one doesn't exist yet. Redeploys reuse .aft/state.json — the slug and edit token stored there — so the URL stays put.

Success prints the live URL and a claim link. Anonymous deploys last 60 minutes unless you pass --expires (up to 7 days). aft login claims the site in this folder. See the claim guide.

After claim + login

Claim on the live URL (or on the preview page with ?token=), then:

aft login
aft whoami
aft sites

aft login opens your browser to sign in, then hands the CLI a session token over a short-lived local server — no password ever touches the terminal. The session is stored in ~/.config/aft.page/credentials.json; override the lookup with the AFT_TOKEN environment variable (handy in CI). From here, management commands mirror the project dashboard: rename, secrets, visibility, invites, rollback.

No browser on that machine (SSH, a server, an agent's sandbox)? aft login notices and prints a short code instead: open the link it shows on any device where you're signed in and approve the code. Force it with aft login --device. Missed the claim link from your first deploy? aft claim-link prints it again with its deadline.

aft.json

Written by aft init or your first deploy. Example:

{
  "name": "my-app",
  "slug": "my-app",
  "runtime": "static"
}

Optional capabilities.secrets / egress lets an app declare what it needs so an owner can approve it on deploy — see the Capabilities guide. Next / Worker runtimes add runtime + upstream — see Frameworks.

Output folders

From a project with package.json and no root index.html, aft deploy looks for dist/, then out/, then build/ — whichever contains an index.html first. If it instead sees src/ or app/ with no build output, it stops and tells you to run npm run build first rather than guessing.

State (.aft/state.json) always stays in the project root, even when you deploy from dist/ — so redeploys keep finding the same slug and edit token no matter which folder you point the CLI at.

Command reference

Command Login? What
aft deploy [dir] no Upload a site, or a small app aft builds and runs (Flask, FastAPI, Django, Express)
aft deploy --check no Preflight JSON, no upload
aft deploy --json no One JSON result on stdout (ok, url, slug, version, claimUrl — or ok:false with error). For agents. Exit 0 = live, 1 = not. From an agent or script the CLI never asks a question or opens a browser. Human mode prints the URL on stdout and a short Personal offer on stderr. --json does not print that offer.
aft init no Write aft.json
aft update no Reinstall the latest CLI
aft login / logout / whoami — Browser session, or a code to approve (--device)
aft claim-link no Print this folder's claim link again
aft sites (aft ls) yes List claimed projects
aft open yes Open this project's live URL
aft rename <slug> yes Change the site URL
aft env list|set|unset (aft secrets) yes Secrets vault — same as the project UI
aft visibility public|private (aft vis) yes Who can open the live site
aft invite <email> [view|edit|admin] yes Email an invite. view is free; edit and admin are collaborators, part of Team. aft invite list shows pending invites and who has access, aft invite revoke <email|id> cancels one. Viewers only need an invite once the site is private: aft visibility private
aft rollback [deployId] yes List or restore prior deploys
aft plugins add — Install the Agent Plugin (Skill + MCP). Open protocols

Examples

aft rename include-xi
aft env set ANTHROPIC_API_KEY=sk-…
aft env list
aft visibility private
aft rollback
aft rollback dep_abc123def456

Rename and secrets need a claimed site you own. The preview UI can also rename with the deploy edit token before claim — see Claim.

Inside an agent sandbox

Agents increasingly run in a sandbox that only reaches the files and network hosts you allow. aft needs very little:

  • Network: allow api.aft.page. Allow aft.page too if the agent installs the CLI itself.
  • Install inside the workspace: set AFT_INSTALL_DIR and AFT_BIN_DIR so nothing is written to your home folder.
  • No login needed to ship. To deploy as you, set AFT_TOKEN instead of running aft login; or point AFT_CREDENTIALS at a file in the workspace. AFT_CLI_PREFS moves the small settings file too; if the home folder is read-only, aft still deploys.
AFT_INSTALL_DIR="$PWD/.aft" AFT_BIN_DIR="$PWD/.aft/bin" \
  sh -c "$(curl -fsSL https://aft.page/install)"
AFT_NO_UPDATE=1 ./.aft/bin/aft deploy

Troubleshooting

"command not found: aft" — the installer puts aft in ~/.local/bin, which isn't always on PATH by default. Add export PATH="$HOME/.local/bin:$PATH" to your shell profile and open a new terminal.

"run npm run build first" — non-interactive aft deploy runs the build itself. Use aft deploy --check to see why/fix JSON without uploading. Or point at output: aft deploy dist.

Commands that need login fail with an auth error — run aft whoami to check the session. Sessions live in ~/.config/aft.page/credentials.json; delete that file (or run aft logout) and aft login again if it's stuck. In CI, skip the browser flow entirely by setting AFT_TOKEN.

CLI feels out of date — run aft update to reinstall the latest build. To turn off the daily version check (for example in CI), set AFT_NO_UPDATE=1.

Next: Claim & share — keep your URL and invite teammates after the first deploy.