@oneharness/sdk 0.6.9 → 0.6.11

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.
@@ -27,6 +27,17 @@
27
27
  "type": "string"
28
28
  }
29
29
  },
30
+ "control": {
31
+ "description": "Out-of-band turn control for this run (`--control`), or `null` when none\nwas requested — which is every ordinary run. It records the socket a\nseparate `oneharness interrupt` process could address, the harness\nmechanism behind it, and each request served, so a consumer can tell an\ninterrupted turn from one that simply ended.",
32
+ "anyOf": [
33
+ {
34
+ "$ref": "#/$defs/ControlReport"
35
+ },
36
+ {
37
+ "type": "null"
38
+ }
39
+ ]
40
+ },
30
41
  "dry_run": {
31
42
  "type": "boolean"
32
43
  },
@@ -150,9 +161,14 @@
150
161
  "spy_file",
151
162
  "history_file",
152
163
  "config_files",
164
+ "control",
153
165
  "results"
154
166
  ],
155
167
  "$defs": {
168
+ "AbsolutePath": {
169
+ "description": "A filesystem path that is known to be absolute.\n\nControl addresses are handed to a *different process* — the socket path in\nthe report is how a supervisor finds the run — so a relative path is not a\nsmaller version of the right answer, it is a different file depending on who\nreads it. The type is the difference between \"we documented it as absolute\"\nand \"it is\".",
170
+ "type": "string"
171
+ },
156
172
  "ActionEvent": {
157
173
  "description": "One normalized action a harness took, harness-agnostic so a single consumer\nassertion works across harnesses. Every field is always serialized (null when\nabsent) so the shape is stable, mirroring the `usage` contract.",
158
174
  "type": "object",
@@ -289,6 +305,146 @@
289
305
  }
290
306
  ]
291
307
  },
308
+ "ControlEvent": {
309
+ "description": "One control request the run handled, recorded in the report so a consumer\ncan tell an interrupted turn from one that simply ended.\n\nA sum type discriminated by `outcome`, so a record can never say \"served,\nand here is the refusal reason\": the reason exists exactly when there was a\nrefusal. Serialized flat — `{\"outcome\":\"served\",\"verb\":…,\"at\":…}` /\n`{\"outcome\":\"refused\",\"verb\":…,\"at\":…,\"reason\":…}`.",
310
+ "oneOf": [
311
+ {
312
+ "description": "The mechanism accepted the request.",
313
+ "type": "object",
314
+ "properties": {
315
+ "at": {
316
+ "description": "When the request was handled.",
317
+ "$ref": "#/$defs/UtcInstant"
318
+ },
319
+ "outcome": {
320
+ "type": "string",
321
+ "const": "served"
322
+ },
323
+ "redirected": {
324
+ "description": "Whether a redirection was committed with the abort. Omitted when it\nwas a plain stop, so an older consumer reads the same record it\nalways did.",
325
+ "type": "boolean"
326
+ },
327
+ "verb": {
328
+ "description": "The verb requested.",
329
+ "$ref": "#/$defs/ControlVerb"
330
+ }
331
+ },
332
+ "required": [
333
+ "outcome",
334
+ "verb",
335
+ "at"
336
+ ]
337
+ },
338
+ {
339
+ "description": "The request was refused, with why.",
340
+ "type": "object",
341
+ "properties": {
342
+ "at": {
343
+ "$ref": "#/$defs/UtcInstant"
344
+ },
345
+ "outcome": {
346
+ "type": "string",
347
+ "const": "refused"
348
+ },
349
+ "reason": {
350
+ "$ref": "#/$defs/ControlReason"
351
+ },
352
+ "verb": {
353
+ "$ref": "#/$defs/ControlVerb"
354
+ }
355
+ },
356
+ "required": [
357
+ "outcome",
358
+ "verb",
359
+ "at",
360
+ "reason"
361
+ ]
362
+ }
363
+ ]
364
+ },
365
+ "ControlReason": {
366
+ "description": "Why a control request could not be served. Distinct reasons because a\nsupervisor reacts differently to each: `unsupported` is permanent for the\nharness, `not_running` means the dispatch is gone, `no_active_turn` means\nthe run is alive but between turns.",
367
+ "oneOf": [
368
+ {
369
+ "description": "The harness declares no [`ControlShape`] — the lever does not exist.",
370
+ "type": "string",
371
+ "const": "unsupported"
372
+ },
373
+ {
374
+ "description": "The run is alive but no turn is in flight right now.",
375
+ "type": "string",
376
+ "const": "no_active_turn"
377
+ },
378
+ {
379
+ "description": "No run is listening on the socket (never started, already exited, or a\nstale socket file left by an abnormally-terminated dispatch).",
380
+ "type": "string",
381
+ "const": "not_running"
382
+ }
383
+ ]
384
+ },
385
+ "ControlReport": {
386
+ "description": "The run report's `control` block: where the socket lived, which mechanism\nbacked it, and every request served over the run's lifetime.",
387
+ "type": "object",
388
+ "properties": {
389
+ "interrupts": {
390
+ "description": "Every control request served, in order.",
391
+ "type": "array",
392
+ "items": {
393
+ "$ref": "#/$defs/ControlEvent"
394
+ }
395
+ },
396
+ "mechanism": {
397
+ "description": "The harness mechanism backing it.",
398
+ "$ref": "#/$defs/ControlShape"
399
+ },
400
+ "socket": {
401
+ "description": "Absolute path of the socket this run listened on.",
402
+ "$ref": "#/$defs/AbsolutePath"
403
+ }
404
+ },
405
+ "required": [
406
+ "socket",
407
+ "mechanism",
408
+ "interrupts"
409
+ ]
410
+ },
411
+ "ControlShape": {
412
+ "description": "How a harness accepts an out-of-band interrupt for an in-flight turn.\n\nRegistry data on [`crate::domain::harness::HarnessSpec::control`], sourced\nfrom a live interrupt against the real CLI — never guessed. `None` there\nmeans `oneharness interrupt` is a loud usage error for the harness, never a\nsilent no-op: a supervisor that is told \"ok\" while the turn keeps running is\nworse off than one told the lever does not exist.",
413
+ "oneOf": [
414
+ {
415
+ "description": "Claude Code: the control frame rides the run process's **own stdin**\n(`-p --input-format stream-json`), so no sidecar server is needed. A\n`{\"type\":\"control_request\",…,\"request\":{\"subtype\":\"interrupt\"}}` line\naborts the turn with a `result` document; the session survives and a\nlater turn continues it with full context. Verified live: a plain user\nmessage written mid-turn is *silently dropped*, so the control frame is\nthe only mechanism that works.",
416
+ "type": "string",
417
+ "const": "claude-control-request"
418
+ },
419
+ {
420
+ "description": "Codex: `turn/interrupt {threadId,turnId}` over the `codex app-server`\nJSON-RPC stdio protocol, which oneharness spawns as the run's own child\nand drives the thread/turn lifecycle on — so the interrupt rides the same\nopen stdin and nothing is shared or pooled.",
421
+ "type": "string",
422
+ "const": "codex-app-server"
423
+ },
424
+ {
425
+ "description": "OpenCode: `POST /api/session/{id}/interrupt` against `opencode serve`.",
426
+ "type": "string",
427
+ "const": "opencode-http"
428
+ },
429
+ {
430
+ "description": "Goose and Copilot: the ACP `session/cancel` **notification** (no `id`)\nover their JSON-RPC stdio servers.",
431
+ "type": "string",
432
+ "const": "acp-cancel"
433
+ },
434
+ {
435
+ "description": "Crush: `POST /v1/workspaces/{id}/agent/sessions/{sid}/cancel` against\n`crush server`.",
436
+ "type": "string",
437
+ "const": "crush-http"
438
+ }
439
+ ]
440
+ },
441
+ "ControlVerb": {
442
+ "description": "The control verb a supervisor sends. Only `interrupt` exists today; the\nframe's `v` is what leaves room for `steer` later.",
443
+ "type": "string",
444
+ "enum": [
445
+ "interrupt"
446
+ ]
447
+ },
292
448
  "ExecutionTelemetry": {
293
449
  "description": "Measured execution telemetry for one harness run: when the invocation ran,\nand — when the harness's transcript supports it — how its wall clock split\nbetween provider latency and tool work.\n\nCarried from the runner/parser to the history writer *and*, since report\nschema `0.5`, serialized on [`RunResult::telemetry`]. Exposing it there is\nwhat lets a consumer read the numbers off the run it just made instead of\nre-opening the history file the same run wrote.\n\nInternally tagged by `source`, so the variant is a value a consumer switches\non rather than a shape it has to sniff. Every variant states only what was\nactually measured — there is no variant meaning \"no telemetry\"; that is a\n`null` field.",
294
450
  "oneOf": [
@@ -388,7 +544,7 @@
388
544
  ]
389
545
  },
390
546
  "FailureKind": {
391
- "description": "The normalized, closed set of failure reasons oneharness can classify from a\nharness's output. It is the single source for the `failure_kind` contract\nvalue: serialized as the snake_case token a consumer reads in the report\n(`auth`, `rate_limit`, `model_not_found`, `quota`, `tool_deferred`), so the\nwire shape is unchanged — modeling it as an enum keeps a misspelled or\ninvalid kind unrepresentable and gives every producer/consumer (classifier,\n`is_failure`, the fallback fall-through rule, the report, history) one\ndefinition to share instead of scattered string literals.",
547
+ "description": "The normalized, closed set of failure reasons oneharness can classify from a\nharness's output. It is the single source for the `failure_kind` contract\nvalue: serialized as the snake_case token a consumer reads in the report\n(`auth`, `rate_limit`, `model_not_found`, `quota`, `session_not_found`,\n`tool_deferred`), so the wire shape is unchanged — modeling it as an enum\nkeeps a misspelled or invalid kind unrepresentable and gives every\nproducer/consumer (classifier, `is_failure`, the fallback fall-through rule,\nthe report, history) one definition to share instead of scattered string\nliterals.",
392
548
  "oneOf": [
393
549
  {
394
550
  "description": "Authentication / authorization rejected the request (401/403, missing or\ninvalid credentials).",
@@ -410,6 +566,11 @@
410
566
  "type": "string",
411
567
  "const": "quota"
412
568
  },
569
+ {
570
+ "description": "The session this run asked to continue does not exist for the identity it\nran as, so the harness refused before doing any work (see\n[`unknown_session_rejection`]). Distinct from every other kind because the\ntask itself is fine: another identity — or a fresh session on this one —\ncan still run it.",
571
+ "type": "string",
572
+ "const": "session_not_found"
573
+ },
413
574
  {
414
575
  "description": "The harness deferred a builtin tool call instead of executing it, so a\nclean-exit run did no useful work (Claude Code bridge deployments; issue\n#1114). The only kind that can appear on a `status: ok` run.",
415
576
  "type": "string",
@@ -575,7 +736,7 @@
575
736
  "format": "int32"
576
737
  },
577
738
  "failure_kind": {
578
- "description": "Best-effort failure reason; `null` when unclassified. Distinct from\n`status`, which records oneharness's relationship to the process. Two\nfamilies: coarse reasons for a non-zero run (`auth`, `rate_limit`,\n`model_not_found`, `quota`), and `tool_deferred` — a run that exited\n*cleanly* but only deferred a builtin tool call instead of executing it\n(Claude Code bridge/managed deployments), so it did no useful work. The\ndeferred case is the only `failure_kind` that can appear on a `status: ok`\nrun, and it also marks the run as failed for exit-code purposes.\nSerialized as its snake_case token (see [`FailureKind`]).",
739
+ "description": "Best-effort failure reason; `null` when unclassified. Distinct from\n`status`, which records oneharness's relationship to the process. Two\nfamilies: coarse reasons for a non-zero run (`auth`, `rate_limit`,\n`model_not_found`, `quota`, `session_not_found`), and `tool_deferred` — a run that exited\n*cleanly* but only deferred a builtin tool call instead of executing it\n(Claude Code bridge/managed deployments), so it did no useful work. The\ndeferred case is the only `failure_kind` that can appear on a `status: ok`\nrun, and it also marks the run as failed for exit-code purposes.\nSerialized as its snake_case token (see [`FailureKind`]).",
579
740
  "anyOf": [
580
741
  {
581
742
  "$ref": "#/$defs/FailureKind"
@@ -907,6 +1068,10 @@
907
1068
  "cache_write_tokens",
908
1069
  "cost_usd"
909
1070
  ]
1071
+ },
1072
+ "UtcInstant": {
1073
+ "description": "An RFC 3339 timestamp in UTC (`Z`), in oneharness's canonical spelling.",
1074
+ "type": "string"
910
1075
  }
911
1076
  }
912
1077
  },
@@ -951,6 +1116,10 @@
951
1116
  }
952
1117
  ],
953
1118
  "$defs": {
1119
+ "AbsolutePath": {
1120
+ "description": "A filesystem path that is known to be absolute.\n\nControl addresses are handed to a *different process* — the socket path in\nthe report is how a supervisor finds the run — so a relative path is not a\nsmaller version of the right answer, it is a different file depending on who\nreads it. The type is the difference between \"we documented it as absolute\"\nand \"it is\".",
1121
+ "type": "string"
1122
+ },
954
1123
  "ActionEvent": {
955
1124
  "description": "One normalized action a harness took, harness-agnostic so a single consumer\nassertion works across harnesses. Every field is always serialized (null when\nabsent) so the shape is stable, mirroring the `usage` contract.",
956
1125
  "type": "object",
@@ -1087,6 +1256,146 @@
1087
1256
  }
1088
1257
  ]
1089
1258
  },
1259
+ "ControlEvent": {
1260
+ "description": "One control request the run handled, recorded in the report so a consumer\ncan tell an interrupted turn from one that simply ended.\n\nA sum type discriminated by `outcome`, so a record can never say \"served,\nand here is the refusal reason\": the reason exists exactly when there was a\nrefusal. Serialized flat — `{\"outcome\":\"served\",\"verb\":…,\"at\":…}` /\n`{\"outcome\":\"refused\",\"verb\":…,\"at\":…,\"reason\":…}`.",
1261
+ "oneOf": [
1262
+ {
1263
+ "description": "The mechanism accepted the request.",
1264
+ "type": "object",
1265
+ "properties": {
1266
+ "at": {
1267
+ "description": "When the request was handled.",
1268
+ "$ref": "#/$defs/UtcInstant"
1269
+ },
1270
+ "outcome": {
1271
+ "type": "string",
1272
+ "const": "served"
1273
+ },
1274
+ "redirected": {
1275
+ "description": "Whether a redirection was committed with the abort. Omitted when it\nwas a plain stop, so an older consumer reads the same record it\nalways did.",
1276
+ "type": "boolean"
1277
+ },
1278
+ "verb": {
1279
+ "description": "The verb requested.",
1280
+ "$ref": "#/$defs/ControlVerb"
1281
+ }
1282
+ },
1283
+ "required": [
1284
+ "outcome",
1285
+ "verb",
1286
+ "at"
1287
+ ]
1288
+ },
1289
+ {
1290
+ "description": "The request was refused, with why.",
1291
+ "type": "object",
1292
+ "properties": {
1293
+ "at": {
1294
+ "$ref": "#/$defs/UtcInstant"
1295
+ },
1296
+ "outcome": {
1297
+ "type": "string",
1298
+ "const": "refused"
1299
+ },
1300
+ "reason": {
1301
+ "$ref": "#/$defs/ControlReason"
1302
+ },
1303
+ "verb": {
1304
+ "$ref": "#/$defs/ControlVerb"
1305
+ }
1306
+ },
1307
+ "required": [
1308
+ "outcome",
1309
+ "verb",
1310
+ "at",
1311
+ "reason"
1312
+ ]
1313
+ }
1314
+ ]
1315
+ },
1316
+ "ControlReason": {
1317
+ "description": "Why a control request could not be served. Distinct reasons because a\nsupervisor reacts differently to each: `unsupported` is permanent for the\nharness, `not_running` means the dispatch is gone, `no_active_turn` means\nthe run is alive but between turns.",
1318
+ "oneOf": [
1319
+ {
1320
+ "description": "The harness declares no [`ControlShape`] — the lever does not exist.",
1321
+ "type": "string",
1322
+ "const": "unsupported"
1323
+ },
1324
+ {
1325
+ "description": "The run is alive but no turn is in flight right now.",
1326
+ "type": "string",
1327
+ "const": "no_active_turn"
1328
+ },
1329
+ {
1330
+ "description": "No run is listening on the socket (never started, already exited, or a\nstale socket file left by an abnormally-terminated dispatch).",
1331
+ "type": "string",
1332
+ "const": "not_running"
1333
+ }
1334
+ ]
1335
+ },
1336
+ "ControlReport": {
1337
+ "description": "The run report's `control` block: where the socket lived, which mechanism\nbacked it, and every request served over the run's lifetime.",
1338
+ "type": "object",
1339
+ "properties": {
1340
+ "interrupts": {
1341
+ "description": "Every control request served, in order.",
1342
+ "type": "array",
1343
+ "items": {
1344
+ "$ref": "#/$defs/ControlEvent"
1345
+ }
1346
+ },
1347
+ "mechanism": {
1348
+ "description": "The harness mechanism backing it.",
1349
+ "$ref": "#/$defs/ControlShape"
1350
+ },
1351
+ "socket": {
1352
+ "description": "Absolute path of the socket this run listened on.",
1353
+ "$ref": "#/$defs/AbsolutePath"
1354
+ }
1355
+ },
1356
+ "required": [
1357
+ "socket",
1358
+ "mechanism",
1359
+ "interrupts"
1360
+ ]
1361
+ },
1362
+ "ControlShape": {
1363
+ "description": "How a harness accepts an out-of-band interrupt for an in-flight turn.\n\nRegistry data on [`crate::domain::harness::HarnessSpec::control`], sourced\nfrom a live interrupt against the real CLI — never guessed. `None` there\nmeans `oneharness interrupt` is a loud usage error for the harness, never a\nsilent no-op: a supervisor that is told \"ok\" while the turn keeps running is\nworse off than one told the lever does not exist.",
1364
+ "oneOf": [
1365
+ {
1366
+ "description": "Claude Code: the control frame rides the run process's **own stdin**\n(`-p --input-format stream-json`), so no sidecar server is needed. A\n`{\"type\":\"control_request\",…,\"request\":{\"subtype\":\"interrupt\"}}` line\naborts the turn with a `result` document; the session survives and a\nlater turn continues it with full context. Verified live: a plain user\nmessage written mid-turn is *silently dropped*, so the control frame is\nthe only mechanism that works.",
1367
+ "type": "string",
1368
+ "const": "claude-control-request"
1369
+ },
1370
+ {
1371
+ "description": "Codex: `turn/interrupt {threadId,turnId}` over the `codex app-server`\nJSON-RPC stdio protocol, which oneharness spawns as the run's own child\nand drives the thread/turn lifecycle on — so the interrupt rides the same\nopen stdin and nothing is shared or pooled.",
1372
+ "type": "string",
1373
+ "const": "codex-app-server"
1374
+ },
1375
+ {
1376
+ "description": "OpenCode: `POST /api/session/{id}/interrupt` against `opencode serve`.",
1377
+ "type": "string",
1378
+ "const": "opencode-http"
1379
+ },
1380
+ {
1381
+ "description": "Goose and Copilot: the ACP `session/cancel` **notification** (no `id`)\nover their JSON-RPC stdio servers.",
1382
+ "type": "string",
1383
+ "const": "acp-cancel"
1384
+ },
1385
+ {
1386
+ "description": "Crush: `POST /v1/workspaces/{id}/agent/sessions/{sid}/cancel` against\n`crush server`.",
1387
+ "type": "string",
1388
+ "const": "crush-http"
1389
+ }
1390
+ ]
1391
+ },
1392
+ "ControlVerb": {
1393
+ "description": "The control verb a supervisor sends. Only `interrupt` exists today; the\nframe's `v` is what leaves room for `steer` later.",
1394
+ "type": "string",
1395
+ "enum": [
1396
+ "interrupt"
1397
+ ]
1398
+ },
1090
1399
  "ExecutionTelemetry": {
1091
1400
  "description": "Measured execution telemetry for one harness run: when the invocation ran,\nand — when the harness's transcript supports it — how its wall clock split\nbetween provider latency and tool work.\n\nCarried from the runner/parser to the history writer *and*, since report\nschema `0.5`, serialized on [`RunResult::telemetry`]. Exposing it there is\nwhat lets a consumer read the numbers off the run it just made instead of\nre-opening the history file the same run wrote.\n\nInternally tagged by `source`, so the variant is a value a consumer switches\non rather than a shape it has to sniff. Every variant states only what was\nactually measured — there is no variant meaning \"no telemetry\"; that is a\n`null` field.",
1092
1401
  "oneOf": [
@@ -1186,7 +1495,7 @@
1186
1495
  ]
1187
1496
  },
1188
1497
  "FailureKind": {
1189
- "description": "The normalized, closed set of failure reasons oneharness can classify from a\nharness's output. It is the single source for the `failure_kind` contract\nvalue: serialized as the snake_case token a consumer reads in the report\n(`auth`, `rate_limit`, `model_not_found`, `quota`, `tool_deferred`), so the\nwire shape is unchanged — modeling it as an enum keeps a misspelled or\ninvalid kind unrepresentable and gives every producer/consumer (classifier,\n`is_failure`, the fallback fall-through rule, the report, history) one\ndefinition to share instead of scattered string literals.",
1498
+ "description": "The normalized, closed set of failure reasons oneharness can classify from a\nharness's output. It is the single source for the `failure_kind` contract\nvalue: serialized as the snake_case token a consumer reads in the report\n(`auth`, `rate_limit`, `model_not_found`, `quota`, `session_not_found`,\n`tool_deferred`), so the wire shape is unchanged — modeling it as an enum\nkeeps a misspelled or invalid kind unrepresentable and gives every\nproducer/consumer (classifier, `is_failure`, the fallback fall-through rule,\nthe report, history) one definition to share instead of scattered string\nliterals.",
1190
1499
  "oneOf": [
1191
1500
  {
1192
1501
  "description": "Authentication / authorization rejected the request (401/403, missing or\ninvalid credentials).",
@@ -1208,6 +1517,11 @@
1208
1517
  "type": "string",
1209
1518
  "const": "quota"
1210
1519
  },
1520
+ {
1521
+ "description": "The session this run asked to continue does not exist for the identity it\nran as, so the harness refused before doing any work (see\n[`unknown_session_rejection`]). Distinct from every other kind because the\ntask itself is fine: another identity — or a fresh session on this one —\ncan still run it.",
1522
+ "type": "string",
1523
+ "const": "session_not_found"
1524
+ },
1211
1525
  {
1212
1526
  "description": "The harness deferred a builtin tool call instead of executing it, so a\nclean-exit run did no useful work (Claude Code bridge deployments; issue\n#1114). The only kind that can appear on a `status: ok` run.",
1213
1527
  "type": "string",
@@ -1338,6 +1652,17 @@
1338
1652
  "type": "string"
1339
1653
  }
1340
1654
  },
1655
+ "control": {
1656
+ "description": "Out-of-band turn control for this run (`--control`), or `null` when none\nwas requested — which is every ordinary run. It records the socket a\nseparate `oneharness interrupt` process could address, the harness\nmechanism behind it, and each request served, so a consumer can tell an\ninterrupted turn from one that simply ended.",
1657
+ "anyOf": [
1658
+ {
1659
+ "$ref": "#/$defs/ControlReport"
1660
+ },
1661
+ {
1662
+ "type": "null"
1663
+ }
1664
+ ]
1665
+ },
1341
1666
  "dry_run": {
1342
1667
  "type": "boolean"
1343
1668
  },
@@ -1461,6 +1786,7 @@
1461
1786
  "spy_file",
1462
1787
  "history_file",
1463
1788
  "config_files",
1789
+ "control",
1464
1790
  "results"
1465
1791
  ]
1466
1792
  },
@@ -1525,7 +1851,7 @@
1525
1851
  "format": "int32"
1526
1852
  },
1527
1853
  "failure_kind": {
1528
- "description": "Best-effort failure reason; `null` when unclassified. Distinct from\n`status`, which records oneharness's relationship to the process. Two\nfamilies: coarse reasons for a non-zero run (`auth`, `rate_limit`,\n`model_not_found`, `quota`), and `tool_deferred` — a run that exited\n*cleanly* but only deferred a builtin tool call instead of executing it\n(Claude Code bridge/managed deployments), so it did no useful work. The\ndeferred case is the only `failure_kind` that can appear on a `status: ok`\nrun, and it also marks the run as failed for exit-code purposes.\nSerialized as its snake_case token (see [`FailureKind`]).",
1854
+ "description": "Best-effort failure reason; `null` when unclassified. Distinct from\n`status`, which records oneharness's relationship to the process. Two\nfamilies: coarse reasons for a non-zero run (`auth`, `rate_limit`,\n`model_not_found`, `quota`, `session_not_found`), and `tool_deferred` — a run that exited\n*cleanly* but only deferred a builtin tool call instead of executing it\n(Claude Code bridge/managed deployments), so it did no useful work. The\ndeferred case is the only `failure_kind` that can appear on a `status: ok`\nrun, and it also marks the run as failed for exit-code purposes.\nSerialized as its snake_case token (see [`FailureKind`]).",
1529
1855
  "anyOf": [
1530
1856
  {
1531
1857
  "$ref": "#/$defs/FailureKind"
@@ -1857,6 +2183,10 @@
1857
2183
  "cache_write_tokens",
1858
2184
  "cost_usd"
1859
2185
  ]
2186
+ },
2187
+ "UtcInstant": {
2188
+ "description": "An RFC 3339 timestamp in UTC (`Z`), in oneharness's canonical spelling.",
2189
+ "type": "string"
1860
2190
  }
1861
2191
  }
1862
2192
  },
@@ -2178,7 +2508,8 @@
2178
2508
  "enum": [
2179
2509
  "1.2",
2180
2510
  "1.3",
2181
- "1.4"
2511
+ "1.4",
2512
+ "1.5"
2182
2513
  ]
2183
2514
  },
2184
2515
  "type": {
@@ -2294,7 +2625,8 @@
2294
2625
  "type": "string",
2295
2626
  "enum": [
2296
2627
  "1.3",
2297
- "1.4"
2628
+ "1.4",
2629
+ "1.5"
2298
2630
  ]
2299
2631
  }
2300
2632
  },
@@ -2360,7 +2692,38 @@
2360
2692
  "schema_version": {
2361
2693
  "type": "string",
2362
2694
  "enum": [
2363
- "1.4"
2695
+ "1.4",
2696
+ "1.5"
2697
+ ]
2698
+ }
2699
+ }
2700
+ }
2701
+ ]
2702
+ },
2703
+ {
2704
+ "anyOf": [
2705
+ {
2706
+ "type": "object",
2707
+ "properties": {
2708
+ "failure_kind": {
2709
+ "enum": [
2710
+ "auth",
2711
+ "rate_limit",
2712
+ "model_not_found",
2713
+ "quota",
2714
+ "tool_deferred",
2715
+ null
2716
+ ]
2717
+ }
2718
+ }
2719
+ },
2720
+ {
2721
+ "type": "object",
2722
+ "properties": {
2723
+ "schema_version": {
2724
+ "type": "string",
2725
+ "enum": [
2726
+ "1.5"
2364
2727
  ]
2365
2728
  }
2366
2729
  }
@@ -2456,7 +2819,8 @@
2456
2819
  "1.1",
2457
2820
  "1.2",
2458
2821
  "1.3",
2459
- "1.4"
2822
+ "1.4",
2823
+ "1.5"
2460
2824
  ]
2461
2825
  },
2462
2826
  "session": {
@@ -2638,7 +3002,8 @@
2638
3002
  "1.1",
2639
3003
  "1.2",
2640
3004
  "1.3",
2641
- "1.4"
3005
+ "1.4",
3006
+ "1.5"
2642
3007
  ]
2643
3008
  },
2644
3009
  "session": {
@@ -2818,7 +3183,8 @@
2818
3183
  "enum": [
2819
3184
  "1.2",
2820
3185
  "1.3",
2821
- "1.4"
3186
+ "1.4",
3187
+ "1.5"
2822
3188
  ]
2823
3189
  },
2824
3190
  "session": {
@@ -2979,7 +3345,8 @@
2979
3345
  "1.1",
2980
3346
  "1.2",
2981
3347
  "1.3",
2982
- "1.4"
3348
+ "1.4",
3349
+ "1.5"
2983
3350
  ]
2984
3351
  },
2985
3352
  "session": {
@@ -3139,7 +3506,8 @@
3139
3506
  "type": "string",
3140
3507
  "enum": [
3141
3508
  "1.3",
3142
- "1.4"
3509
+ "1.4",
3510
+ "1.5"
3143
3511
  ]
3144
3512
  },
3145
3513
  "session": {
@@ -3316,7 +3684,8 @@
3316
3684
  "1.1",
3317
3685
  "1.2",
3318
3686
  "1.3",
3319
- "1.4"
3687
+ "1.4",
3688
+ "1.5"
3320
3689
  ]
3321
3690
  },
3322
3691
  "session": {
@@ -3495,7 +3864,7 @@
3495
3864
  ]
3496
3865
  },
3497
3866
  "FailureKind": {
3498
- "description": "The normalized, closed set of failure reasons oneharness can classify from a\nharness's output. It is the single source for the `failure_kind` contract\nvalue: serialized as the snake_case token a consumer reads in the report\n(`auth`, `rate_limit`, `model_not_found`, `quota`, `tool_deferred`), so the\nwire shape is unchanged — modeling it as an enum keeps a misspelled or\ninvalid kind unrepresentable and gives every producer/consumer (classifier,\n`is_failure`, the fallback fall-through rule, the report, history) one\ndefinition to share instead of scattered string literals.",
3867
+ "description": "The normalized, closed set of failure reasons oneharness can classify from a\nharness's output. It is the single source for the `failure_kind` contract\nvalue: serialized as the snake_case token a consumer reads in the report\n(`auth`, `rate_limit`, `model_not_found`, `quota`, `session_not_found`,\n`tool_deferred`), so the wire shape is unchanged — modeling it as an enum\nkeeps a misspelled or invalid kind unrepresentable and gives every\nproducer/consumer (classifier, `is_failure`, the fallback fall-through rule,\nthe report, history) one definition to share instead of scattered string\nliterals.",
3499
3868
  "oneOf": [
3500
3869
  {
3501
3870
  "description": "Authentication / authorization rejected the request (401/403, missing or\ninvalid credentials).",
@@ -3517,6 +3886,11 @@
3517
3886
  "type": "string",
3518
3887
  "const": "quota"
3519
3888
  },
3889
+ {
3890
+ "description": "The session this run asked to continue does not exist for the identity it\nran as, so the harness refused before doing any work (see\n[`unknown_session_rejection`]). Distinct from every other kind because the\ntask itself is fine: another identity — or a fresh session on this one —\ncan still run it.",
3891
+ "type": "string",
3892
+ "const": "session_not_found"
3893
+ },
3520
3894
  {
3521
3895
  "description": "The harness deferred a builtin tool call instead of executing it, so a\nclean-exit run did no useful work (Claude Code bridge deployments; issue\n#1114). The only kind that can appear on a `status: ok` run.",
3522
3896
  "type": "string",
@@ -3728,7 +4102,8 @@
3728
4102
  "type": "string",
3729
4103
  "enum": [
3730
4104
  "1.3",
3731
- "1.4"
4105
+ "1.4",
4106
+ "1.5"
3732
4107
  ]
3733
4108
  }
3734
4109
  },
@@ -3794,7 +4169,38 @@
3794
4169
  "schema_version": {
3795
4170
  "type": "string",
3796
4171
  "enum": [
3797
- "1.4"
4172
+ "1.4",
4173
+ "1.5"
4174
+ ]
4175
+ }
4176
+ }
4177
+ }
4178
+ ]
4179
+ },
4180
+ {
4181
+ "anyOf": [
4182
+ {
4183
+ "type": "object",
4184
+ "properties": {
4185
+ "failure_kind": {
4186
+ "enum": [
4187
+ "auth",
4188
+ "rate_limit",
4189
+ "model_not_found",
4190
+ "quota",
4191
+ "tool_deferred",
4192
+ null
4193
+ ]
4194
+ }
4195
+ }
4196
+ },
4197
+ {
4198
+ "type": "object",
4199
+ "properties": {
4200
+ "schema_version": {
4201
+ "type": "string",
4202
+ "enum": [
4203
+ "1.5"
3798
4204
  ]
3799
4205
  }
3800
4206
  }
@@ -4071,7 +4477,8 @@
4071
4477
  "enum": [
4072
4478
  "1.2",
4073
4479
  "1.3",
4074
- "1.4"
4480
+ "1.4",
4481
+ "1.5"
4075
4482
  ]
4076
4483
  },
4077
4484
  "session": {
@@ -4671,7 +5078,8 @@
4671
5078
  "enum": [
4672
5079
  "1.2",
4673
5080
  "1.3",
4674
- "1.4"
5081
+ "1.4",
5082
+ "1.5"
4675
5083
  ]
4676
5084
  },
4677
5085
  "session": {
@@ -4846,7 +5254,8 @@
4846
5254
  "enum": [
4847
5255
  "1.2",
4848
5256
  "1.3",
4849
- "1.4"
5257
+ "1.4",
5258
+ "1.5"
4850
5259
  ]
4851
5260
  },
4852
5261
  "session": {
@@ -5019,7 +5428,8 @@
5019
5428
  "enum": [
5020
5429
  "1.2",
5021
5430
  "1.3",
5022
- "1.4"
5431
+ "1.4",
5432
+ "1.5"
5023
5433
  ]
5024
5434
  },
5025
5435
  "session": {
@@ -5193,7 +5603,8 @@
5193
5603
  "type": "string",
5194
5604
  "enum": [
5195
5605
  "1.3",
5196
- "1.4"
5606
+ "1.4",
5607
+ "1.5"
5197
5608
  ]
5198
5609
  },
5199
5610
  "session": {
@@ -6036,7 +6447,7 @@
6036
6447
  ]
6037
6448
  },
6038
6449
  "FailureKind": {
6039
- "description": "The normalized, closed set of failure reasons oneharness can classify from a\nharness's output. It is the single source for the `failure_kind` contract\nvalue: serialized as the snake_case token a consumer reads in the report\n(`auth`, `rate_limit`, `model_not_found`, `quota`, `tool_deferred`), so the\nwire shape is unchanged — modeling it as an enum keeps a misspelled or\ninvalid kind unrepresentable and gives every producer/consumer (classifier,\n`is_failure`, the fallback fall-through rule, the report, history) one\ndefinition to share instead of scattered string literals.",
6450
+ "description": "The normalized, closed set of failure reasons oneharness can classify from a\nharness's output. It is the single source for the `failure_kind` contract\nvalue: serialized as the snake_case token a consumer reads in the report\n(`auth`, `rate_limit`, `model_not_found`, `quota`, `session_not_found`,\n`tool_deferred`), so the wire shape is unchanged — modeling it as an enum\nkeeps a misspelled or invalid kind unrepresentable and gives every\nproducer/consumer (classifier, `is_failure`, the fallback fall-through rule,\nthe report, history) one definition to share instead of scattered string\nliterals.",
6040
6451
  "oneOf": [
6041
6452
  {
6042
6453
  "description": "Authentication / authorization rejected the request (401/403, missing or\ninvalid credentials).",
@@ -6058,6 +6469,11 @@
6058
6469
  "type": "string",
6059
6470
  "const": "quota"
6060
6471
  },
6472
+ {
6473
+ "description": "The session this run asked to continue does not exist for the identity it\nran as, so the harness refused before doing any work (see\n[`unknown_session_rejection`]). Distinct from every other kind because the\ntask itself is fine: another identity — or a fresh session on this one —\ncan still run it.",
6474
+ "type": "string",
6475
+ "const": "session_not_found"
6476
+ },
6061
6477
  {
6062
6478
  "description": "The harness deferred a builtin tool call instead of executing it, so a\nclean-exit run did no useful work (Claude Code bridge deployments; issue\n#1114). The only kind that can appear on a `status: ok` run.",
6063
6479
  "type": "string",
@@ -6380,7 +6796,7 @@
6380
6796
  ]
6381
6797
  },
6382
6798
  "FailureKind": {
6383
- "description": "The normalized, closed set of failure reasons oneharness can classify from a\nharness's output. It is the single source for the `failure_kind` contract\nvalue: serialized as the snake_case token a consumer reads in the report\n(`auth`, `rate_limit`, `model_not_found`, `quota`, `tool_deferred`), so the\nwire shape is unchanged — modeling it as an enum keeps a misspelled or\ninvalid kind unrepresentable and gives every producer/consumer (classifier,\n`is_failure`, the fallback fall-through rule, the report, history) one\ndefinition to share instead of scattered string literals.",
6799
+ "description": "The normalized, closed set of failure reasons oneharness can classify from a\nharness's output. It is the single source for the `failure_kind` contract\nvalue: serialized as the snake_case token a consumer reads in the report\n(`auth`, `rate_limit`, `model_not_found`, `quota`, `session_not_found`,\n`tool_deferred`), so the wire shape is unchanged — modeling it as an enum\nkeeps a misspelled or invalid kind unrepresentable and gives every\nproducer/consumer (classifier, `is_failure`, the fallback fall-through rule,\nthe report, history) one definition to share instead of scattered string\nliterals.",
6384
6800
  "oneOf": [
6385
6801
  {
6386
6802
  "description": "Authentication / authorization rejected the request (401/403, missing or\ninvalid credentials).",
@@ -6402,6 +6818,11 @@
6402
6818
  "type": "string",
6403
6819
  "const": "quota"
6404
6820
  },
6821
+ {
6822
+ "description": "The session this run asked to continue does not exist for the identity it\nran as, so the harness refused before doing any work (see\n[`unknown_session_rejection`]). Distinct from every other kind because the\ntask itself is fine: another identity — or a fresh session on this one —\ncan still run it.",
6823
+ "type": "string",
6824
+ "const": "session_not_found"
6825
+ },
6405
6826
  {
6406
6827
  "description": "The harness deferred a builtin tool call instead of executing it, so a\nclean-exit run did no useful work (Claude Code bridge deployments; issue\n#1114). The only kind that can appear on a `status: ok` run.",
6407
6828
  "type": "string",
@@ -6440,7 +6861,8 @@
6440
6861
  "enum": [
6441
6862
  "1.2",
6442
6863
  "1.3",
6443
- "1.4"
6864
+ "1.4",
6865
+ "1.5"
6444
6866
  ]
6445
6867
  },
6446
6868
  "variant": {
@@ -6562,7 +6984,8 @@
6562
6984
  "type": "string",
6563
6985
  "enum": [
6564
6986
  "1.3",
6565
- "1.4"
6987
+ "1.4",
6988
+ "1.5"
6566
6989
  ]
6567
6990
  }
6568
6991
  },
@@ -6628,7 +7051,38 @@
6628
7051
  "schema_version": {
6629
7052
  "type": "string",
6630
7053
  "enum": [
6631
- "1.4"
7054
+ "1.4",
7055
+ "1.5"
7056
+ ]
7057
+ }
7058
+ }
7059
+ }
7060
+ ]
7061
+ },
7062
+ {
7063
+ "anyOf": [
7064
+ {
7065
+ "type": "object",
7066
+ "properties": {
7067
+ "failure_kind": {
7068
+ "enum": [
7069
+ "auth",
7070
+ "rate_limit",
7071
+ "model_not_found",
7072
+ "quota",
7073
+ "tool_deferred",
7074
+ null
7075
+ ]
7076
+ }
7077
+ }
7078
+ },
7079
+ {
7080
+ "type": "object",
7081
+ "properties": {
7082
+ "schema_version": {
7083
+ "type": "string",
7084
+ "enum": [
7085
+ "1.5"
6632
7086
  ]
6633
7087
  }
6634
7088
  }
@@ -6905,7 +7359,8 @@
6905
7359
  "enum": [
6906
7360
  "1.2",
6907
7361
  "1.3",
6908
- "1.4"
7362
+ "1.4",
7363
+ "1.5"
6909
7364
  ]
6910
7365
  },
6911
7366
  "session": {
@@ -7505,7 +7960,8 @@
7505
7960
  "enum": [
7506
7961
  "1.2",
7507
7962
  "1.3",
7508
- "1.4"
7963
+ "1.4",
7964
+ "1.5"
7509
7965
  ]
7510
7966
  },
7511
7967
  "session": {
@@ -7680,7 +8136,8 @@
7680
8136
  "enum": [
7681
8137
  "1.2",
7682
8138
  "1.3",
7683
- "1.4"
8139
+ "1.4",
8140
+ "1.5"
7684
8141
  ]
7685
8142
  },
7686
8143
  "session": {
@@ -7853,7 +8310,8 @@
7853
8310
  "enum": [
7854
8311
  "1.2",
7855
8312
  "1.3",
7856
- "1.4"
8313
+ "1.4",
8314
+ "1.5"
7857
8315
  ]
7858
8316
  },
7859
8317
  "session": {
@@ -8027,7 +8485,8 @@
8027
8485
  "type": "string",
8028
8486
  "enum": [
8029
8487
  "1.3",
8030
- "1.4"
8488
+ "1.4",
8489
+ "1.5"
8031
8490
  ]
8032
8491
  },
8033
8492
  "session": {
@@ -9036,7 +9495,7 @@
9036
9495
  ]
9037
9496
  },
9038
9497
  "FailureKind": {
9039
- "description": "The normalized, closed set of failure reasons oneharness can classify from a\nharness's output. It is the single source for the `failure_kind` contract\nvalue: serialized as the snake_case token a consumer reads in the report\n(`auth`, `rate_limit`, `model_not_found`, `quota`, `tool_deferred`), so the\nwire shape is unchanged — modeling it as an enum keeps a misspelled or\ninvalid kind unrepresentable and gives every producer/consumer (classifier,\n`is_failure`, the fallback fall-through rule, the report, history) one\ndefinition to share instead of scattered string literals.",
9498
+ "description": "The normalized, closed set of failure reasons oneharness can classify from a\nharness's output. It is the single source for the `failure_kind` contract\nvalue: serialized as the snake_case token a consumer reads in the report\n(`auth`, `rate_limit`, `model_not_found`, `quota`, `session_not_found`,\n`tool_deferred`), so the wire shape is unchanged — modeling it as an enum\nkeeps a misspelled or invalid kind unrepresentable and gives every\nproducer/consumer (classifier, `is_failure`, the fallback fall-through rule,\nthe report, history) one definition to share instead of scattered string\nliterals.",
9040
9499
  "oneOf": [
9041
9500
  {
9042
9501
  "description": "Authentication / authorization rejected the request (401/403, missing or\ninvalid credentials).",
@@ -9058,6 +9517,11 @@
9058
9517
  "type": "string",
9059
9518
  "const": "quota"
9060
9519
  },
9520
+ {
9521
+ "description": "The session this run asked to continue does not exist for the identity it\nran as, so the harness refused before doing any work (see\n[`unknown_session_rejection`]). Distinct from every other kind because the\ntask itself is fine: another identity — or a fresh session on this one —\ncan still run it.",
9522
+ "type": "string",
9523
+ "const": "session_not_found"
9524
+ },
9061
9525
  {
9062
9526
  "description": "The harness deferred a builtin tool call instead of executing it, so a\nclean-exit run did no useful work (Claude Code bridge deployments; issue\n#1114). The only kind that can appear on a `status: ok` run.",
9063
9527
  "type": "string",
@@ -9109,7 +9573,8 @@
9109
9573
  "type": "string",
9110
9574
  "enum": [
9111
9575
  "1.3",
9112
- "1.4"
9576
+ "1.4",
9577
+ "1.5"
9113
9578
  ]
9114
9579
  }
9115
9580
  },
@@ -9175,7 +9640,38 @@
9175
9640
  "schema_version": {
9176
9641
  "type": "string",
9177
9642
  "enum": [
9178
- "1.4"
9643
+ "1.4",
9644
+ "1.5"
9645
+ ]
9646
+ }
9647
+ }
9648
+ }
9649
+ ]
9650
+ },
9651
+ {
9652
+ "anyOf": [
9653
+ {
9654
+ "type": "object",
9655
+ "properties": {
9656
+ "failure_kind": {
9657
+ "enum": [
9658
+ "auth",
9659
+ "rate_limit",
9660
+ "model_not_found",
9661
+ "quota",
9662
+ "tool_deferred",
9663
+ null
9664
+ ]
9665
+ }
9666
+ }
9667
+ },
9668
+ {
9669
+ "type": "object",
9670
+ "properties": {
9671
+ "schema_version": {
9672
+ "type": "string",
9673
+ "enum": [
9674
+ "1.5"
9179
9675
  ]
9180
9676
  }
9181
9677
  }
@@ -9452,7 +9948,8 @@
9452
9948
  "enum": [
9453
9949
  "1.2",
9454
9950
  "1.3",
9455
- "1.4"
9951
+ "1.4",
9952
+ "1.5"
9456
9953
  ]
9457
9954
  },
9458
9955
  "session": {
@@ -10052,7 +10549,8 @@
10052
10549
  "enum": [
10053
10550
  "1.2",
10054
10551
  "1.3",
10055
- "1.4"
10552
+ "1.4",
10553
+ "1.5"
10056
10554
  ]
10057
10555
  },
10058
10556
  "session": {
@@ -10227,7 +10725,8 @@
10227
10725
  "enum": [
10228
10726
  "1.2",
10229
10727
  "1.3",
10230
- "1.4"
10728
+ "1.4",
10729
+ "1.5"
10231
10730
  ]
10232
10731
  },
10233
10732
  "session": {
@@ -10400,7 +10899,8 @@
10400
10899
  "enum": [
10401
10900
  "1.2",
10402
10901
  "1.3",
10403
- "1.4"
10902
+ "1.4",
10903
+ "1.5"
10404
10904
  ]
10405
10905
  },
10406
10906
  "session": {
@@ -10574,7 +11074,8 @@
10574
11074
  "type": "string",
10575
11075
  "enum": [
10576
11076
  "1.3",
10577
- "1.4"
11077
+ "1.4",
11078
+ "1.5"
10578
11079
  ]
10579
11080
  },
10580
11081
  "session": {
@@ -11579,9 +12080,50 @@
11579
12080
  "harnesses"
11580
12081
  ],
11581
12082
  "$defs": {
12083
+ "ControlShape": {
12084
+ "description": "How a harness accepts an out-of-band interrupt for an in-flight turn.\n\nRegistry data on [`crate::domain::harness::HarnessSpec::control`], sourced\nfrom a live interrupt against the real CLI — never guessed. `None` there\nmeans `oneharness interrupt` is a loud usage error for the harness, never a\nsilent no-op: a supervisor that is told \"ok\" while the turn keeps running is\nworse off than one told the lever does not exist.",
12085
+ "oneOf": [
12086
+ {
12087
+ "description": "Claude Code: the control frame rides the run process's **own stdin**\n(`-p --input-format stream-json`), so no sidecar server is needed. A\n`{\"type\":\"control_request\",…,\"request\":{\"subtype\":\"interrupt\"}}` line\naborts the turn with a `result` document; the session survives and a\nlater turn continues it with full context. Verified live: a plain user\nmessage written mid-turn is *silently dropped*, so the control frame is\nthe only mechanism that works.",
12088
+ "type": "string",
12089
+ "const": "claude-control-request"
12090
+ },
12091
+ {
12092
+ "description": "Codex: `turn/interrupt {threadId,turnId}` over the `codex app-server`\nJSON-RPC stdio protocol, which oneharness spawns as the run's own child\nand drives the thread/turn lifecycle on — so the interrupt rides the same\nopen stdin and nothing is shared or pooled.",
12093
+ "type": "string",
12094
+ "const": "codex-app-server"
12095
+ },
12096
+ {
12097
+ "description": "OpenCode: `POST /api/session/{id}/interrupt` against `opencode serve`.",
12098
+ "type": "string",
12099
+ "const": "opencode-http"
12100
+ },
12101
+ {
12102
+ "description": "Goose and Copilot: the ACP `session/cancel` **notification** (no `id`)\nover their JSON-RPC stdio servers.",
12103
+ "type": "string",
12104
+ "const": "acp-cancel"
12105
+ },
12106
+ {
12107
+ "description": "Crush: `POST /v1/workspaces/{id}/agent/sessions/{sid}/cancel` against\n`crush server`.",
12108
+ "type": "string",
12109
+ "const": "crush-http"
12110
+ }
12111
+ ]
12112
+ },
11582
12113
  "HarnessInfo": {
11583
12114
  "type": "object",
11584
12115
  "properties": {
12116
+ "control": {
12117
+ "description": "How `run --control` + `oneharness interrupt` abort an in-flight turn on\nthis harness (the mechanism id), or `null` when it has no out-of-band\nturn control at all — in which case `--control` is a loud usage error for\nit, never a socket that reports success while the turn keeps running.",
12118
+ "anyOf": [
12119
+ {
12120
+ "$ref": "#/$defs/ControlShape"
12121
+ },
12122
+ {
12123
+ "type": "null"
12124
+ }
12125
+ ]
12126
+ },
11585
12127
  "default_bin": {
11586
12128
  "type": "string"
11587
12129
  },
@@ -11687,6 +12229,7 @@
11687
12229
  "supports_resume",
11688
12230
  "session_capable",
11689
12231
  "supports_fork",
12232
+ "control",
11690
12233
  "fork_reuses_cache",
11691
12234
  "modes",
11692
12235
  "supports_native_schema",