Aetherfy agent lifecycle API
Base URL https://agents.aetherfy.com/api/v1, bearer authentication, and the shared
error envelope are described on the Agent REST API index. {agent}
accepts a UUID or a name throughout.
Creating an Aetherfy agent
POST /api/v1/agents → 201
curl -s -X POST https://agents.aetherfy.com/api/v1/agents \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"reporter","description":"Posts the daily summary","workspace_name":"default"}'| Field | Type | Notes |
|---|---|---|
name | string | Required. Up to 47 lowercase letters, digits and hyphens, unique per account; it becomes part of the agent’s hostnames |
description | string | null | Human-readable, up to 1000 characters |
workspace_name | string | The workspace the agent lives in, by name |
workspace_id | string | The same, by id |
Send workspace_name or workspace_id, exactly one: every agent lives in a
workspace. Neither, or both, is 422 VALIDATION_ERROR. On an account with one
workspace, that is default.
These are the platform’s fields, and the only ones a create takes. How the agent
runs (its runtime, type, memory, always-on, idle timeout, regions, entrypoint,
schedule and spawn) is set by its aetherfy.yaml at
deploy; a create naming any of them is refused with 422 VALIDATION_ERROR.
Creating an agent does not deploy it — it reserves the name, in its workspace. See Deployments.
Your agent quota is not checked here. The quota counts deployed agents, and a freshly created agent is a draft, so you can keep as many drafts as you like on any plan — including building a replacement for an agent that is currently serving traffic, before you take the old one down. It is checked when you first deploy an agent, and when you restore one from the archive.
Which agents hold a slot follows from that. A deployed agent holds one, and
stopping it does not give it back: a stopped agent is paused, which keeps it
deployed. Archiving or deleting an agent releases its slot. Drafts never held one.
The per-agent caps — memory, idle timeout, always-on, the dockerfile runtime — are
checked at deploy, against the aetherfy.yaml being deployed.
Checking the quota at deploy rather than at create is not merely a deferral, and the deploy-time check is not redundant with anything: an agent created under your limit can reach its first deploy after a downgrade, or after another agent took the last slot.
| Code | HTTP | Meaning |
|---|---|---|
AGENT_NAME_TAKEN | 409 | Another agent on this account already has that name |
WORKSPACE_NOT_FOUND | 404 | workspace_name or workspace_id names no workspace on your account |
VALIDATION_ERROR | 422 | No workspace, or both forms of it; a field other than name, description and the workspace; or a name that is not a valid agent name |
SERVICE_UNAVAILABLE | 503 | Your plan could not be read, so no limit could be checked. Transient — retry |
Listing and reading Aetherfy agents
GET /api/v1/agents → 200, an array of agent objects.
GET /api/v1/agents/{agent} → 200, one agent object.
curl -s https://agents.aetherfy.com/api/v1/agents/reporter \
-H "Authorization: Bearer $AETHERFY_API_KEY"The agent object carries the creation fields above plus:
| Field | Type | Notes |
|---|---|---|
id | uuid | |
user_id | uuid | |
deployed | boolean | Whether the agent holds a built app right now |
url | string | null | Where to send a request, or null. See below |
status | enum | See the status table below |
regions | string[] | Regions the agent currently occupies |
pending_regions | string[] | Regions a change is still moving into |
regions_total / regions_ready | integer | Convergence counters |
is_degraded | boolean | Some regions are not serving |
degraded_reason | string | null | Why, when is_degraded is true |
failure_code | string | null | Why the agent is not where you asked it to be — failed, still archived after a refused restore, or running but not serving — when nothing else on the record says. Branch on this |
failure_message | string | null | The same reason as prose, for display. Wording may change between releases |
cron_schedule | string | null | The 5-field UTC cron expression, when a schedule is set |
cron_next_run_at | timestamp | null | Next scheduled fire |
cron_paused | boolean | Whether the schedule is paused |
cron_last_run_at | timestamp | null | |
cron_last_status | string | null | What the schedule last did: fired, skipped or missed. fired means a run was started, not that it succeeded |
cron_last_reason | string | null | Why the last occurrence did not fire, when it did not |
last_run | object | null | The most recent scheduled or manual run: id, trigger_source, state, created_at, error_message and release_version, as the run history lists it. Null when the agent has never run |
created_at / updated_at | timestamp | |
github | object | The agent’s GitHub link: the same object GET /api/v1/agents/{agent}/github returns, described in the deployments API. Always present; linked is false for an agent with no link |
failure_code is set only where the reason cannot be recovered from anything else,
and it can be set on any status.
Today it carries 13 values, app_lost_on_provider, image_lost_on_provider, agent_unhealthy, machine_lost_on_provider, restore_refused_agent_limit, restore_refused_agent_safety_limit, restore_refused_usage_limit, restore_refused_payment_issue, restore_refused_code_unavailable, restore_refused_config_not_on_record, restore_refused_plan_settings, restore_refused_region_placement and restore_refused_other.
The first two sit on a failed agent. app_lost_on_provider means the compute
plane no longer has an app for the agent. image_lost_on_provider means the image
a service agent runs is no longer available, so nothing can start from it; a job
agent is never marked this way, because its next run rebuilds the image instead. In
both cases your secrets and the agent’s address are kept, and
afy deploy, run in the agent’s project folder, brings it back from your current code.
Two sit on a running agent that is not serving. agent_unhealthy is set when
every running machine of the agent is failing its health check, so none of them is
being sent requests; a request may wake a resting machine, which then fails the same
way if the code cannot start (see the machine health field below). failure_message
then carries the error the machine reports, and the code clears by itself as soon as
a machine passes again. If your code cannot start, fix it and run afy deploy in the agent’s folder.
machine_lost_on_provider is set on a running service agent when the compute
plane no longer runs any machine of its live release: the machine was lost, or the
host it ran on is down. Nothing brings a machine back by itself, so the agent serves
nothing until afy deploy (run in the agent’s folder) builds new machines; your secrets and the agent’s
address are kept. It clears when a deploy goes live, or by itself if the host comes
back and the machine runs again.
The seven restore_refused_* values sit on an archived agent: a restore was
accepted with a 202 and then refused when it ran (see
archiving and restoring). The agent
stays archived, with its code, secrets and settings kept. Each value names one
thing to do:
| Value | What to do |
|---|---|
restore_refused_agent_limit | Archive or delete another agent, or upgrade your plan, then restore again |
restore_refused_agent_safety_limit | The account already holds the most deployed agents an account may have, which no plan names. Archive or delete another agent, or contact support to raise the limit, then restore again |
restore_refused_usage_limit | The account reached its plan usage limit. Upgrade, or ask support for a custom plan if you are already on the largest one, then restore again |
restore_refused_payment_issue | A payment has not gone through. Update the payment method in billing settings, then restore again |
restore_refused_code_unavailable | The stored code can no longer be used. afy deploy from your project directory |
restore_refused_config_not_on_record | The configuration of the version it was running isn’t on record. afy deploy from your project directory |
restore_refused_plan_settings | Its memory, regions or always-on setting, or a custom Dockerfile runtime, go beyond your current plan. Upgrade and restore again, or deploy with settings your plan includes |
restore_refused_region_placement | The regions it last ran in are no longer open to it: its workspace was removed, or the workspace’s regions no longer include the agent’s region. afy deploy in the agent’s folder places it in a region its workspace has |
restore_refused_other | Refused for a reason with no specific fix published yet. Contact support with the agent’s name |
A restore refusal clears as soon as you ask for a restore again, and whenever the
agent leaves archived by a restore, a deploy or a push. A null failure_code is
not a claim that the agent is healthy — an agent whose build did not compile has
null here and explains itself through its deployment’s error instead.
failure_code is separate from is_degraded on purpose. is_degraded means the
agent is serving and something about it is wrong; a failed agent is not serving at
all, so the two never describe the same condition. For the same reason is_degraded
is withheld, and degraded_reason is null, while agent_unhealthy explains the agent:
an agent none of whose running machines is being sent requests is not serving, and
its failure_message already carries the error the machine reports.
The cron_* fields describe a scheduled task. cron names
the expression format only.
When an Aetherfy agent has a URL
url is the address you send requests to. It is null unless all three of these
are true:
| Condition | Why |
|---|---|
| The agent is deployed | A draft has never been built. An archived agent’s app is destroyed, so its hostname resolves to nothing until you restore it |
agent_type is service | A type: job image is not a web server. It has no listener, so there is no address to publish — see the task contract |
| Aetherfy has assigned its hostname | Assigned at an agent’s first successful deploy, so an agent that has never deployed has none. An agent first deployed before Aetherfy published agent hostnames also has none until Aetherfy backfills it, which is the one case where a deployed service agent still reads null |
deployed and url answer different questions, and a type: job agent is where
the difference shows: it deploys, so deployed is true, and it serves nothing, so
url is null. Do not read url != null as “is it deployed” — read deployed.
An agent’s hostname is fixed for its lifetime. Renaming the agent does not move it, and neither does redeploying it or archiving and restoring it — so an integration pointing at the address never has to be updated. Archiving does take the agent off that address until you restore it, which is the first row above; what the fixed hostname guarantees is that it comes back on the same one.
Aetherfy agent statuses
| Status | Meaning |
|---|---|
pending | Created, nothing built yet |
building | A deployment is building |
deploying | Built, machines coming up |
running | Serving |
failed | The last deployment failed |
paused | You stopped it — see stop below |
stopped | Aetherfy stopped it because the account was suspended |
usage_paused | Aetherfy paused it because a spend limit was reached |
suspended | Account-level suspension |
archived | Torn down, configuration and code retained |
deleting / deleted | Terminal |
paused and stopped are different states with different causes, and the
distinction matters when you are diagnosing an agent that is not serving. paused is
something you did and can undo with start. stopped means the account was
suspended — settle it and Aetherfy returns the agent to running on its own. See
Billing and spend caps.
Updating an Aetherfy agent
PATCH /api/v1/agents/{agent} → 200. It changes the platform’s two fields of an
agent, name and description, and nothing else; each is optional, and an
omitted one is untouched. description: null clears it. How the agent runs
(memory, always-on, regions, schedule, and the rest) is set by its
aetherfy.yaml and changes only by a deploy; a body naming any other field is
refused with 422. Moving an agent to another workspace is
POST /api/v1/agents/{agent}/move, which redeploys it there.
curl -s -X PATCH https://agents.aetherfy.com/api/v1/agents/reporter \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"daily-reporter","description":"Posts the daily summary"}'A rename does not move the agent’s public URL.
| Code | HTTP | Meaning |
|---|---|---|
AGENT_NOT_FOUND | 404 | |
AGENT_NAME_TAKEN | 409 | Another live agent of the account already has that name. Nothing is changed |
VALIDATION_ERROR | 422 | A field other than name and description, a name that is not a valid agent name, or name: null |
Moving an Aetherfy agent to another workspace
POST /api/v1/agents/{agent}/move → 200. Send the target as workspace_name or
workspace_id, exactly one.
curl -s -X POST https://agents.aetherfy.com/api/v1/agents/reporter/move \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"workspace_name":"research"}'The running machines carry their workspace in their environment, so moving a live agent redeploys its serving release into the new workspace — its existing image, with no build — and the response carries that deployment. An agent with nothing serving moves without one. A move that cannot redeploy is refused, and the agent stays where it was. A grant the agent had to the target workspace is dropped, since that is now its own; the workspace it left does not become a grant.
The agent’s conversation history stays in the workspace it left. The memory SDK
keeps conversations in each workspace’s __threads__ collection, shared by every
agent living there, and that collection never moves; after the move the agent’s
MemoryClient reads its new workspace’s. Its AETHERFY_WORKSPACE_ID is the new
workspace’s from the redeploy on. A frozen account can never move an agent: a move
grows nothing but reduces nothing either.
| Code | HTTP | Meaning |
|---|---|---|
AGENT_NOT_FOUND / WORKSPACE_NOT_FOUND | 404 | |
AGENT_DEPLOYMENT_OUTSIDE_NEW_WORKSPACE_SCOPE | 400 | The live deployment runs in regions the target workspace does not have. violations names the deployment version, its regions and the target’s |
AGENT_PAUSED_CANNOT_MOVE | 409 | Start the agent first |
DEPLOYMENT_IN_PROGRESS | 409 | A build is running. Transient — retry |
SOFT_CAP_EXCEEDED / DUNNING_FROZEN | 403 | The account is frozen, and a move reduces nothing — see Deploying while growth is frozen |
RELEASE_CONFIG_NOT_ON_RECORD | 422 | The serving release is from before Aetherfy recorded each release’s configuration. Deploy it again from its source, then move |
Stopping and starting an Aetherfy agent
POST /api/v1/agents/{agent}/stop → 202 {"status": "paused", "machines": "stopping", "agent_id": "…"}
POST /api/v1/agents/{agent}/start → 202 {"status": "running", "agent_id": "…", "readiness": "serving", "resume": null}
curl -s -X POST https://agents.aetherfy.com/api/v1/agents/reporter/stop \
-H "Authorization: Bearer $AETHERFY_API_KEY"Stop moves the agent to paused — note the endpoint is named for the verb and the
resulting status is paused, not stopped. The agent keeps its slot against your
plan’s agent count, its configuration and its code. Start brings the same machines
back without rebuilding — booted afresh, so your code starts from the top and
nothing it held in memory survives the stop.
The pause is in force the moment the call returns: the status is paused, the
agent’s awake time stops counting at that instant, and a deploy or rollback against
the agent is already refused. A paused agent is still deployed, so it keeps accruing
its daily price for its memory and regions; archive it to stop that
(Billing). The machines field reports the remaining work — Aetherfy stops
the machines in the background, giving your server its shutdown grace, and the
machine states you see under GET /api/v1/agents/{agent}/status catch up afterwards
rather than immediately.
A start sent before the machines are down is accepted, and carried out once they
are — see below. Everything else already sees the agent paused. Treat the machine
states as a view that trails, not as the pause itself.
For a service agent, start answers once every machine has booted and its own
/health has answered, or 25 seconds have passed since the call arrived.
readiness says which. A job agent is resumed without starting any machine: its
machines serve only runs, so start restores its auto-start and answers running
at once, and a machine wakes when a run needs it.
readiness | Meaning |
|---|---|
serving | Every machine’s /health answered 200. Requests are served now |
starting | Your server is not listening yet. Requests sent now are held until it is |
load_failed | Your code failed to load, so requests will fail. The reason is in the agent’s logs |
unconfirmed | The machines started in time, but nothing confirmed your code is serving: at least one gave no answer from it before the budget ran out — your code’s startup, check its logs — or a machine was being stopped by an archive, a delete or a pause you made while the start was answering. A stop is never reported as load_failed |
slow_start | Starting the machines took the whole budget, so your code was not checked. The delay was on Aetherfy’s side, not in your code |
null | A job agent, which serves no requests — or an accepted start (below), which answers before anything is started |
The wait costs a resume as long as your server takes to start, up to that bound.
The agent is running either way: readiness describes your code, not the start.
Because a paused agent still holds its quota slot, you cannot pause your way under an agent limit. Archive instead.
| Code | HTTP | Meaning |
|---|---|---|
AGENT_ALREADY_PAUSED | 409 | Already paused, with no start pending |
AGENT_NOT_PAUSED | 409 | start on an agent that was not paused |
AGENT_ALREADY_ARCHIVED | 409 | Restore it first |
AGENT_HAS_PENDING_DEPLOYMENTS | 409 | Wait for the build to finish or fail |
AGENT_NOT_PAUSEABLE_SYSTEM_STATE | 409 | Aetherfy owns the current state, e.g. usage_paused |
AGENT_OPERATION_IN_PROGRESS | 409 | A worker holds the agent, or it is being archived or deleted, or — on stop — the start you asked for earlier is being carried out right now. Transient — retry |
AGENT_NO_MACHINES | 400 | Nothing to start; deploy first |
AGENT_RESUME_FAILED | 503 | The machines could not be started: their host was unreachable. The agent is still paused — retry. A full host is not this error: that start is accepted (below) |
AGENT_OPERATION_IN_PROGRESS is the only 409 here that is safe to retry; the others
describe a state you have to change first.
Starting while the previous stop is still finishing
stop answers once the pause is decided, and the stop itself runs after it, giving your
server its shutdown grace — so a start sent right after a stop finds the stop still
being carried out. That start is accepted:
POST /api/v1/agents/{agent}/start → 202 {"status": "paused", "agent_id": "…", "readiness": null, "resume": {"state": "pending", "reason": null, "requested_at": "…"}, "stop_bound_seconds": …, "wait_bound_seconds": …}
Nothing is started yet, and nothing needs retrying. Aetherfy keeps the request and starts
the agent as soon as the stop completes — closing the dashboard or the terminal loses
nothing. Every other start answer carries "resume": null.
stop_bound_secondsis the longest the stop can still take: how long Aetherfy takes to pick it up, the stop itself and, when a stop attempt failed and is waiting to be retried, that wait too. It is 0 once the stop is done and only the start is left (resume.stateis thenqueued).wait_bound_secondsis how long to wait for the outcome:stop_bound_secondsplus 159 seconds, Aetherfy’s pickup of the start and one full attempt at it. A start that works takes seconds.
If wait_bound_seconds passes with the agent still paused and resume still
pending or queued, the start has not failed: its compute provider refused or was
slow, and Aetherfy keeps retrying it on its own schedule. Stop waiting and read the
agent later — resume becomes null with the agent running once it starts, or
dropped, reason start_failed, if every retry fails. afy start --wait exits 4 at
that point, and the dashboard says Aetherfy is still retrying.
Follow the agent on GET /api/v1/agents/{agent}. Its resume field says what became
of the start:
resume.state | Meaning |
|---|---|
pending | Accepted; the stop is still being carried out. The agent reads paused |
queued | The stop finished — or there was none, for a start accepted on a full host (below) — and Aetherfy is starting the agent. It still reads paused |
dropped | The start was not carried out; resume.reason says why |
Once the agent is started, it reads running and resume is null. afy start --wait
follows this for you, and the dashboard shows the agent as starting once its stop
finishes — or why the start was dropped. Sending start again while one is pending
changes nothing.
resume.reason, when the start was dropped:
resume.reason | Why |
|---|---|
archived | The agent was archived |
deleted | The agent was deleted |
billing_hold | A spend-limit pause or an account suspension took the agent |
agent_failed | The agent failed: its app or its image was lost |
stop_failed | Its stop never completed, so Aetherfy did not start machines whose state it could not establish |
start_failed | Its start never completed: Aetherfy gave up after its retries |
state_changed | The agent left paused some other way |
A dropped start stays on the agent until the agent next runs, or is paused again.
Starting when a machine’s host is full
A stopped machine resumes on the host it last ran on. When that host has no room left
to resume it, start is accepted the same way, at once, instead of waiting while
Aetherfy finds the machine a new host:
POST /api/v1/agents/{agent}/start → 202 {"status": "paused", "agent_id": "…", "readiness": null, "resume": {"state": "queued", "reason": null, "requested_at": "…", "cause": "host_full"}, "stop_bound_seconds": 0, "wait_bound_seconds": 413}
Aetherfy retries for about 30 seconds, then starts a new machine from the agent’s
current release on a host that has room, and destroys the old machine once the new one
is running. That is a cold start on a new machine, not a resume of the old one.
wait_bound_seconds is 413 seconds: the pickup of the start, one attempt at it, the
retries, and one new machine, which can take up to 224 seconds more for each further
machine whose host was full.
resume.cause | Why the start was accepted |
|---|---|
host_full | A machine’s host had no room to resume it, so Aetherfy starts the agent on a new machine |
resume.cause is null for a start accepted while the previous stop finishes.
Follow the agent as above. Once it reads running, its machines_recreated says how
many of its machines were replaced this way — 0 when the retry got through and the
old machine resumed where it was — and keeps saying so until the agent is paused
again. afy start --wait names it as a cold start. If a new machine cannot be started
either, Aetherfy retries the whole start on its own schedule, keeps the agent paused
with its old machine, and resume ends dropped with reason start_failed if every
retry fails.
The latest request wins:
- A
stopwhile a start is pending cancels it and answers 202 as a pause (machinesisstoppedif the stop had already finished). The pause is your own latest request, soresumethen readsnull, notdropped. If the start is already being carried out, thestopanswersAGENT_OPERATION_IN_PROGRESS; retry it once the agent isrunning. - An archive or a delete cancels it (
archived,deleted). - If the stop fails for good, the start is not carried out: Aetherfy does not start
machines whose state it could not establish. The agent stays
pausedand the start readsdropped,stop_failed. Start it again when you want it running.
Archiving and restoring an Aetherfy agent
POST /api/v1/agents/{agent}/archive → 202 {"status": "archiving", …}
POST /api/v1/agents/{agent}/restore → 202 {"status": "restoring", …}
Archiving tears the agent’s infrastructure down and releases its quota slot, keeping its configuration and stored code. It is the way to get under your agent limit without deleting anything.
Restoring rebuilds it — and re-checks quota at that moment, because other agents may have taken the slot meanwhile. An archived agent is therefore not guaranteed to come back if you have filled your plan since.
The 202 means the restore was accepted, not that it is done. When it runs it is
checked again — the agent limit, the usage limit and payment, the stored code, the
plan and the regions — and a restore refused then leaves the agent archived with
failure_code naming the reason and the fix (see the values above). A restore that
is still running has a null failure_code.
| Code | HTTP | Meaning |
|---|---|---|
AGENT_ALREADY_ARCHIVED | 409 | |
AGENT_NOT_ARCHIVED | 409 | restore on an agent that was not archived |
AGENT_NOT_ARCHIVABLE_SYSTEM_STATE | 409 | Aetherfy owns the current state |
AGENT_HAS_PENDING_DEPLOYMENTS | 409 | |
AGENT_HAS_WORKER_DEPENDENTS | 409 | Another agent lists this one in spawn.workers. Carries dependents |
PLAN_LIMIT_EXCEEDED | 403 | On restore: no quota slot free any more |
AGENT_SAFETY_LIMIT_EXCEEDED | 403 | On restore: the account already holds the most deployed agents an account may have; no plan names it, so contact support |
Deleting an Aetherfy agent
DELETE /api/v1/agents/{agent} → 202 {"status": "deleting", "agent_id": "…"}
Deletion is permanent and asynchronous: the agent moves to deleting and a worker
tears down machines and stored code. It is refused while something still depends on
the agent.
| Code | HTTP | Meaning |
|---|---|---|
AGENT_HAS_PENDING_DEPLOYMENTS | 409 | Carries pending_deployments. Wait for active or failed |
AGENT_HAS_WORKER_DEPENDENTS | 409 | Carries dependents — the agents naming this one in spawn.workers |
Deleting is not how you free a quota slot temporarily. Archive does that reversibly.
Reading live Aetherfy machine status
GET /api/v1/agents/{agent}/status → 200
curl -s https://agents.aetherfy.com/api/v1/agents/reporter/status \
-H "Authorization: Bearer $AETHERFY_API_KEY"{
"agent_id": "6f1c2b7e-0a2d-4f8e-9c31-2b0d5a7e4411",
"name": "reporter",
"status": "running",
"url": "https://reporter-k3m7x2.aetherfy.dev",
"machines": [
{
"id": "1857a3d4f21e08",
"region": "iad",
"run_id": null,
"state": "started",
"source": "live",
"health": "ok",
"last_check": "2026-08-19T09:12:44Z",
"instance_id": "01J9…"
}
]
}This route differs from GET /agents/{agent} in one important way: it queries the
machine host directly, so machines[].state is real-time rather than whatever
Aetherfy last recorded.
Read source before trusting state. It is "live" when that machine was in
the host’s response, and "cached" when Aetherfy fell back to its own last-known
value because the host read failed. A cached reading can be up to about a minute
stale. If your automation waits for a machine to reach a state, require
source == "live" — otherwise a stale reading can satisfy the wait before the state
is actually true.
health is the last health-check reading of a started machine: ok, degraded
or unhealthy. A machine in any other state reports unknown — health checks run
only while a machine is started, so a task machine suspended between runs, or an
idle service asleep, has no reading. That is a resting machine, not a problem.
A service machine whose health check fails is taken out of rotation: requests go
only to the agent’s machines whose /health answers. If every machine of the agent
fails its check, none of them is sent a request, so a request waits and is then
answered 503. The wait is the compute plane’s own routing behaviour, not a
platform setting: we measured 37 to 51 seconds. The agent’s reason says why, with
the error its machine reports, and clears once a machine passes again. A second
region gives the agent a second machine, which keeps serving while the other fails.
url is null until the agent has machines. Destroyed machines are omitted.
run_id names the run a machine is executing right now, and is null for a machine
that is not executing one: a service’s machine, or a task machine resting between
runs. It is how to tell which machine holds a run when a task agent has several.
Exporting an Aetherfy agent’s aetherfy.yaml
GET /api/v1/agents/{agent}/yaml → 200, Content-Type: application/yaml
curl -s https://agents.aetherfy.com/api/v1/agents/reporter/yaml \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-o aetherfy.yamlThe response body is YAML, not JSON: the configuration the agent’s live release
was deployed with, as recorded at that deploy. It has every field aetherfy.yaml
owns, starts with the editor line
# yaml-language-server: $schema=https://docs.aetherfy.com/aetherfy-yaml.schema.json,
and never carries name, description or workspace. Deploying it unchanged
releases the same configuration again. It is what the dashboard’s Download YAML,
afy init --agent and afy diff read. See
the aetherfy.yaml reference.
The live release is the newest active one (a paused or stopped agent keeps it); for an archived agent it is the newest archived one, which is what a restore releases.
| Code | HTTP | Meaning |
|---|---|---|
AGENT_NOT_FOUND | 404 | No such agent, or it is being deleted |
AGENT_NOT_DEPLOYED | 404 | A draft: never released, so there is no configuration to export. Carries agent |
RELEASE_CONFIG_NOT_ON_RECORD | 422 | The live release is from before Aetherfy recorded each release’s configuration. Deploy it again from its source. Carries version |