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

# Rosters & versioning

> How a coordinator's roster is snapshotted and version-pinned, what is checked when you save it, how harnesses mix, and the commands that manage it.

A team is only reproducible if its members can't shift under it. Naive Managed Agents guarantees that by **snapshotting the whole coordinator config — including the roster — at create and update time**, and pinning each member to a specific version.

## Version pinning

Each id-referenced roster member is stored with a version:

```jsonc theme={"system"}
{
  "multiagent": {
    "type": "coordinator",
    "agents": [
      { "type": "agent", "id": "agt_9f2c…", "version": 4 },
      { "type": "agent", "id": "agt_4a71…" },   // pinned at save time
      { "type": "self" }
    ]
  }
}
```

* Provide `version` to pin a specific one.
* Omit it and Managed Agents pins the member's **current version at the moment you save the coordinator**. The version is resolved server-side and written into the stored roster, so what comes back always carries an explicit pin. A member never floats.
* Once pinned, a member does **not** auto-adopt later edits to that agent. To use a newer version, **update the coordinator's roster** — an explicit, reviewable act.

This is what makes a team behave the same today and next month: editing a member in isolation cannot silently change how the coordinator runs.

## What a save checks

Saving a roster is not a bookkeeping write. Every id-referenced member is loaded and checked, and a failure is refused **at save**, naming the entry and the reason — never left to surface as a broken delegation an hour into a run.

| Check | Refused when |
| - | - |
| The agent exists | No agent by that id in your organization. |
| The version exists | The pin names a version that agent does not have. |
| One level deep | That agent is itself a coordinator. A team is one level; nothing bounds the spend of a tree. |
| Runnable here | Its harness cannot run on this deployment — see below. |
| Capability match | Its harness cannot serve its own configuration — see below. |

One more check reads **this** agent rather than a member: a coordinator whose own harness declares `injected_tools: false` is refused, naming `multiagent`, because the team tools would never reach its model. No published harness declares `false`, so it stands as a guard rather than a rule you meet. See [Mixing harnesses](#mixing-harnesses).

## Mixing harnesses

**Members may mix harnesses freely.** A member's `harness` is its own — fixed when that agent was created — and the coordinator's harness does not have to match. A `pi` coordinator with a `vetta` member is an ordinary team, and so is the reverse.

**Any published harness can be a coordinator.** Delegation is a *tool*: `send_to_agent` (with `wait: true`) reaches the coordinator's model either as part of the toolset Managed Agents assembles for the turn, or — where the agent is a CLI process in a machine of its own — over the session-scoped tool endpoint that machine is given. One caveat is worth knowing before you pick: on the second kind, `wait_for_agents` does not pause the turn in flight. The coordinator parks once the turn goes idle and the delegated threads open correctly; it costs a few extra model calls, not a wrong answer. A harness declaring [`injected_tools: false`](https://vetta.sh/docs/concepts/harness-capabilities) would still be refused as a coordinator, naming `multiagent` at save and `harness` at session start, but none is published.

A **member** on the same harness is fine, and that distinction is the point: a member is delegated *to*. `send_to_agent` runs in the coordinator's loop, and what reaches the member is a message through its own ordinary session. It needs no delegation of its own — its `send_to_agent`, if its [`handoffs`](https://vetta.sh/docs/capabilities/tools#handoffs) grant one, only hands work *on* with `wait: false`.

What a member's harness must satisfy is that it can serve **its own** configuration, and the check is at save:

* **Runnable on this deployment.** A harness whose agent is a *process in a machine* needs a base image configured for it in that environment. Staging may have one where production does not, so this is a per-deployment fact, not a property of the harness — the refusal reads `runs the … harness, which is not runnable on this deployment`. Delegating to such a member would otherwise buy nothing but a retry ladder against a failure knowable at save time.
* **Typed results.** If the member's own config demands a structured output, its harness must declare `structured_output`. See [Harness capabilities](https://vetta.sh/docs/concepts/harness-capabilities.md) for which do — and for the one that declares it and cannot yet serve it.
* **Approvals.** If the member's toolset carries `permission: "ask"` anywhere, its harness must be able to hold a tool call for a decision. A harness without that seam does not prompt — it silently denies — so admitting the pair would drop an approval policy without a trace.

> [!NOTE]
>
> Which members can return a typed result is also visible to the coordinator at runtime: `list_agents` reports `typed` per member, and a `send_to_agent` carrying an `output_schema` for one that cannot is [refused by name](https://vetta.sh/docs/team/delegation.md#nothing-throws--a-refusal-is-a-tool-result).

What a mixed team then *costs* while it runs is decided by each member's harness independently — see [What a member holds while it runs](https://vetta.sh/docs/team/context-and-budgets.md#what-a-member-holds-while-it-runs).

## Managing the roster

```bash CLI theme={"system"}
vetta team set agt_01j8rm4xp7k2qv6zn9c3h5wfdb --member changelog-writer@4 --member release-notes-qa@2 --board

vetta team add agt_01j8rm4xp7k2qv6zn9c3h5wfdb --member doc-linter@1

vetta team remove agt_01j8rm4xp7k2qv6zn9c3h5wfdb --member release-notes-qa

vetta team show agt_01j8rm4xp7k2qv6zn9c3h5wfdb
```

```typescript TypeScript theme={"system"}
await vetta.agents.update(coordinator.id, {
  expected_version: coordinator.current_version,
  multiagent: {
    type: "coordinator",
    agents: [
      { type: "agent", id: "agt_9f2c…", version: 4 },
      { type: "agent", id: "agt_4a71…", version: 2 },
    ],
    board: true,
  },
});
```

Each `--member` is `name@version`, a bare `name`, or an `agt_` id — plus `self`. The name spelling is resolved by the CLI against your org's agents; the wire only ever carries `{ type: "agent", id, version? }`.

`set` replaces the roster outright and is the only one that takes `--board`; `add` and `remove` keep the rest of the roster as it stands, including its board setting. Removing the last member clears the roster to `null`, because an empty coordinator is not a team.

Because the roster lives on the coordinator's config, a roster change is an ordinary agent [update](https://vetta.sh/docs/concepts/agents.md#versioning): it creates a new coordinator version, under the same optimistic-concurrency guard. Every one of these commands is a read-modify-write under `expected_version`, so two people editing a roster from two terminals cannot silently overwrite each other.

## Data residency

Managed Agents does **not** yet expose a per-agent data-region or residency control — there is no `data_region` field on an agent or a coordinator today, so there is nothing for a team to reconcile across its members. Everything runs in Managed Agents' default region.

> [!NOTE]
>
> Configurable inference regions and a residency posture have not shipped. When region pinning does, a team will be required to keep a single region across the coordinator and every member (or leave it unset everywhere) so work is never split across regions by accident. Until then, do not assume any residency guarantee.

## Limits

| Bound | Limit |
| - | - |
| Unique agents per roster | 1 to 20 |
| `self` entries per roster | 1 |
| Delegation depth | 1 level (a member cannot itself be a coordinator) |

> [card] [Next: context & budgets](https://vetta.sh/docs/team/context-and-budgets.md)
>
> What sessions share, what a member holds while it runs, and how spend flows across a team.


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