@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.
Files changed (226) hide show
  1. package/CHANGELOG.md +407 -0
  2. package/CODE_OF_CONDUCT.md +21 -0
  3. package/CONTRIBUTING.md +224 -0
  4. package/LICENSE +202 -0
  5. package/NOTICE +9 -0
  6. package/README.md +798 -0
  7. package/SECURITY.md +72 -0
  8. package/assets/clio-coder-logo-128.webp +0 -0
  9. package/damage-control-rules.yaml +419 -0
  10. package/dist/acp-UMLFVA3F.js +92 -0
  11. package/dist/agents-Q4MYPMUW.js +91 -0
  12. package/dist/auth-O6HYIJ6J.js +521 -0
  13. package/dist/chunk-262G75JS.js +35 -0
  14. package/dist/chunk-26BZQOAD.js +1281 -0
  15. package/dist/chunk-2J63S4SF.js +508 -0
  16. package/dist/chunk-3DANZDGR.js +717 -0
  17. package/dist/chunk-4UQA7NCT.js +29 -0
  18. package/dist/chunk-527KG6XR.js +497 -0
  19. package/dist/chunk-5LDRNKX2.js +1063 -0
  20. package/dist/chunk-5N2FG33Q.js +25 -0
  21. package/dist/chunk-67MTHP2E.js +135 -0
  22. package/dist/chunk-6CWDTGUC.js +20 -0
  23. package/dist/chunk-7BHLZB3A.js +2115 -0
  24. package/dist/chunk-7RBKDI66.js +348 -0
  25. package/dist/chunk-AMFR5YA3.js +541 -0
  26. package/dist/chunk-BBUH4VAA.js +1224 -0
  27. package/dist/chunk-BYEU76JP.js +899 -0
  28. package/dist/chunk-CLJ5HLUD.js +458 -0
  29. package/dist/chunk-D5YD55AR.js +116 -0
  30. package/dist/chunk-DXQNI4PC.js +61 -0
  31. package/dist/chunk-E3NYWENM.js +1004 -0
  32. package/dist/chunk-GNGDQYDU.js +34688 -0
  33. package/dist/chunk-GOTUR54M.js +9 -0
  34. package/dist/chunk-HBU5MTAM.js +41 -0
  35. package/dist/chunk-HMYNFFY4.js +28 -0
  36. package/dist/chunk-JPOWPFCU.js +1010 -0
  37. package/dist/chunk-JWHCJDCI.js +1215 -0
  38. package/dist/chunk-KBR4MZZR.js +41 -0
  39. package/dist/chunk-KKKPTZLM.js +93 -0
  40. package/dist/chunk-ME6DNWIU.js +66 -0
  41. package/dist/chunk-NI4DEJMC.js +88 -0
  42. package/dist/chunk-O4EJEDHO.js +659 -0
  43. package/dist/chunk-PIDUD6M2.js +31 -0
  44. package/dist/chunk-PS4PFJQP.js +29459 -0
  45. package/dist/chunk-QV47YRF4.js +48 -0
  46. package/dist/chunk-RQDWMVRB.js +279 -0
  47. package/dist/chunk-TFSSEXL6.js +136 -0
  48. package/dist/chunk-TKHQ4DGZ.js +8290 -0
  49. package/dist/chunk-TPOCL34A.js +2876 -0
  50. package/dist/chunk-UGYAX5YI.js +565 -0
  51. package/dist/chunk-UHTSULZS.js +461 -0
  52. package/dist/chunk-UU3R62TT.js +128 -0
  53. package/dist/chunk-UWIJNAOB.js +3906 -0
  54. package/dist/chunk-VOO7NYPP.js +914 -0
  55. package/dist/chunk-VPAWTYLY.js +117 -0
  56. package/dist/chunk-WD6AJM35.js +1216 -0
  57. package/dist/chunk-X3BR7HWV.js +115 -0
  58. package/dist/chunk-X3NE4WVW.js +120 -0
  59. package/dist/chunk-XNISANGE.js +1395 -0
  60. package/dist/chunk-XV4ZJ6ZM.js +3177 -0
  61. package/dist/cli/index.js +236 -0
  62. package/dist/clio-KIQ5SNDS.js +53 -0
  63. package/dist/components-JVHMUBEB.js +653 -0
  64. package/dist/config-ZFCDBMDC.js +372 -0
  65. package/dist/configure-G4E3A2PG.js +27 -0
  66. package/dist/context-CDXTP2MP.js +293 -0
  67. package/dist/context-E3KIFVXI.js +185 -0
  68. package/dist/context-clear-3F4PLXOS.js +102 -0
  69. package/dist/context-index-Q7YSYTR3.js +106 -0
  70. package/dist/docs-YIETIWZI.js +280 -0
  71. package/dist/doctor-M5HJJZOL.js +61 -0
  72. package/dist/domains/agents/builtins/architect.md +33 -0
  73. package/dist/domains/agents/builtins/coder.md +31 -0
  74. package/dist/domains/agents/builtins/context-bootstrap.md +38 -0
  75. package/dist/domains/agents/builtins/debugger.md +30 -0
  76. package/dist/domains/agents/builtins/documenter.md +31 -0
  77. package/dist/domains/agents/builtins/git-master.md +30 -0
  78. package/dist/domains/agents/builtins/provenance.md +30 -0
  79. package/dist/domains/agents/builtins/researcher.md +71 -0
  80. package/dist/domains/agents/builtins/scout.md +42 -0
  81. package/dist/domains/agents/builtins/tester.md +31 -0
  82. package/dist/domains/agents/builtins/verifier.md +30 -0
  83. package/dist/domains/agents/builtins/wiki-writer.md +41 -0
  84. package/dist/eval-B3KZZESM.js +2674 -0
  85. package/dist/evidence-V67CHM35.js +233 -0
  86. package/dist/evolve-YDZSUQYA.js +518 -0
  87. package/dist/extensions-SRG7XCAH.js +207 -0
  88. package/dist/fleet-CA2CRTVG.js +760 -0
  89. package/dist/fleet-preflight-CLIAX7YR.js +21 -0
  90. package/dist/init-2OZDJE2D.js +227 -0
  91. package/dist/memory-3PIQQAKX.js +207 -0
  92. package/dist/models-DY35XI7Y.js +237 -0
  93. package/dist/paths-5OMXW7Z4.js +57 -0
  94. package/dist/preload-KZVHET2B.js +11 -0
  95. package/dist/reset-PIFYNOS3.js +216 -0
  96. package/dist/run-3VSPP24F.js +735 -0
  97. package/dist/share-D36RQCXM.js +241 -0
  98. package/dist/skills-F2MRLELY.js +445 -0
  99. package/dist/skills-eval-E2ZTW4PL.js +932 -0
  100. package/dist/targets-DZMEZAH4.js +977 -0
  101. package/dist/trace-7NYCUI2J.js +250 -0
  102. package/dist/uninstall-AD3JWHBB.js +322 -0
  103. package/dist/upgrade-WYYBKGDY.js +301 -0
  104. package/dist/usage-ULIDAGFF.js +755 -0
  105. package/dist/version-ROZ6CZKH.js +16 -0
  106. package/dist/wiki-generate-PKFIX6OB.js +377 -0
  107. package/dist/worker/entry.js +1739 -0
  108. package/docs/README.md +93 -0
  109. package/docs/acp.md +120 -0
  110. package/docs/alcf-provider.md +72 -0
  111. package/docs/architecture.md +172 -0
  112. package/docs/artifact-versions.md +54 -0
  113. package/docs/built-in-agents.md +265 -0
  114. package/docs/capacity-and-scheduling.md +97 -0
  115. package/docs/commands-and-modes.md +554 -0
  116. package/docs/config-knobs-audit.md +115 -0
  117. package/docs/configuration-and-targets.md +812 -0
  118. package/docs/context-engine.md +236 -0
  119. package/docs/dispatch-architecture-rationale.md +126 -0
  120. package/docs/documentation-coverage.md +46 -0
  121. package/docs/documentation-guide.md +166 -0
  122. package/docs/environment-variables.md +105 -0
  123. package/docs/eval-runner.md +205 -0
  124. package/docs/evals-internal.md +298 -0
  125. package/docs/evidence-and-memory.md +243 -0
  126. package/docs/evolution.md +143 -0
  127. package/docs/exit-codes-and-output.md +74 -0
  128. package/docs/extensions-and-sharing.md +306 -0
  129. package/docs/fleet-demo-runbook.md +179 -0
  130. package/docs/fleet-dispatch.md +591 -0
  131. package/docs/glossary.md +75 -0
  132. package/docs/html/agents_blueprint.html +936 -0
  133. package/docs/html/alcf_blueprint.html +324 -0
  134. package/docs/html/architecture_blueprint.html +850 -0
  135. package/docs/html/commands_blueprint.html +794 -0
  136. package/docs/html/config_knobs_audit_blueprint.html +178 -0
  137. package/docs/html/configuration_blueprint.html +1080 -0
  138. package/docs/html/context_blueprint.html +603 -0
  139. package/docs/html/documentation_blueprint.html +832 -0
  140. package/docs/html/environment_blueprint.html +404 -0
  141. package/docs/html/eval_blueprint.html +743 -0
  142. package/docs/html/evals_internal_blueprint.html +190 -0
  143. package/docs/html/evolution_blueprint.html +674 -0
  144. package/docs/html/extensions_blueprint.html +2065 -0
  145. package/docs/html/fleet_dispatch_blueprint.html +286 -0
  146. package/docs/html/index.html +919 -0
  147. package/docs/html/lifecycle_blueprint.html +723 -0
  148. package/docs/html/memory_blueprint.html +699 -0
  149. package/docs/html/middleware_blueprint.html +664 -0
  150. package/docs/html/models_blueprint.html +2366 -0
  151. package/docs/html/observability_blueprint.html +683 -0
  152. package/docs/html/provider_adapter_blueprint.html +245 -0
  153. package/docs/html/safety_blueprint.html +1386 -0
  154. package/docs/html/shared.css +571 -0
  155. package/docs/html/shared.js +143 -0
  156. package/docs/html/skills_blueprint.html +671 -0
  157. package/docs/html/soak_blueprint.html +182 -0
  158. package/docs/html/tool_usage_blueprint.html +350 -0
  159. package/docs/html/tools_blueprint.html +2249 -0
  160. package/docs/html/trace_blueprint.html +235 -0
  161. package/docs/html/tui_design_blueprint.html +314 -0
  162. package/docs/html/validation_blueprint.html +961 -0
  163. package/docs/html/worker_dispatch_blueprint.html +231 -0
  164. package/docs/installation-and-lifecycle.md +308 -0
  165. package/docs/middleware-and-components.md +148 -0
  166. package/docs/model-catalog.md +189 -0
  167. package/docs/observability.md +233 -0
  168. package/docs/proactive-memory.md +452 -0
  169. package/docs/prompt-envelope-and-tools.md +142 -0
  170. package/docs/provider-adapter-cookbook.md +148 -0
  171. package/docs/release-cut-checklist.md +138 -0
  172. package/docs/safety-model.md +357 -0
  173. package/docs/scientific-validation.md +105 -0
  174. package/docs/session-lifecycle.md +156 -0
  175. package/docs/skills-marketplace.md +46 -0
  176. package/docs/tool-usage.md +527 -0
  177. package/docs/trace-store.md +132 -0
  178. package/docs/troubleshooting.md +33 -0
  179. package/docs/tui-design.md +239 -0
  180. package/docs/worker-dispatch-mechanics.md +242 -0
  181. package/package.json +132 -0
  182. package/skills/README.md +408 -0
  183. package/skills/git/commit-crafting/SKILL.md +79 -0
  184. package/skills/git/commit-crafting/evals.md +92 -0
  185. package/skills/git/create-pr/SKILL.md +116 -0
  186. package/skills/git/create-pr/evals.md +114 -0
  187. package/skills/git/investigate-issue/SKILL.md +139 -0
  188. package/skills/git/investigate-issue/evals.md +94 -0
  189. package/skills/git/resolve-merge-conflicts/SKILL.md +96 -0
  190. package/skills/git/resolve-merge-conflicts/evals.md +58 -0
  191. package/skills/git/review-changes/SKILL.md +103 -0
  192. package/skills/git/review-changes/evals.md +85 -0
  193. package/skills/git/worktree-create/SKILL.md +92 -0
  194. package/skills/git/worktree-create/evals.md +97 -0
  195. package/skills/git/worktree-create/references/worktree-setup.md +66 -0
  196. package/skills/git/worktree-merge/SKILL.md +95 -0
  197. package/skills/git/worktree-merge/evals.md +114 -0
  198. package/skills/skill-marketplace.json +261 -0
  199. package/skills/workflow/cut-it/SKILL.md +86 -0
  200. package/skills/workflow/cut-it/evals.md +42 -0
  201. package/src/domains/agents/builtins/architect.md +33 -0
  202. package/src/domains/agents/builtins/coder.md +31 -0
  203. package/src/domains/agents/builtins/context-bootstrap.md +38 -0
  204. package/src/domains/agents/builtins/debugger.md +30 -0
  205. package/src/domains/agents/builtins/documenter.md +31 -0
  206. package/src/domains/agents/builtins/git-master.md +30 -0
  207. package/src/domains/agents/builtins/provenance.md +30 -0
  208. package/src/domains/agents/builtins/researcher.md +71 -0
  209. package/src/domains/agents/builtins/scout.md +42 -0
  210. package/src/domains/agents/builtins/tester.md +31 -0
  211. package/src/domains/agents/builtins/verifier.md +30 -0
  212. package/src/domains/agents/builtins/wiki-writer.md +41 -0
  213. package/src/domains/agents/fleets/build-review.md +34 -0
  214. package/src/domains/agents/fleets/build-test.md +35 -0
  215. package/src/domains/agents/fleets/sdlc.md +86 -0
  216. package/src/domains/prompts/fragments/identity/clio-worker.md +11 -0
  217. package/src/domains/prompts/fragments/identity/clio.md +26 -0
  218. package/src/domains/prompts/fragments/operating/contract.md +64 -0
  219. package/src/domains/prompts/fragments/safety/auto-edit.md +14 -0
  220. package/src/domains/prompts/fragments/safety/full-auto.md +14 -0
  221. package/src/domains/prompts/fragments/safety/read-only.md +13 -0
  222. package/src/domains/prompts/fragments/safety/suggest.md +13 -0
  223. package/src/domains/prompts/fragments/wiki/page.md +75 -0
  224. package/src/domains/prompts/fragments/wiki/plan.md +48 -0
  225. package/src/domains/providers/models/cloud-models/alcf.yaml +40 -0
  226. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +993 -0
@@ -0,0 +1,242 @@
1
+ # Worker Dispatch Mechanics
2
+
3
+ > [!TIP]
4
+ > **Interactive Spec Available:** An interactive NDJSON protocol timeline stream and heartbeat watchdog simulator is located at [docs/html/worker_dispatch_blueprint.html](html/worker_dispatch_blueprint.html) (Version: 0.3.0).
5
+
6
+ This document describes the design and lifecycle of Clio Coder dispatched workers, focusing on the spawning sequence, execution isolation, the standard input/output NDJSON communication loop, and permission escalation routing.
7
+
8
+ Source of truth:
9
+ - Subprocess entry: [src/worker/entry.ts](../src/worker/entry.ts)
10
+ - Input demultiplexing: [src/worker/stdin-demux.ts](../src/worker/stdin-demux.ts)
11
+ - Heartbeat loop: [src/worker/heartbeat.ts](../src/worker/heartbeat.ts)
12
+ - Spec contracts and exit codes: [src/worker/spec-contract.ts](../src/worker/spec-contract.ts)
13
+ - Dispatch orchestrator: [src/domains/dispatch/index.ts](../src/domains/dispatch/index.ts)
14
+ - Engine worker runtime: [src/engine/worker-runtime.ts](../src/engine/worker-runtime.ts)
15
+
16
+ ---
17
+
18
+ ## 1. Spawning Sequence & Environment Isolation
19
+
20
+ When the orchestrator dispatches a task to a fleet agent (such as via the `dispatch` tool or `clio-coder eval` execution), it spins up a child process running the compiled worker entry.
21
+
22
+ 1. **Child Process Creation:**
23
+ The parent process spawns a Node.js subprocess pointing to `dist/worker/entry.js`.
24
+ 2. **Environment Scrubbing:**
25
+ To ensure clean execution, the child process runs with a sanitized environment. The orchestrator scrubs user-interactive flags (e.g., `CLIO_CODER_INTERACTIVE` is removed from `process.env`) to prevent child workers from attempting to mount TUI elements or intercept standard input signals.
26
+ 3. **Spec Injection & Attestation Handshake:**
27
+ The orchestrator serializes a `WorkerSpec` JSON document and writes it as the very first line of `stdin` to the child worker. Before reaching a model, every worker announces its attestation on the structured stderr control lane (`@clio-control/1 ` prefix): protocol version (`WORKER_PROTOCOL_VERSION = 1`), spec version, process ID, process group ID (or null), host, settings fingerprint, worker-computed spec digest (`specDigest`), runtime ID, target ID, endpoint identity hash (`endpointIdentityHash`), wire model ID, effective tool signature, and bounded node resource facts (labels, CPU count, total memory, free memory, GPU count, VRAM, and resident models). The orchestrator compares each field against the approved plan and terminates a drifting peer instead of running it. Bulk NDJSON on `stdout` is accepted only once that attestation verifies.
28
+
29
+ ```mermaid
30
+ sequenceDiagram
31
+ participant Orchestrator
32
+ participant WorkerSubprocess as Worker (entry.ts)
33
+ participant Engine as Engine (worker-runtime.ts)
34
+
35
+ Orchestrator->>WorkerSubprocess: Spawn (node entry.js)
36
+ Orchestrator->>WorkerSubprocess: Send WorkerSpec (NDJSON on stdin)
37
+ WorkerSubprocess->>Orchestrator: announce control frame (stderr @clio-control/1)
38
+ Note over WorkerSubprocess: Starts heartbeat on stderr control lane
39
+ WorkerSubprocess->>Engine: startWorkerRun(input)
40
+ loop Execution Loop
41
+ Engine->>WorkerSubprocess: Emit event
42
+ WorkerSubprocess->>Orchestrator: NDJSON event (stdout bulk lane)
43
+ end
44
+ ```
45
+
46
+ ---
47
+
48
+ ## 2. Standard Input/Output NDJSON Protocol
49
+
50
+ Dispatched workers are non-interactive. Coordination between the orchestrator and the worker occurs across two dedicated communication lanes plus standard input:
51
+
52
+ ### 2.1 Worker Output Lanes
53
+
54
+ Clio divides worker output into two isolated streams to protect control signals from bulk data starvation:
55
+
56
+ 1. **Bulk Lane (`stdout`)**:
57
+ Streams turn execution events as single-line NDJSON objects, capped by `WORKER_BULK_FRAME_MAX_BYTES` (4 MiB). To prevent quadratic payload explosion during streaming, `projectWorkerEventForStdout` (`src/worker/event-projection.ts`) slims `message_update` events by stripping cumulative message snapshots before emission. Major event kinds on stdout include:
58
+ * **Logs / Stream chunks:** Output segments generated by the model during a turn.
59
+ * **Tool Invocation:** Requests to run specific tools.
60
+ * **Permission Escalation:** Emitted when a tool requires approval under the `escalate` posture.
61
+ * **Completion / Failure:** Marks the final state of the run, providing execution receipts.
62
+
63
+ 2. **Control Lane (`stderr`)**:
64
+ Emits out-of-band control frames prefixed by `@clio-control/1 `, capped at `WORKER_CONTROL_FRAME_MAX_BYTES` (16 KiB). Because control frames travel over `stderr`, they bypass backpressured bulk stdout streams and reach orchestrator watchdogs immediately. Control frame kinds include:
65
+ * **Announce:** `{"kind": "announce", "attestation": ...}` sent immediately upon startup.
66
+ * **Heartbeat:** `{"kind": "heartbeat", "at": 1720186123000}` emitted every 1000 milliseconds.
67
+ * **Steer / Cancel Acknowledgments:** Confirming reception of stdin control directives.
68
+
69
+ ### 2.2 Worker Input (`stdin`)
70
+ The worker entry mounts a custom stdin demultiplexer (`createWorkerStdinDemux`) that parses lines arriving after the initial `WorkerSpec`. It processes two types of JSON messages:
71
+ 1. **Steering Commands:**
72
+ `{"type": "steer", "text": "guidance message", "sequence": 1}`
73
+ Instructs a live-input HTTP or SDK worker to alter course. Its runtime emits
74
+ the receipt-bearing `clio_steer_received` event only after accepting the
75
+ message for the next turn boundary. Single-shot subprocess runtimes install
76
+ no steering handler, drop unexpected guidance without claiming receipt, and
77
+ are not offered steering by the dispatch contract or TUI.
78
+ 2. **Permission Decisions:**
79
+ `{"type": "permission_decision", "requestId": "req-xxx", "decision": "approve"|"deny"}`
80
+ Resolves a parked tool call that was escalated to the operator.
81
+
82
+ Any stdin chunk that is not a valid JSON structure matching these schemas is logged as a dropped line and does not crash the worker.
83
+
84
+ ---
85
+
86
+ ## 3. Heartbeats and the Watchdog
87
+
88
+ Even when a model is processing a long thinking phase or generating a heavy output, the worker must prove it is alive to prevent the parent orchestrator's watchdog from reclaiming it.
89
+
90
+ * **Emission:** The heartbeat loop (`startWorkerHeartbeat` in `src/worker/heartbeat.ts`) writes a heartbeat control frame (`{"kind": "heartbeat", "at": ...}`) to the `stderr` control lane every 1000 milliseconds.
91
+ * **Stream Isolation:** Because heartbeats ride the control lane rather than `stdout`, a large bulk output or queued tool result cannot starve or delay the watchdog check.
92
+ * **Non-Blocking Timer:** The heartbeat timer interval is explicitly `.unref()`'d, ensuring the Node.js runtime is not kept alive past the natural lifetime of the worker run.
93
+ * **Termination:** Once `startWorkerRun` resolves, the timer is cleared before returning the worker's exit code.
94
+
95
+ ---
96
+
97
+ ## 4. Permission Escalation and Parking
98
+
99
+ When a tool requires explicit confirmation (for example executing a mutating file change or running a bash command at `suggest` autonomy), the worker evaluates `onPermission`:
100
+
101
+ ```mermaid
102
+ stateDiagram-v2
103
+ [*] --> CheckPermission
104
+ CheckPermission --> DenyPosture : onPermission = "deny"
105
+ CheckPermission --> FailPosture : onPermission = "fail"
106
+ CheckPermission --> EscalatePosture : onPermission = "escalate"
107
+
108
+ DenyPosture --> ToolDenied : Return structured denial to model
109
+ FailPosture --> AbortRun : Exit process with code 3 (WORKER_EXIT_PERMISSION_REQUIRED)
110
+
111
+ state EscalatePosture {
112
+ [*] --> ParkCall
113
+ ParkCall --> EmitEscalatedEvent : stdout <- clio_permission_escalated
114
+ EmitEscalatedEvent --> WaitForInput
115
+ WaitForInput --> ResolveApprove : stdin -> permission_decision (approve)
116
+ WaitForInput --> ResolveDeny : stdin -> permission_decision (deny)
117
+ WaitForInput --> TimeoutFallback : timeoutMs reached
118
+ }
119
+
120
+ ResolveApprove --> RunTool : Execute tool
121
+ ResolveDeny --> ToolDenied : Return structured denial to model
122
+ TimeoutFallback --> ApplyFallback : Apply fallback posture (deny | fail)
123
+ ```
124
+
125
+ 1. **Deny:** Immediately returns a structured denial to the model, allowing the run to continue without making the call.
126
+ 2. **Fail:** Terminate the run immediately, exiting the worker subprocess with exit code `3` (`WORKER_EXIT_PERMISSION_REQUIRED`).
127
+ 3. **Escalate (Parking Loop):**
128
+ - The worker parks the tool execution thread.
129
+ - It generates a unique `requestId` and emits a `clio_permission_escalated` event to `stdout`.
130
+ - The parent process intercepts this event, displays the approval prompt in the interactive TUI, and waits for the operator.
131
+ - If the operator selects approve or deny, the parent writes `{"type":"permission_decision", "requestId":"...", "decision":"..."}` to the worker's `stdin`.
132
+ - The demuxer resolves the parked promise, resuming tool execution.
133
+ - **Timeout Safety:** If no decision arrives within `escalation.timeoutMs` (default `120000` ms), the worker resumes and applies the `escalation.fallback` posture (default `deny`). If running headlessly (no operator attached) or on runtimes that cannot support park loops, the posture collapses to the fallback immediately.
134
+
135
+ ---
136
+
137
+ ## 5. Assignment-aware retry and failover
138
+
139
+ A worker process produces one immutable **attempt**. Dispatch groups attempts
140
+ under a logical **assignment** whose id is the first attempt's
141
+ `lineage.rootRunId`. Attached and batch `finalPromise` handles resolve to the
142
+ terminal attempt receipt, not to an earlier failure that happened to trigger a
143
+ retry. Receipt bytes and integrity versions remain unchanged; assignment state
144
+ is maintained separately in `assignments.json` with the attempt ids, terminal
145
+ run id, and status.
146
+
147
+ Detached `monitor collect` resolves the assignment's terminal run and returns
148
+ its complete `attemptRunIds` history. `status`, `wait`, `steer`, permission
149
+ resolution, and cancellation also accept the assignment id and address the
150
+ current attempt. Cancellation prevents queued or future attempts. Pipelines
151
+ therefore receive terminal fallback output as their next-stage input.
152
+
153
+ The assignment also owns the event stream. `dispatch()` returns a single
154
+ stream carrying every attempt's frames in order, separated by a synthetic
155
+ `attempt_start` frame (`attempt`, `runId`, `previousRunId`, `reason`). The
156
+ stream ends when the assignment settles, not when one attempt's worker exits,
157
+ so a consumer that drains it has seen exactly the run the terminal receipt
158
+ describes. A canceled assignment ends its stream immediately.
159
+
160
+ Retry timing is governed by `workers.maxRetries` and exponential backoff alone.
161
+ Target cooldowns gate *new* dispatches to a known-bad target and are not
162
+ applied to retries of an in-flight assignment, whose retry budget already
163
+ bounds it. A retry refused at admission settles the assignment failed and
164
+ records the denial reason in the assignment's `outcomeDetail`.
165
+
166
+ Retry also requires evidence that reusing the same checkout is safe. Each
167
+ receipt seals `safety.toolTelemetry`: coverage is `complete`, `partial`, or
168
+ `unavailable`, with ingestion errors and unmatched tool starts preserved.
169
+ Dispatch suppresses automatic retry after an executed state-changing call,
170
+ after an unfinished state-changing call, or when an opaque mutation-capable
171
+ runtime cannot prove that the failed attempt left the workspace unchanged.
172
+ Claude CLI runs technically constrained to read-only tools retain retries;
173
+ mutation-capable subprocess and ACP runs fail closed until isolated retry
174
+ workspaces exist.
175
+
176
+ Failover modes are:
177
+
178
+ - `none`: exact pins remain fail-closed; retries can only repeat the same tuple.
179
+ - `approved`: candidates must be exact members of the operator-approved
180
+ agent/target/model/node envelope.
181
+ - `automatic`: typed failures may replace only implicated route parts. Node
182
+ channel failure excludes the node; target rate limiting excludes the target.
183
+
184
+ Operator cancellation, policy rejection, permission refusal, and deterministic
185
+ task failures do not retry. The first three are neutral to target/node
186
+ infrastructure breakers.
187
+
188
+ ### 5.1 Failure Taxonomy & Route Exclusion
189
+
190
+ The coordinator classifies failures into 13 explicit categories (`src/domains/dispatch/failure-classification.ts`) to determine which route parts (`agent`, `target`, `model`, `node`, `runtime`) are excluded during an assignment retry:
191
+
192
+ | Failure Class | Trigger Pattern / Exit Code | Excluded Route Part | Retryable? |
193
+ | --- | --- | --- | --- |
194
+ | `operator-cancel` | User abort, `canceled` outcome | None (Neutral) | No |
195
+ | `policy` | Policy denial, `denied_by_policy` | None (Neutral) | No |
196
+ | `permission` | `WORKER_EXIT_PERMISSION_REQUIRED` (code 3) | None (Neutral) | No |
197
+ | `deterministic-task` | `isDeterministicOutcomeCode()` (e.g. `result_contract_exhausted`) | None | No |
198
+ | `model-quality` | Quality gate failure | `agent, model` | Yes |
199
+ | `node-channel` | Stall killed, `spawn_failed`, SSH exit code 255 | `node` | Yes |
200
+ | `node-resource` | VRAM/GPU OOM error pattern | `node` | Yes |
201
+ | `target-auth` | HTTP 401/403, invalid API key | `target` | Yes |
202
+ | `target-rate-limit` | HTTP 429, rate limit error pattern | `target` | Yes (Delayed) |
203
+ | `target-transient` | Timeout, HTTP 502/503/504 | `target` | Yes |
204
+ | `capacity` | Queue full / overload pattern | `node` | Yes |
205
+ | `worker-runtime` | `failed` outcome after more-specific classifiers do not match | `runtime` | Yes |
206
+ | `internal` | No more-specific termination evidence; coordinator fallback | None | Yes |
207
+
208
+ ### 5.2 Canonical Receipt Integrity Serialization
209
+
210
+ Receipts carry exactly one integrity version (`RUN_RECEIPT_INTEGRITY_VERSION = 15`); any other version is invalid. It computes a cryptographic SHA-256 digest over a strictly sorted, canonical JSON representation (`serializeCanonical` in `src/domains/dispatch/receipt-integrity.ts`).
211
+
212
+ - **Object Key Sorting**: Keys are sorted lexicographically before serialization (`Object.keys(obj).sort()`).
213
+ - **Strict Primitive Handling**: `undefined` object properties are omitted; non-finite numbers (`NaN`, `Infinity`) or `bigint` throw an explicit serialization error.
214
+ - **Coverage**: Includes every current receipt field and reconstructible ledger field, including route intent/decision/quality, execution role, worker identity, result-contract conformance, node/reroute/gate/plan provenance, briefing, steering, and `outcomeCode`.
215
+
216
+ ### 5.3 Acceptance Coverage
217
+
218
+ The assignment contract's acceptance scenarios map to deterministic contract
219
+ tests as follows:
220
+
221
+ | # | Scenario | Contract test |
222
+ | --- | --- | --- |
223
+ | 1 | Remote stall, approved local fallback, attached success | `dispatch-envelope.test.ts`: "falls back from remote to local only within an approved envelope" |
224
+ | 2 | Detached collection returns successful terminal fallback | `dispatch-assignment-detached.test.ts`: "collects the terminal retry…" |
225
+ | 3 | Pipeline consumes terminal fallback output | `dispatch-assignment-detached.test.ts`: "threads the successful retry output…" |
226
+ | 4 | Failed attempt remains visible and integrity-verifiable | `dispatch-assignment.test.ts`: "resolves attached dispatch…" (also covered by detached collection) |
227
+ | 5 | Cancellation starts no retry | `dispatch-assignment.test.ts`: "canceling the root attempt starts no retry" |
228
+ | 6 | Cancellation does not cool the target | `dispatch-failure-class.test.ts`: "keeps cancellation and permission neutral…" |
229
+ | 7 | Permission/policy rejection is retry- and breaker-neutral | `dispatch-failure-class.test.ts`: classification/decision table and neutral-target test |
230
+ | 8 | Node-channel failure changes node but retains model | `dispatch-failure-class.test.ts`: "moves only the node…" |
231
+ | 9 | Rate limit retains agent/model and delays or changes target | `dispatch-failure-class.test.ts`: "changes target after rate limiting…" |
232
+ | 10 | Exhaustion returns one failure with all attempt receipts | `dispatch-assignment.test.ts`: "settles exhausted retries…" |
233
+ | 11 | Exact manual pin never falls back | `dispatch-envelope.test.ts`: "keeps a manual exact pin fail-closed…" |
234
+ | 12 | Approved envelope never spawns outside its candidate list | `dispatch-envelope.test.ts`: "settles failed instead of spawning an unlisted candidate" |
235
+
236
+ ## 6. Worker Exit Codes
237
+
238
+ The child process exits with specific status codes to signal run outcomes to the orchestrator:
239
+ * **`0`**: The worker process completed without a runtime error; dispatch still requires a nonempty receipt-sealed final answer before classifying the run as successful.
240
+ * **`2`**: Worker runtime initialization failed (e.g., target runtime not registered, or `WorkerSpec` invalid/mismatched).
241
+ * **`3` (`WORKER_EXIT_PERMISSION_REQUIRED`)**: The run aborted because a tool required permission and `onPermission` was set to `fail` (or timed out to a `fail` fallback).
242
+ * **Other (e.g., `1` or uncaught exceptions)**: Represents an unhandled crash or internal error within the runner.
package/package.json ADDED
@@ -0,0 +1,132 @@
1
+ {
2
+ "name": "@iowarp/clio-coder",
3
+ "version": "0.3.0",
4
+ "description": "Coding agent for HPC and scientific-software developers, part of IOWarp's CLIO ecosystem of agentic science.",
5
+ "keywords": [
6
+ "ai",
7
+ "agentic-ai",
8
+ "agentic-coding",
9
+ "agentic-science",
10
+ "coding",
11
+ "repository",
12
+ "terminal",
13
+ "developer-tools",
14
+ "llm",
15
+ "agents",
16
+ "model-targets",
17
+ "multi-agent",
18
+ "coding-agents",
19
+ "software-engineering",
20
+ "research-software",
21
+ "scientific-computing",
22
+ "hpc",
23
+ "clio",
24
+ "iowarp"
25
+ ],
26
+ "type": "module",
27
+ "license": "Apache-2.0",
28
+ "author": "Anthony Kougkas <a.kougkas@gmail.com> (https://github.com/akougkas)",
29
+ "contributors": [
30
+ "IOWarp <https://iowarp.ai>",
31
+ "Gnosis Research Center <https://grc.iit.edu/>"
32
+ ],
33
+ "homepage": "https://iowarp.ai",
34
+ "bugs": "https://github.com/iowarp/clio-coder/issues",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/iowarp/clio-coder.git"
38
+ },
39
+ "engines": {
40
+ "node": ">=22.19.0"
41
+ },
42
+ "bin": {
43
+ "clio-coder": "dist/cli/index.js"
44
+ },
45
+ "files": [
46
+ "dist",
47
+ "!dist/**/*.map",
48
+ "assets/clio-coder-logo-128.webp",
49
+ "src/domains/agents/builtins/**",
50
+ "src/domains/agents/fleets/**",
51
+ "skills/workflow/cut-it/**",
52
+ "skills/git/**",
53
+ "skills/skill-marketplace.json",
54
+ "src/domains/providers/models/**",
55
+ "src/domains/prompts/fragments/**",
56
+ "docs/*.md",
57
+ "docs/html/**",
58
+ "README.md",
59
+ "CHANGELOG.md",
60
+ "CONTRIBUTING.md",
61
+ "SECURITY.md",
62
+ "CODE_OF_CONDUCT.md",
63
+ "NOTICE",
64
+ "LICENSE",
65
+ "damage-control-rules.yaml"
66
+ ],
67
+ "publishConfig": {
68
+ "access": "public"
69
+ },
70
+ "scripts": {
71
+ "build": "tsup",
72
+ "dev": "tsup --watch",
73
+ "clean": "rm -rf dist",
74
+ "typecheck": "tsc -p tsconfig.tests.json",
75
+ "format": "biome format --write .",
76
+ "lint": "biome check .",
77
+ "check:boundaries": "node --import tsx --import ./tests/harness/tmp-root.ts --test 'tests/boundaries/**/*.test.ts'",
78
+ "test:file": "node --import tsx --import ./tests/harness/tmp-root.ts --test",
79
+ "test:smoke": "node --import tsx --import ./tests/harness/tmp-root.ts --test 'tests/smoke/**/*.test.ts'",
80
+ "test:contracts": "node --import tsx --import ./tests/harness/tmp-root.ts --test 'tests/contracts/**/*.test.ts'",
81
+ "test": "node --import tsx --import ./tests/harness/tmp-root.ts --test 'tests/contracts/**/*.test.ts' 'tests/smoke/**/*.test.ts' 'tests/boundaries/**/*.test.ts'",
82
+ "test:coverage": "node --import tsx --import ./tests/harness/tmp-root.ts --test --experimental-test-coverage --test-coverage-include='src/**/*.ts' --test-coverage-exclude='src/**/*.d.ts' 'tests/contracts/**/*.test.ts' 'tests/smoke/**/*.test.ts' 'tests/boundaries/**/*.test.ts'",
83
+ "test:repeat": "node tests/harness/repeat-tests.mjs",
84
+ "test:trace-viewer": "npm --prefix apps/trace-viewer test",
85
+ "trace:ui": "node apps/trace-viewer/server.mjs",
86
+ "ci": "npm run typecheck && npm run lint && npm run skills:check && npm run build && npm run test && npm run test:trace-viewer",
87
+ "ci:release": "npm run ci && node scripts/check-release.mjs",
88
+ "test:live": "node scripts/live-smoke.mjs",
89
+ "test:live-eval": "node scripts/live-eval-recon.mjs",
90
+ "test:live-eval:fleet-dispatch": "node scripts/live-eval-fleet-dispatch.mjs",
91
+ "test:live-verify:dispatch-routing": "node scripts/live-verify-dispatch-routing.mjs",
92
+ "bench:swe": "python3 benchmarks/community/swe-bench-lite/swebench_clio.py",
93
+ "bench:scicode": "python3 benchmarks/community/scicode/scicode_clio.py",
94
+ "bench:tb": "python3 benchmarks/community/clio_fleet.py",
95
+ "install:local": "bash scripts/install-local.sh",
96
+ "prepublishOnly": "npm run ci:release",
97
+ "skills:pin": "node --import tsx scripts/pin-skills.ts",
98
+ "skills:check": "node --import tsx scripts/pin-skills.ts --check",
99
+ "test:lifecycle": "node --import tsx scripts/lifecycle-matrix.mjs"
100
+ },
101
+ "dependencies": {
102
+ "@anthropic-ai/claude-agent-sdk": "0.3.186",
103
+ "@earendil-works/pi-agent-core": "0.83.0",
104
+ "@earendil-works/pi-ai": "0.83.0",
105
+ "@earendil-works/pi-tui": "0.83.0",
106
+ "@lmstudio/sdk": "1.5.0",
107
+ "@silvia-odwyer/photon-node": "^0.3.4",
108
+ "@vscode/tree-sitter-wasm": "^0.3.1",
109
+ "chalk": "5.6.2",
110
+ "diff": "9.0.0",
111
+ "ollama": "0.6.3",
112
+ "tree-sitter-wasms": "^0.1.13",
113
+ "typebox": "1.3.0",
114
+ "undici": "8.5.0",
115
+ "uuid": "14.0.1",
116
+ "yaml": "2.9.0"
117
+ },
118
+ "overrides": {
119
+ "@anthropic-ai/sdk": "0.105.0",
120
+ "ip-address": "10.2.0",
121
+ "esbuild": "0.28.1"
122
+ },
123
+ "devDependencies": {
124
+ "@biomejs/biome": "2.5.1",
125
+ "@types/node": "24.12.2",
126
+ "esbuild": "0.28.1",
127
+ "node-pty": "1.1.0",
128
+ "tsup": "8.5.1",
129
+ "tsx": "4.22.4",
130
+ "typescript": "6.0.3"
131
+ }
132
+ }