Skip to main content

Fleet management

A platform app bootstraps a template once per end user. After a thousand bootstraps you have a thousand agents that came from one description, and the template is the only thing that still describes them all.

Two questions become hard at that point, and neither has a good answer through the per-agent API:

  • How many are behind? Each agent records the template version it was provisioned from. Nothing aggregates that.
  • How do I move them forward? Editing the template changes what future bootstraps produce. It does not touch the agents already out there.

The fleet routes answer both. A fleet is simply every agent one template provisioned.

Requirements

The Platform API requires a Pro or higher subscription. Fleet routes accept your plt_ app key or a user JWT for the org that owns the app.

The thing to understand first

Every route on this page does what it does a thousand times, and nobody reviews it per agent.

That single fact explains every restriction below. A patch that would be unremarkable on one agent — raising a spend limit, enabling transaction signing — is a different kind of act when it lands on an entire cohort at once. So the fleet surface is deliberately narrower than the per-agent API, not wider.

Fleet status

1claw platform fleet status <appId> <templateId>
{
"template_id": "…",
"template_name": "onboarding",
"current_version": 4,
"spec_hash": "9f2a…",
"total_agents": 1240,
"version_skew": [
{ "template_version": 2, "agents": 310 },
{ "template_version": 3, "agents": 500 },
{ "template_version": 4, "agents": 430 }
],
"agents_on_current_version": 430,
"agents_behind": 810,
"drifted_agents": 12,
"bulk_patchable_fields": ["system_prompt", "description", "…"]
}

spec_hash is a hash of the template spec. A version number moves on every edit, including edits that changed nothing meaningful; the hash tells you whether the cohort is actually behind anything.

drifted_agents counts agents a previous rollout declined to touch because someone had changed them outside fleet control. It is the standing answer to "why is this agent still behind?".

What is bulk-patchable

1claw platform fleet patch <appId> <templateId> --set system_prompt="You are…"

The allowlist is returned on the fleet summary as bulk_patchable_fields. Read it from there rather than hard-coding it — it is narrower than a single-agent PATCH and may narrow further.

Two categories are excluded, and will stay excluded:

Guardrailsmax_transaction_value_usd, daily_spend_limit_usd, and the rest. Raising a spend limit across a fleet is not a deployment operation. It is a thousand separate decisions that happen to share a form, and each one belongs to the agent it affects, through the guardrail approval flow.

Capability flagsintents_api_enabled, execution_intents_enabled. Turning on transaction signing for an entire cohort in one request is the largest privilege change this API can express. It should not be reachable without per-agent review.

A field outside the allowlist returns 400 naming the field, and refuses the whole patch rather than applying the acceptable parts. A partially-applied bulk patch across a thousand agents is far worse than a rejected one.

Rollouts

1claw platform fleet rollout <appId> <templateId> --dry-run
1claw platform fleet rollout <appId> <templateId>

A rollout brings the cohort up to the template's current version.

Hand edits are skipped, not corrected. If an agent's field was changed outside fleet control, the rollout leaves it alone and records the field on the agent. Someone changed it for a reason; a rollout that overwrites that reason at cohort scale destroys a thousand reasons at once. This is the same rule 1claw apply uses.

{
"job_id": "…",
"to_version": 4,
"synced": 798,
"already_current": 430,
"skipped_drifted": 12,
"outcomes": [
{ "outcome": "synced", "agent_id": "…", "fields": ["system_prompt"] },
{ "outcome": "skipped_drifted", "agent_id": "…", "drift_fields": ["system_prompt"] }
]
}

--force overrides the skip. It still cannot carry a guardrail or a capability flag, even when the template specifies one — those are filtered out of what a rollout is allowed to move, forced or not.

--dry-run reports the plan and changes nothing. It also claims no job, so job_id comes back null and a dry run never blocks the real rollout that follows it.

Only one rollout runs per template at a time. A second returns 409: two concurrent rollouts would race and leave the cohort half on each version.

Pausing

1claw platform fleet pause <appId> <templateId>

Deactivates every agent in the cohort. The blast radius is the point — this exists for the moment you need a thousand agents to stop at once.

MCP

The MCP server exposes fleets read-only: platform_get_fleet, platform_list_fleet_agents, and platform_plan_fleet_rollout, which always runs as a dry run.

Bulk-patch and pause are not available to agents through MCP. Changing a thousand agents from one call, with no per-agent review, is a decision for a human at a terminal or a deliberate SDK call.

Endpoints

MethodPath
GET/v1/platform/apps/{app_id}/fleets/{template_id}
GET/v1/platform/apps/{app_id}/fleets/{template_id}/agents
POST/v1/platform/apps/{app_id}/fleets/{template_id}/bulk-patch
POST/v1/platform/apps/{app_id}/fleets/{template_id}/rollout
POST/v1/platform/apps/{app_id}/fleets/{template_id}/pause

SDK

const { data: fleet } = await client.platform.getFleet(appId, templateId);
console.log(`${fleet.agents_behind} of ${fleet.total_agents} behind`);

// Read the allowlist rather than assuming it.
if (fleet.bulk_patchable_fields.includes("system_prompt")) {
await client.platform.bulkPatchFleet(appId, templateId, {
system_prompt: "You are a careful assistant.",
});
}

const { data: plan } = await client.platform.rolloutFleet(appId, templateId, {
dry_run: true,
});
// A dry run claims no job.
console.log(plan.job_id); // null
fleet = client.platform.get_fleet(app_id, template_id).data
plan = client.platform.rollout_fleet(app_id, template_id, dry_run=True).data