Skip to Content
Agent computeREST: runs & schedules
Raw

Aetherfy runs, schedules and spawns 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 an agent UUID or its name throughout.

Running an Aetherfy agent on demand

POST /api/v1/agents/{agent}/run → 202

curl -s -X POST https://agents.aetherfy.com/api/v1/agents/reporter/run \ -H "Authorization: Bearer $AETHERFY_API_KEY" \ -H "Content-Type: application/json" \ -d '{"payload":{"date":"2026-08-19"}}'

The body is optional; {"payload": { … }} passes input the agent reads back through the payload route. Omit it entirely to run with no input.

{ "deployment_id": "3c9a5f10-7b2e-4d81-a6f4-19e0c8b7d224", "version": 12, "job_id": "8e41b0c7-2d15-4a93-b7e2-5f0c6a91d338" }

Both agent types can be run this way. A type: job agent runs its entrypoint; a type: service agent is sent one request to its POST /aetherfy/run route — see /agents/task-contract. The agent must already be deployed; run does not build.

A manual run and a scheduled task occurrence produce the same kind of ephemeral run, and both appear in the history below. A manual run does not touch the schedule: it does not move cron_next_run_at, and it does not count as that schedule having fired.

CodeHTTPMeaning
AGENT_NOT_DEPLOYED422Deploy the agent first
AGENT_RUN_INELIGIBLE_STATE409The status does not allow a run. Carries current_state
AGENT_RUN_CONCURRENCY_LIMIT_EXCEEDED429The account’s runs-in-flight limit is full. Same code and detail as a spawn’s, below
SOFT_CAP_EXCEEDED403A spend limit was reached; new runs are frozen

A run of an agent that already has a run in flight is not refused: a type: job agent whose machine is busy gets a machine of its own for the new run, exactly as a spawn does, and a type: service agent serves it as another request.

AGENT_RUN_INELIGIBLE_STATE names what to do in its message: a paused agent needs starting, a usage_paused one needs the spend limit raised, an archived one needs restoring, and a stopped one belongs to a suspended account — settle it and the agent resumes on its own. The same rule holds for a schedule and a spawn: an agent that cannot be run by hand is not fired by its schedule or spawned by another agent.

Listing Aetherfy run history

GET /api/v1/agents/{agent}/runs → 200, newest first.

curl -s "https://agents.aetherfy.com/api/v1/agents/reporter/runs?limit=50&trigger_source=cron" \ -H "Authorization: Bearer $AETHERFY_API_KEY"
ParameterDefaultNotes
limit20Clamped to 1–100
trigger_sourcebothcron or manual
before—The cursor of the last run you saw; returns the runs after it
[ { "id": "3c9a5f10-7b2e-4d81-a6f4-19e0c8b7d224", "trigger_source": "cron", "state": "completed", "created_at": "2026-08-19T02:00:00Z", "error_message": null, "machine_started_at": "2026-08-19T02:00:07Z", "machine_stopped_at": "2026-08-19T02:01:31Z", "duration_seconds": 84, "has_result": true, "result_error": null, "cursor": "WyIyMDI2LTA4LTE5VDAyOjAwOjAwKzAwOjAwIiw0Ml0" } ]

state is the deployment state, so a finished run reads completed and a failed one failed with error_message set. The timing fields are the machine’s real wall-clock, and duration_seconds is null until the run has both started and stopped. A run of a type: service agent holds no machine of its own, so its two machine fields are always null, and its duration_seconds runs from the moment the service’s machine accepted the run to the moment its outcome was reported.

A run’s id is also its deployment id, which is what makes the rest of the run inspectable: pass it as deployment_id to the logs route to read just that run’s output, or to the payload route to see the input it was started with.

has_result says whether the run returned a result; this history never carries the values themselves, because it can hold a hundred runs. Read the one you want from GET /deployments/{deployment_id}. result_error does ride along, since it is a short reason and finding the run that went wrong is what this list is for.

Spawned runs are deliberately excluded. Only runs this agent triggered itself — cron and manual — appear here. A run created by another agent spawning this one belongs to the parent’s story and trigger_source=spawn is not addressable on this route.

Page with before, not with an offset: pass the cursor of the last row you saw. Treat it as opaque. Runs created in the same instant can fall on either side of a page boundary, and the cursor is what places each of them on exactly one page.

CodeHTTPMeaning
AGENT_RUNS_INVALID_TRIGGER_SOURCE422Carries allowed: ["cron","manual"]
AGENT_RUNS_INVALID_BEFORE422before was not the cursor of a run from this list

Pausing and resuming an Aetherfy scheduled task

POST /api/v1/agents/{agent}/schedule/pause → 200 POST /api/v1/agents/{agent}/schedule/resume → 200

curl -s -X POST https://agents.aetherfy.com/api/v1/agents/reporter/schedule/pause \ -H "Authorization: Bearer $AETHERFY_API_KEY"
{"cron_paused": true, "cron_next_run_at": "2026-08-20T02:00:00Z", "changed": true}

Both are idempotent: pausing an already-paused schedule answers 200 with changed: false and alters nothing.

This is an operational pause, like stopping an agent — not a configuration change. The schedule stays declared in aetherfy.yaml, so deploying again re-applies what that file says, and deploying schedule: null clears the pause along with the schedule.

Resuming never backfills. Aetherfy recomputes the next occurrence from the moment you resume, so occurrences that elapsed while paused are simply not run — a task paused for a week runs once when resumed, not seven times. Resuming a schedule that was already live leaves the existing cursor untouched, so a redundant resume cannot shift the next fire.

To change when a task runs, edit the schedule: expression and redeploy; these routes only pause and resume it. See Scheduled tasks.

CodeHTTPMeaning
AGENT_SCHEDULE_NOT_SET422The agent has no schedule to pause or resume
AGENT_NOT_FOUND404
AGENT_OPERATION_IN_PROGRESS409A worker holds the agent. Transient — retry

Spawning an Aetherfy worker agent

POST /api/v1/agents/{agent}/spawn → 202

{agent} is the parent. The body names the child to start. Called with the AETHERFY_API_KEY Aetherfy injects into an agent, what this route allows is in the table of agent-scoped keys.

curl -s -X POST https://agents.aetherfy.com/api/v1/agents/orchestrator/spawn \ -H "Authorization: Bearer $AETHERFY_API_KEY" \ -H "Content-Type: application/json" \ -d '{"child_agent_id":"reporter","payload":{"customer":"acme"}}'
FieldTypeNotes
child_agent_idstringRequired. UUID or name of the agent to spawn, of either type
payloadobjectInput the child reads back at GET /deployments/{spawn_id}/payload
{ "spawn_id": "b41e77c9-58a0-4de6-9a72-3c1f8e05d6b7", "job_id": "d0f2a613-9c47-4b85-8e30-71a5c9f24e10", "child_agent_id": "9a3f0c58-6b21-4e79-bd04-8f2e1c73a065", "workspace": "research", "region": "iad", "status": "queued", "estimated_start": "2026-08-19T09:15:02Z" }

workspace is the child’s own workspace, by name; never null, since every agent lives in one. A spawn never moves the child into the parent’s workspace.

spawn_id is the child’s deployment id — the value Aetherfy injects into the child as AETHERFY_SPAWN_ID, and the one to use when reading its payload or looking the run up. A type: job child starts in the same region as its parent. A type: service child’s run goes to a region where the service has a running machine: the parent’s region when it has one there, otherwise another of its release’s regions, and region in the response says which. A service with no running machine anywhere is refused with 409 AGENT_SERVICE_NOT_RUNNING, whose message and detail.regions name the regions its release is in.

Spawning requires configuration on both sides: the parent’s aetherfy.yaml needs spawn.enabled: true and must list the child in spawn.workers (or list ["*"], meaning any of your agents), and the child must already be deployed. An empty list allows no spawns; why the list is explicit is on the aetherfy.yaml page. The child can be of either type: a type: service child’s run is a request to its POST /aetherfy/run. Spawning records the parent on the run, not on the child, so a child that has a schedule of its own keeps it. Chains are bounded by a maximum spawn depth.

CodeHTTPMeaning
AGENT_NOT_SPAWN_ENABLED403Set spawn.enabled in the parent’s aetherfy.yaml, and deploy it
AGENT_WORKER_NOT_ALLOWED403The child is not in the parent’s spawn.workers, and the list is not ["*"]. An empty list refuses every child
AGENT_SPAWN_DEPTH_INVALID400The chain is too deep
AGENT_PARENT_NOT_SPAWNABLE409The parent’s state does not allow spawning
AGENT_PARENT_PAUSED409Start the parent
AGENT_WORKER_PAUSED409Start the child
AGENT_RUN_INELIGIBLE_STATE409The child’s status does not allow a run — usage_paused, stopped, archived and the like. Carries current_state
AGENT_CHILD_NOT_DEPLOYED400Deploy the child first
AGENT_PARENT_NO_DEPLOYMENT400The parent has never deployed
AGENT_RUN_CONCURRENCY_LIMIT_EXCEEDED429Too many task runs in flight for this account
AGENT_SERVICE_NOT_RUNNING409The service child has no running machine in any region. Start or redeploy it
AGENT_SPAWN_RATE_LIMITED503A deploy of the same agent held its version lock too long. Transient — retry
SOFT_CAP_EXCEEDED403A spend limit was reached

The two throttles are different and want different handling. The 429 is your plan’s cap on task runs in flight across the whole account, and it counts every run, not only spawned ones: a run you started by hand and a run a schedule fired occupy the same budget. detail.limit reads max_in_flight_runs, with detail.max_in_flight_runs (the cap) and detail.in_flight_count (where you are) beside it, and the per-plan numbers are on Limits. It also carries where to go next, the same field the plan-limit 403 carries: detail.upgrade_url on a plan that can be upgraded, detail.support_url on Performance, and neither on Enterprise, whose cap is set on the contract. Nothing is queued and no run row is created — wait for some to finish. The 503 means another deploy of the same agent was holding its version lock when this spawn asked for one. Aetherfy serialises that allocation, so this is not a collision and nothing was corrupted — the spawn simply gave up waiting. Retry it; if the same spawn keeps being refused, a deploy on that agent is stuck rather than slow.

Reading Aetherfy agent logs

GET /api/v1/agents/{agent}/logs → 200, an array of log entries.

curl -s "https://agents.aetherfy.com/api/v1/agents/reporter/logs?tail=200&level=ERROR" \ -H "Authorization: Bearer $AETHERFY_API_KEY"
ParameterDefaultNotes
tail50Lines to return, up to 1000
since—Relative window, N followed by s, m, h or d: 45s, 30m, 1h, 7d
level—One of INFO, WARN, ERROR, DEBUG, SYSTEM
stream—stdout, stderr or system
search—Case-insensitive substring match on the message
deployment_id—Narrow to one deployment — the way to read a single run’s output
after_id / before_id—Keyset cursors on the integer id

The sort order depends on after_id. Without it you get newest-first (descending id), which is what you want for “show me the last 200 lines”. Pass after_id and the order flips to oldest-first (ascending), so that following a live agent moves forward through time. A client that assumes one order will silently reverse when it starts paging.

[ { "id": 918273, "timestamp": "2026-08-19T02:00:41Z", "stream": "stdout", "level": "INFO", "message": "report generated for acme" } ]

level buckets several stored spellings: WARN covers WARNING, ERROR covers CRITICAL and FATAL, and DEBUG covers TRACE. Those five bucket names are the only accepted values.

These are the agent’s runtime logs. Build output is a different thing and is not available through the API — see Deployments.

To read one scheduled or spawned run’s output, take the run’s id from the run history above and pass it as deployment_id.

Retention is 7 days on every plan. See Limits.

CodeHTTPMeaning
AGENT_LOGS_INVALID_SINCE400since was not a recognised duration
AGENT_LOGS_INVALID_FILTER422level or stream was not one of the accepted values
AGENT_LOGS_INVALID_DEPLOYMENT_ID422deployment_id was not a UUID
Last updated on