PILOT BOOK — PASSAGE PLANS IN DETAIL
Radar tells you about collisions while they happen. Passage plans prevent them: before starting to code, an agent (or human) files the footprint it intends to change and gets a traffic advisory back — before any code is written. A plan is an advisory reservation, never a lock: anyone can still edit anything; they just do it informed.
┌──────────── expires_at (24h TTL) ───────────┐
▼ │
filed ──edits inside footprint──▶ active ◀──rejoin route──┐ │
│ │ │ │
│ edits outside │ │
│ ▼ │ │
└──edits outside───────────▶ drifted ───────────────────┘ │
│
completed ← session closes / assignment completes / │
withdrawn ← farled_complete_plan / assignment fails │
expired ← TTL lapses ─────────────────────────────────────┘
| Status | Meaning | Who sets it |
|---|---|---|
| filed | declared, no work observed yet | filing |
| active | observed edits match the footprint — the plan is confirmed by reality | server, on change reports |
| drifted | observed edits left the footprint; a plan_drift signal is open | server, on change reports |
| completed | work shipped | session close, assignment completion, or farled_complete_plan |
| withdrawn | abandoned | explicit call, or assignment failure (Cloud) |
| expired | 24h TTL lapsed — the backstop for anything that dies silently | server, lazily |
Live status flows from three independent sources, in trust order: observed edits (reconciled on every change report), lifecycle events (session close; on Cloud, assignments reaching terminal states), and explicit calls — with the TTL as the final backstop. A dead laptop can never reserve water for more than 24 hours.
At the end of the planning phase, call the MCP tool (or POST /v1/work-plans with the same body):
farled_file_plan {
"repository_id": "github.com/acme/app",
"actor_id": "my-agent",
"intended_paths": ["src/checkout/**", "src/lib/currency.ts"],
"summary": "Fix checkout summary TypeError + regression test",
"confidence": "medium",
"work_session_id": "<reporter session id, if one is running>"
}
Declare the narrowest footprint you honestly can — over-broad globs generate advisories against you and dilute everyone's traffic picture. Passing work_session_id links the plan to your reporter session, which enables drift reconciliation and automatic completion when the session closes.
The response carries a deterministic recommendation — same state, same answer, no model in the loop:
| Recommendation | Meaning | Rule |
|---|---|---|
| clear | no live plans or active edits on this footprint | — |
| sequence_after | another live plan overlaps yours | earlier filing holds the water; the newcomer sequences after it or rescopes |
| coordinate | a live session is already editing inside your footprint | observed work outranks declared work — talk first |
Overlap rules: plan-vs-plan compares glob literal prefixes (src/checkout/** overlaps src/**; src/a/** does not overlap src/b/**) — deliberately erring toward warning. Plan-vs-observed matches your globs against real changed paths. Your own plans never conflict with you.
On every change report, the server reconciles the session's observed edits against its filed plan:
Drift never blocks anything. It flags scope creep and tells other traffic that this plan's reservation no longer describes reality.
Add one paragraph to your repo's agent instructions (CLAUDE.md, AGENTS.md, or equivalent):
At the end of your planning phase — before writing any code — file a
passage plan with farled_file_plan declaring the paths you intend to
change, and follow its advisory. When your work ships or you abandon
it, call farled_complete_plan.
That's the entire integration. Plans are optional everywhere: unplanned work is still observed, detected, and advised exactly as before.
| Surface | Call |
|---|---|
| MCP | farled_file_plan · farled_list_plans · farled_complete_plan |
| HTTP | POST /v1/work-plans · GET /v1/work-plans?repository_id= · POST /v1/work-plans/{id}/status |
| Protocol | work_plan.schema.json (farled/v1, additive) · Signal type plan_drift |