> ## Documentation Index
> Fetch the complete documentation index at: https://docs.litmus.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Agents

> Your agent as a record Litmus can run: how it is reached, its versions and its environment.

38 routes. Every example runs with `LITMUS_URL`, `LITMUS_TOKEN` and `LITMUS_ORG` (your org tag) set in your shell (see [Authentication](/authentication)). A `$NAME` in a path is an id you read from the listing route on this page; a `<field>` in a body is a value you supply, and every field the handler reads is shown, so send only the ones you need. Fields are what the handler's source reads and writes, listed mechanically; they are not a schema.

| Method | Path | Scope |
| - | - | - |
| GET | `/v0/orgs/{orgtag}/agents` | `read` |
| POST | `/v0/orgs/{orgtag}/agents` | `push` |
| POST | `/v0/orgs/{orgtag}/agents/first` | `push` |
| GET | `/v0/orgs/{orgtag}/agents/{aid}` | `read` |
| PATCH | `/v0/orgs/{orgtag}/agents/{aid}` | `push` |
| DELETE | `/v0/orgs/{orgtag}/agents/{aid}` | `push` |
| POST | `/v0/orgs/{orgtag}/agents/{aid}/retire` | `push` |
| POST | `/v0/orgs/{orgtag}/agents/{aid}/probe` | `push` |
| POST | `/v0/orgs/{orgtag}/agents/{aid}/smoke` | `push` |
| POST | `/v0/orgs/{orgtag}/agents/{aid}/onboard` | `push` |
| POST | `/v0/orgs/{orgtag}/agents/{aid}/discover` | `push` |
| GET | `/v0/orgs/{orgtag}/agents/{aid}/touched-coverage` | `read` |
| GET | `/v0/orgs/{orgtag}/agents/{aid}/discoveries` | `read` |
| POST | `/v0/orgs/{orgtag}/agents/{aid}/primary` | `push` |
| POST | `/v0/orgs/{orgtag}/agents/{aid}/detect` | `push` |
| POST | `/v0/orgs/{orgtag}/agents/{aid}/scan` | `push` |
| POST | `/v0/orgs/{orgtag}/agents/{aid}/server-repo` | `push` |
| POST | `/v0/orgs/{orgtag}/agents/{aid}/server-refs` | `push` |
| GET | `/v0/orgs/{orgtag}/agents/{aid}/server-tools/{sha}` | `read` |
| POST | `/v0/orgs/{orgtag}/agents/{aid}/main` | `push` |
| GET | `/v0/orgs/{orgtag}/agents/{aid}/write-path` | `read` |
| POST | `/v0/orgs/{orgtag}/agents/{aid}/write-path` | `push` |
| POST | `/v0/orgs/{orgtag}/agents/{aid}/write-path/accept` | `push` |
| POST | `/v0/orgs/{orgtag}/agents/{aid}/versions` | `push` |
| PATCH | `/v0/orgs/{orgtag}/agents/{aid}/versions/{version}` | `push` |
| GET | `/v0/orgs/{orgtag}/agents/{aid}/versions/{version:path}/changes` | `read` |
| POST | `/v0/orgs/{orgtag}/agents/{aid}/versions/{version:path}/changes` | `push` |
| POST | `/v0/orgs/{orgtag}/agents/{aid}/versions/{version:path}/skills` | `push` |
| POST | `/v0/orgs/{orgtag}/agents/{aid}/versions/{version:path}/tool-texts` | `push` |
| GET | `/v0/orgs/{orgtag}/agent-env` | `admin` |
| PUT | `/v0/orgs/{orgtag}/agent-env/{name}` | `admin` |
| DELETE | `/v0/orgs/{orgtag}/agent-env/{name}` | `admin` |
| POST | `/v0/orgs/{orgtag}/github/installations` | `push` |
| GET | `/v0/orgs/{orgtag}/github/installation` | `read` |
| POST | `/v0/orgs/{orgtag}/github/installation` | `push` |
| GET | `/v0/orgs/{orgtag}/github/repositories` | `read` |
| GET | `/v0/orgs/{orgtag}/github/refs` | `read` |
| GET | `/v0/orgs/{orgtag}/github/unrecorded` | `read` |

## `GET /v0/orgs/{orgtag}/agents`

This org's agents: the connected rows, then the built-in harnesses.

| | |
| - | - |
| Token scope | `read` (any org token) |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents"]["GET"]` |
| CLI | `litmus-ai experiment` |

**Path parameters:** `orgtag`

**Query parameters the handler or its helper reads:** `retired`

**Response fields written in the helper the handler answers through:** `as_of`, `behind` (added to a stored record whose own keys are not in the source)

```bash theme={null}
curl -sS "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents" \
  -H "Authorization: Bearer $LITMUS_TOKEN"
```

## `POST /v0/orgs/{orgtag}/agents`

Connect an agent: `{kind, name, version?, command | url | repo fields, token_env?, env?, model?, notes?}`.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`

**Body fields the handler or its helper reads:** `adapter`, `command`, `egress`, `env`, `kind`, `model`, `name`, `notes`, `run`, `token_env`, `url`, `version`

**Response fields written in the handler:** `job`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"adapter": "<adapter>", "command": "<command>", "egress": "<egress>", "env": "<env>", "kind": "<kind>", "model": "<model>", "name": "<name>", "notes": "<notes>", "run": "<run>", "token_env": "<token_env>", "url": "<url>", "version": "<version>"}'
```

## `POST /v0/orgs/{orgtag}/agents/first`

The org's first agent, written if it has none.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/first"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`

**Response fields written in the handler:** `agent`, `agents`, `created`, `org`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/first" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## `GET /v0/orgs/{orgtag}/agents/{aid}`

One agent: its versions, the groups it ran, and where its traces are.

| | |
| - | - |
| Token scope | `read` (any org token) |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}"]["GET"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Response fields written in the handler:** `agent`, `groups`, `langfuse`

```bash theme={null}
curl -sS "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID" \
  -H "Authorization: Bearer $LITMUS_TOKEN"
```

## `PATCH /v0/orgs/{orgtag}/agents/{aid}`

Change an agent, or pin a new version of it.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}"]["PATCH"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Body fields the handler or its helper reads:** `adapter`, `command`, `egress`, `env`, `model`, `name`, `notes`, `ref`, `run`, `setup`, `token_env`, `url`, `version`

**Response:** JSON: a stored record or a helper's result, answered as it is, so its keys are not written in the source and none are listed.

This call changes state in the org.

```bash theme={null}
curl -sS -X PATCH "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"adapter": "<adapter>", "command": "<command>", "egress": "<egress>", "env": "<env>", "model": "<model>", "name": "<name>", "notes": "<notes>", "ref": "<ref>", "run": "<run>", "setup": "<setup>", "token_env": "<token_env>", "url": "<url>", "version": "<version>"}'
```

## `DELETE /v0/orgs/{orgtag}/agents/{aid}`

Disconnect an agent.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}"]["DELETE"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Response fields written in the handler:** `deleted`, `kept`

This call changes state in the org.

```bash theme={null}
curl -sS -X DELETE "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID" \
  -H "Authorization: Bearer $LITMUS_TOKEN"
```

## `POST /v0/orgs/{orgtag}/agents/{aid}/retire`

Retire an agent, or restore one: `POST …/agents/{aid}/retire`, body `{retired: bool, by?}`.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/retire"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Body fields the handler or its helper reads:** `by`, `retired`

**Response fields written in the handler:** `agent`, `kept`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/retire" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"by": "<by>", "retired": "<retired>"}'
```

## `POST /v0/orgs/{orgtag}/agents/{aid}/probe`

Ask the agent one fixture question, and store the shape of its answer.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/probe"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Body fields the handler or its helper reads:** `version`

**Response fields written in the handler:** `agent`, `job`, `note`, `poll`, `probe`, `stages`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/probe" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"version": "<version>"}'
```

## `POST /v0/orgs/{orgtag}/agents/{aid}/smoke`

One trial of the agent on the fixture household: the connect step's smoke.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/smoke"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Body fields the handler or its helper reads:** `version`

**Response fields written in the handler:** `accepted_ms`, `agent`, `job`, `note`, `poll`, `stages`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/smoke" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"version": "<version>"}'
```

## `POST /v0/orgs/{orgtag}/agents/{aid}/onboard`

POST /v0/orgs/\{org}/agents/\{aid}/onboard — `{version?, against?, surface?, tasks?, allow_cannot?, environments?}`, and for a surface agent the change to its surface: `{description_overrides?, added_tools?, removed_tools?, redeclared_tools?, origin?, by?}` — an added tool is `{name, description, input_schema, behaviour}`, compiled deterministically from its declared behaviour; a redeclared tool is `{name, behaviour, description?}`, an EXISTING tool whose function is replaced by its declared one (e.g. `rows_by_match`: rows the world holds, by a fixed query), stamped `tools_redeclared` and named in the surface diff; `origin` is `{kind: operator_edit|declared|branch, ref?, repo?, sha?}`, stored as a field on B's stamp and the version's ready row. One job from a connected version to "ready: run it vs the last version on n shared tasks".

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/onboard"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Body fields the handler or its helper reads:** `added_tools`, `against`, `allow_cannot`, `by`, `description_overrides`, `environments`, `origin`, `redeclared_tools`, `removed_tools`, `surface`, `tasks`, `version`

**Response fields written in the helper the handler answers through:** `against`, `agent`, `job`, `note`, `poll`, `stages`, `version`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/onboard" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"added_tools": "<added_tools>", "against": "<against>", "allow_cannot": "<allow_cannot>", "by": "<by>", "description_overrides": "<description_overrides>", "environments": "<environments>", "origin": "<origin>", "redeclared_tools": "<redeclared_tools>", "removed_tools": "<removed_tools>", "surface": "<surface>", "tasks": "<tasks>", "version": "<version>"}'
```

## `POST /v0/orgs/{orgtag}/agents/{aid}/discover`

Ask a connected agent version a few tasks against a surface this org serves, and store which operations it used and who answered each.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/discover"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Body fields the handler or its helper reads:** `surface`, `tasks`, `version`

**Response fields written in the handler:** `agent`, `job`, `note`, `poll`, `stages`, `surface`, `tasks`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/discover" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"surface": "<surface>", "tasks": "<tasks>", "version": "<version>"}'
```

## `GET /v0/orgs/{orgtag}/agents/{aid}/touched-coverage`

GET /v0/orgs/\{org}/agents/\{aid}/touched-coverage?version=\&tools=\&set=\&group= — before any B run: which tools a surface change touches, how many of the set's tasks call each, which production calls (when the Datadog grammar holds them), and the tasks to generate for the gap, priced. A read: nothing runs and nothing is written; the gap plan's confirm is `POST …/environments/{id}/tasks {count, tool}`, once per row.

| | |
| - | - |
| Token scope | `read` (any org token) |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/touched-coverage"]["GET"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Response:** JSON: a stored record or a helper's result, answered as it is, so its keys are not written in the source and none are listed.

```bash theme={null}
curl -sS "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/touched-coverage" \
  -H "Authorization: Bearer $LITMUS_TOKEN"
```

## `GET /v0/orgs/{orgtag}/agents/{aid}/discoveries`

This agent's discover runs, newest first.

| | |
| - | - |
| Token scope | `read` (any org token) |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/discoveries"]["GET"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Response fields written in the handler:** `agent`, `discoveries`

```bash theme={null}
curl -sS "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/discoveries" \
  -H "Authorization: Bearer $LITMUS_TOKEN"
```

## `POST /v0/orgs/{orgtag}/agents/{aid}/primary`

Make this agent the org's primary: `POST /v0/orgs/{org}/agents/{aid}/primary`, body `{by?}`. The Agents page's one "Make primary" control; a sandbox's Run and the Runner default to it. A built-in harness is not an agent this org connected, so it cannot be made primary.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/primary"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Body fields the handler or its helper reads:** `by`

**Response fields written in the handler:** `primary_agent`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/primary" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"by": "<by>"}'
```

## `POST /v0/orgs/{orgtag}/agents/{aid}/detect`

Read the repository again and probe what it proposes.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/detect"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Response fields written in the handler:** `agent`, `job`, `poll`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/detect" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## `POST /v0/orgs/{orgtag}/agents/{aid}/scan`

Scan for new versions of this agent now: `POST /v0/orgs/{org}/agents/{aid}/scan`, body `{paths?, cadence?}`.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/scan"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Body fields the handler or its helper reads:** `cadence`, `paths`

**Response fields written in the handler:** `agent`, `job`, `poll`, `stages`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/scan" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"cadence": "<cadence>", "paths": "<paths>"}'
```

## `POST /v0/orgs/{orgtag}/agents/{aid}/server-repo`

POST /v0/orgs/\{org}/agents/\{aid}/server-repo — `{url, ref?, paths?, listing?, run?, setup?, upstream_env?}`. A surface agent names the repository its MCP server lives in: `ref` is the base branch (what the served surface A stands for, default `main`), `paths` the tool definitions a commit must touch to count, `listing` a static `tools/list` file. Read through the org's Litmus GitHub App installation for the owner (contents: read) — derived here from the org in the path. The base is resolved to a commit once, now; nothing is built or run.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/server-repo"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Body fields the handler or its helper reads:** `listing`, `paths`, `ref`, `run`, `setup`, `upstream_env`, `url`

**Response fields written in the handler:** `agent`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/server-repo" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"listing": "<listing>", "paths": "<paths>", "ref": "<ref>", "run": "<run>", "setup": "<setup>", "upstream_env": "<upstream_env>", "url": "<url>"}'
```

## `POST /v0/orgs/{orgtag}/agents/{aid}/server-refs`

POST /v0/orgs/\{org}/agents/\{aid}/server-refs — `{ref, behaviours?, by?, supersedes?}`. The ref of the server repository — a branch, tag, commit or pull request (`refs/pull/<n>/head`, `pull/<n>`) — becomes a surface version: its tool listing is read (`serverref.read_change`: the served build, else a static listing file, else the tool definitions in its source, else one model call over the diff, tier `llm-derived`), stored by commit with the fork point's, the head's ancestry to the base recorded as `merge`, diffed from where the branch forked from the base to its head, and applied to A — changed descriptions as overrides, added tools from their declared behaviour, removed tools dropped — through the surface onboard, `origin: {kind: branch, ref, repo, sha}`. An added tool with no behaviour (the listing's, or `behaviours: {tool: line}`) stores the version `needs_behaviour` and compiles nothing. A head the base already reaches is `merged` and compiles nothing. `supersedes` names a declared version this branch replaces: it stays listed, reads "declared from the customer's description, superseded", and is no longer makeable main. 202 with the onboard's job; 200 when there is nothing to ready yet.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/server-refs"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Body fields the handler or its helper reads:** `behaviours`, `by`, `ref`, `supersedes`

**Response fields written in the helper the handler answers through:** `agent`, `job`, `poll`, `same`, `surface_version` (added to a stored record whose own keys are not in the source)

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/server-refs" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"behaviours": "<behaviours>", "by": "<by>", "ref": "<ref>", "supersedes": "<supersedes>"}'
```

## `GET /v0/orgs/{orgtag}/agents/{aid}/server-tools/{sha}`

GET /v0/orgs/\{org}/agents/\{aid}/server-tools/\{sha} — the tool definitions read from the server repository at one commit (`main` for main's): `{sha, reader, count, tools: [{name, description, input_schema, data_source?}]}`, as a deterministic reader read them. 404 for a commit no reader read.

| | |
| - | - |
| Token scope | `read` (any org token) |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/server-tools/{sha}"]["GET"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`, `sha`

**Response:** JSON: a stored record or a helper's result, answered as it is, so its keys are not written in the source and none are listed.

```bash theme={null}
curl -sS "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/server-tools/$SHA" \
  -H "Authorization: Bearer $LITMUS_TOKEN"
```

## `POST /v0/orgs/{orgtag}/agents/{aid}/main`

POST /v0/orgs/\{org}/agents/\{aid}/main — `{version, by?}`. Make a declared version of a surface agent's tools its MAIN version: the one the next change is applied to and the one the page says is live. `version` is the agent version the declared row was readied on, or the row's surface id; `base` (or the connected tools' surface id) makes the tools it was connected on main again. The main it replaces stays listed, "was main until ‹date›". Nothing is re-served and no model is called: the declared version's tools are already ready.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/main"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Body fields the handler or its helper reads:** `by`, `version`

**Response fields written in the handler:** `agent`, `main`, `same`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/main" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"by": "<by>", "version": "<version>"}'
```

## `GET /v0/orgs/{orgtag}/agents/{aid}/write-path`

The agent's write path by tool: `GET /v0/orgs/{org}/agents/{aid}/write-path`. The last count's lines, their coverage ("over B of T batches"), the threshold, the proposals, and the count running now if one is. Reads one small record; never a trace.

| | |
| - | - |
| Token scope | `read` (any org token) |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/write-path"]["GET"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Query parameters the handler or its helper reads:** `audience`

**Response fields written in the helper the handler answers through:** `accepted`, `agent`, `counted`, `counted_at`, `job`, `org`, `running`, `threshold`, `tier` (added to a stored record whose own keys are not in the source)

```bash theme={null}
curl -sS "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/write-path" \
  -H "Authorization: Bearer $LITMUS_TOKEN"
```

## `POST /v0/orgs/{orgtag}/agents/{aid}/write-path`

Count the agent's write path by tool now: `POST /v0/orgs/{org}/agents/{aid}/write-path`. A job (`write_path`) reads every stored trace batch of the org one at a time and stores the lines the page reads. No model call. 202 with the job to follow; 409 while one is running.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/write-path"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Response fields written in the handler:** `job`, `model_calls`, `poll`, `stages`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/write-path" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## `POST /v0/orgs/{orgtag}/agents/{aid}/write-path/accept`

Record one proposal as a known failure mode: `POST /v0/orgs/{org}/agents/{aid}/write-path/accept`, `{tool, by}`. The mode the last count proposed for `tool`, stored through the failure-modes route's own checks (`failuremodes.body_of`, `feedback.prepare`) in the name of who confirmed it. No model call. A tool the count did not propose is refused by name; a second accept is a duplicate, not a second mode. The task in the bucket is the next step, and it is the one that calls a model (`next`).

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/write-path/accept"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Body fields the handler or its helper reads:** `author_member`, `by`, `tool`, `visibility`

**Response fields written in the handler:** `agent`, `duplicate`, `mode`, `model_calls`, `next`, `org`, `stored`, `tool`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/write-path/accept" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"author_member": "<author_member>", "by": "<by>", "tool": "<tool>", "visibility": "<visibility>"}'
```

## `POST /v0/orgs/{orgtag}/agents/{aid}/versions`

Add a version of a repository agent from a ref: `POST …/agents/{aid}/versions`, body `{ref, by?}` — or of an http agent by its label: `{version, url?, by?}`, the endpoint only when it changed.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/versions"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`

**Body fields the handler or its helper reads:** `by`

**Response fields written in the handler:** `agent`, `version`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/versions" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"by": "<by>"}'
```

## `PATCH /v0/orgs/{orgtag}/agents/{aid}/versions/{version}`

Retire a version, or restore one: `PATCH …/agents/{aid}/versions/{version}`, body `{retired: bool, by?}`.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/versions/{version}"]["PATCH"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`, `version`

**Body fields the handler or its helper reads:** `by`, `retired`

**Response:** JSON: a stored record or a helper's result, answered as it is, so its keys are not written in the source and none are listed.

This call changes state in the org.

```bash theme={null}
curl -sS -X PATCH "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/versions/$VERSION" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"by": "<by>", "retired": "<retired>"}'
```

## `GET /v0/orgs/{orgtag}/agents/{aid}/versions/{version:path}/changes`

GET /v0/orgs/\{org}/agents/\{aid}/versions/\{version}/changes — what a tracked version of the server repository changes, by file, as it was read once and kept on the version record: `{version, changes?: {base, head, files, names, areas: {tools, handlers, skills, registration, other}, by_area, statuses, additions, deletions, reader, tier, line}}`. `version` is the version's name ("tools v3"), its ref or its commit. A version no repository ref made — a declared one, or main — answers with no `changes` and its `line`, never an error; a tracked one not read yet says so the same way. File names and counts only: no file's contents.

| | |
| - | - |
| Token scope | `read` (any org token) |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/versions/{version:path}/changes"]["GET"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`, `version`

**Response fields written in the helper the handler answers through:** `changes`, `version` (added to a stored record whose own keys are not in the source)

```bash theme={null}
curl -sS "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/versions/$VERSION/changes" \
  -H "Authorization: Bearer $LITMUS_TOKEN"
```

## `POST /v0/orgs/{orgtag}/agents/{aid}/versions/{version:path}/changes`

POST /v0/orgs/\{org}/agents/\{aid}/versions/\{version}/changes — read the changed-file list between a tracked version's fork point and its head through the org's installed GitHub App (`GET /repos/{o}/{r}/compare/ {base}...{head}`, a token minted for that one repository with `contents: read`, never returned or logged) and keep it on the version record. Read ONCE: a version already read answers what is kept with `same: true`. Areas are the declared path table in `versionchanges.AREAS`; no model call, \$0. A repository the installation does not cover is a 409 `not_covered`; a version no repository ref made answers with no `changes` and its `line`, and nothing is written.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/versions/{version:path}/changes"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`, `version`

**Response fields written in the helper the handler answers through:** `changes`, `version` (added to a stored record whose own keys are not in the source)

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/versions/$VERSION/changes" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## `POST /v0/orgs/{orgtag}/agents/{aid}/versions/{version:path}/skills`

POST /v0/orgs/\{org}/agents/\{aid}/versions/\{version}/skills — `{ref, paths?}`: register "main's tools + this version's skills". Each listed skill file is read at the commit the version names, through the org's installed GitHub App (`GET /repos/{o}/{r}/contents/{path}?ref= {sha}`, a token minted for that one repository with `contents: read`, never returned or logged), kept as one of the org's documents, and pinned by sha on a new agent version whose tools are main's. `paths` defaults to the skill files the version's kept changed-file list names. Refused: a path outside a `skills/` directory (422 `outside_skills`), a ref the version does not name (409 `ref_not_named`), a repository the installation does not cover (409 `not_covered`); the read answers GET only, so it never writes to git. The same files at the same commit on the same tools answer the arm already kept with `same: true`. Answers `{arm, row}` — names, refs, shas and counts; never a file's text. No model call, \$0.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/versions/{version:path}/skills"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`, `version`

**Body fields the handler or its helper reads:** `paths`, `ref`

**Response fields written in the handler:** `arm`, `row`, `same`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/versions/$VERSION/skills" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"paths": "<paths>", "ref": "<ref>"}'
```

## `POST /v0/orgs/{orgtag}/agents/{aid}/versions/{version:path}/tool-texts`

POST /v0/orgs/\{org}/agents/\{aid}/versions/\{version}/tool-texts — `{by, dry_run?}`: carry a tracked version's MCP tool texts onto the served API tools their data source names, as a STAND-IN beside a control. From main's stored source definitions and the version's (`server-tools/{sha}`), each MCP tool's `data_source` routes are matched to the routes the run's door recorded for its tools (`contract.json`); the set is every served tool an MCP tool whose description differs between main and the ref reaches, and each one's description is the texts of every MCP tool that calls it, sorted by name and prefixed by it — main's texts for the control, the ref's for the arm (`tooltexts.plan`). Unless `dry_run`, both are compiled through the onboard's compile (`description_overrides`, `origin {kind: declared, ref, sha}`) and re-served on main's standing environments in one job; each is then a version a re-run moves to (`runs/start {group, agent_version: sfv-…}`), labelled "main's tool texts on the run's tools (stand-in)" and "‹ref›'s tool texts on the run's tools (stand-in)". The same commit pair answers the kept pair with `same: true`. Refused: a version with no stored source definitions (`no_source`), a ref that changes no description (`no_description_change`), texts that reach no served tool (`nothing_reached`, `no_routes`). Answers counts and tool NAMES only — `{reached, carried, not_carried: {schema, data_source, no_served_route, added, removed}, control, arm}` — never a description. No model call, \$0.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agents/{aid}/versions/{version:path}/tool-texts"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`, `aid`, `version`

**Body fields the handler or its helper reads:** `by`, `dry_run`

**Response fields written in the handler:** `code`, `error`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agents/$AID/versions/$VERSION/tool-texts" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"by": "<by>", "dry_run": "<dry_run>"}'
```

## `GET /v0/orgs/{orgtag}/agent-env`

The names this org has set, who set each and when — never a value.

| | |
| - | - |
| Token scope | `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agent-env"]["GET"]` |
| CLI | — |

**Path parameters:** `orgtag`

**Response fields written in the handler:** `env`, `org`, `prefix`, `tier`

```bash theme={null}
curl -sS "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agent-env" \
  -H "Authorization: Bearer $LITMUS_TOKEN"
```

## `PUT /v0/orgs/{orgtag}/agent-env/{name}`

Set one value, `{value}`. Answers the name and who set it, not the value.

| | |
| - | - |
| Token scope | `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agent-env/{name}"]["PUT"]` |
| CLI | — |

**Path parameters:** `orgtag`, `name`

**Body fields the handler or its helper reads:** `by`, `value`

**Response fields written in the handler:** `org`, `set`

This call changes state in the org.

```bash theme={null}
curl -sS -X PUT "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agent-env/$NAME" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"by": "<by>", "value": "<value>"}'
```

## `DELETE /v0/orgs/{orgtag}/agent-env/{name}`

Remove one value. 404 for a name the org never set.

| | |
| - | - |
| Token scope | `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/agent-env/{name}"]["DELETE"]` |
| CLI | — |

**Path parameters:** `orgtag`, `name`

**Response fields written in the handler:** `deleted`, `org`

This call changes state in the org.

```bash theme={null}
curl -sS -X DELETE "$LITMUS_URL/v0/orgs/$LITMUS_ORG/agent-env/$NAME" \
  -H "Authorization: Bearer $LITMUS_TOKEN"
```

## `POST /v0/orgs/{orgtag}/github/installations`

Record a Litmus GitHub App installation on this org: `{installation_id, account_login?}`.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/github/installations"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`

**Body fields the handler or its helper reads:** `account_login`, `by`, `installation_id`, `setup_action`

**Response fields written in the handler:** `github_app`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/github/installations" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"account_login": "<account_login>", "by": "<by>", "installation_id": "<installation_id>", "setup_action": "<setup_action>"}'
```

## `GET /v0/orgs/{orgtag}/github/installation`

The installations this org references: `{org, installations: [{installation_id, account, account_type}]}`.

| | |
| - | - |
| Token scope | `read` (any org token) |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/github/installation"]["GET"]` |
| CLI | — |

**Path parameters:** `orgtag`

**Response fields written in the handler:** `installations`, `org`, `tier`

```bash theme={null}
curl -sS "$LITMUS_URL/v0/orgs/$LITMUS_ORG/github/installation" \
  -H "Authorization: Bearer $LITMUS_TOKEN"
```

## `POST /v0/orgs/{orgtag}/github/installation`

Reference, from this org, an installation an org the caller acts for already holds: `{installation_id, from_org?}`.

| | |
| - | - |
| Token scope | `push` or `admin` |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/github/installation"]["POST"]` |
| CLI | — |

**Path parameters:** `orgtag`

**Body fields the handler or its helper reads:** `by`, `from_org`, `installation_id`

**Response fields written in the handler:** `github_app`

This call changes state in the org.

```bash theme={null}
curl -sS -X POST "$LITMUS_URL/v0/orgs/$LITMUS_ORG/github/installation" \
  -H "Authorization: Bearer $LITMUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"by": "<by>", "from_org": "<from_org>", "installation_id": "<installation_id>"}'
```

## `GET /v0/orgs/{orgtag}/github/repositories`

The repositories this org's Litmus GitHub App installations cover: `{org, installations: [{account, installation_id, repositories: [{full_name, clone_url, default_branch, private, pushed_at}], refusal}]}`.

| | |
| - | - |
| Token scope | `read` (any org token) |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/github/repositories"]["GET"]` |
| CLI | — |

**Path parameters:** `orgtag`

**Response fields written in the handler:** `installations`, `org`, `tier`

```bash theme={null}
curl -sS "$LITMUS_URL/v0/orgs/$LITMUS_ORG/github/repositories" \
  -H "Authorization: Bearer $LITMUS_TOKEN"
```

## `GET /v0/orgs/{orgtag}/github/refs`

One covered repository's branches and open pull requests: `GET /v0/orgs/{org}/github/refs?repo=owner/name` → `{org, repo, account, installation_id, branches: [{name, sha}], pulls: [{number, title, head_ref, head_sha, base_ref}], pulls_refusal, refusal}`.

| | |
| - | - |
| Token scope | `read` (any org token) |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/github/refs"]["GET"]` |
| CLI | — |

**Path parameters:** `orgtag`

**Query parameters the handler or its helper reads:** `repo`

**Response fields written in the handler:** `org`, `tier`

```bash theme={null}
curl -sS "$LITMUS_URL/v0/orgs/$LITMUS_ORG/github/refs" \
  -H "Authorization: Bearer $LITMUS_TOKEN"
```

## `GET /v0/orgs/{orgtag}/github/unrecorded`

Installations of the Litmus GitHub App that GitHub holds and no org has recorded, on the account `?owner=` names: `{org, owner, unrecorded: [{installation_id, account}]}`.

| | |
| - | - |
| Token scope | `read` (any org token) |
| Org comes from | the `{orgtag}` path segment; a token for another org is refused with 403 |
| Policy row | `apitokens.POLICY["/v0/orgs/{orgtag}/github/unrecorded"]["GET"]` |
| CLI | — |

**Path parameters:** `orgtag`

**Query parameters the handler or its helper reads:** `owner`

**Response fields written in the handler:** `org`, `owner`, `refusal`, `tier`, `unrecorded`

```bash theme={null}
curl -sS "$LITMUS_URL/v0/orgs/$LITMUS_ORG/github/unrecorded" \
  -H "Authorization: Bearer $LITMUS_TOKEN"
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.