@iowarp/clio-coder 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +407 -0
- package/CODE_OF_CONDUCT.md +21 -0
- package/CONTRIBUTING.md +224 -0
- package/LICENSE +202 -0
- package/NOTICE +9 -0
- package/README.md +798 -0
- package/SECURITY.md +72 -0
- package/assets/clio-coder-logo-128.webp +0 -0
- package/damage-control-rules.yaml +419 -0
- package/dist/acp-UMLFVA3F.js +92 -0
- package/dist/agents-Q4MYPMUW.js +91 -0
- package/dist/auth-O6HYIJ6J.js +521 -0
- package/dist/chunk-262G75JS.js +35 -0
- package/dist/chunk-26BZQOAD.js +1281 -0
- package/dist/chunk-2J63S4SF.js +508 -0
- package/dist/chunk-3DANZDGR.js +717 -0
- package/dist/chunk-4UQA7NCT.js +29 -0
- package/dist/chunk-527KG6XR.js +497 -0
- package/dist/chunk-5LDRNKX2.js +1063 -0
- package/dist/chunk-5N2FG33Q.js +25 -0
- package/dist/chunk-67MTHP2E.js +135 -0
- package/dist/chunk-6CWDTGUC.js +20 -0
- package/dist/chunk-7BHLZB3A.js +2115 -0
- package/dist/chunk-7RBKDI66.js +348 -0
- package/dist/chunk-AMFR5YA3.js +541 -0
- package/dist/chunk-BBUH4VAA.js +1224 -0
- package/dist/chunk-BYEU76JP.js +899 -0
- package/dist/chunk-CLJ5HLUD.js +458 -0
- package/dist/chunk-D5YD55AR.js +116 -0
- package/dist/chunk-DXQNI4PC.js +61 -0
- package/dist/chunk-E3NYWENM.js +1004 -0
- package/dist/chunk-GNGDQYDU.js +34688 -0
- package/dist/chunk-GOTUR54M.js +9 -0
- package/dist/chunk-HBU5MTAM.js +41 -0
- package/dist/chunk-HMYNFFY4.js +28 -0
- package/dist/chunk-JPOWPFCU.js +1010 -0
- package/dist/chunk-JWHCJDCI.js +1215 -0
- package/dist/chunk-KBR4MZZR.js +41 -0
- package/dist/chunk-KKKPTZLM.js +93 -0
- package/dist/chunk-ME6DNWIU.js +66 -0
- package/dist/chunk-NI4DEJMC.js +88 -0
- package/dist/chunk-O4EJEDHO.js +659 -0
- package/dist/chunk-PIDUD6M2.js +31 -0
- package/dist/chunk-PS4PFJQP.js +29459 -0
- package/dist/chunk-QV47YRF4.js +48 -0
- package/dist/chunk-RQDWMVRB.js +279 -0
- package/dist/chunk-TFSSEXL6.js +136 -0
- package/dist/chunk-TKHQ4DGZ.js +8290 -0
- package/dist/chunk-TPOCL34A.js +2876 -0
- package/dist/chunk-UGYAX5YI.js +565 -0
- package/dist/chunk-UHTSULZS.js +461 -0
- package/dist/chunk-UU3R62TT.js +128 -0
- package/dist/chunk-UWIJNAOB.js +3906 -0
- package/dist/chunk-VOO7NYPP.js +914 -0
- package/dist/chunk-VPAWTYLY.js +117 -0
- package/dist/chunk-WD6AJM35.js +1216 -0
- package/dist/chunk-X3BR7HWV.js +115 -0
- package/dist/chunk-X3NE4WVW.js +120 -0
- package/dist/chunk-XNISANGE.js +1395 -0
- package/dist/chunk-XV4ZJ6ZM.js +3177 -0
- package/dist/cli/index.js +236 -0
- package/dist/clio-KIQ5SNDS.js +53 -0
- package/dist/components-JVHMUBEB.js +653 -0
- package/dist/config-ZFCDBMDC.js +372 -0
- package/dist/configure-G4E3A2PG.js +27 -0
- package/dist/context-CDXTP2MP.js +293 -0
- package/dist/context-E3KIFVXI.js +185 -0
- package/dist/context-clear-3F4PLXOS.js +102 -0
- package/dist/context-index-Q7YSYTR3.js +106 -0
- package/dist/docs-YIETIWZI.js +280 -0
- package/dist/doctor-M5HJJZOL.js +61 -0
- package/dist/domains/agents/builtins/architect.md +33 -0
- package/dist/domains/agents/builtins/coder.md +31 -0
- package/dist/domains/agents/builtins/context-bootstrap.md +38 -0
- package/dist/domains/agents/builtins/debugger.md +30 -0
- package/dist/domains/agents/builtins/documenter.md +31 -0
- package/dist/domains/agents/builtins/git-master.md +30 -0
- package/dist/domains/agents/builtins/provenance.md +30 -0
- package/dist/domains/agents/builtins/researcher.md +71 -0
- package/dist/domains/agents/builtins/scout.md +42 -0
- package/dist/domains/agents/builtins/tester.md +31 -0
- package/dist/domains/agents/builtins/verifier.md +30 -0
- package/dist/domains/agents/builtins/wiki-writer.md +41 -0
- package/dist/eval-B3KZZESM.js +2674 -0
- package/dist/evidence-V67CHM35.js +233 -0
- package/dist/evolve-YDZSUQYA.js +518 -0
- package/dist/extensions-SRG7XCAH.js +207 -0
- package/dist/fleet-CA2CRTVG.js +760 -0
- package/dist/fleet-preflight-CLIAX7YR.js +21 -0
- package/dist/init-2OZDJE2D.js +227 -0
- package/dist/memory-3PIQQAKX.js +207 -0
- package/dist/models-DY35XI7Y.js +237 -0
- package/dist/paths-5OMXW7Z4.js +57 -0
- package/dist/preload-KZVHET2B.js +11 -0
- package/dist/reset-PIFYNOS3.js +216 -0
- package/dist/run-3VSPP24F.js +735 -0
- package/dist/share-D36RQCXM.js +241 -0
- package/dist/skills-F2MRLELY.js +445 -0
- package/dist/skills-eval-E2ZTW4PL.js +932 -0
- package/dist/targets-DZMEZAH4.js +977 -0
- package/dist/trace-7NYCUI2J.js +250 -0
- package/dist/uninstall-AD3JWHBB.js +322 -0
- package/dist/upgrade-WYYBKGDY.js +301 -0
- package/dist/usage-ULIDAGFF.js +755 -0
- package/dist/version-ROZ6CZKH.js +16 -0
- package/dist/wiki-generate-PKFIX6OB.js +377 -0
- package/dist/worker/entry.js +1739 -0
- package/docs/README.md +93 -0
- package/docs/acp.md +120 -0
- package/docs/alcf-provider.md +72 -0
- package/docs/architecture.md +172 -0
- package/docs/artifact-versions.md +54 -0
- package/docs/built-in-agents.md +265 -0
- package/docs/capacity-and-scheduling.md +97 -0
- package/docs/commands-and-modes.md +554 -0
- package/docs/config-knobs-audit.md +115 -0
- package/docs/configuration-and-targets.md +812 -0
- package/docs/context-engine.md +236 -0
- package/docs/dispatch-architecture-rationale.md +126 -0
- package/docs/documentation-coverage.md +46 -0
- package/docs/documentation-guide.md +166 -0
- package/docs/environment-variables.md +105 -0
- package/docs/eval-runner.md +205 -0
- package/docs/evals-internal.md +298 -0
- package/docs/evidence-and-memory.md +243 -0
- package/docs/evolution.md +143 -0
- package/docs/exit-codes-and-output.md +74 -0
- package/docs/extensions-and-sharing.md +306 -0
- package/docs/fleet-demo-runbook.md +179 -0
- package/docs/fleet-dispatch.md +591 -0
- package/docs/glossary.md +75 -0
- package/docs/html/agents_blueprint.html +936 -0
- package/docs/html/alcf_blueprint.html +324 -0
- package/docs/html/architecture_blueprint.html +850 -0
- package/docs/html/commands_blueprint.html +794 -0
- package/docs/html/config_knobs_audit_blueprint.html +178 -0
- package/docs/html/configuration_blueprint.html +1080 -0
- package/docs/html/context_blueprint.html +603 -0
- package/docs/html/documentation_blueprint.html +832 -0
- package/docs/html/environment_blueprint.html +404 -0
- package/docs/html/eval_blueprint.html +743 -0
- package/docs/html/evals_internal_blueprint.html +190 -0
- package/docs/html/evolution_blueprint.html +674 -0
- package/docs/html/extensions_blueprint.html +2065 -0
- package/docs/html/fleet_dispatch_blueprint.html +286 -0
- package/docs/html/index.html +919 -0
- package/docs/html/lifecycle_blueprint.html +723 -0
- package/docs/html/memory_blueprint.html +699 -0
- package/docs/html/middleware_blueprint.html +664 -0
- package/docs/html/models_blueprint.html +2366 -0
- package/docs/html/observability_blueprint.html +683 -0
- package/docs/html/provider_adapter_blueprint.html +245 -0
- package/docs/html/safety_blueprint.html +1386 -0
- package/docs/html/shared.css +571 -0
- package/docs/html/shared.js +143 -0
- package/docs/html/skills_blueprint.html +671 -0
- package/docs/html/soak_blueprint.html +182 -0
- package/docs/html/tool_usage_blueprint.html +350 -0
- package/docs/html/tools_blueprint.html +2249 -0
- package/docs/html/trace_blueprint.html +235 -0
- package/docs/html/tui_design_blueprint.html +314 -0
- package/docs/html/validation_blueprint.html +961 -0
- package/docs/html/worker_dispatch_blueprint.html +231 -0
- package/docs/installation-and-lifecycle.md +308 -0
- package/docs/middleware-and-components.md +148 -0
- package/docs/model-catalog.md +189 -0
- package/docs/observability.md +233 -0
- package/docs/proactive-memory.md +452 -0
- package/docs/prompt-envelope-and-tools.md +142 -0
- package/docs/provider-adapter-cookbook.md +148 -0
- package/docs/release-cut-checklist.md +138 -0
- package/docs/safety-model.md +357 -0
- package/docs/scientific-validation.md +105 -0
- package/docs/session-lifecycle.md +156 -0
- package/docs/skills-marketplace.md +46 -0
- package/docs/tool-usage.md +527 -0
- package/docs/trace-store.md +132 -0
- package/docs/troubleshooting.md +33 -0
- package/docs/tui-design.md +239 -0
- package/docs/worker-dispatch-mechanics.md +242 -0
- package/package.json +132 -0
- package/skills/README.md +408 -0
- package/skills/git/commit-crafting/SKILL.md +79 -0
- package/skills/git/commit-crafting/evals.md +92 -0
- package/skills/git/create-pr/SKILL.md +116 -0
- package/skills/git/create-pr/evals.md +114 -0
- package/skills/git/investigate-issue/SKILL.md +139 -0
- package/skills/git/investigate-issue/evals.md +94 -0
- package/skills/git/resolve-merge-conflicts/SKILL.md +96 -0
- package/skills/git/resolve-merge-conflicts/evals.md +58 -0
- package/skills/git/review-changes/SKILL.md +103 -0
- package/skills/git/review-changes/evals.md +85 -0
- package/skills/git/worktree-create/SKILL.md +92 -0
- package/skills/git/worktree-create/evals.md +97 -0
- package/skills/git/worktree-create/references/worktree-setup.md +66 -0
- package/skills/git/worktree-merge/SKILL.md +95 -0
- package/skills/git/worktree-merge/evals.md +114 -0
- package/skills/skill-marketplace.json +261 -0
- package/skills/workflow/cut-it/SKILL.md +86 -0
- package/skills/workflow/cut-it/evals.md +42 -0
- package/src/domains/agents/builtins/architect.md +33 -0
- package/src/domains/agents/builtins/coder.md +31 -0
- package/src/domains/agents/builtins/context-bootstrap.md +38 -0
- package/src/domains/agents/builtins/debugger.md +30 -0
- package/src/domains/agents/builtins/documenter.md +31 -0
- package/src/domains/agents/builtins/git-master.md +30 -0
- package/src/domains/agents/builtins/provenance.md +30 -0
- package/src/domains/agents/builtins/researcher.md +71 -0
- package/src/domains/agents/builtins/scout.md +42 -0
- package/src/domains/agents/builtins/tester.md +31 -0
- package/src/domains/agents/builtins/verifier.md +30 -0
- package/src/domains/agents/builtins/wiki-writer.md +41 -0
- package/src/domains/agents/fleets/build-review.md +34 -0
- package/src/domains/agents/fleets/build-test.md +35 -0
- package/src/domains/agents/fleets/sdlc.md +86 -0
- package/src/domains/prompts/fragments/identity/clio-worker.md +11 -0
- package/src/domains/prompts/fragments/identity/clio.md +26 -0
- package/src/domains/prompts/fragments/operating/contract.md +64 -0
- package/src/domains/prompts/fragments/safety/auto-edit.md +14 -0
- package/src/domains/prompts/fragments/safety/full-auto.md +14 -0
- package/src/domains/prompts/fragments/safety/read-only.md +13 -0
- package/src/domains/prompts/fragments/safety/suggest.md +13 -0
- package/src/domains/prompts/fragments/wiki/page.md +75 -0
- package/src/domains/prompts/fragments/wiki/plan.md +48 -0
- package/src/domains/providers/models/cloud-models/alcf.yaml +40 -0
- package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +993 -0
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
# Fleet Dispatch
|
|
2
|
+
|
|
3
|
+
> **Interactive Spec Available:** An interactive fleet node topology planner, scout router, receipt verifier, and failure taxonomy simulator is located at [docs/html/fleet_dispatch_blueprint.html](html/fleet_dispatch_blueprint.html) (Version: 0.3.0).
|
|
4
|
+
|
|
5
|
+
Clio Coder dispatches bounded worker agents. With a fleet configured, those
|
|
6
|
+
workers run on remote machines over SSH while the orchestrator keeps every
|
|
7
|
+
guarantee it makes locally: one admission path, one autonomy matrix, one
|
|
8
|
+
receipt chain. This page covers the architecture, node setup, the doctor
|
|
9
|
+
preflight, placement, topologies, failure semantics, and the residency
|
|
10
|
+
default. For the end-to-end demo see
|
|
11
|
+
[fleet-demo-runbook.md](fleet-demo-runbook.md).
|
|
12
|
+
|
|
13
|
+
Source of truth: `src/domains/dispatch/**`, `src/domains/scheduling/cluster.ts`,
|
|
14
|
+
`src/tools/dispatch.ts`, `src/tools/monitor.ts`, and the contract tests under
|
|
15
|
+
`tests/contracts/`.
|
|
16
|
+
|
|
17
|
+
## Architecture
|
|
18
|
+
|
|
19
|
+
The worker protocol is transport-neutral: the orchestrator writes one
|
|
20
|
+
WorkerSpec JSON line to the worker's stdin and reads NDJSON events from its
|
|
21
|
+
stdout. A remote worker is exactly the same protocol tunneled through
|
|
22
|
+
`ssh -T`, so nothing about prompts, safety, receipts, or telemetry changes
|
|
23
|
+
with distance. Transport is a ladder: `local` and `ssh` exist today; a future
|
|
24
|
+
container or cloud tier implements the same `WorkerTransport` interface
|
|
25
|
+
(`src/domains/dispatch/transport.ts`) without touching the protocol.
|
|
26
|
+
|
|
27
|
+
Both local and SSH native workers must emit `worker_announce` as their first
|
|
28
|
+
protocol event over the structured stderr control lane. The transport consumes it,
|
|
29
|
+
checks the dispatched WorkerSpec version, and accepts ordinary events only after
|
|
30
|
+
that check. The worker then attests protocol version (WORKER_PROTOCOL_VERSION = 1),
|
|
31
|
+
spec version, process ID, process group ID (or null), host, settings fingerprint,
|
|
32
|
+
worker-computed spec digest, runtime ID, target ID, endpoint identity hash, wire
|
|
33
|
+
model ID, effective tool signature, and bounded node resource facts (labels, CPU count,
|
|
34
|
+
total memory, free memory, GPU count, VRAM, and resident models) before any model
|
|
35
|
+
call. Drift from the approved identity kills the whole process group. The announcement and
|
|
36
|
+
attestation are strict protocol evidence, not proof against a malicious child
|
|
37
|
+
that controls its own process; SSH also uses the attested remote process group
|
|
38
|
+
for bounded abort escalation.
|
|
39
|
+
|
|
40
|
+
Scout routing is advisory rather than forced: the worker operating contract
|
|
41
|
+
steers explicit broad repository exploration to the read-only `scout` recipe,
|
|
42
|
+
and middleware emits a continuation nudge after nine or more manual
|
|
43
|
+
read-only exploration calls without a successful Scout dispatch. Direct reads
|
|
44
|
+
remain allowed; Clio does not automatically rewrite a broad request into a
|
|
45
|
+
Scout run.
|
|
46
|
+
|
|
47
|
+
Design decisions that shape everything else:
|
|
48
|
+
|
|
49
|
+
- Per-node inference targets, no central proxy. Target URLs resolve on the
|
|
50
|
+
node the worker runs on, so `localhost` in a worker's target means that
|
|
51
|
+
node's own inference server. The orchestrator-resolved API key rides the
|
|
52
|
+
WorkerSpec.
|
|
53
|
+
- Shared filesystem. Remote nodes see the project at the same absolute path.
|
|
54
|
+
The doctor preflight verifies this parity per node; hosts with a disjoint
|
|
55
|
+
filesystem fail admission with a clear reason.
|
|
56
|
+
- Deterministic placement and measured routing. Exact pins remain exact.
|
|
57
|
+
Unpinned placement prefers lower durable lease usage and declaration order;
|
|
58
|
+
the cross-process lease state is the final capacity authority. Route quality
|
|
59
|
+
can be activated only for named roles/postures after exact-tuple readiness,
|
|
60
|
+
and hard constraints always eliminate before any score.
|
|
61
|
+
- Environment whitelist. The SSH command carries an explicit environment
|
|
62
|
+
(`CLIO_CODER_RESIDENCY=observe`, `CLIO_CODER_WORKER_PGID=$$`, and any configured
|
|
63
|
+
`CLIO_CODER_WORKER_LABELS`); the orchestrator's `process.env` never crosses the
|
|
64
|
+
wire. `CLIO_CODER_WORKER_PGID` names the remote process group so an abort escalates
|
|
65
|
+
against the whole group rather than one process.
|
|
66
|
+
|
|
67
|
+
## Worker prompt and budget admission
|
|
68
|
+
|
|
69
|
+
Dispatch resolves the recipe, target, effective autonomy, and final canonical toolkit before compiling one stable Clio worker harness. The harness contains identity-lite, the shared operating contract, the exact native tool surface (or honest no-tools wording), safety for the enforced autonomy, and the recipe or bounded override persona. Project context, memory, bounded briefing, pipeline input, task text, and run posture remain dynamic messages and therefore do not churn stable hashes. Briefing is explicitly untrusted task data and does not transport conversation or session history.
|
|
70
|
+
|
|
71
|
+
One run has a first-class singular shape: `task` is the worker assignment and
|
|
72
|
+
`briefing` is separate bounded context/data. Briefing never replaces task,
|
|
73
|
+
never gets copied into the receipt task, and remains a separately delimited
|
|
74
|
+
dynamic prompt message. `tasks` is the batch form. A shared top-level briefing
|
|
75
|
+
applies to string tasks and task objects without an override; an object-level
|
|
76
|
+
briefing wins. Supplying both `task` and `tasks` fails instead of choosing one.
|
|
77
|
+
After approval, execution consumes only the registry-owned resolved plan, so
|
|
78
|
+
later mutation of raw arguments cannot change either field.
|
|
79
|
+
|
|
80
|
+
Recipes may declare `budget: {toolCalls, readReserve, synthesis}`. `toolCalls` is the admitted-call phase boundary; the final `readReserve` slots accept canonical `read` plus the agent's granted mutation tools, so a writer can still deliver inside its own reserve; `synthesis: true` forces a text-only final round, while `false` stops after the admitted phase. `guardrails.workerToolCallCap` is transported separately as the ceiling on executed calls and always wins when lower. Native workers and Claude SDK enforce this policy. Claude Code and Antigravity reject explicit-budget recipes because their black-box loops cannot provide equivalent per-call mediation. Before launch, every admitted WorkerSpec v3 contains one concrete effective budget and a settings fingerprint, including custom recipes whose source omitted a budget.
|
|
81
|
+
|
|
82
|
+
## Node setup
|
|
83
|
+
|
|
84
|
+
Fleet nodes are declared under `fleet.nodes` in `settings.yaml`. The implicit
|
|
85
|
+
`local` node always exists and is never declared.
|
|
86
|
+
|
|
87
|
+
```yaml
|
|
88
|
+
fleet:
|
|
89
|
+
nodes:
|
|
90
|
+
- id: node-a
|
|
91
|
+
host: node-a.example.net
|
|
92
|
+
user: me # optional; defaults to the SSH config
|
|
93
|
+
port: 22 # optional
|
|
94
|
+
identityFile: ~/.ssh/id_fleet # optional
|
|
95
|
+
labels: [cpu] # optional operator labels
|
|
96
|
+
maxWorkers: 2 # per-node cap; defaults to 2
|
|
97
|
+
residency: observe # observe (default) or manage
|
|
98
|
+
- id: node-b
|
|
99
|
+
host: node-b.example.net
|
|
100
|
+
maxWorkers: 1
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`clioEntry` may override the remote invocation (default `clio-coder worker`).
|
|
104
|
+
Node ids must be unique and `local` is reserved.
|
|
105
|
+
|
|
106
|
+
Worker profiles can pin work to a node: `workers.profiles.<name>.node` routes
|
|
107
|
+
every dispatch bound to that profile. The `/fleet` overlay's profiles tab
|
|
108
|
+
edits the pin (`o` key), and the dispatch tool accepts an explicit `node`
|
|
109
|
+
argument per task.
|
|
110
|
+
|
|
111
|
+
## Doctor preflight
|
|
112
|
+
|
|
113
|
+
A remote node is dispatch-eligible only after one preflight pass proved, over
|
|
114
|
+
the node's real SSH channel:
|
|
115
|
+
|
|
116
|
+
1. reachability (SSH connects in batch mode),
|
|
117
|
+
2. a version-matched `clio-coder` on the remote invocation path,
|
|
118
|
+
3. path parity for the project root (the shared-filesystem assumption),
|
|
119
|
+
4. a writable remote state directory,
|
|
120
|
+
5. node-scoped target reachability, runtime/model compatibility, endpoint
|
|
121
|
+
identity, and explicit resource facts where the target exposes them.
|
|
122
|
+
|
|
123
|
+
Run it with `clio-coder doctor`. Results persist under the state dir
|
|
124
|
+
(`fleet-preflight.json`) keyed by node and project root, so eligibility
|
|
125
|
+
survives across processes. A record is invalidated by a changed host, a
|
|
126
|
+
changed project root, or a local `clio-coder` upgrade; admission then fails closed
|
|
127
|
+
with a reason that names the fix (run `clio-coder doctor` again). Failing nodes are
|
|
128
|
+
doctor warnings, never fatal: the fleet degrades to the nodes that passed.
|
|
129
|
+
|
|
130
|
+
## Placement and process-safe admission
|
|
131
|
+
|
|
132
|
+
Placement and admission are separate, deterministic authorities:
|
|
133
|
+
|
|
134
|
+
1. An explicit request pin, profile pin, or approved route envelope restricts
|
|
135
|
+
the eligible node set. Unknown, offline, stale-preflight, or incompatible
|
|
136
|
+
pins fail closed; they never silently fall back.
|
|
137
|
+
2. For unpinned eligible nodes, placement prefers lower durable lease usage
|
|
138
|
+
read through the fleet registry; declaration order breaks ties.
|
|
139
|
+
3. The capacity lease store decides under one cross-process state lock (`dispatch-admission.json`).
|
|
140
|
+
A stale placement preference cannot over-admit a node.
|
|
141
|
+
4. If a pinned or selected node is momentarily full, the bounded admission
|
|
142
|
+
queue preserves priority/FIFO order until its finite deadline instead of
|
|
143
|
+
silently selecting another node.
|
|
144
|
+
|
|
145
|
+
The durable capacity state file (`dispatch-admission.json`) uses schema version 2 and owns global and per-node leases, heartbeats, reservation transfer, retry rebinding, and the TTL-bounded operator drain (`DEFAULT_CAPACITY_DRAIN_TTL_MS` = 3,600,000 ms). A lease acts as durable expiring authority (`DEFAULT_CAPACITY_LEASE_TTL_MS` = 30,000 ms) and is reclaimed only with owner-liveness evidence when a process birth token cannot prove process death. A plan reserves its peak wave, and a retry rebinds the same assignment member to its actual node and cost bound so that an assignment retry belongs to its existing plan slot and cannot queue behind or outspend itself. Full leasing schema and locking protocols are specified in [capacity-and-scheduling.md](capacity-and-scheduling.md).
|
|
146
|
+
|
|
147
|
+
Use `clio-coder fleet drain [--json]` before maintenance to close that shared
|
|
148
|
+
admission authority. Existing workers continue, but new plans and every new
|
|
149
|
+
execution start—including a retry or a previously reserved member—fail closed.
|
|
150
|
+
The drain expires after one hour so an abandoned operator process cannot wedge
|
|
151
|
+
future dispatch; repeating the command renews the deadline. `clio-coder fleet
|
|
152
|
+
status [--json]` reports the active deadline, requesting PID, and request time.
|
|
153
|
+
Use `clio-coder fleet resume [--json]` to reopen admission early. Detailed drain mechanics are documented in [capacity-and-scheduling.md](capacity-and-scheduling.md).
|
|
154
|
+
|
|
155
|
+
With no fleet configured and nothing requested, placement resolves to the
|
|
156
|
+
implicit local path and optional fleet-node provenance may remain absent.
|
|
157
|
+
Every new receipt uses strict integrity v15; older receipt formats are not
|
|
158
|
+
accepted by the current reader.
|
|
159
|
+
|
|
160
|
+
## Failure semantics
|
|
161
|
+
|
|
162
|
+
- Channel failures (a stalled heartbeat, a spawn failure, SSH exit 255) count
|
|
163
|
+
against the node; completing the protocol counts for it; operator cancels
|
|
164
|
+
are neutral.
|
|
165
|
+
- Two consecutive channel failures classify the node dead. Every other
|
|
166
|
+
in-flight run on that node is reaped through the stall path, finalizes as
|
|
167
|
+
`stalled` (retryable), and its bounded retry re-enters placement on a
|
|
168
|
+
surviving node.
|
|
169
|
+
- Every failover hop is recorded as a reroute (`fromNode`, `toNode`, reason)
|
|
170
|
+
on the ledger row and the receipt, so the placement lineage of a run is
|
|
171
|
+
reconstructable from evidence alone.
|
|
172
|
+
- An idle node is never auto-offlined by staleness; only consecutive channel
|
|
173
|
+
failures change the process-local registry health to `offline`. Doctor
|
|
174
|
+
preflight is a separate durable eligibility gate: a failed or stale record
|
|
175
|
+
blocks placement without pretending it changed channel health.
|
|
176
|
+
|
|
177
|
+
## Topologies
|
|
178
|
+
|
|
179
|
+
All topologies go through the dispatch tool, the same admission chain, and
|
|
180
|
+
the autonomy matrix. Workers never exceed the orchestrator's authority; a
|
|
181
|
+
request-level `autonomy` can only narrow the level (reviewers and judges run
|
|
182
|
+
`read-only`).
|
|
183
|
+
|
|
184
|
+
| Topology | Invocation | Semantics |
|
|
185
|
+
| --- | --- | --- |
|
|
186
|
+
| Singular | `task: "..."` | One assignment, with optional separate `briefing`. |
|
|
187
|
+
| Parallel (default) | `tasks: [...]` | Fan out, wait for all, one summary. |
|
|
188
|
+
| Sequential | `mode: "sequential"` | One at a time, stop reporting on timeout/abort. |
|
|
189
|
+
| Pipeline | `mode: "pipeline"` | Each step receives the previous step's output as data. |
|
|
190
|
+
| Detached | `detach: true` | Return logical assignment ids and a batch id immediately; collect later. |
|
|
191
|
+
| Review gate | `review: {reviewer?, max_cycles?}` | Builder, read-only reviewer verdict, bounded revise loop. |
|
|
192
|
+
| Compete | `mode: "compete", candidates: 2..4` | N candidates in scratch worktrees, read-only judge, winner applied or preserved. |
|
|
193
|
+
| Agent automation | `agent: "auto"` | Baselines candidate agent from task shape via shared classifier (`coder`, `tester`, `documenter`, `verifier`, `researcher`, `scout`); advisory unless activated. |
|
|
194
|
+
|
|
195
|
+
### Detached fan-out, backgrounding, and collect
|
|
196
|
+
|
|
197
|
+
`detach: true` validates, admits, and spawns every task, then returns. The
|
|
198
|
+
reported id is the logical assignment id (also the first attempt's run id).
|
|
199
|
+
For an in-flight attached dispatch, pressing `Alt+S` or `Ctrl+Alt+B` converts
|
|
200
|
+
the running attached dispatch into a detached batch. Backgrounding checks
|
|
201
|
+
against a refusal table: it refuses Scout dependency plans driving stages from
|
|
202
|
+
the turn, compete judge gates, review cycle gates, multi-step pipelines,
|
|
203
|
+
dispatches with explicit `timeout_ms`, or missing detached records.
|
|
204
|
+
|
|
205
|
+
Attempts keep streaming into the board and immutable run ledger. The batch and
|
|
206
|
+
assignment index are durable (`batches.json` and `assignments.json` under the
|
|
207
|
+
state dir), so collection survives session exit. Gather results with the
|
|
208
|
+
monitor tool: `mode="wait"` observes one assignment for a bounded time (it
|
|
209
|
+
never cancels it; `steer` with `action="cancel"` cancels its current attempt
|
|
210
|
+
and suppresses later attempts); `mode="collect"` is the barrier over a batch id
|
|
211
|
+
or assignment-id list. It returns a pending snapshot while assignments are in
|
|
212
|
+
flight, then each assignment's terminal attempt plus `attemptRunIds` history.
|
|
213
|
+
Collecting marks the batch so the turn-end nudge stops firing. `wait` observes
|
|
214
|
+
without collecting; `collect` is the authoritative terminal batch operation.
|
|
215
|
+
Collect every detached batch before final synthesis.
|
|
216
|
+
|
|
217
|
+
### Review gate
|
|
218
|
+
|
|
219
|
+
The builder runs the task. A reviewer then inspects the workspace against the
|
|
220
|
+
task. The reviewer defaults to the builtin `verifier` recipe
|
|
221
|
+
(`DEFAULT_GATE_DECIDER_AGENT_ID`) and never falls back to the builder's own
|
|
222
|
+
agent; it is pinned to read-only autonomy and is routable to a different node,
|
|
223
|
+
model, or target.
|
|
224
|
+
|
|
225
|
+
The reviewer answers a typed `verifier-report` contract rather than trailing
|
|
226
|
+
prose:
|
|
227
|
+
|
|
228
|
+
```json
|
|
229
|
+
{"verdict":"pass","checks":[{"name":"npm run typecheck","passed":true,"evidence":"exit 0"}]}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
`revise` is not a verdict a model authors. The reviewer answers `pass` or
|
|
233
|
+
`fail`, and `decideReviewGate` in
|
|
234
|
+
`src/domains/dispatch/gate-decisions.ts` owns the continuation policy: a
|
|
235
|
+
non-passing verdict below the terminal cycle becomes `revise` and re-runs the
|
|
236
|
+
builder with only the failed checks threaded as input data, bounded by
|
|
237
|
+
`max_cycles` (default 2, max 4). On the terminal cycle the verdict settles as
|
|
238
|
+
reported. A reviewer that produces no structured result settles as `exhausted`
|
|
239
|
+
and surfaces as an explicit operator decision, never a silent failure.
|
|
240
|
+
|
|
241
|
+
### Compete
|
|
242
|
+
|
|
243
|
+
N candidate builders (2 to 4) run the same task, each in its own scratch git
|
|
244
|
+
worktree under `.clio-coder/worktrees/<group>/` on its own
|
|
245
|
+
`clio/compete/<group>/<n>` branch. Each candidate's work is committed on its
|
|
246
|
+
branch; a read-only judge ranks the branches and names a winner
|
|
247
|
+
(`WINNER: <n>`). At full-auto the winning branch is merged. At supervised
|
|
248
|
+
levels the winner's branch and worktree are preserved and the operator
|
|
249
|
+
confirms through `apply_winner`, whose approval prompt is the winner
|
|
250
|
+
confirmation. Losers are cleaned on every path, including abort.
|
|
251
|
+
|
|
252
|
+
The compete group is a durable transaction owner. Its manifest records the
|
|
253
|
+
coordinator identity and every admitted worker process before the dispatch
|
|
254
|
+
handle is returned. At orchestrator startup, Clio uses process birth tokens
|
|
255
|
+
to distinguish the leased process from PID reuse, terminates an abandoned
|
|
256
|
+
worker or ACP process group, and then removes the group's registered
|
|
257
|
+
worktrees and branches. If a judge output is waiting in the decision journal,
|
|
258
|
+
the workers are quiesced but the candidates remain until that output is bound
|
|
259
|
+
to an integrity-verified judge receipt; a recovered winner is preserved for
|
|
260
|
+
operator inspection rather than silently auto-applied after restart.
|
|
261
|
+
|
|
262
|
+
### ExecutionPlan and plan approval
|
|
263
|
+
|
|
264
|
+
Every orchestration shape compiles to one strict ExecutionPlan v2 DAG with
|
|
265
|
+
stable task ids, explicit dependencies, requested and approved authority,
|
|
266
|
+
capacity-bounded waves, stop/continue semantics, and authenticated structured
|
|
267
|
+
handoffs. The scheduler performs whole-plan preflight and reservation before
|
|
268
|
+
the first worker spawns. A missing authority grant is an admission failure.
|
|
269
|
+
|
|
270
|
+
A plan-scale dispatch call (more than one task, review, compete, effective
|
|
271
|
+
remote placement, or `apply_winner`) maps to an approval ask at supervised
|
|
272
|
+
autonomy levels. Before asking, Clio resolves the effective agent, target,
|
|
273
|
+
model, node, bounded review cycles/candidates/judge, and scheduling cost
|
|
274
|
+
ceiling, then reserves the plan's capacity and budget as a unit. The parked
|
|
275
|
+
call shows that sanitized artifact, including the approved fallback candidates
|
|
276
|
+
in preference order, and one approval covers the whole plan. Declining the plan
|
|
277
|
+
rolls the whole reservation back.
|
|
278
|
+
|
|
279
|
+
A reservation holds three scarce things and nothing else: a global concurrency
|
|
280
|
+
slot, a per-node slot, and a budget upper bound. It never pins route identity.
|
|
281
|
+
Capacity and budget are checked for the plan as a unit at approval time, per
|
|
282
|
+
wave, so a three-step sequential plan holds one slot rather than three and N
|
|
283
|
+
parallel tasks whose individual estimates each fit but whose sum breaches the
|
|
284
|
+
ceiling are denied together with the aggregate figure. A member is consumed
|
|
285
|
+
once by its assignment and released once when that assignment settles; a retry
|
|
286
|
+
that lands on a different node or a differently priced route rebinds the member
|
|
287
|
+
atomically and fails closed if the new node has no free slot or the new
|
|
288
|
+
estimate breaches the ceiling. Reservations owned by a dead process are
|
|
289
|
+
reclaimed at startup, with a TTL as the backstop, and live sibling processes'
|
|
290
|
+
reservations are preserved. Execution consumes the
|
|
291
|
+
same pins, including each expanded builder/reviewer/candidate/judge role and
|
|
292
|
+
the SSH node's transport kind and host. A placement, host, capability, or
|
|
293
|
+
cost-ceiling change fails before launch rather than silently choosing an
|
|
294
|
+
unapproved alternative. Full-auto skips the stop and seals the
|
|
295
|
+
same plan hash into every run's receipt instead
|
|
296
|
+
(`plan.approval: "full-auto"`). Read-only autonomy denies dispatch outright,
|
|
297
|
+
as it denies every non-read action.
|
|
298
|
+
|
|
299
|
+
The registry boundary is resolved dispatch plan v3. `deadlineMs` is required:
|
|
300
|
+
a fleet plan carries a positive finite number and a non-fleet plan carries
|
|
301
|
+
explicit `null`. Older versions, missing fields, and compatibility shapes are
|
|
302
|
+
rejected.
|
|
303
|
+
|
|
304
|
+
### Shipped fleets and contract versions
|
|
305
|
+
|
|
306
|
+
Clio ships three builtin fleet contracts under `src/domains/agents/fleets/`: `build-test`, `build-review`, and `sdlc`. Projects can declare custom fleet contracts or shadow builtin fleets by placing Markdown files under `.clio-coder/fleets/<name>.md`. A file named `.clio-coder/fleets/<name>.md` shadows a builtin fleet of the same name.
|
|
307
|
+
|
|
308
|
+
Fleet contracts support schema versions 1 through 4:
|
|
309
|
+
- Version 1: Supports agent steps only.
|
|
310
|
+
- Version 2: Introduces deterministic code steps.
|
|
311
|
+
- Version 3: Adds bounded check/repair loops and commit steps with `commitFrom` message sources.
|
|
312
|
+
- Version 4 (`FLEET_WRITE_BOUNDARY_VERSION = 4`): Introduces per-step declared write boundaries (`writes`) and orchestrator post-step enforcement.
|
|
313
|
+
|
|
314
|
+
### Per-step write boundaries (Contract v4)
|
|
315
|
+
|
|
316
|
+
Contract v4 requires every step to declare its write boundary using the `writes` allowlist property. Steps with scope `readonly` declare an empty allowlist (`[]`).
|
|
317
|
+
|
|
318
|
+
The grammar for declared write boundary entries requires repository-relative POSIX paths:
|
|
319
|
+
- Trailing `/` indicates a directory subtree allowlist.
|
|
320
|
+
- Exact relative paths without a trailing `/` permit changes to that single file.
|
|
321
|
+
- Declarations must not contain glob characters (`*`, `?`, `[`, `]`, `{`, `}`), `..` or `.` segments, backslashes, or absolute paths.
|
|
322
|
+
- Each step declaration is capped at a maximum of 32 entries (`WRITE_BOUNDARY_MAX_ENTRIES = 32`).
|
|
323
|
+
|
|
324
|
+
Write boundary enforcement is detect-and-rollback, never OS or filesystem sandboxing. A step runs with whatever filesystem permissions its underlying execution environment possesses. Upon step completion, the orchestrator inspects the working tree to verify compliance:
|
|
325
|
+
1. Snapshot baseline: Before a step executes, the orchestrator captures a snapshot (`captureWorkspaceSnapshot`) recording the baseline git HEAD commit and existing dirty path content tokens.
|
|
326
|
+
2. Workspace diffing: After step completion, the orchestrator runs git status inspection (`diffWorkspace`) to identify changed paths relative to the snapshot baseline commit.
|
|
327
|
+
3. Rollback execution: Unauthorized changes (modified paths not covered by the step's declared allowlist) are automatically rolled back (`rollbackPath`).
|
|
328
|
+
4. Content source: Rollback restores content strictly from what git already has in the pinned baseline commit (`snapshot.head`). If a path was already dirty when the step snapshot was captured, its prior content is not stored in git, so in-place restoration cannot be guaranteed. The working tree is left as the step made it, and the status settles as `rollback-incomplete`.
|
|
329
|
+
5. Violation handling: Any unauthorized change fails the step with the typed reason `writes_boundary_violation`.
|
|
330
|
+
6. Window attribution: Enforcement evaluates scheduling windows (`wave-<n>` or `revalidate-<stepId>-<n>`). A wave window cannot combine steps with overlapping declared boundaries or multiple concurrent step writers, ensuring single-step attribution.
|
|
331
|
+
7. Ignored paths and state subtraction: Enforcement evaluates paths reported by git status. Git-ignored paths remain outside enforcement. The Clio state directory (`.clio-coder/` or `clioStateDir()`) is subtracted from status checks so orchestrator receipts, code step log artifacts, and boundary verdicts do not trigger false violations.
|
|
332
|
+
8. Durable records: Verdicts are serialized as JSON records at `write-boundaries/<rootId>/<window>.json` under the Clio state directory, carrying the baseline HEAD commit, checked paths, violations, rollback actions, status, and SHA-256 digest.
|
|
333
|
+
|
|
334
|
+
### Bounded check/repair loops
|
|
335
|
+
|
|
336
|
+
Contract v3 and v4 support declared check/repair loops (`kind: loop`). A loop declares `id`, `maxAttempts` (an integer between 1 and `FLEET_LOOP_MAX_ATTEMPTS = 5`), `check` (a code command or agent reviewer), and `repair` (an agent coder).
|
|
337
|
+
|
|
338
|
+
At plan compilation, the orchestrator unrolls each loop statically into a deterministic hashed DAG containing `maxAttempts` verification check steps (`<loopId>.check.<n>`) and `maxAttempts - 1` repair steps (`<loopId>.repair.<n>`).
|
|
339
|
+
- Receipt per attempt: Every attempt in an unrolled loop executes as an independent plan node and produces its own receipt.
|
|
340
|
+
- Recovery role: Repair attempts following the first check are assigned the `recovery` execution role.
|
|
341
|
+
- Spent bounds: Reaching `maxAttempts` without a passing check settles the loop with the terminal reason `loop_bound_exhausted`.
|
|
342
|
+
- Four terminal reasons: A loop concludes with one of four reasons: `resolved` (verification passed), `loop_bound_exhausted` (attempt ceiling spent), `loop_step_failed` (underlying step errored or was denied), or `loop_not_reached` (prior plan dependencies failed).
|
|
343
|
+
- Node counting: Unneeded nodes (verifications or repairs remaining after a loop resolves) are counted separately from skipped nodes.
|
|
344
|
+
- Verification staleness: The scheduler enforces verification staleness by re-running a check step if a subsequent workspace-editing step executes after it.
|
|
345
|
+
|
|
346
|
+
### Deterministic code steps
|
|
347
|
+
|
|
348
|
+
Deterministic code steps (`kind: code`) execute known commands directly as subprocesses rather than calling an agent model.
|
|
349
|
+
- Registry binding: The `command` property must reference a command ID declared in `.clio-coder/fleets/commands.yaml`. Invocation strings are never generated from model output.
|
|
350
|
+
- Execution environment: Code steps run unattended with arguments bound from the command registry, fixed working directory, closed environment allowlist (`FLEET_COMMAND_BASE_ENV` plus declared command env), bounded timeout (`timeoutMs`), byte-capped output capture (`CODE_STEP_CAPTURE_MAX_BYTES` = 1 MB log artifact, `CODE_STEP_EXCERPT_MAX_BYTES` = 8 KB excerpt), no stdin pipe, no permission prompt, and no shell interpreter.
|
|
351
|
+
- Missing registry diagnostic: If a contract declares code steps but `.clio-coder/fleets/commands.yaml` is missing in the repository, `clio-coder fleet list` reports the fleet status as `setup` and provides the remedy: `needs .clio-coder/fleets/commands.yaml declaring <id>; declare each id there under commands: with an argv list; clio-coder docs fleet_dispatch has the schema`.
|
|
352
|
+
- Commit message sources: A code step with `commitFrom` populates its `commitMessage` placeholder from the output of preceding agent steps.
|
|
353
|
+
- Route quality: Code steps do not consume model tokens or cost estimates; their quality reports `unmeasured` rather than zero.
|
|
354
|
+
|
|
355
|
+
#### Command Registry Schema (`.clio-coder/fleets/commands.yaml`)
|
|
356
|
+
|
|
357
|
+
The repository command registry binds command IDs to exact argument vectors:
|
|
358
|
+
|
|
359
|
+
```yaml
|
|
360
|
+
version: 1
|
|
361
|
+
commands:
|
|
362
|
+
test:
|
|
363
|
+
argv: ["npm", "test"]
|
|
364
|
+
timeoutMs: 600000
|
|
365
|
+
description: "Run repository test suite"
|
|
366
|
+
lint:
|
|
367
|
+
argv: ["npm", "run", "lint"]
|
|
368
|
+
timeoutMs: 300000
|
|
369
|
+
build:
|
|
370
|
+
argv: ["npm", "run", "build"]
|
|
371
|
+
timeoutMs: 600000
|
|
372
|
+
commit:
|
|
373
|
+
argv: ["git", "commit", "-m"]
|
|
374
|
+
timeoutMs: 60000
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
Each command entry supports:
|
|
378
|
+
- `argv` (required): Array of command arguments starting with the binary name (no shell strings).
|
|
379
|
+
- `cwd` (optional): Repository-relative working directory (defaults to repository root).
|
|
380
|
+
- `timeoutMs` (optional): Per-step execution timeout in milliseconds (defaults to 600,000 ms; bounds: 1,000 to 3,600,000 ms).
|
|
381
|
+
- `env` (optional): Array of extra environment variable names to pass through on top of `FLEET_COMMAND_BASE_ENV` (`PATH`, `HOME`, `LANG`, `LC_ALL`, `TZ`, `TMPDIR`).
|
|
382
|
+
- `description` (optional): Human-readable description.
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
## Measured route selection and agent automation
|
|
386
|
+
|
|
387
|
+
The joint resolver treats agent, target, model, runtime, and node as one
|
|
388
|
+
bounded tuple. Manual pins, the approved plan envelope, authority, audience,
|
|
389
|
+
required tools and skills, result contract, response-schema support, locality,
|
|
390
|
+
authentication, network policy, endpoint reachability, context, resource fit,
|
|
391
|
+
capacity, budget, deadline, and cooldown are hard filters. Only survivors are
|
|
392
|
+
estimated and Pareto-ranked by conservative quality, reliability, completed
|
|
393
|
+
cost and latency, queue wait, and cache affinity. The complete bounded
|
|
394
|
+
candidate/rejection set is sealed; at most three fallbacks are projected.
|
|
395
|
+
|
|
396
|
+
Shadow is the default and never changes the explicit route. Active route
|
|
397
|
+
selection requires both the execution role and posture to be named:
|
|
398
|
+
|
|
399
|
+
```yaml
|
|
400
|
+
routing:
|
|
401
|
+
activeRoles: [researcher, verifier, reviewer, judge]
|
|
402
|
+
activePostures: [quality, balanced]
|
|
403
|
+
agentAutomation:
|
|
404
|
+
activeAgentRoles: []
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
For every exact tuple, `evaluateRouteReadiness` requires consistent hard-
|
|
408
|
+
constraint evaluation, no integrity failures, at least six role-specific
|
|
409
|
+
quality labels, conservative quality and reliability floors, known cost,
|
|
410
|
+
fresh node/endpoint/resource/capacity/settings facts, and decision p95 below
|
|
411
|
+
10 ms. If no tuple is ready, active mode refuses the assignment. It never
|
|
412
|
+
falls back to the fixed route, and manual or `failover: none` intent never
|
|
413
|
+
drifts.
|
|
414
|
+
|
|
415
|
+
`agent: "auto"` first filters recipe audience, authority, tools, skills,
|
|
416
|
+
result contract, locality, and governance. Bounded task features affect cold
|
|
417
|
+
priors only; one truthful role-quality label retires the task prior. Agent
|
|
418
|
+
automation has its own readiness report per agent/spec/role and stays shadow
|
|
419
|
+
unless the operator names an exact agent/role pair. A read-only Scout can
|
|
420
|
+
settle reconnaissance directly or return at most four typed subtasks. The
|
|
421
|
+
coordinator validates ids, dependencies, expected result contracts, and
|
|
422
|
+
requested authority and rejects embedded agents, routes, deadlines, costs, or
|
|
423
|
+
other control fields. Escalation to workspace editing requires authenticated
|
|
424
|
+
plan approval or existing full-auto authority.
|
|
425
|
+
|
|
426
|
+
## Assignments, attempts, and failover
|
|
427
|
+
|
|
428
|
+
A dispatch is a logical assignment containing one or more immutable run
|
|
429
|
+
attempts. The assignment id and terminal run ids are distinct identities;
|
|
430
|
+
there is no `runIds` compatibility alias. Public `finalPromise` handles resolve only when the assignment succeeds,
|
|
431
|
+
is canceled, or exhausts its retry policy; the returned receipt is the
|
|
432
|
+
terminal attempt's unchanged receipt. Earlier attempts stay independently
|
|
433
|
+
addressable and integrity-verifiable.
|
|
434
|
+
|
|
435
|
+
The assignment owns the event stream as well as the terminal receipt. The
|
|
436
|
+
stream returned by `dispatch()` yields attempt 1's frames, then a synthetic
|
|
437
|
+
`attempt_start` frame for each retry, then that attempt's frames, and ends when
|
|
438
|
+
the assignment settles. A consumer therefore observes the same run the receipt
|
|
439
|
+
describes, and the marker tells it to discard state accumulated from an attempt
|
|
440
|
+
that has been superseded. The stream is single-consumer and bounded
|
|
441
|
+
(drop-oldest), so a slow reader degrades live display and never stalls a worker.
|
|
442
|
+
|
|
443
|
+
Manual `target`, `model`, or `node` pins default to exact failover (`none`): a
|
|
444
|
+
retry may repeat the tuple but cannot silently move away from it. `approved`
|
|
445
|
+
failover requires an ordered `allowedCandidates` envelope of exact
|
|
446
|
+
agent/target/model/node tuples and can never leave that set. `automatic`
|
|
447
|
+
failover lets typed infrastructure failures exclude only the failed route
|
|
448
|
+
part—for example, an SSH channel failure can move the node while retaining the
|
|
449
|
+
agent, target, and model. Cancellation, policy rejection, and permission
|
|
450
|
+
refusal neither retry nor penalize infrastructure.
|
|
451
|
+
|
|
452
|
+
A plan-approved task is never `automatic`. An explicitly pinned task seals its
|
|
453
|
+
exact tuple with `failover: "none"`; any other planned task seals
|
|
454
|
+
`failover: "approved"` with a bounded candidate list enumerated by
|
|
455
|
+
`route-candidates.ts` and rendered into the plan text the operator approves.
|
|
456
|
+
Validation rejects `automatic` on a request carrying plan provenance, so an
|
|
457
|
+
approved dispatch can only reroute to a tuple the approval actually showed.
|
|
458
|
+
|
|
459
|
+
Retries are governed by `workers.maxRetries` and backoff, and by nothing else.
|
|
460
|
+
A target cooldown protects new work from a known-bad target; it does not gate
|
|
461
|
+
an assignment already in flight, because that assignment's own retry budget is
|
|
462
|
+
the correct and sufficient bound. A retry denied at admission settles the
|
|
463
|
+
assignment failed, reports the reason on stderr, and records it in the
|
|
464
|
+
assignment's `outcomeDetail`.
|
|
465
|
+
|
|
466
|
+
Assignment status, attempt ids, and terminal run id are stored separately in
|
|
467
|
+
`assignments.json` while each attempt keeps its own strict v15 receipt.
|
|
468
|
+
Pipelines and batches await assignment terminals, so downstream stages consume
|
|
469
|
+
the successful fallback output rather than an earlier failed attempt.
|
|
470
|
+
|
|
471
|
+
Editing assignments also own one baseline-pinned workspace transaction. Every
|
|
472
|
+
attempt gets a distinct worktree. Before any winning diff can reach the
|
|
473
|
+
destination checkout, a pure gate checks terminal outcome, receipt integrity,
|
|
474
|
+
result conformance, and quality-gate success; protected artifacts, baseline
|
|
475
|
+
ancestry, and destination cleanliness are then rechecked on disk. Refusal
|
|
476
|
+
preserves the winner and recovery instructions, and the transaction cannot be
|
|
477
|
+
closed while a winner remains unapplied.
|
|
478
|
+
|
|
479
|
+
## Receipts
|
|
480
|
+
|
|
481
|
+
Receipts carry exactly one integrity version (`RUN_RECEIPT_INTEGRITY_VERSION = 15`), which authenticates the complete receipt and reconstructible ledger provenance surface. There is no historical verification path: any other version is invalid, and a receipt that fails verification is never read as evidence. The fleet provenance fields covered by the digest
|
|
482
|
+
include:
|
|
483
|
+
|
|
484
|
+
- `node`: the fleet node the worker ran on (`id`, `kind`, `host`).
|
|
485
|
+
- `reroutes`: dead-node failover hops, oldest first.
|
|
486
|
+
- `gate`: review/compete provenance (role, group, cycle, subject run ids with
|
|
487
|
+
their receipt digests, and the verdict that caused a revise builder).
|
|
488
|
+
- `plan`: plan-approval provenance (hash, topology, task count, cost ceiling,
|
|
489
|
+
approval kind, and the registry approval identity when supervised).
|
|
490
|
+
- `briefing`: byte count and SHA-256 of the exact canonical parent briefing;
|
|
491
|
+
the prose is not retained and is distinct from bounded project context.
|
|
492
|
+
- `steering`: ordered byte/hash/timestamp and acknowledgement provenance for
|
|
493
|
+
successfully written steers; steering prose is never stored.
|
|
494
|
+
- `outcomeCode`: the stable terminal classifier, including
|
|
495
|
+
`worker_final_output_missing` when an otherwise successful worker exits
|
|
496
|
+
without a nonempty receipt-sealed final answer.
|
|
497
|
+
- `routingIntent`, `routeDecision`, and `quality`: the normalized hard bounds,
|
|
498
|
+
complete current-policy decision, exact execution role, route estimate and
|
|
499
|
+
readiness evidence, and authenticated quality sources.
|
|
500
|
+
- `resultContract`: the admitted contract identity and `valid`, `invalid`, or
|
|
501
|
+
`not-reached` conformance state. Only a due correctness-bearing contract can
|
|
502
|
+
label route quality.
|
|
503
|
+
- `validationGrounding`: claimed versus grounded validations checked against canonical executed commands.
|
|
504
|
+
- `capabilityMismatch`: capability class versus task shape verdict (`refuse` vs `flag`).
|
|
505
|
+
- worker attestation identity: settings/WorkerSpec fingerprints, runtime,
|
|
506
|
+
target, endpoint, model, tool surface, node, and bounded resource facts.
|
|
507
|
+
|
|
508
|
+
Process exit zero is not a delegated deliverable. Native and ACP runs succeed
|
|
509
|
+
only when the drained event stream yields a nonempty receipt output with
|
|
510
|
+
`state: "final"`. A missing final answer fails with
|
|
511
|
+
`outcomeCode: "worker_final_output_missing"`; any captured unfinished text is
|
|
512
|
+
retained only as `state: "partial"` diagnostics and automatic retry is
|
|
513
|
+
suppressed. Dispatch, monitor, ledger, receipt, terminal bus event, and retry
|
|
514
|
+
policy all consume that same final classification.
|
|
515
|
+
|
|
516
|
+
Receipt integrity and evidence verification are separate axes. Integrity says
|
|
517
|
+
that the sealed receipt matches its ledger envelope; evidence verification
|
|
518
|
+
reports whether Clio observed an applicable validation tool (or marks the
|
|
519
|
+
basis unknown/not applicable). A read-only Scout can therefore report `receipt_integrity=verified/v15/sha256` alongside
|
|
520
|
+
`evidence_verification=not_applicable/read-only-agent`. Briefing provenance and
|
|
521
|
+
bounded `project_context` provenance are also rendered independently; neither
|
|
522
|
+
hash substitutes for the other.
|
|
523
|
+
|
|
524
|
+
Gate references point backward: a reviewer references the builder it
|
|
525
|
+
reviewed, a revise builder references the reviewer whose findings it
|
|
526
|
+
received, and a judge references every candidate. Because a worker receipt
|
|
527
|
+
seals before the coordinator parses its final verdict, terminal pass/fail,
|
|
528
|
+
exhaustion, winner, and confirmation outcomes are append-only integrity-
|
|
529
|
+
covered gate-decision artifacts under the state directory. Evidence builds
|
|
530
|
+
discover them from linked receipt ids and export `gate-decisions.json`.
|
|
531
|
+
Reviewer and judge terminal output first crosses an integrity-covered
|
|
532
|
+
write-ahead boundary under `state/gate-decisions/pending/`, before the caller
|
|
533
|
+
waits for the final receipt. Restart recovery verifies the receipt, applies
|
|
534
|
+
the same verdict/winner parser, materializes the final artifact idempotently,
|
|
535
|
+
and only then clears the pending record. Missing receipts, tampering, or a
|
|
536
|
+
conflicting artifact fail closed and leave the journal and any compete
|
|
537
|
+
worktrees available for inspection.
|
|
538
|
+
|
|
539
|
+
Protected-artifact hard blocks follow compete work into candidate worktrees:
|
|
540
|
+
Clio mirrors every applicable parent-checkout path into each admitted worker
|
|
541
|
+
spec and independently rejects a winner branch whose diff touches a protected
|
|
542
|
+
parent path. The merge/apply coordinator rechecks the live protection state,
|
|
543
|
+
so neither full-auto nor a later supervised winner approval can override that
|
|
544
|
+
hard block.
|
|
545
|
+
|
|
546
|
+
## Operator visibility
|
|
547
|
+
|
|
548
|
+
- The dispatch board shows per-run cards with the node id (absent placement
|
|
549
|
+
renders `local`), gate badges (`gate reviewer c2`), reroute badges, live
|
|
550
|
+
tool activity (names only; arguments never cross the worker stdout seam),
|
|
551
|
+
and a per-worker context meter.
|
|
552
|
+
- The context meter renders the worker's last-message context occupancy
|
|
553
|
+
against the model's context window: healthy below 80 percent, warn from 80,
|
|
554
|
+
critical from 95.
|
|
555
|
+
- `/fleet` cycles status (running and retrying runs with a node column),
|
|
556
|
+
nodes (the registry view with state, capacity, and last-seen), profiles
|
|
557
|
+
(with the node pin), and bindings.
|
|
558
|
+
- The monitor tool reports the node and reroute lineage on `status`, `list`,
|
|
559
|
+
and `collect`.
|
|
560
|
+
- `clio-coder fleet status [--json]` shows the durable ledger view cross-process.
|
|
561
|
+
|
|
562
|
+
## Speculation observer
|
|
563
|
+
|
|
564
|
+
A shadow-mode observer watches every dispatch, computes the plan a rule-based
|
|
565
|
+
pipeline would have chosen (synchronous keyword rules, no model calls), and
|
|
566
|
+
records plan-versus-actual accuracy into a bounded JSONL under
|
|
567
|
+
`<state>/speculation/observations.jsonl`. It never influences dispatch;
|
|
568
|
+
disabling it changes nothing else.
|
|
569
|
+
|
|
570
|
+
## Residency
|
|
571
|
+
|
|
572
|
+
Remote workers default to residency observe: the SSH transport exports
|
|
573
|
+
`CLIO_CODER_RESIDENCY=observe`, so a worker on a node that serves resident models
|
|
574
|
+
(for example a GPU box running the operator's inference server) never evicts
|
|
575
|
+
them. A node opts into management explicitly with `residency: manage` in its
|
|
576
|
+
fleet entry.
|
|
577
|
+
|
|
578
|
+
## Opt-in live regression
|
|
579
|
+
|
|
580
|
+
After `npm run build`, an operator with a configured model target can run the
|
|
581
|
+
single-turn, read-only fleet lifecycle check explicitly:
|
|
582
|
+
|
|
583
|
+
```bash
|
|
584
|
+
CLIO_CODER_LIVE_EVAL=1 npm run test:live-eval:fleet-dispatch
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
It is not part of deterministic CI. The script copies the repository into an
|
|
588
|
+
isolated committed workspace, sandboxes all Clio config/state/data/cache,
|
|
589
|
+
exercises Scout, bounded spot-checking, detached Debugger briefing, steering,
|
|
590
|
+
wait, and collect, and fails if any workspace content changes. Failures retain
|
|
591
|
+
their isolated artifacts for diagnosis.
|