afy init, deploy, deployments, redeploy, and rollback
The Aetherfy deployment commands
Five Aetherfy CLI commands cover the path from an empty directory to a running agent and back again.
| Command | Purpose |
|---|---|
afy init [path] | Scan a directory and generate aetherfy.yaml |
afy deploy [path] | Upload the code, build an image, and deploy it |
afy deployments <agent> | List the agent’s deployment history |
afy redeploy <agent> [version] | Rebuild a version from its stored source, with current secrets |
afy rollback <agent> [version] | Re-deploy a previously built version |
A first deployment on Aetherfy is normally two commands:
afy init
afy deployGenerating an Aetherfy manifest with afy init
afy init [path] scans a directory, detects the runtime and entrypoint, and
writes an aetherfy.yaml manifest. The path argument is optional and defaults to
..
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--name | string | empty | Agent name (skips prompt) | |
--runtime | string | empty | Runtime: python3.11, python3.12, python3.13, node20, node22, node20-ts, node22-ts, bun, dockerfile (skips prompt) | |
--entrypoint | string | empty | Entrypoint file, e.g. main.py or index.js (skips prompt) | |
--type | string | empty | Agent type: service or job (skips prompt) | |
--region | string | empty | Region: us-east-1, eu-central-1, ap-southeast-1 (skips prompt) | |
--memory | int | 0 | Memory in MB: 256, 512, 1024 (skips prompt) | |
--keep-alive | bool | false | Enable always-on billing (skips billing prompt) | |
--workspace | bool | false | Enable VectorDB workspace (skips workspace prompt) | |
--force | -f | bool | false | Overwrite existing aetherfy.yaml without asking |
--yes | -y | bool | false | Accept every prompt’s default (non-interactive) |
--schedule | string | empty | Schedule — runs the agent as a scheduled task on a 5-field cron expression in UTC, min every 5 minutes, e.g. '0 3 * * *' |
Interactive by default; any flag above skips its prompt.
Two flags in that table read as if they take a value and do not. --workspace
is a boolean toggle that answers the “enable a vector workspace?” prompt —
it does not accept a workspace name, and afy init --workspace research will
read research as the path argument. The workspace an agent joins is named by
the workspace: key in aetherfy.yaml, or set later with
afy update <name> --workspace <ws>. --keep-alive is the same shape.
The --memory help text lists the three values the prompt offers, not the whole
allowed set. memory_mb in the manifest accepts 256, 512, 1024, 2048
and 8192, each still bounded by your plan’s maximum — see
the aetherfy.yaml reference and
/platform/limits.
# Interactive
afy init
# Fully specified, non-interactive
afy init ./services/scraper \
--name catalogue-scraper \
--runtime python3.12 \
--entrypoint main.py \
--type job \
--region eu-central-1 \
--memory 512 \
--schedule '0 3 * * *' \
--yesBehaviour of the two boolean shortcuts in the Aetherfy CLI:
| Flag | Effect |
|---|---|
--yes / -y | Accepts every prompt’s default. It does not imply --force. |
--force / -f | Overwrites an existing aetherfy.yaml. Required even alongside -y. |
The non-interactive defaults Aetherfy applies under --yes:
| Setting | Default |
|---|---|
| Name | The directory name |
| Type | service |
| Region | us-east-1 |
| Memory | 256 MB |
| Always-on billing | Off |
| Runtime | Detected — afy init --yes fails if the runtime cannot be detected |
The schedule prompt appears for either type in interactive mode. The
resulting schedule: key is what makes the agent a scheduled task; see
/agents/scheduled-tasks and the full manifest
reference at /agents/aetherfy-yaml.
Deploying to Aetherfy with afy deploy
afy deploy [path] validates the manifest, archives the directory, uploads it to
Aetherfy, builds an image, and deploys it. The path argument is optional and
defaults to ..
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--detach | -d | bool | false | Return immediately after upload without waiting for completion |
--agent | -a | string | empty | Agent ID or name (reads from aetherfy.yaml if not specified) |
--from-github | string | empty | Deploy from a public GitHub repo: owner/repo[@ref] | |
--yes | -y | bool | false | Skip the overage confirmation prompt and proceed (non-interactive) |
--create | bool | false | Create the agent from aetherfy.yaml’s type and runtime if it does not exist. Required to create without a terminal; --yes never implies it |
# Deploy the current directory
afy deploy
# Deploy a subdirectory, non-interactively, in CI
afy deploy ./services/scraper --yes
# Upload and return immediately
afy deploy --detach
# Target an agent explicitly
afy deploy --agent catalogue-scraper
# Create the agent if it does not exist yet, then deploy into it
afy deploy --createThe order of operations is: validate aetherfy.yaml, archive the project
directory as a gzipped tarball, upload, build the image, deploy.
afy deploy is one of the Aetherfy commands that exits 1 on failure, so it is
safe to rely on its status in a pipeline. That includes a deployment that fails
after the upload, and a wait that runs out before the deployment finishes;
afy redeploy and afy rollback exit the same way.
Deploying to an Aetherfy agent that does not exist yet
A deploy whose target agent has no record on Aetherfy answers
[404] ... (AGENT_NOT_FOUND). Rather than stopping there, afy deploy can
create the agent and continue into it — but only with consent, which it takes
one of exactly two ways.
| Context | Behaviour |
|---|---|
Terminal, no --yes, no --create | Asks Agent '<name>' doesn't exist. Create it as <type>/<runtime> (from aetherfy.yaml)? [y/N], defaulting to No |
--create | The flag is the consent. Creates without asking, in a terminal or not |
No terminal, or --yes present, without --create | Never asks and never creates. The deploy fails with AGENT_NOT_FOUND |
--yes and --create are separate consents and neither implies the other:
--yes answers the overage cost prompt, --create answers the missing-agent
question. A CI deploy of a brand-new agent always needs --create, and needs
--yes as well whenever the deploy would cross the plan allowance — which is
why the CI recommendation below is to pass --yes unconditionally.
The type and runtime the agent is created with come from aetherfy.yaml and
are never inferred. A manifest missing either key, or carrying a type: that is
neither service nor job, is refused with a message naming the key to add —
the deploy does not fall back to a default. A --agent value in UUID form is
also refused: it names a record that is expected to exist, so the CLI will not
create an agent named after an ID.
The agent is created with the same POST /agents that afy create
issues, so creating up front and consenting mid-deploy produce the same record.
Note that on the create path the archive is uploaded twice — once for the
attempt that discovers the agent is missing, and once for the deploy that
follows the create.
Files excluded from an Aetherfy deploy archive
The archive respects a .afyignore file in the project directory. On top of
whatever it contains, the Aetherfy CLI always excludes these built-in defaults:
| Pattern |
|---|
.git |
.gitignore |
.env |
.env.* |
__pycache__ |
*.pyc |
*.pyo |
.pytest_cache |
.mypy_cache |
node_modules |
.npm |
venv |
.venv |
env |
.DS_Store |
Thumbs.db |
*.log |
.afyignore |
Because .env and .env.* are excluded unconditionally, environment values must
reach the agent as Aetherfy secrets rather than as files — see
/cli/secrets.
An example .afyignore:
tests/
fixtures/
*.ipynb
docs/Deploying to Aetherfy directly from a public GitHub repository
--from-github owner/repo[@ref] deploys from a public GitHub repository without
a local clone.
afy deploy --from-github myorg/my-agent
afy deploy --from-github myorg/[email protected]
afy deploy --from-github myorg/my-agent@8f2c1b0d9e4a7c3f5b1d6e8a0c2f4b6d8e0a2c4f| Detail | Value |
|---|---|
| Ref default | main |
| Accepted refs | Branch, tag, or a full 40-character commit SHA |
| Local requirement | git must be installed locally |
| Repository visibility | Public only |
For private repositories and push-triggered deploys, use the Aetherfy GitHub App instead — see /cli/github.
Aetherfy plan overage confirmation on deploy
If a deployment would push your account’s usage beyond the plan allowance, the Aetherfy CLI asks for confirmation before proceeding.
--yesaccepts the prompt and proceeds non-interactively.- Without
--yesin a non-interactive shell the command fails and tells you to re-run with--yes.
CI pipelines that deploy to Aetherfy should therefore always pass --yes:
export AETHERFY_API_KEY=afy_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
afy deploy --yesPlan allowances are documented at /platform/limits.
Aetherfy runs one deployment per agent at a time. Starting a second while the
first is still building or deploying returns HTTP 409 DEPLOYMENT_IN_PROGRESS.
This is worth handling in CI, where two pushes in quick succession are the
normal way to hit it: wait for the first to reach a terminal state, or cancel it
with afy cancel <agent> before starting another.
Partially successful multi-region Aetherfy deployments
A deployment that succeeds in some regions and not others is reported by the Aetherfy CLI as:
Deployment is serving but DEGRADED — N/M regions ready.The agent is serving traffic from the regions that came up. Check
afy status <name> for the per-region detail, and afy logs <name> for
the failure reason in the regions that did not.
Listing Aetherfy deployment history
afy deployments <agent> lists the agent’s deployments, newest first. It takes
one required argument and has no flags of its own; it honours the global
-o json.
afy deployments catalogue-scraper
afy deployments catalogue-scraper -o json| Column | Meaning |
|---|---|
| Version | The version number — the value you pass to afy rollback |
| State | Deployment state, with a glyph |
| Release | On a run, the version of the release it executed — which is not the run’s own Version. A dash on a release |
| Created | When the deployment was created |
| Error | Failure reason, when there is one |
State glyphs used by the Aetherfy CLI:
| Glyph | State |
|---|---|
● | active |
✗ | failed |
○ | superseded |
· | queued |
⟳ | building |
⟳ | deploying |
↩ | rolled_back |
When the newest deployment failed, the Aetherfy CLI prints a suggested rollback
command underneath the table, and — when the build stage is what failed — the
build output under a Build output: heading. That block is the tail of what the
failing step printed, so it says which step failed rather than repeating the
short reason in the Error column. afy deploy prints the same block when a
deploy it is watching fails.
Nothing is printed when the deployment failed somewhere other than the build — a region that never came up, or a cancellation — because there is no build output to quote.
Rolling back an Aetherfy deployment
afy rollback <agent> [version] re-deploys a previously built version.
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--detach | -d | bool | false | Return immediately without waiting for completion |
Called with only the agent name, it prints the deployment history so you can choose a version:
afy rollback catalogue-scraperCalled with a version, it rolls back to it:
afy rollback catalogue-scraper 3The version is a bare integer. afy rollback catalogue-scraper v3 is
rejected by the Aetherfy CLI with Version must be a positive integer.
| Property | Behaviour |
|---|---|
| Build step | Skipped — the target version’s already-built image is re-deployed directly |
| Valid targets | A version whose image, or whose code archive, is still stored: active, superseded and rolled_back versions, and a failed one that got as far as an image (it failed while launching or in its health check) |
| Invalid targets | A failed build, which has neither. No rollback is accepted while a deployment is queued, building or deploying |
Because the build is skipped, a rollback on Aetherfy is substantially faster than
a fresh afy deploy of the same code.
Redeploying an Aetherfy agent to apply secrets
afy redeploy <agent> [version] re-runs a version’s build from the
source archive Aetherfy stored for it.
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--detach | -d | bool | false | Return immediately without waiting for completion |
This is the CLI counterpart of the dashboard’s Redeploy button, and it is not
a rollback. Aetherfy injects secrets while the machine is built, so a secret you
store with afy secrets set reaches a running service only on its next build.
Rollback re-deploys an existing image and cannot apply one; redeploy rebuilds and
does.
Called with only the agent name, it rebuilds the active deployment — the one whose environment a newly stored secret is missing from:
afy redeploy catalogue-scraperCalled with a version, it rebuilds that version instead:
afy redeploy catalogue-scraper 3As with afy rollback, the version is a bare integer.
| Property | Behaviour |
|---|---|
| Build step | Runs — that is what injects current secrets |
| Configuration | Unchanged; the archive is not re-read for memory, regions or any other setting |
| Valid targets | Versions whose stored source archive still exists |
| Archive retention | The ten most recent successful deployments; a failed build’s archive is deleted |
afy redeploy is not a retry for a failed build. Aetherfy deletes the code
archive as soon as a build fails, so nothing remains to rebuild — and re-running
the same build would fail the same way. Fix the code and run afy deploy again,
or push to the linked repository. A deployment that built successfully but failed
to launch keeps its archive, so that one can be redeployed.
A type: job agent needs no redeploy to pick up a new secret, but not because
every run is a new machine — a task agent reuses its machine between runs.
Aetherfy records which secret set each machine was created from, and refuses to
send a run to a machine whose set no longer matches; it creates a current machine
for that run instead. The value is applied, at the price of a cold start on every
run until you redeploy. Services keep their environment until they are rebuilt,
which is what this command does.