fleet

Several sessions, one controller.

A skill distributed by casp — and not part of CASP. It launches sessions, therefore it orchestrates, and CASP never orchestrates. It ships in the npm package next to /casp and /next, which are not protocol verbs either. Written from three measured trials on three separate repositories.

The boundary, first

fleet orchestrates. That is why it is not CASP.

The whole wedge of CASP is that it does one job and refuses the rest: it proves a project’s recorded state matches git, deterministically, and exits non-zero on drift. Launching sessions is the opposite kind of act. So the boundary is stated here rather than implied, and each claim is testable:

  1. It launches sessions, therefore it orchestrates — and orchestration is outside CASP by definition. Nothing in it is a protocol verb.
  2. No casp check rule reads it, or anything it produces, and nothing in it gates a push. Delete the skill and every verdict on your repository is unchanged.
  3. Its model default is empty. The reasoning ships — a controller and its workers do not need to run at the same tier — but a model name never does: naming one would contradict a model-agnostic tool and date the file at the next release.
What it is for

The measured value is contradiction, not speed.

Nothing in the three trials demonstrated a speed gain, so no speed gain is claimed here. What was demonstrated is narrower and harder to get any other way: workers refusing a controller’s mistaken order, and read-only reviewers surfacing defects in code already shipped. Those are paths that pass silently in a single session, because a single session has nobody positioned to refuse it.

Read that as the acceptance test for whether you want a fleet at all. If the thing you need is throughput, this is the wrong tool and the arithmetic below says why. If the thing you need is a second party who can say no with evidence, that is what it was measured to provide.

Cost

N sessions cost N quotas.

There is no shared pool and no discount. A fleet is a per-effort decision with a stated shape and a stated cost, written before launch — not a default mode. The serial queue remains the norm.

Load

The work moves. It does not disappear.

The controller becomes the bottleneck and the single point of unverified assertion, and its self-correction degrades as it holds more lanes. The counterweight is to measure rather than believe: recount with git diff --stat, paste raw gate output, and treat any “0 errors” without the line that proves it as unproven.

What three trials measured

The collisions that actually happen are not file writes.

The intuitive fix for parallel sessions is a lock: have each session claim the paths it owns, and refuse writes elsewhere. casp live can do exactly that. Wiring it into a launcher was ruled out rather than deferred, on the count below.

14
recorded incidents across three trials
1
a path claim would have caught
2
writes it would have refused on entirely legitimate paths

The guard is imprecise in both directions, so the net balance is negative — it is not merely aimed at the wrong family. And the family that actually occurs travels through the git index, HEAD, the working tree, a dev-server port, a lockfile, a build cache. None of those is a file-writing tool call, so no path claim ever sees them.

Stating that publicly is more useful than leaving it out. It points at the mitigations that do work, all of them procedural:

  • Commit by pathspecgit commit <paths>, never git add -A, never git commit -a. A commit without a pathspec publishes the entire index, and the index is one object shared by every process in the repository: it will carry whatever a neighbouring session had staged, under your message. Measured once at 945 lines of an unrelated session’s deletions.
  • Shared surfaces get exactly one scribe. The cockpit, session logs, agent-instruction files, lockfiles, shared types, common i18n files: nobody owns them, the controller writes them, workers report what needs writing. This single rule removes most collisions before any tooling.
  • A git fetch and a bounded ahead/behind report at open, and again before the final report. The dominant failure mode in every trial was a stale belief — a session reasoning about shared state it stopped observing hours ago. A session is rarely wrong about its own work; it is wrong about everyone else’s, and the gap grows with session length. A tracking ref without a fetch is a local cache that makes a pushed commit look absent.

A guard believed to be on, and off, is worse than no guard.

casp live can reserve paths, and it arms that category only while a controller and another lane are each backed by a process the machine can probe. A controller declared from a bare terminal instead of from inside a session takes a fallback identity carrying no process id — and therefore arms nothing. Until 0.15.1, the only way to discover that was to notice that a guard which should have fired never did.

Since 0.15.1, casp live claims states where the reserved category stands and why, in every state, on its own line: no controller declared · the controller row carries no process id · no other lane is held · no other lane carries a process id · or enforced. Failing open is the contract. Failing open in silence is not: a protection believed to be on and actually off is worse than no protection, because it is trusted.

How it runs

The default shape: one writer, N adversarial readers.

A multi-writer fleet is not the starting point. The default is one session that writes, plus one or more read-only sessions holding no lane at all, whose entire mandate is to contradict — audit slices already shipped, adversarially review the writer’s diff, refute claims instead of confirming them. In that shape the concurrent-write family of failures is empty by construction: there is nothing to collide.

Departing from it requires a written reason — a second writing lane that actually exists, not a task list sorted into folders. A slice whose parts are internally coupled has no second lane, and saying so is an arbitration, not a refusal to work.

Before launching anything

Are the project’s gates isolable per session?

Answer yes / no / not measured — ports, databases, test fixtures — and write the answer down before any brief. It is a per-project property to be measured, not assumed. Two measured extremes: one repository forbade more than one session outright, its end-to-end target tearing down the running stack unconditionally on fixed ports against a single shared database — and it failed silently. Another allowed parallel gates everywhere except one build command, which failed loudly, naming the shared directory. The readability of the failure, not its existence, separates a manageable constraint from a trap: two sessions verifying on a non-isolated harness do not produce a git conflict, they produce red runs that get blamed on the diff.

If there is more than one writer, a lane is a path list

Not a domain — “the frontend” is not a lane. An explicit list of owned paths, declared before launch. A file claimed by two lanes blocks the launch: resolve it before, not during. A worker that must touch a file outside its lane reports it to the controller, who edits it as scribe.

Every worker starts already loaded

Launch each session with its brief as its initial input, under a stable addressable name, rather than opening idle sessions and messaging tasks into them. A lane without a written brief is not a task, it is an intention — and a worker launched without a perimeter writes everywhere.

What fleet is not

  • Not a CASP feature. See the boundary above. The protocol validates state against git and never launches anything.
  • Not a launcher. The skill ships no launch script: how sessions are opened is specific to a terminal, an operating system, sometimes a machine per session. The two requirements stay the same everywhere — each worker starts with its brief loaded, under a stable addressable name.
  • Not a lock system. Advisory path claims are casp live’s job, and even there they never gate a push and never change a casp check verdict.
  • Not sub-agents. A fleet is made of real sessions a human sees, interrupts, and reads in their own terminal — not background agents that die with their parent.
  • Not the default mode. The serial queue is.
Where it comes from

It is already in the package.

The fleet skill ships inside @justethales/casp from 0.16.0, under skills/fleet, alongside /casp, /next and /audit-batch. Installing casp installs it; nothing else is fetched and nothing phones home. The release also ships the check that keeps this page honest: the skill is mechanically tested for zero absolute paths, zero model names, zero repository names other than the package’s own, and zero speed claims.

The model holds the context. CASP proves the state is true — against git.

fleet is the orchestration layer that stays outside the protocol. The protocol itself is on the roadmap, and the reasoning is on the blog.
$ npm i -g @justethales/casp