Route index
Every route in the spec of the release api.felix.run runs, one line each. A route a guide explains links to that section; the rest link to their operation in the OpenAPI explorer, which has the request schema and a request builder but not the response shape — every harness route returns a plain object, so the spec cannot describe one. The REST API and Management API guides are where those shapes are written down.
178 routes, 141 of them explained in a guide.
System
GET /Agent CardREST API, Well-known.well-known/ agent-card.json GET /JWKSREST API, Well-known.well-known/ jwks.json GET /Liveness — {"status":"ok","env":…,"version":…,"multi_region":false,"federation":null}REST API, Systemhealth GET /Liveness, named for what it is — the same static body as /health, no I/OREST API, Systemlive GET /Prometheus text exposition.REST API, Systemmetrics GET /Readiness. Probes the dependencies and answers 503 when one is down, so a pod with a dead database leaves rotation instead of being restartedREST API, Systemready
A2A
POST /A2A RPCExplorer, POST /a2aa2a
Approvals
GET /Approvals awaiting a decision, newest first.Management API, GET /approvalsapprovals GET /Get ApprovalExplorer, GET /approvals/{approval_id}approvals/ {approval_id} POST /Decide ApprovalManagement API, POST /approvals/{approval_id}/decideapprovals/ {approval_id}/ decide
Artifacts
GET /Get ArtifactManagement API, Artifactsartifacts/ {manifest_id}/ {artifact_id}
Audit
GET /List AuditManagement API, GET /auditaudit GET /Every matching event as JSONL, newest first — the whole range, not a page.Management API, GET /audit/exportaudit/ export GET /Roll up recent ``tool_call`` audit rows for the inspector metrics panel.Management API, GET /audit/metricsaudit/ metrics
Auth
POST /Redeem Github Actions LoginREST API, From GitHub Actionsauth/ github/ actions GET /GitHub's return. Checks `state` against this browser's flow cookie, exchanges the code, mints, and redirects back to the app with the token waiting in a one-load cookie.REST API, GitHub loginauth/ github/ callback POST /Start Github LoginREST API, GitHub loginauth/ github/ device POST /The app collects the token its sign-in left waiting, once.REST API, GitHub loginauth/ github/ exchange POST /Redeem Github LoginREST API, GitHub loginauth/ github/ token GET /Google's return. Checks `state` against this browser's flow cookie, exchanges the code, verifies the ID token, checks the allowlist, mints, and redirects back to the app with the token waiting in a one-load cookie.REST API, GitHub loginauth/ google/ callback POST /The app collects the token its sign-in left waiting, once.REST API, GitHub loginauth/ google/ exchange GET /Which ways in this deployment offers, for a client that holds no credential yet.REST API, GitHub loginauth/ methods DELETE /Forget your GitHub connection here and withdraw the App's authorization at GitHub.Explorer, DELETE /github/connectiongithub/ connection GET /Whether Felix holds a GitHub connection for you in this tenant.Explorer, GET /github/connectiongithub/ connection GET /Every stored GitHub connection in your tenant (`github:admin`).Explorer, GET /github/connectionsgithub/ connections DELETE /Revoke anyone's GitHub connection in your tenant (`github:admin`).Explorer, DELETE /github/connections/{github_user_id}github/ connections/ {github_user_id}
Threads
POST /Run a turn. With an `Idempotency-Key`, run it once per key per principal.REST API, POST /chatchat POST /Chat AbortREST API, Abort, continue, thinking, compactchat/ abort POST /Answer one question from a thread's context, leaving the thread exactly as it was.REST API, Abort, continue, thinking, compactchat/ ask POST /Chat CompactREST API, Abort, continue, thinking, compactchat/ compact POST /Resume after abort/error without a new user message (wake-based).REST API, Abort, continue, thinking, compactchat/ continue POST /Copy a thread's active branch into a new thread, recording the source as its parent.Explorer, POST /chat/forkchat/ fork DELETE /Reset the session logREST API, Sessionschat/ history/ {thread_id} GET /Flat transcript, newest window — {thread_id, messages, events, oldest_seq, has_more}REST API, Sessionschat/ history/ {thread_id} POST /Set the thread's permission mode: `default`, `plan`, `accept_edits` or `bypass`.REST API, Abort, continue, thinking, compactchat/ mode POST /Chat RewindExplorer, POST /chat/rewindchat/ rewind GET /Poll a durable chat fiber started with ``spec.execution.mode: durable``.Explorer, GET /chat/runs/{resume_token}chat/ runs/ {resume_token} GET /List sessions, newest first, one page at a time — {sessions:[…], items:[…], next_cursor}.REST API, Sessionschat/ sessions POST /{thread_id, content, in_context, metadata, role}REST API, Sessionschat/ sessions/ custom POST /{thread_id, event_id, rating: "up" \| "down" \| null, note?} — rate an assistant turnREST API, Sessionschat/ sessions/ feedback POST /{thread_id, event_id, label}REST API, Sessionschat/ sessions/ label POST /Take or renew a hold: `exclusive` drives the thread, `shared` observes it read-only.Explorer, POST /chat/sessions/leasechat/ sessions/ lease POST /Drop the one hold `token` names; every other hold stays.Explorer, POST /chat/sessions/lease/releasechat/ sessions/ lease/ release POST /{thread_id, name} — also appends a session_info eventREST API, Sessionschat/ sessions/ name GET /Postgres full-text search — {query, hits}REST API, Sessionschat/ sessions/ search GET /Authoritative snapshotREST API, Sessionschat/ sessions/ {thread_id} GET /Active branch as JSONL (application/x-ndjson, attachment)REST API, Sessionschat/ sessions/ {thread_id}/ export GET /Who holds the thread: the exclusive holder, if any, and every observer.Explorer, GET /chat/sessions/{thread_id}/leasechat/ sessions/ {thread_id}/ lease POST /Queue a steer (interrupt remaining tools) or follow-up (after idle) message.Explorer, POST /chat/steerchat/ steer POST /Run a turn as an SSE stream.REST API, POST /chat/streamchat/ stream GET /Reattach to a thread after a dropped connection or a page refresh.REST API, GET /chat/stream/{thread_id}chat/ stream/ {thread_id} POST /Set how the thread's agent writes: one of the manifest's `spec.output_styles`, or `null` for its default.REST API, Abort, continue, thinking, compactchat/ style POST /Chat ThinkingREST API, Abort, continue, thinking, compactchat/ thinking POST /Complete a client-executed tool that paused the active agent run.Explorer, POST /chat/tool_resultchat/ tool_result POST /Resolve a pending select/confirm/input prompt from the web client.Explorer, POST /chat/uichat/ ui POST /Delete one workspace file, and tell the agent.REST API, Reading and writing the workspacechat/ workspace/ delete POST /Delete one workspace folder and everything in it, and tell the agent.REST API, Reading and writing the workspacechat/ workspace/ delete_folder POST /Tell the agent the operator edited, deleted or renamed a workspace file directly.Explorer, POST /chat/workspace/editedchat/ workspace/ edited GET /One workspace file, whole, from the workspace `GET /chat/workspace/tree` lists.REST API, Reading and writing the workspacechat/ workspace/ file POST /Move one workspace file to another path in the same workspace, and tell the agent.REST API, Reading and writing the workspacechat/ workspace/ rename POST /Move one workspace folder to another path in the same workspace, and tell the agent.REST API, Reading and writing the workspacechat/ workspace/ rename_folder GET /Every file and directory in the thread's workspace, for the operator's file pane.REST API, Reading and writing the workspacechat/ workspace/ tree POST /Replace one workspace file with the operator's text, and tell the agent.REST API, Reading and writing the workspacechat/ workspace/ write
Repos
DELETE /Delete this thread's checkout.Explorer, DELETE /chat/sessions/{thread_id}/workspace/repochat/ sessions/ {thread_id}/ workspace/ repo GET /This thread's checkout: its state, and once ready, its branch, commits ahead and whether it has uncommitted changes.Explorer, GET /chat/sessions/{thread_id}/workspace/repochat/ sessions/ {thread_id}/ workspace/ repo POST /Clone a repository you can reach into this thread's checkout.Explorer, POST /chat/sessions/{thread_id}/workspace/repochat/ sessions/ {thread_id}/ workspace/ repo GET /The files in this thread's checkout — tracked, and untracked but not ignored — each with its size and git status, sorted by path.Explorer, GET /chat/sessions/{thread_id}/workspace/repo/fileschat/ sessions/ {thread_id}/ workspace/ repo/ files GET /The repositories you can open: where the App is installed and you have access.Explorer, GET /github/reposgithub/ repos
Documents
GET /Documents in this tenant's corpus, newest first.Management API, Documentsdocuments POST /Ingest or replace one document.Management API, Documentsdocuments GET /Hybrid retrieval over the corpus, with the channels that surfaced each hit.Management API, Documentsdocuments/ search DELETE /Remove a document and every chunk of it.Management API, Documentsdocuments/ {doc_id}
Eval
GET /List DatasetsManagement API, Evaleval/ datasets GET /Get DatasetManagement API, Evaleval/ datasets/ {name} PUT /Write a dataset whole — name, description and items.Management API, Evaleval/ datasets/ {name} POST /Deprecated: `POST /eval/runs` with `dataset_name` in the body starts the same run.Management API, Evaleval/ datasets/ {name}/ run GET /List Eval RunsManagement API, Evaleval/ runs POST /Start Eval RunManagement API, Evaleval/ runs POST /Comparative eval: baseline vs candidates on one dataset.Management API, Evaleval/ runs/ compare GET /Get Eval RunManagement API, Evaleval/ runs/ {run_id}
Files
POST /Store bytes and return the id a later message can reference.Management API, Filesfiles DELETE /Remove an upload.Management API, Filesfiles/ {file_id} GET /Read an upload back, base64-encoded as it was sent.Management API, Filesfiles/ {file_id}
Internal
POST /Append a queue write-back event after content screening.Explorer, POST /internal/sessions/{session_id}/eventsinternal/ sessions/ {session_id}/ events
Jobs
GET /List JobsManagement API, Jobsjobs DELETE /Delete JobManagement API, Jobsjobs/ {name} GET /Get JobManagement API, Jobsjobs/ {name} PUT /Create or replace a job. It runs as `cron` on behalf of whoever wrote it last, with their scopes: the manifest's inbound auth is checked against them on every firing, so writing a job reaches no manifest the writer could not run by asking.Management API, Jobsjobs/ {name} POST /Run a job now, without waiting for its schedule, and return the run.Management API, Jobsjobs/ {name}/ run GET /List Job RunsManagement API, Jobsjobs/ {name}/ runs
Manifests
GET /List ManifestsExplorer, GET /manifestsmanifests GET /Resolve a manifest as a request would see it.Explorer, GET /manifests/{name}manifests/ {name} PUT /Upsert ManifestManagement API, PUT /manifests/{name}manifests/ {name} DELETE /Clear CanaryManagement API, Canary and rollbackmanifests/ {name}/ canary POST /Set CanaryManagement API, Canary and rollbackmanifests/ {name}/ canary POST /Rollback ManifestManagement API, Canary and rollbackmanifests/ {name}/ rollback GET /The stored versions of a manifest, newest first — what a rollback can go back to.Explorer, GET /manifests/{name}/versionsmanifests/ {name}/ versions
MCP
GET /MCP InfoREST API, MCPmcp POST /MCP RPCREST API, MCPmcp
Memory
GET /Active memories, newest first; or, with `status=forgotten`, the forgotten ones, most recently forgotten first.Management API, Memorymemory POST /Store a memory directly.Management API, Memorymemory GET /What was believed at a past turn, including facts since superseded.Management API, Memorymemory/ as-of/ {turn_seq} GET /Hybrid recall — the same ranking the agent sees, so an operator can reproduce it.Management API, Memorymemory/ search DELETE /Hide a memory from recall.Management API, Memorymemory/ {memory_id} POST /Undo a forget: the memory is recalled again.Management API, Memorymemory/ {memory_id}/ restore
Plans
GET /Plans, most recently updated first.Management API, Plansplans DELETE /Delete PlanManagement API, Plansplans/ {plan_id} GET /Get PlanManagement API, Plansplans/ {plan_id} PUT /Upsert PlanManagement API, Plansplans/ {plan_id}
Push
DELETE /Forget this browser. Not an error when it was never subscribed.Management API, DELETE /push/subscriptionspush/ subscriptions POST /Register (or refresh) this browser.Management API, POST /push/subscriptionspush/ subscriptions GET /The application server key a browser passes to `pushManager.subscribe`.Management API, GET /push/vapid-public-keypush/ vapid-public-key
Skill library
GET /A library's skills by name -- the tenant's, or under `~{library}` a person's -- each with its live and newest version.Management API, Skill libraryskill-library POST /Save a new skill as an operator draft (version 0.1.0), and publish it if `publish`.Management API, Skill libraryskill-library GET /The skills a GitHub repository offers at one commit: every directory with a `SKILL.md` under the usual roots (`skills/`, `.claude/skills/`, Claude Code plugin layouts, …), with the name and description its frontmatter declares.Management API, Skill libraryskill-library/ -/ browse GET /Feedback across every skill in one status (`pending` by default), oldest first: the one that has waited longest is the one to read next.Management API, Skill libraryskill-library/ -/ feedback POST /Accept pending feedback. With `improve` (the default) the worker rewrites the skill from it into a draft for review; the feedback moves to `applied` with `result_version`, or to `failed` with `error`.Management API, Skill libraryskill-library/ -/ feedback/ {feedback_id}/ accept POST /Reject pending feedback, recording the note.Management API, Skill libraryskill-library/ -/ feedback/ {feedback_id}/ reject POST /Fetch the skill at `source`, pinned to the commit `ref` resolves to, and save it as a draft.Management API, Skill libraryskill-library/ -/ import GET /Every personal library in the tenant, for an administrator: whose it is, its digest -- the `~{library}` that reads or archives it -- and how many skills it holds, archived ones included.Management API, Skill libraryskill-library/ -/ personal DELETE /Drop the tenant's own policy, so the settings alone decide; returns the policy now in force.Management API, Skill libraryskill-library/ -/ policy GET /The gate every publish and rollback passes: the deployment's `FELIX_SKILL_PUBLISH_*` settings, tightened by the tenant's own policy when it has one.Management API, Skill libraryskill-library/ -/ policy PATCH /Set fields of the tenant's own publish policy; returns the policy now in force.Management API, Skill libraryskill-library/ -/ policy GET /Every draft in the tenant awaiting a decision, oldest first, across skills.Management API, Skill libraryskill-library/ -/ review GET /The tenant's imported skills, by name, each against its origin: the upstream commit, whether its files moved from the newest version's (`update_available`), and when the cooldown lets them in.Management API, Skill libraryskill-library/ -/ upstream DELETE /Take a skill out of every catalog.Management API, Skill libraryskill-library/ {name} GET /One skill and every version it holds (metadata only; files are read per version).Management API, Skill libraryskill-library/ {name} POST /Re-import an imported skill from its stored origin, exactly as `POST /-/import` would: a new draft (201), or 200 `unchanged`; `too_recent` inside the cooldown, `origin_mismatch` if the name's newest version came from elsewhere.Management API, Skill libraryskill-library/ {name}/ -/ update GET /An imported skill against its origin now: the commit the ref names, whether the kept files moved, when this tenant first saw them and when the cooldown lets them in, and a per-file diff against the live version (the newest when nothing is live).Management API, Skill libraryskill-library/ {name}/ -/ upstream GET /One skill's evaluations, newest first, optionally of one version.Management API, Skill libraryskill-library/ {name}/ evals GET /One evaluation, with each scenario's prompt, both scores and the judge's reasons.Management API, Skill libraryskill-library/ {name}/ evals/ {eval_id} GET /One skill's feedback, newest first, optionally in one status.Management API, Skill libraryskill-library/ {name}/ feedback POST /File feedback on a skill as the caller (`source: human`), on `target_version` or the live version.Management API, Skill libraryskill-library/ {name}/ feedback PUT /Save a new version of an existing skill, edited from `parent_version`.Management API, Skill libraryskill-library/ {name}/ versions GET /One version: its review record, the checks and scan findings it was saved with, and its files' digests.Management API, Skill libraryskill-library/ {name}/ versions/ {version} POST /Vouch for an imported version: save its files, byte for byte, as a new operator draft built on it that no longer carries `lineage_import`, recording who adopted it, why, and from which version (`adopted_from`).Management API, Skill libraryskill-library/ {name}/ versions/ {version}/ adopt POST /Queue an evaluation of a version; the worker runs it within a minute.Management API, Skill libraryskill-library/ {name}/ versions/ {version}/ eval GET /One file of a version, checked against the digest recorded when it was saved.Management API, Skill libraryskill-library/ {name}/ versions/ {version}/ files/ {path} GET /Re-run review and the security scan on the stored bytes and say whether the publish policy would pass them.Management API, Skill libraryskill-library/ {name}/ versions/ {version}/ preview POST /Publish a draft: it becomes the live version, and the version it replaces is archived.Management API, Skill libraryskill-library/ {name}/ versions/ {version}/ publish POST /Archive a draft without publishing it, recording the note.Management API, Skill libraryskill-library/ {name}/ versions/ {version}/ reject POST /Make a version that was once live, live again -- through the same gate as a publish, without its evaluation requirement.Management API, Skill libraryskill-library/ {name}/ versions/ {version}/ rollback GET /A library's skills by name -- the tenant's, or under `~{library}` a person's -- each with its live and newest version.Explorer, GET /skill-library/~{library}skill-library/ ~{library} POST /Save a new skill as an operator draft (version 0.1.0), and publish it if `publish`.Explorer, POST /skill-library/~{library}skill-library/ ~{library} DELETE /Take a skill out of every catalog.Explorer, DELETE /skill-library/~{library}/{name}skill-library/ ~{library}/ {name} GET /One skill and every version it holds (metadata only; files are read per version).Explorer, GET /skill-library/~{library}/{name}skill-library/ ~{library}/ {name} PUT /Save a new version of an existing skill, edited from `parent_version`.Explorer, PUT /skill-library/~{library}/{name}/versionsskill-library/ ~{library}/ {name}/ versions GET /One version: its review record, the checks and scan findings it was saved with, and its files' digests.Explorer, GET /skill-library/~{library}/{name}/versions/{version}skill-library/ ~{library}/ {name}/ versions/ {version} GET /One file of a version, checked against the digest recorded when it was saved.Explorer, GET /skill-library/~{library}/{name}/versions/{version}/files/{path}skill-library/ ~{library}/ {name}/ versions/ {version}/ files/ {path} GET /Re-run review and the security scan on the stored bytes and say whether the publish policy would pass them.Explorer, GET /skill-library/~{library}/{name}/versions/{version}/previewskill-library/ ~{library}/ {name}/ versions/ {version}/ preview POST /Propose a version of your own library to the tenant's: its files, byte for byte, saved as a draft of the tenant's skill of the name (`source: promoted`, `promoted_from` naming your version), for the tenant's ordinary review queue.Explorer, POST /skill-library/~{library}/{name}/versions/{version}/promoteskill-library/ ~{library}/ {name}/ versions/ {version}/ promote POST /Publish a draft: it becomes the live version, and the version it replaces is archived.Explorer, POST /skill-library/~{library}/{name}/versions/{version}/publishskill-library/ ~{library}/ {name}/ versions/ {version}/ publish POST /Archive a draft without publishing it, recording the note.Explorer, POST /skill-library/~{library}/{name}/versions/{version}/rejectskill-library/ ~{library}/ {name}/ versions/ {version}/ reject POST /Make a version that was once live, live again -- through the same gate as a publish, without its evaluation requirement.Explorer, POST /skill-library/~{library}/{name}/versions/{version}/rollbackskill-library/ ~{library}/ {name}/ versions/ {version}/ rollback
Skills
GET /Every skill this manifest can reach, and which are currently active.Management API, Skillsskills/ {manifest_name} GET /Which skill activated on which turn, newest first.Management API, Skillsskills/ {manifest_name}/ activations/ recent GET /One skill, including the instructions `activate_skill` would return.Management API, Skillsskills/ {manifest_name}/ {skill_name}
Triggers
POST /Receive TriggerREST API, POST /triggers/{id}triggers/ {trigger_id}
Usage
GET /Usage rows, newest first, each with the cost it was priced at.Management API, GET /usageusage GET /Spend grouped by manifest, model and UTC day, with totals.Management API, GET /usage/summaryusage/ summary GET /Spend grouped by thread over a window, most recently active first.Management API, GET /usage/threadsusage/ threads
OpenAI
POST /Chat CompletionsREST API, OpenAI-compatible surfacev1/ chat/ completions GET /List bundled + discoverable manifests as OpenAI models with Felix catalog metadata.REST API, OpenAI-compatible surfacev1/ models
Workflows
GET /The tenant's workflows, most recently saved first, without their definitions.Management API, Workflowsworkflows POST /Ports and problems for a definition, without saving it — what the editor shows as you wire.Management API, Workflowsworkflows/ -/ check GET /The step kinds a workflow can use: built in, and any a plugin registered.Management API, Workflowsworkflows/ -/ kinds GET /The tools a `tool_call` step naming `manifest` can call, with their input schemas.Management API, Workflowsworkflows/ -/ tools DELETE /Delete a workflow; with `If-Match`, only that revision.Management API, Workflowsworkflows/ {workflow_id} GET /Get WorkflowManagement API, Workflowsworkflows/ {workflow_id} PUT /Save a definition whole. `201` when this created it, `200` when it replaced one.Management API, Workflowsworkflows/ {workflow_id} GET /The workflow's runs, newest first, each with its steps' statuses.Management API, Workflowsworkflows/ {workflow_id}/ runs POST /Start a run of the workflow's current revision with `inputs`.Management API, Workflowsworkflows/ {workflow_id}/ runs GET /Get RunManagement API, Workflowsworkflows/ {workflow_id}/ runs/ {run_id} POST /Ask the run to stop: `cancelling` until the orchestrator aborts what is in flight.Management API, Workflowsworkflows/ {workflow_id}/ runs/ {run_id}/ cancel GET /The transcript of one step's child run: the snapshot `GET /chat/sessions/{id}` answers.Management API, Workflowsworkflows/ {workflow_id}/ runs/ {run_id}/ steps/ {step_id}/ thread GET /The run as it changes: a `workflow_run` frame for each new version, then `[DONE]` once over.Management API, Workflowsworkflows/ {workflow_id}/ runs/ {run_id}/ stream