sneakoscope 2.0.4 → 2.0.5

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 (104) hide show
  1. package/README.md +12 -8
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/crates/sks-core/src/main.rs +1 -1
  5. package/dist/.sks-build-stamp.json +4 -4
  6. package/dist/bin/sks.js +1 -1
  7. package/dist/build-manifest.json +73 -8
  8. package/dist/commands/doctor.js +14 -0
  9. package/dist/core/agents/agent-proof-evidence.js +35 -0
  10. package/dist/core/agents/agent-roster.js +35 -6
  11. package/dist/core/agents/agent-schema.js +1 -1
  12. package/dist/core/agents/native-worker-backend-router.js +31 -9
  13. package/dist/core/agents/ollama-worker-config.js +164 -15
  14. package/dist/core/codex/codex-0-137-compat.js +119 -0
  15. package/dist/core/codex-control/codex-control-proof.js +4 -1
  16. package/dist/core/codex-control/codex-sdk-capability.js +1 -1
  17. package/dist/core/codex-control/codex-task-runner.js +329 -5
  18. package/dist/core/codex-control/python-codex-sdk-adapter.js +197 -0
  19. package/dist/core/codex-control/python-codex-sdk-event-translator.js +14 -0
  20. package/dist/core/commands/local-model-command.js +65 -19
  21. package/dist/core/commands/naruto-command.js +118 -7
  22. package/dist/core/commands/run-command.js +1 -1
  23. package/dist/core/doctor/doctor-readiness-matrix.js +21 -2
  24. package/dist/core/fsx.js +1 -1
  25. package/dist/core/local-llm/local-llm-backpressure.js +20 -0
  26. package/dist/core/local-llm/local-llm-capability.js +29 -0
  27. package/dist/core/local-llm/local-llm-client.js +100 -0
  28. package/dist/core/local-llm/local-llm-config.js +6 -1
  29. package/dist/core/local-llm/local-llm-context-cache.js +21 -0
  30. package/dist/core/local-llm/local-llm-control-adapter.js +101 -0
  31. package/dist/core/local-llm/local-llm-json-repair.js +52 -0
  32. package/dist/core/local-llm/local-llm-metrics.js +42 -0
  33. package/dist/core/local-llm/local-llm-ollama-client.js +67 -0
  34. package/dist/core/local-llm/local-llm-openai-compatible-client.js +30 -0
  35. package/dist/core/local-llm/local-llm-prompt-cache.js +12 -0
  36. package/dist/core/local-llm/local-llm-scheduler.js +29 -0
  37. package/dist/core/local-llm/local-llm-schema-enforcer.js +15 -0
  38. package/dist/core/local-llm/local-llm-smoke.js +83 -0
  39. package/dist/core/local-llm/local-llm-warmup.js +20 -0
  40. package/dist/core/local-llm/local-worker-eligibility.js +27 -0
  41. package/dist/core/naruto/hardware-capacity-probe.js +36 -0
  42. package/dist/core/naruto/naruto-active-pool.js +118 -0
  43. package/dist/core/naruto/naruto-backpressure.js +13 -0
  44. package/dist/core/naruto/naruto-concurrency-governor.js +65 -0
  45. package/dist/core/naruto/naruto-finalizer.js +18 -0
  46. package/dist/core/naruto/naruto-generation-scheduler.js +18 -0
  47. package/dist/core/naruto/naruto-gpt-final-pack.js +49 -0
  48. package/dist/core/naruto/naruto-parallel-patch-apply.js +95 -0
  49. package/dist/core/naruto/naruto-patch-transaction-batch.js +42 -0
  50. package/dist/core/naruto/naruto-role-policy.js +107 -0
  51. package/dist/core/naruto/naruto-verification-dag.js +42 -0
  52. package/dist/core/naruto/naruto-verification-pool.js +18 -0
  53. package/dist/core/naruto/naruto-work-graph.js +198 -0
  54. package/dist/core/naruto/naruto-work-item.js +40 -0
  55. package/dist/core/naruto/naruto-work-stealing.js +11 -0
  56. package/dist/core/naruto/resource-pressure-monitor.js +32 -0
  57. package/dist/core/pipeline/finalize-pipeline-result.js +58 -0
  58. package/dist/core/pipeline/gpt-final-required.js +12 -0
  59. package/dist/core/prompt/prompt-placeholder-guard.js +30 -0
  60. package/dist/core/router/capability-card.js +13 -0
  61. package/dist/core/router/route-cache.js +3 -0
  62. package/dist/core/router/ultra-router.js +2 -1
  63. package/dist/core/routes.js +4 -4
  64. package/dist/core/version.js +1 -1
  65. package/dist/core/zellij/zellij-lane-runtime.js +2 -2
  66. package/dist/core/zellij/zellij-naruto-dashboard.js +36 -0
  67. package/dist/core/zellij/zellij-worker-pane-manager.js +4 -4
  68. package/dist/scripts/blackbox-command-import-smoke.js +10 -1
  69. package/dist/scripts/check-package-boundary.js +12 -3
  70. package/dist/scripts/codex-0-137-compat-check.js +27 -0
  71. package/dist/scripts/codex-environment-scoped-approvals-check.js +10 -0
  72. package/dist/scripts/codex-plugin-list-json-check.js +8 -0
  73. package/dist/scripts/codex-thread-runtime-choice-check.js +10 -0
  74. package/dist/scripts/local-collab-all-pipelines-final-gpt-check.js +21 -0
  75. package/dist/scripts/local-llm-all-pipelines-check.js +11 -0
  76. package/dist/scripts/local-llm-cache-performance-check.js +10 -0
  77. package/dist/scripts/local-llm-capability-check.js +14 -0
  78. package/dist/scripts/local-llm-smoke-check.js +23 -0
  79. package/dist/scripts/local-llm-structured-output-check.js +11 -0
  80. package/dist/scripts/local-llm-throughput-check.js +10 -0
  81. package/dist/scripts/local-llm-tool-call-repair-check.js +10 -0
  82. package/dist/scripts/local-llm-warmup-check.js +11 -0
  83. package/dist/scripts/naruto-active-pool-check.js +27 -0
  84. package/dist/scripts/naruto-concurrency-governor-check.js +52 -0
  85. package/dist/scripts/naruto-gpt-final-pack-check.js +34 -0
  86. package/dist/scripts/naruto-parallel-patch-apply-check.js +41 -0
  87. package/dist/scripts/naruto-real-local-gpt-final-smoke.js +16 -0
  88. package/dist/scripts/naruto-role-distribution-check.js +23 -0
  89. package/dist/scripts/naruto-shadow-clone-swarm-check.js +6 -0
  90. package/dist/scripts/naruto-verification-pool-check.js +36 -0
  91. package/dist/scripts/naruto-work-graph-check.js +24 -0
  92. package/dist/scripts/naruto-zellij-massive-ui-check.js +23 -0
  93. package/dist/scripts/prompt-placeholder-guard-check.js +33 -0
  94. package/dist/scripts/python-codex-sdk-all-pipelines-check.js +47 -0
  95. package/dist/scripts/python-codex-sdk-capability-check.js +75 -0
  96. package/dist/scripts/python-codex-sdk-sandbox-policy-check.js +10 -0
  97. package/dist/scripts/python-codex-sdk-stream-bridge-check.js +12 -0
  98. package/dist/scripts/release-parallel-check.js +1 -1
  99. package/dist/scripts/release-real-check.js +5 -0
  100. package/dist/scripts/zellij-worker-pane-manager-check.js +1 -1
  101. package/package.json +33 -4
  102. package/schemas/local-llm/local-model-config.schema.json +74 -0
  103. package/schemas/naruto/naruto-concurrency-governor.schema.json +21 -0
  104. package/schemas/naruto/naruto-work-graph.schema.json +22 -0
package/README.md CHANGED
@@ -16,7 +16,7 @@ Set up this agent project with Sneakoscope Codex. Use [[mandarange/Sneakoscope-C
16
16
 
17
17
  ## Current Release
18
18
 
19
- SKS **2.0.4** is a P0 Codex App Fast UI and MAD Zellij worker-pane closure patch on top of the 2.0 execution layer. `sks --mad` now relies on launch-time Fast/high overrides instead of user-level Codex config rewrites, safe Fast UI repair runs through `sks doctor --fix`, provider badges read env/auth/config.toml consistently, and interactive MAD worker panes attach to the real Zellij session as scheduler slots spawn.
19
+ SKS **2.0.5** is a P0 Codex App Fast UI and MAD Zellij worker-pane closure patch on top of the 2.0 execution layer. `sks --mad` now relies on launch-time Fast/high overrides instead of user-level Codex config rewrites, safe Fast UI repair runs through `sks doctor --fix`, provider badges read env/auth/config.toml consistently, and interactive MAD worker panes attach to the real Zellij session as scheduler slots spawn.
20
20
 
21
21
  What changed:
22
22
 
@@ -398,9 +398,9 @@ Manual fan-out syntax:
398
398
 
399
399
  Effort is assigned per agent. Simple read-only/docs slices can run low, ordinary tooling and lease mapping use medium, safety/DB/schema/release lanes use high, and frontier/forensic research can escalate to xhigh. If a lease conflict, schema failure, proof blocker, DB risk, or release risk appears, the parent can escalate that lane while keeping unrelated lanes cheaper and faster.
400
400
 
401
- ### Naruto Shadow Clone Swarm (`$Naruto`)
401
+ ### Naruto Massive Parallel Work Swarm (`$Naruto`)
402
402
 
403
- `$Naruto` (影分身 / Kage Bunshin no Jutsu) is a high-scale mode of the native agent kernel for broad fan-out work codebase-wide sweeps, parallel drafting, large audits. It lifts the standard 20-agent ceiling to **up to 100 clone sessions** (only for this route; every other route keeps the 20 cap).
403
+ `$Naruto` (影分身 / Kage Bunshin no Jutsu) is the hardware-safe massive parallel work mode of the native agent kernel. It is not limited to validation. A Naruto run builds a mixed work graph, keeps a safe active worker pool full, and assigns clones to implementation, modification, test generation, verification, research, documentation, conflict resolution, rollback planning, integration support, and GPT final review input work. It lifts the standard 20-agent ceiling to **up to 100 total clone generations** for this route while keeping active workers under the live hardware, lease, memory, terminal UI, file descriptor, local LLM, and remote API caps.
404
404
 
405
405
  ```sh
406
406
  sks naruto run "sweep the codebase for TODO comments and summarize"
@@ -411,9 +411,11 @@ sks naruto status
411
411
 
412
412
  Aliases: `$ShadowClone`, `$Kagebunshin`, and the CLI flag `sks --naruto`.
413
413
 
414
- - **System-aware concurrency:** `--clones N` is the total work fan-out, but `$Naruto` never spawns the whole count at once. Live concurrency is throttled to a host-safe number derived from CPU cores and free memory (heavier cap for real `codex-sdk` workers, tighter packing for in-process `fake`). So `--clones 100` on a small host still processes all 100 work units while only running a safe handful at a time; the run reports when it throttles. Override with `SKS_NARUTO_MAX_CONCURRENCY=<n>`.
414
+ - **Hardware-safe governor:** `--clones N` is the total work fan-out, but `$Naruto` never spawns the whole count at once. Live concurrency is throttled by current load, memory, file descriptors, Zellij pane budget, local LLM request budget, remote API budget, disk pressure, pending queue, and active lease conflicts.
415
+ - **Dynamic active pool:** completed workers are drained and replaced while runnable work remains, so the active pool does not sit empty between generations.
415
416
  - **Dynamic per-clone effort (like Team):** truly simple / no-tool work runs at `low`, any tool use lifts a clone to `medium` (never high/xhigh), and every clone runs in fast service tier.
416
- - **Safe parallel writes:** clones coordinate through the same lease-based patch-swarm (merge coordinator + conflict rebase + transaction journal) as Team.
417
+ - **Safe parallel writes:** write-capable clones produce patch envelopes for leased files. Non-overlapping envelopes can apply in parallel; overlapping envelopes serialize or route to conflict resolution. Local worker output remains a draft until the GPT final arbiter approves or modifies it.
418
+ - **Massive UI without pane overload:** Zellij shows visible active worker panes up to the UI cap and tracks the remaining active headless workers in the Naruto dashboard.
417
419
 
418
420
  See [docs/naruto.md](docs/naruto.md) for the full reference.
419
421
 
@@ -513,18 +515,20 @@ $DB inspect this migration for destructive risk
513
515
 
514
516
  ### Optional Local LLM Workers
515
517
 
516
- Local Ollama workers are off by default, so SKS stays GPT-only unless you explicitly enable them. Use the Codex App prompt commands:
518
+ Local model workers are off by default, so SKS stays GPT-only unless you explicitly enable them. Use the Codex App prompt commands:
517
519
 
518
520
  ```text
519
521
  $with-local-llm-on
520
522
  $with-local-llm-off
521
523
  ```
522
524
 
523
- When enabled, the local model can only help with policy-eligible simple code patch-envelope work or read-only collection. GPT/Codex still owns strategy, planning, design, review, verification, safety, and integration. Check or tune the machine-local setting from the terminal:
525
+ When enabled, SKS auto-detects an installed local model from a running MLX LM server, OpenAI-compatible local server, or Ollama. If no local model is available, activation stays blocked and reports that no local model was found. The local model can only help with policy-eligible simple code patch-envelope work or read-only collection. GPT/Codex still owns strategy, planning, design, review, verification, safety, and integration. Check or tune the machine-local setting from the terminal:
524
526
 
525
527
  ```sh
526
528
  sks with-local-llm status --json
527
- sks with-local-llm on --model rafw007/qwen36-a3b-claude-coder:q4_K_M
529
+ sks with-local-llm on
530
+ sks with-local-llm on --provider mlx-lm --model mlx-community/Qwen3.6-35B-A3B-4bit --base-url http://127.0.0.1:8080
531
+ sks with-local-llm on --provider ollama --model rafw007/qwen36-a3b-claude-coder:q4_K_M
528
532
  sks with-local-llm off
529
533
  ```
530
534
 
@@ -76,7 +76,7 @@ dependencies = [
76
76
 
77
77
  [[package]]
78
78
  name = "sks-core"
79
- version = "2.0.4"
79
+ version = "2.0.5"
80
80
  dependencies = [
81
81
  "serde_json",
82
82
  ]
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "sks-core"
3
- version = "2.0.4"
3
+ version = "2.0.5"
4
4
  edition = "2021"
5
5
 
6
6
  [dependencies]
@@ -4,7 +4,7 @@ use std::io::{self, Read, Seek, SeekFrom};
4
4
  fn main() {
5
5
  let mut args = std::env::args().skip(1);
6
6
  match args.next().as_deref() {
7
- Some("--version") => println!("sks-rs 2.0.4"),
7
+ Some("--version") => println!("sks-rs 2.0.5"),
8
8
  Some("compact-info") => {
9
9
  let mut input = String::new();
10
10
  let _ = io::stdin().read_to_string(&mut input);
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schema": "sks.dist-build-stamp.v1",
3
3
  "package_name": "sneakoscope",
4
- "package_version": "2.0.4",
5
- "source_digest": "bd67ddf989e2e0b702453d422e2cf991e8ca397d3d4afc14fdfa06b4610452c9",
6
- "source_file_count": 1879,
7
- "built_at_source_time": 1780569940553
4
+ "package_version": "2.0.5",
5
+ "source_digest": "696706cb9d175c4200c967130fbc5e680f4b6c905ec6e7fad5b1671827bcb4cb",
6
+ "source_file_count": 1948,
7
+ "built_at_source_time": 1780613485190
8
8
  }
package/dist/bin/sks.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const FAST_PACKAGE_VERSION = '2.0.4';
2
+ const FAST_PACKAGE_VERSION = '2.0.5';
3
3
  const args = process.argv.slice(2);
4
4
  try {
5
5
  if (args[0] === '--agent' && args[1] === 'worker') {
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "schema": "sks.dist-build.v2",
3
- "version": "2.0.4",
4
- "package_version": "2.0.4",
3
+ "version": "2.0.5",
4
+ "package_version": "2.0.5",
5
5
  "typescript": true,
6
6
  "mjs_runtime_files": 0,
7
- "compiled_file_count": 949,
8
- "compiled_js_count": 949,
7
+ "compiled_file_count": 1014,
8
+ "compiled_js_count": 1014,
9
9
  "compiled_dts_count": 0,
10
- "source_digest": "bd67ddf989e2e0b702453d422e2cf991e8ca397d3d4afc14fdfa06b4610452c9",
11
- "source_file_count": 1879,
12
- "source_files_hash": "c43d09b591370ad58937365d6bbfca2be0b60fcf04a43fdbb9a56d9288752814",
13
- "source_list_hash": "c43d09b591370ad58937365d6bbfca2be0b60fcf04a43fdbb9a56d9288752814",
10
+ "source_digest": "696706cb9d175c4200c967130fbc5e680f4b6c905ec6e7fad5b1671827bcb4cb",
11
+ "source_file_count": 1948,
12
+ "source_files_hash": "50906865545a9076d7b2736ee379a428160a8869749b85ee79c4ddab8eab4b12",
13
+ "source_list_hash": "50906865545a9076d7b2736ee379a428160a8869749b85ee79c4ddab8eab4b12",
14
14
  "src_mjs_runtime_files": 0,
15
15
  "dist_stamp_schema": "sks.dist-build-stamp.v1",
16
16
  "files": [
@@ -216,6 +216,8 @@
216
216
  "core/codex-control/gpt-final-context-compressor.js",
217
217
  "core/codex-control/gpt-final-proof-pack.js",
218
218
  "core/codex-control/gpt-final-review-schema.js",
219
+ "core/codex-control/python-codex-sdk-adapter.js",
220
+ "core/codex-control/python-codex-sdk-event-translator.js",
219
221
  "core/codex-control/schemas/agent-worker-result.schema.js",
220
222
  "core/codex-exec-output-schema.js",
221
223
  "core/codex-hooks/codex-hook-actual-discovery.js",
@@ -237,6 +239,7 @@
237
239
  "core/codex/codex-0-134-compat.js",
238
240
  "core/codex/codex-0-135-compat.js",
239
241
  "core/codex/codex-0-136-compat.js",
242
+ "core/codex/codex-0-137-compat.js",
240
243
  "core/codex/codex-cli-syntax-builder.js",
241
244
  "core/codex/codex-config-eperm-repair.js",
242
245
  "core/codex/codex-config-readability.js",
@@ -362,7 +365,22 @@
362
365
  "core/json-schema-validator.js",
363
366
  "core/language-preference.js",
364
367
  "core/local-llm/local-collaboration-policy.js",
368
+ "core/local-llm/local-llm-backpressure.js",
369
+ "core/local-llm/local-llm-capability.js",
370
+ "core/local-llm/local-llm-client.js",
365
371
  "core/local-llm/local-llm-config.js",
372
+ "core/local-llm/local-llm-context-cache.js",
373
+ "core/local-llm/local-llm-control-adapter.js",
374
+ "core/local-llm/local-llm-json-repair.js",
375
+ "core/local-llm/local-llm-metrics.js",
376
+ "core/local-llm/local-llm-ollama-client.js",
377
+ "core/local-llm/local-llm-openai-compatible-client.js",
378
+ "core/local-llm/local-llm-prompt-cache.js",
379
+ "core/local-llm/local-llm-scheduler.js",
380
+ "core/local-llm/local-llm-schema-enforcer.js",
381
+ "core/local-llm/local-llm-smoke.js",
382
+ "core/local-llm/local-llm-warmup.js",
383
+ "core/local-llm/local-worker-eligibility.js",
366
384
  "core/loop-blocker.js",
367
385
  "core/mad-sks/audit-ledger.js",
368
386
  "core/mad-sks/authorization-manifest.js",
@@ -393,6 +411,22 @@
393
411
  "core/mission.js",
394
412
  "core/mistake-memory.js",
395
413
  "core/mistake-recall.js",
414
+ "core/naruto/hardware-capacity-probe.js",
415
+ "core/naruto/naruto-active-pool.js",
416
+ "core/naruto/naruto-backpressure.js",
417
+ "core/naruto/naruto-concurrency-governor.js",
418
+ "core/naruto/naruto-finalizer.js",
419
+ "core/naruto/naruto-generation-scheduler.js",
420
+ "core/naruto/naruto-gpt-final-pack.js",
421
+ "core/naruto/naruto-parallel-patch-apply.js",
422
+ "core/naruto/naruto-patch-transaction-batch.js",
423
+ "core/naruto/naruto-role-policy.js",
424
+ "core/naruto/naruto-verification-dag.js",
425
+ "core/naruto/naruto-verification-pool.js",
426
+ "core/naruto/naruto-work-graph.js",
427
+ "core/naruto/naruto-work-item.js",
428
+ "core/naruto/naruto-work-stealing.js",
429
+ "core/naruto/resource-pressure-monitor.js",
396
430
  "core/no-question-guard.js",
397
431
  "core/openclaw.js",
398
432
  "core/perf-bench.js",
@@ -406,6 +440,8 @@
406
440
  "core/pipeline/agent-stage-policy.js",
407
441
  "core/pipeline/final-gpt-patch-stage.js",
408
442
  "core/pipeline/final-gpt-review-stage.js",
443
+ "core/pipeline/finalize-pipeline-result.js",
444
+ "core/pipeline/gpt-final-required.js",
409
445
  "core/pipeline/pipeline-plan-writer.js",
410
446
  "core/pipeline/plan-schema.js",
411
447
  "core/pipeline/prompt-context-answer.js",
@@ -438,6 +474,7 @@
438
474
  "core/ppt.js",
439
475
  "core/preflight/parallel-preflight-engine.js",
440
476
  "core/prompt-context-builder.js",
477
+ "core/prompt/prompt-placeholder-guard.js",
441
478
  "core/proof-field.js",
442
479
  "core/proof/auto-finalize.js",
443
480
  "core/proof/claim-ledger.js",
@@ -568,6 +605,7 @@
568
605
  "core/zellij/zellij-lane-runtime.js",
569
606
  "core/zellij/zellij-launcher.js",
570
607
  "core/zellij/zellij-layout-builder.js",
608
+ "core/zellij/zellij-naruto-dashboard.js",
571
609
  "core/zellij/zellij-pane-proof.js",
572
610
  "core/zellij/zellij-screen-proof.js",
573
611
  "core/zellij/zellij-worker-pane-manager.js",
@@ -679,6 +717,7 @@
679
717
  "scripts/codex-0-134-runner-truth-check.js",
680
718
  "scripts/codex-0-135-compat-check.js",
681
719
  "scripts/codex-0-136-compat-check.js",
720
+ "scripts/codex-0-137-compat-check.js",
682
721
  "scripts/codex-app-fast-ui-preservation-check.js",
683
722
  "scripts/codex-app-provider-badge-check.js",
684
723
  "scripts/codex-app-ui-clobber-guard-check.js",
@@ -696,6 +735,7 @@
696
735
  "scripts/codex-control-structured-output-check.js",
697
736
  "scripts/codex-control-thread-registry-check.js",
698
737
  "scripts/codex-control-tool-call-sequence-repair-check.js",
738
+ "scripts/codex-environment-scoped-approvals-check.js",
699
739
  "scripts/codex-exec-output-schema-actual-syntax-check.js",
700
740
  "scripts/codex-fast-mode-profile-propagation-check.js",
701
741
  "scripts/codex-history-search-check.js",
@@ -710,6 +750,7 @@
710
750
  "scripts/codex-managed-proxy-env-check.js",
711
751
  "scripts/codex-output-schema-fixture-check.js",
712
752
  "scripts/codex-permission-profiles-check.js",
753
+ "scripts/codex-plugin-list-json-check.js",
713
754
  "scripts/codex-profile-primary-check.js",
714
755
  "scripts/codex-project-config-policy-merge-regression.js",
715
756
  "scripts/codex-project-config-policy-splitter-check.js",
@@ -731,6 +772,7 @@
731
772
  "scripts/codex-sdk-thread-registry-check.js",
732
773
  "scripts/codex-sdk-ux-ppt-review-pipeline-check.js",
733
774
  "scripts/codex-sdk-zellij-pane-binding-check.js",
775
+ "scripts/codex-thread-runtime-choice-check.js",
734
776
  "scripts/codex-web-adapter-check.js",
735
777
  "scripts/computer-use-live-evidence-check.js",
736
778
  "scripts/computer-use-live-optional-check.js",
@@ -802,9 +844,18 @@
802
844
  "scripts/lib/real-codex-parallel-gate.js",
803
845
  "scripts/lib/real-codex-parallel-proof-fixture.js",
804
846
  "scripts/lib/valid-png-fixture.js",
847
+ "scripts/local-collab-all-pipelines-final-gpt-check.js",
805
848
  "scripts/local-collab-gpt-final-availability-check.js",
806
849
  "scripts/local-collab-no-local-only-final-check.js",
807
850
  "scripts/local-collab-policy-check.js",
851
+ "scripts/local-llm-all-pipelines-check.js",
852
+ "scripts/local-llm-cache-performance-check.js",
853
+ "scripts/local-llm-capability-check.js",
854
+ "scripts/local-llm-smoke-check.js",
855
+ "scripts/local-llm-structured-output-check.js",
856
+ "scripts/local-llm-throughput-check.js",
857
+ "scripts/local-llm-tool-call-repair-check.js",
858
+ "scripts/local-llm-warmup-check.js",
808
859
  "scripts/loop-blocker-check.js",
809
860
  "scripts/mad-preflight-blocks-unreadable-config-check.js",
810
861
  "scripts/mad-sks-actual-executor-blackbox.js",
@@ -831,7 +882,16 @@
831
882
  "scripts/mcp-tool-naming-parity-check.js",
832
883
  "scripts/memory-summary-rebuild-check.js",
833
884
  "scripts/mutation-callsite-coverage-check.js",
885
+ "scripts/naruto-active-pool-check.js",
886
+ "scripts/naruto-concurrency-governor-check.js",
887
+ "scripts/naruto-gpt-final-pack-check.js",
888
+ "scripts/naruto-parallel-patch-apply-check.js",
889
+ "scripts/naruto-real-local-gpt-final-smoke.js",
890
+ "scripts/naruto-role-distribution-check.js",
834
891
  "scripts/naruto-shadow-clone-swarm-check.js",
892
+ "scripts/naruto-verification-pool-check.js",
893
+ "scripts/naruto-work-graph-check.js",
894
+ "scripts/naruto-zellij-massive-ui-check.js",
835
895
  "scripts/non-recursive-pipeline-check.js",
836
896
  "scripts/npm-publish-performance-check.js",
837
897
  "scripts/official-docs-compat-report.js",
@@ -856,8 +916,13 @@
856
916
  "scripts/prepublish-fast-check.js",
857
917
  "scripts/prepublish-release-check-or-fast.js",
858
918
  "scripts/priority-full-closure-check.js",
919
+ "scripts/prompt-placeholder-guard-check.js",
859
920
  "scripts/provider-badge-context-check.js",
860
921
  "scripts/provider-context-config-toml-check.js",
922
+ "scripts/python-codex-sdk-all-pipelines-check.js",
923
+ "scripts/python-codex-sdk-capability-check.js",
924
+ "scripts/python-codex-sdk-sandbox-policy-check.js",
925
+ "scripts/python-codex-sdk-stream-bridge-check.js",
861
926
  "scripts/python-tools-smoke-check.js",
862
927
  "scripts/qa-actual-route-backfill-check.js",
863
928
  "scripts/qa-backfill-route-blackbox.js",
@@ -17,6 +17,7 @@ import { inventoryCodexPermissionProfiles } from '../core/codex/codex-permission
17
17
  import { appendMigrationEvents, hashConfigText } from '../core/migration/migration-transaction-journal.js';
18
18
  import { repairCodexAppFastUi } from '../core/codex-app/codex-app-fast-ui-repair.js';
19
19
  import { resolveProviderContext } from '../core/provider/provider-context.js';
20
+ import { readLocalModelConfig } from '../core/agents/ollama-worker-config.js';
20
21
  export async function run(_command, args = []) {
21
22
  let setupRepair = null;
22
23
  let migrationPreFix = null;
@@ -136,6 +137,7 @@ export async function run(_command, args = []) {
136
137
  }))
137
138
  : codexAppUiPlan;
138
139
  const zellij = await checkZellijCapability({ root, require: process.env.SKS_REQUIRE_ZELLIJ === '1' });
140
+ const localModel = await readLocalModelConfig().catch(() => null);
139
141
  const permissionProfiles = await inventoryCodexPermissionProfiles(root, { writeReport: true });
140
142
  const globalSksInstallCleanup = flag(args, '--fix') && !flag(args, '--local-only')
141
143
  ? await cleanDuplicateGlobalSksInstalls({ root, fix: true }).catch((err) => ({ schema: 'sks.global-sks-install-cleanup.v1', ok: false, fix: true, error: err?.message || String(err), blockers: ['global_sks_install_cleanup_exception'] }))
@@ -151,6 +153,7 @@ export async function run(_command, args = []) {
151
153
  codex_doctor: codexDoctor,
152
154
  require_codex_doctor: flag(args, '--fix') || flag(args, '--require-actual-codex'),
153
155
  zellij,
156
+ local_model: localModel,
154
157
  repair: configRepair,
155
158
  codex_app_ui: codexAppUi,
156
159
  require_codex_cli_config_load: flag(args, '--fix') || flag(args, '--require-actual-codex'),
@@ -175,6 +178,7 @@ export async function run(_command, args = []) {
175
178
  codex_doctor: codexDoctor,
176
179
  codex_doctor_diff: codexDoctorDiff,
177
180
  zellij,
181
+ local_model: localModel,
178
182
  zellij_readiness: zellijReadiness,
179
183
  codex_permission_profiles: permissionProfiles,
180
184
  imagegen: {
@@ -234,6 +238,16 @@ export async function run(_command, args = []) {
234
238
  }
235
239
  }
236
240
  console.log(`codex-lb: ${codexLb.ok ? 'ok' : `warning ${codexLb.circuit?.state || 'unknown'}`}`);
241
+ if (localModel) {
242
+ console.log('Local LLM:');
243
+ console.log(` enabled: ${localModel.enabled ? 'yes' : 'no'}`);
244
+ console.log(` status: ${localModel.status}`);
245
+ console.log(` provider: ${localModel.provider}`);
246
+ console.log(` model: ${localModel.model}`);
247
+ console.log(` endpoint: ${localModel.base_url}`);
248
+ console.log(` last smoke: ${localModel.last_smoke?.ok ? `ok ${localModel.last_smoke.latency_ms || 0}ms ${localModel.last_smoke.tokens_per_second || 0} tok/s` : 'missing'}`);
249
+ console.log(' final arbiter: GPT required');
250
+ }
237
251
  console.log(`Permissions: config profile and permission profile are tracked separately (${permissionProfiles.codex_config_profile_field}, ${permissionProfiles.codex_permission_profile_field})`);
238
252
  console.log('Ready:');
239
253
  console.log(` cli_ready: ${ready.cli_ready ? 'yes' : 'no'}`);
@@ -31,6 +31,13 @@ export async function writeAgentProofEvidence(root, input) {
31
31
  const patchSwarm = input.patchSwarm || await readJson(path.join(root, 'agent-patch-swarm-runtime.json'), null);
32
32
  const localCollaborationPolicy = input.localCollaborationPolicy || await readJson(path.join(root, 'local-collaboration-policy.json'), null) || resolveLocalCollaborationPolicy();
33
33
  const gptFinalArbiter = input.gptFinalArbiter || await readJson(path.join(root, 'gpt-final-arbiter', 'gpt-final-arbiter.json'), null);
34
+ const narutoWorkGraph = await readJson(path.join(root, 'naruto-work-graph.json'), null);
35
+ const narutoRoleDistribution = await readJson(path.join(root, 'naruto-role-distribution.json'), null);
36
+ const narutoConcurrencyGovernor = await readJson(path.join(root, 'naruto-concurrency-governor.json'), null);
37
+ const narutoActivePool = await readJson(path.join(root, 'naruto-active-pool.json'), null);
38
+ const narutoVerificationDag = await readJson(path.join(root, 'naruto-verification-dag.json'), null);
39
+ const narutoGptFinalPack = await readJson(path.join(root, 'naruto-gpt-final-pack.json'), null);
40
+ const narutoZellijDashboard = await readJson(path.join(root, 'naruto-zellij-dashboard.json'), null);
34
41
  const localParticipated = localCollaborationParticipated(input.results || []) || Number(gptFinalArbiter?.local_outputs_count || 0) > 0;
35
42
  const finalGptPatchStage = input.finalGptPatchStage || null;
36
43
  const localFinalGate = gptFinalArbiter?.final_gate || evaluateLocalCollaborationFinalGate({
@@ -74,6 +81,7 @@ export async function writeAgentProofEvidence(root, input) {
74
81
  const workQueueGoalRefsOk = Boolean(workQueue?.items?.length) && workQueue.items.every((item) => item.goal_mode_ref);
75
82
  const workQueueStrategyRefsOk = Boolean(workQueue?.items?.length) && workQueue.items.every((item) => item.slice?.strategy_refs);
76
83
  const route = String(input.route || taskGraph?.route_type || '$Agent');
84
+ const isNarutoRoute = route === '$Naruto';
77
85
  const routeCommand = String(input.routeCommand || 'sks agent run');
78
86
  const genericAgentRouteStandIn = !/\$?agent$/i.test(route) && /\bagent\s+run\b/i.test(routeCommand) && /--route/i.test(routeCommand);
79
87
  const realRouteCommandUsed = !genericAgentRouteStandIn;
@@ -177,6 +185,16 @@ export async function writeAgentProofEvidence(root, input) {
177
185
  ...(localParticipated && localFinalGate.ok !== true ? localFinalGate.blockers || ['gpt_final_arbiter_gate_not_ok'] : []),
178
186
  ...(localParticipated && gptFinalArbiter?.ok !== true ? gptFinalArbiter?.blockers || ['gpt_final_arbiter_not_ok'] : []),
179
187
  ...(localParticipated && finalGptPatchStage?.ok === false ? finalGptPatchStage.blockers || ['final_gpt_patch_stage_not_ok'] : []),
188
+ ...(isNarutoRoute && !narutoWorkGraph ? ['naruto_work_graph_missing'] : []),
189
+ ...(isNarutoRoute && narutoWorkGraph?.ok === false ? narutoWorkGraph.blockers || ['naruto_work_graph_not_ok'] : []),
190
+ ...(isNarutoRoute && !narutoRoleDistribution ? ['naruto_role_distribution_missing'] : []),
191
+ ...(isNarutoRoute && narutoRoleDistribution?.ok === false ? narutoRoleDistribution.blockers || ['naruto_role_distribution_not_ok'] : []),
192
+ ...(isNarutoRoute && !narutoConcurrencyGovernor ? ['naruto_concurrency_governor_missing'] : []),
193
+ ...(isNarutoRoute && !narutoActivePool ? ['naruto_active_pool_missing'] : []),
194
+ ...(isNarutoRoute && narutoActivePool?.ok === false ? narutoActivePool.blockers || ['naruto_active_pool_not_ok'] : []),
195
+ ...(isNarutoRoute && !narutoVerificationDag ? ['naruto_verification_dag_missing'] : []),
196
+ ...(isNarutoRoute && !narutoGptFinalPack ? ['naruto_gpt_final_pack_missing'] : []),
197
+ ...(isNarutoRoute && !narutoZellijDashboard ? ['naruto_zellij_dashboard_missing'] : []),
180
198
  ...agentChangedFileLeaseViolations(input.results || [], input.partition?.leases || [])
181
199
  ];
182
200
  const evidence = {
@@ -222,6 +240,23 @@ export async function writeAgentProofEvidence(root, input) {
222
240
  gpt_final_patch_source: finalGptPatchStage?.final_patch_source || (localParticipated ? 'blocked' : 'not_applicable'),
223
241
  gpt_final_gate_ok: localFinalGate.ok === true,
224
242
  gpt_final_gate: localFinalGate,
243
+ naruto_work_graph: narutoWorkGraph ? 'naruto-work-graph.json' : null,
244
+ naruto_total_work_items: Number(narutoWorkGraph?.total_work_items || 0),
245
+ naruto_mixed_work_kinds: narutoWorkGraph?.mixed_work_kinds || [],
246
+ naruto_write_allowed_count: Number(narutoWorkGraph?.write_allowed_count || 0),
247
+ naruto_role_distribution: narutoRoleDistribution ? 'naruto-role-distribution.json' : null,
248
+ naruto_role_distribution_entries: narutoRoleDistribution?.entries || [],
249
+ naruto_verifier_only: narutoRoleDistribution?.verifier_only === true,
250
+ naruto_implementation_like_ratio: Number(narutoRoleDistribution?.implementation_like_ratio || 0),
251
+ naruto_concurrency_governor: narutoConcurrencyGovernor ? 'naruto-concurrency-governor.json' : null,
252
+ naruto_safe_active_workers: Number(narutoConcurrencyGovernor?.safe_active_workers || 0),
253
+ naruto_safe_zellij_visible_panes: Number(narutoConcurrencyGovernor?.safe_zellij_visible_panes || 0),
254
+ naruto_headless_workers: Number(narutoConcurrencyGovernor?.headless_workers || 0),
255
+ naruto_active_pool: narutoActivePool ? 'naruto-active-pool.json' : null,
256
+ naruto_active_pool_refill_events: Number(narutoActivePool?.refill_events || 0),
257
+ naruto_verification_dag: narutoVerificationDag ? 'naruto-verification-dag.json' : null,
258
+ naruto_gpt_final_pack: narutoGptFinalPack ? 'naruto-gpt-final-pack.json' : null,
259
+ naruto_zellij_dashboard: narutoZellijDashboard ? 'naruto-zellij-dashboard.json' : null,
225
260
  patch_swarm_runtime: patchSwarm ? 'agent-patch-swarm-runtime.json' : null,
226
261
  patch_queue: patchSwarm ? 'agent-patch-queue.json' : null,
227
262
  patch_queue_events: patchSwarm ? 'agent-patch-queue-events.jsonl' : null,
@@ -2,6 +2,7 @@ import os from 'node:os';
2
2
  import { DEFAULT_AGENT_CONCURRENCY, DEFAULT_AGENT_COUNT, DEFAULT_NARUTO_CLONES, MAX_AGENT_COUNT, MAX_NARUTO_AGENT_COUNT, agentSessionId } from './agent-schema.js';
3
3
  import { defaultAgentPersonas, validatePersonaUniqueness } from './agent-persona.js';
4
4
  import { buildAgentEffortPolicy, decideAgentEffort, decideNarutoCloneEffort } from './agent-effort-policy.js';
5
+ import { mapNarutoRoleToAgentRole, narutoRoleAllowsWrite } from '../naruto/naruto-role-policy.js';
5
6
  // $Naruto must never blindly spawn the full clone count at once, but the live
6
7
  // CONCURRENCY ceiling is NOT a function of CPU cores. Each clone is a separate CLI
7
8
  // worker process that spends ~all of its wall-clock awaiting the Codex API
@@ -156,28 +157,40 @@ export function buildNarutoCloneRoster(opts = {}) {
156
157
  const basePool = pool.length ? pool : defaultAgentPersonas(DEFAULT_AGENT_COUNT);
157
158
  const personas = [];
158
159
  const roster = [];
160
+ const roleCycle = narutoRoleCycle(readonly);
159
161
  for (let index = 0; index < cloneCount; index += 1) {
160
162
  const base = basePool[index % basePool.length];
161
163
  const cloneTag = 'clone-' + String(index + 1).padStart(3, '0');
162
164
  const id = 'naruto_' + cloneTag.replace(/-/g, '_');
163
- const cloneReadonly = readonly || base.read_only;
165
+ const narutoRole = roleCycle[index % roleCycle.length] || 'verifier';
166
+ const writeAllowed = !readonly && narutoRoleAllowsWrite(narutoRole);
167
+ const cloneReadonly = readonly || !writeAllowed;
168
+ const role = mapNarutoRoleToAgentRole(narutoRole);
169
+ const allowedTools = writeAllowed ? ['read', 'search', 'edit', 'test'] : narutoRole === 'verifier' ? ['read', 'search', 'test'] : ['read', 'search'];
164
170
  // Dynamic per-clone effort like team mode, capped at low/medium and always fast.
165
- const effort = decideNarutoCloneEffort({ persona: base, prompt: opts.prompt || '', agentId: id, readonly: cloneReadonly });
171
+ const effort = decideNarutoCloneEffort({ persona: { ...base, role, allowed_tools: allowedTools, read_only: cloneReadonly, write_policy: writeAllowed ? 'exclusive Naruto patch-envelope lease required' : 'read-only Naruto role' }, prompt: opts.prompt || '', agentId: id, readonly: cloneReadonly });
166
172
  const persona = {
167
173
  ...base,
168
174
  id,
169
175
  stable_id: base.stable_id + '-' + cloneTag,
170
- read_only: readonly || base.read_only,
171
- prompt: 'SHADOW CLONE: ' + cloneTag + ' (Kage Bunshin of ' + base.stable_id + ')\n' + base.prompt
176
+ role,
177
+ naruto_role: narutoRole,
178
+ write_allowed: writeAllowed,
179
+ read_only: cloneReadonly,
180
+ allowed_tools: allowedTools,
181
+ write_policy: writeAllowed ? 'exclusive Naruto patch-envelope lease required' : 'read-only Naruto role',
182
+ prompt: 'SHADOW CLONE: ' + cloneTag + ' (Kage Bunshin of ' + base.stable_id + ')\nNARUTO ROLE: ' + narutoRole + '\n' + base.prompt
172
183
  };
173
184
  personas.push(persona);
174
185
  roster.push({
175
186
  id,
176
187
  session_id: agentSessionId(id, index + 1),
177
188
  persona_id: id,
178
- role: base.role,
189
+ role,
190
+ naruto_role: narutoRole,
191
+ write_allowed: writeAllowed,
179
192
  index: index + 1,
180
- write_policy: cloneReadonly ? 'read-only' : base.write_policy,
193
+ write_policy: cloneReadonly ? 'read-only' : 'exclusive Naruto patch-envelope lease required',
181
194
  status: 'pending',
182
195
  reasoning_effort: effort.reasoning_effort,
183
196
  model_reasoning_effort: effort.model_reasoning_effort,
@@ -208,4 +221,20 @@ export function buildNarutoCloneRoster(opts = {}) {
208
221
  };
209
222
  return { ...result, effort_policy: buildAgentEffortPolicy(result) };
210
223
  }
224
+ function narutoRoleCycle(readonly) {
225
+ if (readonly)
226
+ return ['verifier', 'researcher', 'verifier', 'gpt_final_arbiter'];
227
+ return [
228
+ 'implementer',
229
+ 'modifier',
230
+ 'test_writer',
231
+ 'verifier',
232
+ 'researcher',
233
+ 'conflict_resolver',
234
+ 'rollback_planner',
235
+ 'integrator',
236
+ 'modifier',
237
+ 'test_writer'
238
+ ];
239
+ }
211
240
  //# sourceMappingURL=agent-roster.js.map
@@ -14,7 +14,7 @@ export const DEFAULT_AGENT_CONCURRENCY = 5;
14
14
  // cap; every other roster/scheduler caller keeps MAX_AGENT_COUNT as the default.
15
15
  export const MAX_NARUTO_AGENT_COUNT = 100;
16
16
  export const DEFAULT_NARUTO_CLONES = 12;
17
- export const AGENT_BACKENDS = ['fake', 'process', 'codex-sdk', 'zellij', 'ollama'];
17
+ export const AGENT_BACKENDS = ['fake', 'process', 'codex-sdk', 'zellij', 'ollama', 'local-llm'];
18
18
  export function normalizeAgentBackend(input) {
19
19
  const value = String(input || 'codex-sdk');
20
20
  return AGENT_BACKENDS.includes(value) ? value : 'codex-sdk';
@@ -86,7 +86,8 @@ export async function runNativeWorkerBackendRouter(input) {
86
86
  verification: { status: ollamaRun.status === 'done' ? 'passed' : 'failed', checks: [...(ollamaRun.verification?.checks || []), 'native-worker-backend-router', 'ollama-api-generate'] }
87
87
  });
88
88
  }
89
- else if (backend === 'codex-sdk' || backend === 'zellij') {
89
+ else if (backend === 'codex-sdk' || backend === 'zellij' || backend === 'local-llm') {
90
+ const localPreferred = backend === 'local-llm';
90
91
  const sdkTask = await runCodexTask({
91
92
  route: String(input.intake.route || '$Agent'),
92
93
  tier: 'worker',
@@ -111,6 +112,12 @@ export async function runNativeWorkerBackendRouter(input) {
111
112
  user_confirmed_full_access: false,
112
113
  mad_sks_authorized: input.intake.mad_sks_authorized === true || process.env.SKS_MAD_SKS_ACTIVE === '1'
113
114
  },
115
+ backendPreference: localPreferred ? ['local-llm', 'codex-sdk'] : ['codex-sdk'],
116
+ allowLocalLlm: localPreferred,
117
+ ...(localPreferred ? { localLlmPolicy: {
118
+ mode: 'local_preferred',
119
+ requiresGptFinal: true
120
+ } } : {}),
114
121
  mutationLedgerRoot: path.join(root, input.workerDirRel),
115
122
  zellijPaneId: await readZellijPaneId(root, input.workerDirRel),
116
123
  reliabilityPolicy: {
@@ -121,12 +128,14 @@ export async function runNativeWorkerBackendRouter(input) {
121
128
  outputLastMessagePath = sdkTask.workerResultPath;
122
129
  const sdkWorkerResult = await readJson(sdkTask.workerResultPath, null);
123
130
  patchEnvelopes = normalizeSdkPatchEnvelopes(sdkWorkerResult?.patch_envelopes || [], input, sdkTask.sdkThreadId);
124
- proofLevel = sdkTask.ok ? (patchEnvelopes.length ? 'model_authored' : 'codex_sdk_thread_proven') : 'blocked';
131
+ proofLevel = sdkTask.ok ? (patchEnvelopes.length ? 'model_authored' : sdkTask.backend === 'local-llm' ? 'local_llm_worker_proven' : 'codex_sdk_thread_proven') : 'blocked';
125
132
  const sdkReport = {
126
133
  schema: 'sks.codex-sdk-worker-adapter.v1',
127
- backend: 'codex-sdk',
134
+ backend: sdkTask.backend,
135
+ backend_family: sdkTask.backend_family,
128
136
  sdk_thread_id: sdkTask.sdkThreadId,
129
137
  sdk_run_id: sdkTask.sdkRunId,
138
+ local_llm_proof_path: sdkTask.localLlmProofPath || null,
130
139
  stream_event_count: sdkTask.streamEventCount,
131
140
  structured_output_valid: sdkTask.structuredOutputValid,
132
141
  worker_result_path: sdkTask.workerResultPath,
@@ -136,17 +145,30 @@ export async function runNativeWorkerBackendRouter(input) {
136
145
  childReports = [sdkReport];
137
146
  result = validateAgentWorkerResult({
138
147
  ...sdkWorkerResult,
139
- backend: 'codex-sdk',
148
+ backend: sdkTask.backend === 'local-llm' ? 'local-llm' : 'codex-sdk',
140
149
  patch_envelopes: patchEnvelopes,
141
150
  codex_child_report: sdkReport,
142
151
  codex_sdk_thread: sdkReport,
143
152
  model_authored_patch_envelopes: patchEnvelopes.length > 0,
144
153
  fixture_patch_envelopes: false,
145
- artifacts: [...new Set([...(sdkWorkerResult?.artifacts || []), path.relative(root, sdkTask.workerResultPath), path.join(input.workerDirRel, 'codex-control-proof.json'), path.join(input.workerDirRel, 'codex-thread-registry.json'), path.join(input.workerDirRel, 'codex-sdk-events.jsonl')])],
154
+ artifacts: [...new Set([
155
+ ...(sdkWorkerResult?.artifacts || []),
156
+ path.relative(root, sdkTask.workerResultPath),
157
+ path.join(input.workerDirRel, 'codex-control-proof.json'),
158
+ path.join(input.workerDirRel, 'codex-thread-registry.json'),
159
+ sdkTask.backend === 'local-llm' ? path.join(input.workerDirRel, 'local-llm-events.jsonl') : path.join(input.workerDirRel, 'codex-sdk-events.jsonl'),
160
+ ...(sdkTask.localLlmProofPath ? [path.relative(root, sdkTask.localLlmProofPath)] : [])
161
+ ])],
146
162
  blockers: [...(sdkWorkerResult?.blockers || []), ...sdkTask.blockers],
147
163
  verification: {
148
164
  status: sdkTask.ok ? 'passed' : 'failed',
149
- checks: [...(sdkWorkerResult?.verification?.checks || []), 'codex-sdk-control-plane', 'codex-sdk-event-stream', 'codex-sdk-structured-output']
165
+ checks: [
166
+ ...(sdkWorkerResult?.verification?.checks || []),
167
+ sdkTask.backend === 'local-llm' ? 'local-llm-control-plane' : 'codex-sdk-control-plane',
168
+ sdkTask.backend === 'local-llm' ? 'local-llm-event-stream' : 'codex-sdk-event-stream',
169
+ sdkTask.backend === 'local-llm' ? 'local-llm-structured-output' : 'codex-sdk-structured-output',
170
+ ...(sdkTask.backend === 'local-llm' ? ['gpt-final-required-before-acceptance'] : [])
171
+ ]
150
172
  }
151
173
  });
152
174
  }
@@ -221,13 +243,13 @@ async function maybeAutoSelectOllamaBackend(backend, input) {
221
243
  model: input.intake?.ollama_model || null,
222
244
  baseUrl: input.intake?.ollama_base_url || null
223
245
  }).catch(() => null);
224
- if (!config?.ok || config.enabled !== true)
246
+ if (!config?.ok || config.enabled !== true || config.status !== 'verified')
225
247
  return backend;
226
248
  const policy = classifyOllamaWorkerSlice(input.slice, { route: input.intake?.route, agent: input.agent });
227
- return policy.ok ? 'ollama' : backend;
249
+ return policy.ok ? 'local-llm' : backend;
228
250
  }
229
251
  function normalizeBackend(value) {
230
- return value === 'fake' || value === 'process' || value === 'codex-sdk' || value === 'zellij' || value === 'ollama' ? value : null;
252
+ return value === 'fake' || value === 'process' || value === 'codex-sdk' || value === 'zellij' || value === 'ollama' || value === 'local-llm' ? value : null;
231
253
  }
232
254
  function envelopeOpts(input, source, childPid) {
233
255
  return {