HTTP API reference¶
Every endpoint the Agent Factory daemon serves over its local Unix socket, generated from the daemon's route catalog (the same table the af api command prints). This page is regenerated by scripts/gen-docs.sh and verified in CI — do not edit it by hand.
For the transport, socket path, authentication model, response envelope, and status codes, see the HTTP API guide. Run af api to print this catalog with a ready-to-run curl example for each route and the resolved socket path for your machine.
Ordinary daemon HTTP errors include optional boolean error.daemon_rejected: true. An unmarked 5xx or unfamiliar error envelope leaves a mutation's outcome uncertain; check its state before retrying. Only boolean true counts; the web client also treats 502/504 as uncertain even with a marker. The existing error.code: "mutation_committed" takes precedence over that boolean and means the mutation must not be retried. See the response envelope contract for details.
Session snapshot tabs[] records include web_proxied for web tabs: true means use the daemon proxy, false means the daemon will not proxy the target. Before direct navigation, clients must also check browser URL canonicalization: a target that still resolves to loopback must be blocked, not opened on the viewer’s machine. It is derived by session.IsLoopbackWebTarget, the same predicate the proxy checks; clients should use this decision rather than classify the URL themselves. Non-web tabs omit it, and clients of older daemons may fall back when it is absent.
CreateSession.force_remote remains accepted for compatibility with older clients. It selects the hook backend when backend is empty; an explicit backend takes precedence. New clients should use backend (for example, "hook"), as the TUI creation form does.
Endpoints¶
Request fields are the JSON keys of each route's request body; a — means the route takes no body (or an empty {}).
| Method | Path | Request fields | Description |
|---|---|---|---|
GET |
/v1/health |
— | Lifecycle health probe (alias for Ping): version, boot/transaction identity, phase, and bound listeners; answers before readiness. |
POST |
/v1/CreateSession |
title, title_base, repo_path, program, account, prompt, in_place, force_remote, backend |
Create a new session (git worktree + agent) in a repo. |
POST |
/v1/ListBackends |
repo_path |
List the runtimes a session in this repo can be created on, whether the repo's config supports each, and the backend an unspecified create defaults to. |
POST |
/v1/ListPrograms |
repo_path |
List the agent programs a session can be created with, and the program an unspecified create defaults to. |
POST |
/v1/SuggestSessionName |
— | Suggest a random, readable session name (adjective-noun) not used by any live session, for the create form's autocreate placeholder. |
POST |
/v1/Snapshot |
repo_id, live, statuses, created_after, limit |
List sessions from the daemon's authoritative in-memory state, with optional live/status, created-after, and limit filters applied before transfer (empty repo_id = all repos). |
POST |
/v1/KillSession |
title, repo_id, id |
Tear down a session: kill its tmux/agent and remove its worktree and record. |
POST |
/v1/ArchiveSession |
title, repo_id, id |
Archive a session: tear down tmux and relocate its worktree to the archive dir, keeping the record; refused before mutation when enabled tasks target it. |
POST |
/v1/RestoreArchived |
title, repo_id, id |
Restore an archived session: move its worktree back next to the repo and re-spawn the agent. |
POST |
/v1/RestoreSession |
title, repo_id, id, expected_daemon_boot_id, force_reap |
Restore an archived, Lost, or Dead session; an optional expected daemon boot ID refuses before admission if the process changed. |
POST |
/v1/SendPrompt |
title, repo_id, prompt, id |
Send a prompt to an existing session's agent. |
POST |
/v1/ResumeFromLimit |
title, repo_id, id |
Resume a usage-limit-blocked session, or explicitly retry an inspected handoff whose mission delivery was ambiguous. |
POST |
/v1/HandoffSession |
title, repo_id, id, to, account, brief |
Continue a session in place under a different agent (to), another account for the same agent (account), or both (to and account). Keep its worktree and branch, and deliver a mission brief with the goal and existing work to the replacement conversation. Omit to to keep the current agent. |
POST |
/v1/DeleteProject |
repo_path, repo_id |
Delete a project (a repo's session grouping): archive its live sessions (restorable), tear down in-place ones, and drop its root_agents opt-in — the real git repo is untouched. |
POST |
/v1/RegisterProject |
path |
Register a git checkout as a durable, sessionless project by path (expand ~, resolve the git root, validate, persist to the registry) — resolved on the daemon's filesystem, idempotent for a known checkout. |
POST |
/v1/ListProjects |
— | List every durable project in the daemon's registry (id, last-known root, path_exists) — the read a web/TUI client unions with its derived project list. |
POST |
/v1/ListDirectory |
path |
List the child DIRECTORIES of one directory on the daemon's filesystem, marking which are git checkouts — the read behind an Add-project picker. Resolves ~ and symlinks and answers with canonical paths; an unreadable directory is an error, never an empty list. |
POST |
/v1/DeliverPrompt |
title, repo_path, program, prompt, defer_while_attached |
Deliver a prompt to a session, auto-creating it if it does not exist yet. |
POST |
/v1/CreateTab |
title, repo_id, command, name, shell, kind, url, port, id |
Spawn a tab in a session: a process tab (command) or shell tab in the worktree, a web tab (kind=web) that iframes a url/port (localhost is daemon-proxied, external is direct), or a VS Code tab (kind=vscode) serving the session's worktree in a daemon-managed code-server (no url/port: the worktree is the target). |
POST |
/v1/CloseTab |
title, repo_id, tab_name, tab_index, id, tab_id |
Close a non-agent tab of a session (the agent tab cannot be closed). Address the tab by tab_id (its stable id) when you have one: it wins over tab_name/tab_index, which name a tab that may since have been closed and had its name or slot reused. A tab_id that no longer resolves is refused rather than falling back — closing is destructive, so a misroute kills the wrong tab's session. |
POST |
/v1/RenameTab |
title, repo_id, tab_name, tab_index, new_name, id, tab_id |
Rename a tab of a session. Only web, process and VS Code tabs can be renamed — agent and shell tabs render fixed labels. The name is sanitized and made unique, so the resolved name is returned. Address the tab by tab_id (its stable id) when you have one: it wins over tab_name/tab_index, which name a tab that may since have been closed and had its name or slot reused. A tab_id that no longer resolves is refused rather than falling back. |
POST |
/v1/ReorderTab |
title, repo_id, tab_name, tab_index, new_index, id, tab_id |
Move a tab within a session's roster. Index 0 is reserved for the agent tab, so only slots 1..n-1 can be moved or targeted. Address the tab by tab_id (its stable id) when you have one — see RenameTab; it matters most here, since a reorder is what invalidates every other client's tab_index. |
POST |
/v1/ListAccounts |
agent, repo_path |
List the agent accounts registered in the daemon host's agent-factory home, each with its logged-in state (read from the presence of the agent's own credential file, never its contents), plus the agents an account can be registered for. |
POST |
/v1/RegisterAccount |
agent, name |
Create an agent account's credential directory on the daemon host without logging in — idempotent, and the register half of the accounts UI. Log in to it with AccountLogin. |
POST |
/v1/AccountLogin |
agent, name |
Open an agent's OWN login flow (claude auth login / codex login / gemini) in a bare tmux session scoped to one registered account: the account's credential directory injected, every ambient identity variable removed. Registers the account if it does not exist. Returns the tmux session and socket to attach to, and the account's logged-in state read from the agent's own credential file. af never reads, stores, or forwards the credential. |
POST |
/v1/GetConfig |
— | List every user-facing global config key with its purpose, type, default, and current value. |
POST |
/v1/SetConfigValue |
key, value |
Set one global config key, exactly as af config set does (validated, locked, atomic). |
POST |
/v1/UnsetConfigValue |
key |
Clear one migrated global backend setting, exactly as af config unset does (both alias spellings, atomically). |
POST |
/v1/ListOnComplete |
— | List task spawned-session lifecycle choices and consequences, least destructive first. |
POST |
/v1/ListTasks |
— | List every task across all repos. |
POST |
/v1/AddTask |
task, actor |
Append a new task and re-arm the scheduler; an enabled archived/archiving target_session is refused before commit. |
POST |
/v1/UpdateTask |
id, update, expect, actor |
Apply a field-level patch to a task (only the fields in update are changed), preserving every unspecified field and the scheduler-owned fields; an enabled archived/archiving target_session is refused before commit. |
POST |
/v1/RemoveTask |
id, expect |
Remove a task by ID. |
POST |
/v1/RestartTask |
id, expect |
Stop and replace one enabled watch task without overlapping its process tree. |
POST |
/v1/TriggerTask |
id, expect |
Fire a cron task now through the daemon's scheduler path (refuses disabled and watch tasks). |
Nested request payloads¶
The Request fields column above lists each body's TOP-LEVEL keys. Where one of those is an object, its own keys are listed here as dotted paths, so a request can be constructed from this page alone.
| Path | Nested fields |
|---|---|
/v1/AddTask |
task.id, task.name, task.prompt, task.cron_expr, task.watch_cmd, task.target_session, task.max_concurrent_runs, task.on_complete, task.project_path, task.repo_id, task.program, task.enabled, task.created_at, task.last_run_at, task.last_run_status, task.dropped_events, task.audit, task.overdue, task.missed_occurrences, task.missed_occurrences_capped, task.unschedulable, task.unschedulable_reason, task.unassessable, task.next_run_at, task.arming, task.ordinal, task.store_generation |
/v1/UpdateTask |
update.name, update.prompt, update.cron_expr, update.watch_cmd, update.target_session, update.max_concurrent_runs, update.on_complete, update.project_path, update.program, update.enabled, expect.enforce, expect.project_path |
/v1/RemoveTask |
expect.enforce, expect.project_path |
/v1/RestartTask |
expect.enforce, expect.project_path |
/v1/TriggerTask |
expect.enforce, expect.project_path |