Use with agents & CI
The canonical playbook for driving flypod from an agent or CI job. Covers non-interactive output, capturing the URL, exit codes, authentication, and idempotent re-deploys.
flypod is built to be driven by machines. Deploys are non-interactive by default whenever stdout isn't a TTY: no prompts, no animation. This page is the reference for running it from an agent or a CI job.
Capture the URL
The live URL is always on stdout; the banner, spinner, and hints go to stderr. So you can capture the URL directly:
URL=$(npx flypod ./dist --quiet)Or parse structured output:
npx flypod ./dist --json | jq -r .urlflypod auto-detects a non-TTY stdout and strips the animation. You don't need a
flag for that, but --quiet (URL only) and --json (structured) make the
contract explicit and are recommended in scripts.
The two output modes
| Mode | stdout | stderr |
|---|---|---|
--quiet | the live URL | nothing |
--json | a JSON object (see below) | nothing |
--quiet prints no token. It used to emit the manage_token on stderr, and
-q is exactly the mode whose stderr ends up in a build log that outlives the
site — and the token can't be rotated, only outlived. If a job needs the token,
use --json, which is explicit, structured, and the documented agent contract.
The --json object, for an anonymous deploy:
{
"ok": true,
"url": "https://ab12cd34.flypod.dev",
"site_id": "ab12cd34",
"version_id": "v_...",
"expires_at": 1781308800000,
"manage_token": "fk_...",
"claim_token": "fk_...",
"source": "./dist",
"files": 12,
"bytes": 48211,
"elapsed_ms": 734
}Two things to parse carefully:
expires_atis epoch milliseconds, ornullwhen the site is owned. It is not an ISO string.- Keys that don't apply are omitted, not
null. An anonymous deploy has noowner_account_idkey; an owned deploy has noclaim_tokenkey. Test for presence, not fornull.
Don't stash the claim_token in job state or a transcript. To make deploys
permanent, authenticate the job (FLYPOD_TOKEN) or run
flypod login on the machine — login claims every
anonymous site that machine remembers, in one step, with no token handling.
Exit codes
| Code | Meaning |
|---|---|
0 | Success. |
| non-zero | Failure (deploy error, network, auth). |
2 | Unknown top-level flag (and unknown flags on flypod install skill). Subcommands like update silently ignore flags they don't recognize, so don't rely on 2 to catch a typo in flypod update --sight x. |
Check the exit code, not the text:
if URL=$(npx flypod ./dist --quiet); then
echo "deployed: $URL"
else
echo "deploy failed" >&2
exit 1
fiAuthenticate in a job
Agents running on a developer machine use the session saved by the browser device flow:
flypod login
npx flypod ./dist --quietFor a stateless job, pass an existing account session token through the secret store. No login file is written:
# FLYPOD_TOKEN is read straight from the environment. Set it from the job's
# secret store; no login file is written and none is read.
npx flypod ./dist --quietFLYPOD_TOKEN takes precedence over a saved login. The legacy
FLYPOD_API_KEY name is still accepted as a fallback for older integrations.
With no credential, the deploy is anonymous.
Authenticated deploys are owned and permanent. No 14-day TTL. Anonymous deploys (no login) expire after 14 days. See Accounts & claiming.
Idempotent re-deploys
To ship a new version to the same site instead of creating a new one, use
flypod update. flypod links the working directory to its
site, so no ID is needed:
npx flypod update --quietupdate is safe to run on every push: versions are content-addressed, so a run with
unchanged files resolves to the existing version id instead of growing the history.
The upload still happens, so it is not free — just not accumulating. If the linked site is gone
(404), flypod drops the stale link and tells you to run flypod to deploy
fresh. In an ephemeral CI checkout where no folder link exists, pass
--site <id> — plus --token <manage_token> if the site is anonymous, which is
the case an authenticated job avoids entirely.
Ephemeral config dirs
A CI container usually has no persistent FLYPOD_CONFIG_DIR, so there is no
folder link to carry between runs. Two consequences worth designing around:
- Authenticate the job with
FLYPOD_TOKEN. Deploys are then owned and permanent immediately, there is no 14-day clock, and--site <id>alone is enough to update later — no per-site token to move around. - If the config dir is read-only or ephemeral and the deploy is anonymous,
flypod can't remember the site for you. It warns and prints the
manage_token(on stderr, even under-q), because at that point the job is the only holder of the site's only credential.
Server override
Point the CLI at a different backend with DEPLOY_URL:
DEPLOY_URL=https://example.internal npx flypod ./dist --jsonOther recognized env vars: FLYPOD_CONFIG_DIR (credential/link location),
NO_COLOR, FORCE_COLOR.
Minimal agent recipe
# FLYPOD_TOKEN comes from the job's secret store and is read from the
# environment. Nothing to set up here.
# first deploy → capture site_id for later
SITE=$(npx flypod ./dist --json | jq -r .site_id)
# subsequent runs → idempotent update to the same site
npx flypod update --site "$SITE" --json | jq -r .urlNext steps
How to deploy a static site from an AI agent
Run npx flypod ./dist from any coding agent to get a live URL back on stdout, with no account and no config. Covers the one-line deploy, teaching the agent to do it unprompted, and making the URL permanent.
Enable comments on a site
Turn on the anchored comments widget for a deployed site, choose an access mode, and read the review feed.