---
slug: cli/agents
title: afy agents — Aetherfy agent lifecycle reference
kind: reference
surface: cli
summary: Complete reference for the afy agents command group in the Aetherfy CLI — list, create, delete, stop, start, archive, restore, cancel, status, rename, update, pull, diff, run, runs, and schedule pause/resume, with every flag and default.
sources:
  - aetherfy-cli:cmd/agents.go
  - aetherfy-cli:internal/api/agents.go
  - aetherfy-cli:internal/yamldiff/diff.go
---

# afy agents

## The afy agents command group in the Aetherfy CLI

`afy agents` manages the lifecycle of Aetherfy agents. The group has two
aliases, `agent` and `a`, so `afy a list` and `afy agents list` are the same
command.

| Subcommand | Purpose |
|---|---|
| `afy agents list` | List every agent in the account |
| `afy agents create <name>` | Create an agent record |
| `afy agents delete <name>` | Delete an agent permanently |
| `afy agents stop <name>` | Pause an agent |
| `afy agents start <name>` | Resume a paused agent |
| `afy agents archive <name>` | Free the plan quota slot, keeping configuration and code |
| `afy agents restore <name>` | Re-provision an archived agent |
| `afy agents cancel <name>` | Cancel a pending deployment |
| `afy agents status <name>` | Show detailed agent status |
| `afy agents rename <current> <new>` | Rename an agent |
| `afy agents update <name>` | Change workspace assignment or description |
| `afy agents pull <name>` | Export the agent's configuration as `aetherfy.yaml` |
| `afy agents diff` | Compare local `aetherfy.yaml` against deployed state |
| `afy agents run <name>` | Run a task agent once, immediately |
| `afy agents runs <name>` | Show run history |
| `afy agents schedule pause <name>` | Pause the agent's scheduled task |
| `afy agents schedule resume <name>` | Resume the agent's scheduled task |

Two things do not exist in the Aetherfy CLI and are commonly assumed:

- There is no `afy agents schedule set`. A schedule is declared with the
  `schedule:` key in `aetherfy.yaml` and applied by `afy deploy`. See
  [/agents/scheduled-tasks](/agents/scheduled-tasks).
- There is no `afy agents pause` or `afy agents resume`. The pause and resume
  verbs for an agent are `afy agents stop` and `afy agents start`.

## Listing Aetherfy agents

`afy agents list` prints every agent in the account. It takes no arguments and
no flags of its own.

```bash
afy agents list
afy agents list -o json
```

The default columns are:

| Column | Meaning |
|---|---|
| Name | The agent name |
| Type | `SERVICE` or `JOB` |
| Status | Current lifecycle status |
| Region | Deployed region |
| ID | The Aetherfy agent ID |

When at least one agent in the account has a scheduled task, the table grows to
eight columns: Name, Type, Status, Region, Schedule, Next Run, Last Run, ID.

| Column | Rendering |
|---|---|
| Schedule | The declared schedule expression |
| Next Run | A UTC timestamp, or `(paused)` when the schedule is paused |
| Last Run | A fired / skipped / missed badge plus a relative time, or `never` |

A status of `usage_paused` renders as `paused (usage limit)` — the agent was
paused by the Aetherfy usage meter, not by `afy agents stop`.

## Creating an Aetherfy agent

`afy agents create <name>` creates the agent record. It takes exactly one
positional argument, the name.

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--description` | `-d` | string | empty | Agent description |
| `--type` | `-t` | string | `SERVICE` | Agent type: SERVICE or JOB |
| `--runtime` | `-r` | string | `python3.11` | Runtime: python3.11, python3.12, python3.13, node20, node22, node20-ts, node22-ts, bun, dockerfile |
| `--spawn-enabled` | | bool | false | Enable spawning for this agent |

`--type` accepts only `SERVICE` or `JOB`; anything else is rejected.

```bash
afy agents create scraper \
  --type JOB \
  --runtime python3.12 \
  --description "Nightly catalogue scrape"
```

`afy agents create` has **no `--workspace` flag**. To put a new Aetherfy agent in
a workspace, either run `afy agents update <name> --workspace <ws>` afterwards,
or declare the `workspace:` key in `aetherfy.yaml` before deploying.

## Deleting an Aetherfy agent

`afy agents delete <name>` permanently deletes the agent.

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--force` | `-f` | bool | false | Skip confirmation prompt |

Without `--force` the Aetherfy CLI asks for confirmation and requires you to type
the agent name exactly before it proceeds.

```bash
afy agents delete scraper
afy agents delete scraper --force
```

If your goal is to free a plan quota slot rather than lose the agent, use
`afy agents archive` instead — it preserves the configuration and the stored code
bundle.

## Pausing and resuming an Aetherfy agent with stop and start

`afy agents stop <name>` pauses an Aetherfy agent. It stops every machine and
prevents the proxy from re-waking the agent on incoming traffic. The pause is
reversible.

`afy agents start <name>` resumes an agent that was paused with `stop`.

```bash
afy agents stop api-gateway
afy agents start api-gateway
```

Neither command takes flags. A stopped Aetherfy agent still bills at the base
rate — stopping suspends execution, not billing. To stop billing for an agent you
are not using, archive it.

## Archiving and restoring an Aetherfy agent

`afy agents archive <name>` destroys the underlying application to free the plan
quota slot while preserving the agent's configuration and its stored code bundle.
It is reversible.

`afy agents restore <name>` re-provisions an archived Aetherfy agent from the
preserved bundle.

```bash
afy agents archive old-worker
afy agents restore old-worker
```

Restoring consumes a plan quota slot, and the quota is re-checked at restore
time. If you are already at your plan limit the restore is rejected until you
free a slot or upgrade. Plan quotas are documented at
[/platform/limits](/platform/limits).

## Cancelling a pending Aetherfy deployment

`afy agents cancel <name>` cancels a pending deployment for the agent. It takes
no flags.

```bash
afy agents cancel scraper
```

Only deployments in the QUEUED state are cancellable. A deployment whose build is
already in flight returns HTTP 409 from the Aetherfy API and cannot be cancelled;
wait for it to finish, then roll back with `afy rollback` if the result is wrong.

## Inspecting an Aetherfy agent with status

`afy agents status <name>` prints the detailed state of a single Aetherfy agent.
It takes no flags of its own and honours `-o json`.

```bash
afy agents status scraper
afy agents status scraper -o json
```

The text output covers:

| Field | Notes |
|---|---|
| ID | The Aetherfy agent ID |
| Name | The agent name |
| Type | `SERVICE` or `JOB` |
| Status | Current lifecycle status, with health or degraded detail when present |
| Region | Deployed region |
| Spawn Enabled | Whether this agent may start child agents |
| Workspace | The workspace the agent belongs to, if any |
| Schedule | The schedule expression, labelled UTC |
| Next run | Next scheduled fire time, or `(paused)` |
| Last run | Outcome and time of the most recent run |
| Created | Creation timestamp |
| Updated | Last-modified timestamp |
| Description | The agent description |
| Spawn relationships | Parent and child agents |

## Renaming an Aetherfy agent

`afy agents rename <current-name> <new-name>` changes the agent's name. It takes
exactly two positional arguments, which must differ.

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--force` | `-f` | bool | false | Skip confirmation prompt |

```bash
afy agents rename scraper catalogue-scraper --force
```

The Aetherfy agent URL is not derived from the name and does not change, so
existing integrations, links, and webhooks keep working across a rename. Only the
name changes.

## Updating an Aetherfy agent's workspace or description

`afy agents update <name>` changes the mutable metadata of an Aetherfy agent.

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--workspace` | | string | empty | Assign the agent to this workspace |
| `--no-workspace` | | bool | false | Clear the agent's workspace (make it workspaceless) |
| `--description` | `-d` | string | empty | Set the agent's description |

Rules enforced by the Aetherfy CLI:

- At least one flag is required; with none, the command errors.
- `--workspace` and `--no-workspace` are mutually exclusive.
- `--workspace ""` is rejected. Use `--no-workspace` to clear the assignment.

```bash
afy agents update scraper --workspace research
afy agents update scraper --no-workspace
afy agents update scraper -d "Nightly catalogue scrape"
```

This is also the supported way to move an existing Aetherfy agent into a
workspace, because `afy agents create` has no `--workspace` flag.

## Exporting an Aetherfy agent's configuration with pull

`afy agents pull <agent-name>` exports the agent's current configuration in
`aetherfy.yaml` form. By default it writes to stdout so it can be redirected.

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--output` | `-o` | string | empty | Write the YAML to this file instead of stdout |

**Warning:** on `afy agents pull` alone, `-o` means an output **file path**, not
the global Aetherfy output format. `afy agents pull scraper -o json` writes a
file named `json`. This subcommand shadows the global `--output` flag.

```bash
# To stdout
afy agents pull scraper

# Redirect
afy agents pull scraper > aetherfy.yaml

# Or write directly
afy agents pull scraper -o aetherfy.yaml
```

The emitted YAML is the declarative subset only — fields the Aetherfy server
derives are excluded. Re-deploying the pulled file is therefore a no-op against
the agent it came from.

## Diffing local aetherfy.yaml against deployed Aetherfy state

`afy agents diff` compares the local `aetherfy.yaml` against the agent's current
state on Aetherfy and prints what a deploy would change under merge-patch
semantics. It takes **no positional arguments** — the agent is identified from
the manifest.

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--path` | `-p` | string | `.` | Project directory containing aetherfy.yaml |

```bash
afy agents diff
afy agents diff --path ./services/scraper
```

The output legend:

| Marker | Meaning |
|---|---|
| `~ field: old → new` | The deploy would change this field |
| `+ field: value` | The deploy would set this field |
| `- field` | The deploy would clear this field |
| `= field: value` | No-op — local and deployed values match |
| ` field: value` | Preserved — not present locally, left untouched |

A `runtime` change is annotated `(immutable — deploy will reject)`, because the
Aetherfy runtime cannot be changed on an existing agent.

`afy agents diff` **exits non-zero when there are changes**, which makes it a
drift gate in CI:

```bash
afy agents diff --path ./services/scraper
if [ $? -ne 0 ]; then
  echo "Deployed Aetherfy state has drifted from aetherfy.yaml"
  exit 1
fi
```

## Running an Aetherfy task agent on demand

`afy agents run <name>` runs a task agent once, immediately, outside its
schedule. Only deployed agents declared as `type: job` can be run this way.

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--payload` | `-p` | string | empty | JSON payload to pass to the run |
| `--payload-file` | `-f` | string | empty | Read the JSON payload from a file |
| `--wait` | | bool | false | Wait for the run to finish (exit 1 if it fails) |

`--payload` and `--payload-file` are mutually exclusive, and the payload must be
a JSON **object**.

```bash
# Fire and forget
afy agents run scraper

# With an inline payload
afy agents run scraper --payload '{"since":"2026-08-01","full":true}'

# With a payload file
afy agents run scraper --payload-file ./payload.json

# Block until the run finishes; non-zero exit if it fails
afy agents run scraper --wait
```

Without `--wait`, the Aetherfy CLI prints the Run ID and suggests
`afy logs <name> --run <id>`. With `--wait`, it polls for up to 30 minutes; a
failed run exits 1, and on timeout the run keeps going on Aetherfy — only the
waiting stops.

Error hints the Aetherfy CLI prints:

| Error code | Meaning and fix |
|---|---|
| `AGENT_NOT_DEPLOYED` | The agent exists but has no deployment. Deploy it first: `afy deploy`. |
| `AGENT_SCHEDULE_NOT_SET` | Add a `schedule:` key to `aetherfy.yaml` and deploy. |
| `AGENT_RUN_REQUIRES_JOB_TYPE` | Only `type: job` agents can be run on demand. |

## Listing Aetherfy run history

`afy agents runs <name>` shows the run history for an agent, newest first.

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--limit` | | int | 20 | Maximum number of runs to show (max 100) |

```bash
afy agents runs scraper
afy agents runs scraper --limit 100
afy agents runs scraper -o json
```

Columns:

| Column | Meaning |
|---|---|
| When | Time of the run |
| Trigger | What started it — `cron` for a scheduled fire, or a manual trigger |
| State | Run outcome |
| Duration | Wall-clock run time |
| Run ID | Pass to `afy logs <name> --run <id>` |

Only scheduled and manual runs appear here. Runs started by a parent agent
through `afy spawn` belong to the parent's history and are deliberately excluded
from the child's list — see [/cli/spawn](/cli/spawn).

## Pausing and resuming an Aetherfy scheduled task

`afy agents schedule pause <name>` pauses the agent's scheduled task. No
scheduled runs fire until it is resumed. Manual runs via `afy agents run` are
unaffected. The command is idempotent — pausing an already-paused schedule
succeeds.

`afy agents schedule resume <name>` resumes a paused scheduled task, and is
likewise idempotent.

```bash
afy agents schedule pause scraper
afy agents schedule resume scraper
```

On resume the next run time is recomputed from now. Occurrences that elapsed
while the schedule was paused are **skipped, never backfilled** — Aetherfy does
not replay a missed window.

Both subcommands print whether anything actually changed, the resulting paused
flag, and the next run time (or `(paused)`). Both honour `-o json`.

Neither command edits `aetherfy.yaml`. The schedule expression itself is
declared there and applied by `afy deploy`; see
[/agents/scheduled-tasks](/agents/scheduled-tasks) and
[/agents/aetherfy-yaml](/agents/aetherfy-yaml).
