Three Agents, Zero Collisions

Project11 min · Scope → Isolate → Supervise → Land · Updated 2026-09-15

You end this lesson with: fleet/collision-report.md — evidence three concurrent agents did not collide, plus the failure you caused on purpose.

Chapters

  1. Brief
    01
  2. The Rule This Lab Tests
    02
  3. Steps
    03
  4. Acceptance
    04
  5. Rubric
    05
  6. Key Takeaways
    06

Project 02. Three Agents, Zero Collisions

Illustrative composite. A three-person team once ran three agents against one shared dev database, because writing a separate .env file for a twenty-minute task felt like busywork. Two of the agents defaulted to the same $DB_PATH. By the time the third agent's pull request came up for review, four seeded rows had quietly become three — one agent's write had overwritten another's mid-run, and neither process had thrown an error. The bug took longer to find in review than either task had taken to build, because nothing about the failure looked like a collision; it looked like a bug in the code.

Lesson four gave you a launcher that assigns a port range and a private database per agent. Lessons five through seven added a containment tier, a permission policy tied to it, and a credential and egress policy the agents run under. This project asks you to actually run three agents at once, against one repository, and produce evidence — not a claim — that those controls held. Then it asks you to break one control on purpose, on the same repository, and write down exactly what happened, because the fastest way to learn what an isolation control actually stops is to watch it fail. You hand over both halves in one file.

Your deliverable is fleet/collision-report.md — evidence that three concurrent agents did not collide, plus the failure you caused on purpose. It serves the Isolate stage: the boundary work from module two only counts once you have watched it hold, and watched it fail, under real concurrency.

Brief

Run the three tasks below concurrently, in three worktrees, under fleet/isolate.sh from lesson four. Use your own repository if it fits the shape — a dev server bound to one port, a local database file — or use the sample layout.

Sample repository: orbit-tasks

orbit-tasks/ src/ server.ts # dev server, binds to $PORT (default 4000) db.ts # opens the sqlite file at $DB_PATH (default ./data/orbit.db) routes/ # auto-loaded by filename, one route per file tasks.ts jobs/ # auto-loaded by filename, one job per file components/ data/ orbit.db # sqlite dev database, gitignored .env.example

server.ts reads $PORT and $DB_PATH at startup and nothing else. Every route and job file registers itself by living in its own directory, so adding one never requires editing a file another task also touches.

The three task specs

Task 1, "the search route." Goal: add GET /tasks/search?q= returning every task whose title contains q, case-insensitive. Files it may touch: src/routes/search.ts only, a new file. Interfaces it must not invent: no new query language, call the existing db.query() helper. Done test: a request against the agent's own assigned port returns the matching rows as JSON. Ceiling: 20 minutes.

Task 2, "the archive job." Goal: add a job that sets archived = 1 on every task older than 30 days with status = "done". Files it may touch: src/jobs/archive.ts only, a new file. Interfaces it must not invent: no new scheduler, the job runs once when invoked directly. Done test: running the job against the seed data flips the expected rows and no others. Ceiling: 20 minutes.

Task 3, "the tag filter." Goal: add a dropdown component that filters the rendered task list by tag, client-side only. Files it may touch: src/components/TagFilter.tsx only, a new file. Interfaces it must not invent: no new state library, read from the list already in scope. Done test: selecting a tag in the running dev server narrows the visible rows. Ceiling: 20 minutes.

The three tasks are disjoint by construction: no shared file, no undefined interface between them, so lesson two's test marks all three parallel before isolation even enters the picture. That is what makes this project about the boundary the worktree does not give you for free, not about task scheduling.

diagram
drawing
Three agents isolated, versus one control removed.

The left half is what you prove first. The right half is what you build on purpose in step three, so the report holds evidence of both shapes, not just the one that worked.

The acceptance checks (given in full)

  • Distinct ports: each agent's dev server is bound to its own assigned port, confirmed by a request to that exact port, not to a port you remembered starting.
  • No shared database writes: each agent's $DB_PATH points at its own copy of data/orbit.db; no write from one agent's run appears in another agent's database file.
  • Three branches: three worktrees, three branches, one commit per agent, no agent committing to another's branch.
  • No cross-tree file edits: git diff --stat for each agent's branch touches only the one file its task spec names.

The Rule This Lab Tests

Use a bare git worktree add when the only thing separating your agents is which branch is checked out — between agents you already trust with your host's ports, its dependencies, its credentials. Isolate every other shared resource yourself: port, database, credentials — or accept that two agents will eventually collide on one of them. This project is where that rule gets tested against a stopwatch instead of a claim: the three task specs above are already disjoint by file, so the worktree's own guarantee, a private branch, comes for free. Everything else in fleet/collision-report.md is what you had to allocate yourself, and the failure you cause on purpose in step three is what happens the moment you stop.

ResourceDoes a worktree isolate it for free?What this project asks you to prove
Branch and working directoryYesNothing — the three branches in step 1 cost nothing extra
Network portNoA distinct port per agent, confirmed by a real request
Database fileNoA distinct $DB_PATH per agent, confirmed by a real query

Steps

Step 1 is worked — a filled launcher example is given below. Step 3 is faded: you pick which control to break and check your reasoning before you run the drill. Steps 4 and 5 are open — what you find and how you restore it depend entirely on the control you chose.

  1. Launch three agents under fleet/isolate.sh, one per task spec — worked. A filled example for one agent: fleet/isolate.sh agent-1 main prints its assigned port and database path, something like port: 4001 db: data/orbit-agent-1.db; run the same command for agent-2 and agent-3 before any agent starts working. Confirm the launcher assigned each a distinct port and a distinct copy of data/orbit.db. Output: three launcher-assigned rows referenced from fleet/collision-report.md.

  2. Run all three tasks to completion. Collect the evidence the acceptance checks ask for: a request against each port, a query against each database copy, git diff --stat for each branch. Output: the evidence section of fleet/collision-report.md, one subsection per check.

  3. Remove one isolation control on purpose — faded. Pick one: point all three agents' $DB_PATH at the same file, point all three at the same $PORT, or drop the per-agent worktree and run all three from one checkout. Decide which one is likeliest to fail quietly instead of loudly before you check your reasoning below, then re-run one task, or a fresh fourth task shaped like the other three, under the weakened setup. Output: the exact control you changed, named precisely, in fleet/collision-report.md.

  4. Document exactly what broke — open. The symptom you saw — an overwritten row, a refused port bind, a file neither task's spec named — which of lesson four through seven's controls would have stopped it, and how you would notice it in a real fleet before it reached review. Output: the failure section of fleet/collision-report.md.

  5. Restore the control and confirm the fleet is clean again — open. Re-run the same task under the restored isolation and show the check passing. Output: the closing line of fleet/collision-report.md.

Acceptance

  • Three worktrees launched from fleet/isolate.sh, each with a distinct port and a distinct database copy, confirmed before any agent starts working.
  • Evidence exists for all four checks from the Brief: distinct ports, no shared database writes, three branches, no cross-tree file edits.
  • Exactly one isolation control is removed on purpose and named precisely — which file, which environment variable, which flag.
  • The failure is reproduced and described with its actual symptom, not a predicted one.
  • The failure section names which lesson-four-through-seven control would have stopped it.
  • The control is restored and the same task re-run clean, with that result shown in the report.

Rubric

CriterionWeakStrong
Collision evidence"No collisions happened," with no artifact attachedA port response, a database query and a git diff --stat per agent, all attached
Task fidelityTasks edited until they no longer touch a real shared resourceThe three task specs run unmodified, genuinely disjoint by file
Deliberate failureA hypothetical: "removing the port assignment would probably collide"A real removed control, a real re-run, a real captured symptom
Root-cause naming"Isolation broke"The specific control removed is named and tied to the specific lesson that introduced it
RecoveryThe report ends at the failureThe control is restored and a clean re-run is shown

Key Takeaways

  • Prove isolation with evidence per agent, not a clean-looking terminal.
  • Keep the three tasks genuinely disjoint so any collision found is real.
  • Remove exactly one control at a time so the failure has one traceable cause.
  • Name the broken control and the lesson that introduced it, precisely.
  • Restore the control and show the re-run clean before closing the report.

What You Have Now

fleet/collision-report.md — evidence that three concurrent agents did not collide, plus the failure you caused on purpose. It sits beside fleet/isolate.sh, fleet/port-map.md, fleet/containment.md, fleet/permissions/ and fleet/access.md as proof that module two's controls hold under real concurrency, not only in the lesson that introduced each one. Module three's venue cutover reuses this same evidence-over-claim standard for a fleet that has left your laptop.


NO-QUIZ

Quiz coming to this lesson

This lesson doesn't have a graded quiz yet — completion is still tracked, just not verified against questions.

Reading is free — your progress isn't being saved

Nothing you did on this page is recorded. Paid students get saved progress and verified completions, recorded quiz answers, the spaced-repetition review queue, labs, and a certificate for each course they finish.

30-day money-back guarantee. One-time payment — lifetime access and updates.