sneakoscope 2.0.1 → 2.0.2

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 (52) hide show
  1. package/README.md +26 -5
  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 +15 -8
  8. package/dist/cli/command-registry.js +2 -0
  9. package/dist/commands/doctor.js +29 -3
  10. package/dist/core/agents/agent-command-surface.js +13 -3
  11. package/dist/core/agents/agent-orchestrator.js +22 -0
  12. package/dist/core/agents/agent-output-validator.js +2 -1
  13. package/dist/core/agents/agent-patch-schema.js +2 -1
  14. package/dist/core/agents/agent-roster.js +1 -1
  15. package/dist/core/agents/agent-runner-ollama.js +411 -0
  16. package/dist/core/agents/agent-schema.js +1 -1
  17. package/dist/core/agents/intelligent-work-graph.js +45 -3
  18. package/dist/core/agents/native-cli-session-swarm.js +8 -1
  19. package/dist/core/agents/native-cli-worker.js +1 -1
  20. package/dist/core/agents/native-worker-backend-router.js +44 -2
  21. package/dist/core/agents/ollama-worker-config.js +118 -0
  22. package/dist/core/auto-review.js +39 -6
  23. package/dist/core/codex-app/codex-app-fast-ui-repair.js +42 -3
  24. package/dist/core/commands/basic-cli.js +36 -1
  25. package/dist/core/commands/local-model-command.js +105 -0
  26. package/dist/core/commands/mad-sks-command.js +58 -9
  27. package/dist/core/commands/run-command.js +29 -1
  28. package/dist/core/commands/team-command.js +31 -2
  29. package/dist/core/doctor/doctor-readiness-matrix.js +4 -0
  30. package/dist/core/feature-fixtures.js +1 -0
  31. package/dist/core/fsx.js +1 -1
  32. package/dist/core/hooks-runtime.js +1 -1
  33. package/dist/core/init.js +2 -0
  34. package/dist/core/provider/provider-context.js +72 -9
  35. package/dist/core/retention.js +11 -0
  36. package/dist/core/routes.js +21 -1
  37. package/dist/core/team-live.js +7 -1
  38. package/dist/core/update-check.js +156 -1
  39. package/dist/core/verification/verification-worker-pool.js +12 -0
  40. package/dist/core/version.js +1 -1
  41. package/dist/core/zellij/zellij-worker-pane-manager.js +19 -2
  42. package/dist/scripts/agent-ast-aware-work-graph-check.js +1 -1
  43. package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +12 -2
  44. package/dist/scripts/mad-sks-app-ui-no-mutation-check.js +92 -0
  45. package/dist/scripts/mad-sks-zellij-default-pane-worker-check.js +37 -0
  46. package/dist/scripts/mad-sks-zellij-launch-check.js +2 -1
  47. package/dist/scripts/provider-context-config-toml-check.js +63 -0
  48. package/dist/scripts/release-gate-existence-audit.js +4 -0
  49. package/dist/scripts/runtime-no-mjs-scripts-check.js +3 -2
  50. package/dist/scripts/zellij-worker-pane-manager-check.js +3 -0
  51. package/dist/scripts/zellij-worker-pane-manager-single-owner-check.js +39 -0
  52. package/package.json +7 -3
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.1** is a Codex App Fast UI preservation patch on top of the 2.0 execution layer. Native workers still run through the Codex SDK Control Plane, UltraRouter still classifies orchestrator/worker tasks, Reliability Shield still hardens long SDK streams, and Zellij worker panes now carry provider/service-tier proof while spawning only when scheduler slot generations need them.
19
+ SKS **2.0.2** 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
 
@@ -285,6 +285,7 @@ sks deps check --yes
285
285
  sks codex-app check
286
286
  sks doctor --fix
287
287
  sks fix-path
288
+ sks update now
288
289
  ```
289
290
 
290
291
  ### Open Codex CLI With Zellij
@@ -356,7 +357,7 @@ sks --mad
356
357
  sks --mad --allow-package-install --allow-service-control --allow-network --yes
357
358
  ```
358
359
 
359
- This syncs existing codex-lb provider auth, creates/uses the `sks-mad-high` high-power maintenance profile, opens the MAD-SKS permission gate for that Zellij run, starts a same-mission read-only native agent swarm, and launches a Codex CLI layout whose right-side lanes read that MAD ledger. Bare `sks --mad` grants target-project file and shell scope only; add explicit `--allow-*` flags for packages, services, network, Computer Use, browser use, generated assets, file permissions, DB writes, or other high-risk scopes. MAD-SKS is not a DB-only unlock: it is explicit user authorization to widen approved target-project scopes. Catastrophic database wipe/all-row/project-management safeguards remain active, and the pipeline contract still forbids unrequested fallback implementation code.
360
+ This syncs existing codex-lb provider auth, creates/uses the `sks-mad-high` xhigh maintenance profile, opens the MAD-SKS permission gate for that Zellij run, starts a same-mission read-only native agent swarm, and launches a Codex CLI layout whose right-side lanes read that MAD ledger. Bare `sks --mad` grants target-project file and shell scope only; add explicit `--allow-*` flags for packages, services, network, Computer Use, browser use, generated assets, file permissions, DB writes, or other high-risk scopes. MAD-SKS is not a DB-only unlock: it is explicit user authorization to widen approved target-project scopes. Catastrophic database wipe/all-row/project-management safeguards remain active, and the pipeline contract still forbids unrequested fallback implementation code.
360
361
 
361
362
  Before launching, SKS checks npm for a newer `sneakoscope`; answer `y` to update or `n` to continue. Use `--yes` to approve missing dependency installs automatically. Tune MAD swarm startup with `--mad-agents <n>`, `--mad-swarm-work-items <n>`, and `--mad-swarm-backend <backend>`; `--no-mad-swarm` keeps only the cockpit UI if you need a temporary fallback.
362
363
 
@@ -498,6 +499,8 @@ Then open Codex App and use prompt commands directly in the chat. Examples:
498
499
 
499
500
  ```text
500
501
  $Team implement the checkout fix and verify it
502
+ $with-local-llm-on
503
+ $with-local-llm-off
501
504
  $DFix change this label and spacing only
502
505
  $QA-LOOP dogfood localhost:3000 and fix safe issues
503
506
  $PPT create an investor deck as HTML/PDF
@@ -508,6 +511,23 @@ $Wiki refresh and validate the context pack
508
511
  $DB inspect this migration for destructive risk
509
512
  ```
510
513
 
514
+ ### Optional Local LLM Workers
515
+
516
+ Local Ollama workers are off by default, so SKS stays GPT-only unless you explicitly enable them. Use the Codex App prompt commands:
517
+
518
+ ```text
519
+ $with-local-llm-on
520
+ $with-local-llm-off
521
+ ```
522
+
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:
524
+
525
+ ```sh
526
+ sks with-local-llm status --json
527
+ sks with-local-llm on --model rafw007/qwen36-a3b-claude-coder:q4_K_M
528
+ sks with-local-llm off
529
+ ```
530
+
511
531
  Generated app files include:
512
532
 
513
533
  | Path | Purpose |
@@ -568,7 +588,7 @@ SKS_HERMES=1 sks status --json
568
588
 
569
589
  Use these inside Codex App or another agent prompt. They are prompt commands, not terminal commands.
570
590
 
571
- Common prompts: `$Team`, `$From-Chat-IMG`, `$DFix`, `$Answer`, `$SKS`, `$QA-LOOP`, `$PPT`, `$Computer-Use`/`$CU`, `$Goal`, `$Research`, `$AutoResearch`, `$DB`, `$MAD-SKS`, `$GX`, `$Wiki`, and `$Help`.
591
+ Common prompts: `$Team`, `$From-Chat-IMG`, `$with-local-llm-on`, `$with-local-llm-off`, `$DFix`, `$Answer`, `$SKS`, `$QA-LOOP`, `$PPT`, `$Computer-Use`/`$CU`, `$Goal`, `$Research`, `$AutoResearch`, `$DB`, `$MAD-SKS`, `$GX`, `$Wiki`, and `$Help`.
572
592
 
573
593
  ## Common Workflows
574
594
 
@@ -590,7 +610,7 @@ sks
590
610
  # or: sks --mad
591
611
  ```
592
612
 
593
- Use Codex App routes with `$Team`, `$DFix`, `$QA-LOOP`, `$PPT`, `$Goal`, `$Wiki`, and `$DB`. Team missions write artifacts under `.sneakoscope/missions/`; validate them with `sks validate-artifacts latest`.
613
+ Use Codex App routes with `$Team`, `$with-local-llm-on`/`$with-local-llm-off`, `$DFix`, `$QA-LOOP`, `$PPT`, `$Goal`, `$Wiki`, and `$DB`. Team missions write artifacts under `.sneakoscope/missions/`; validate them with `sks validate-artifacts latest`.
594
614
 
595
615
  Refresh context before risky work:
596
616
 
@@ -630,11 +650,12 @@ If PATH or npm has duplicate global installs, `sks doctor --fix` keeps one globa
630
650
 
631
651
  ```sh
632
652
  sks update-check --json
653
+ sks update now
633
654
  npm ls -g sneakoscope --depth=0
634
655
  sks doctor --fix
635
656
  ```
636
657
 
637
- Update prompts compare npm latest against the effective installed version from source metadata, PATH `sks --version`, and global npm package metadata. If a global update succeeded but an old shim remains earlier on PATH, `sks doctor --fix` can remove duplicate global installs and refresh the managed setup.
658
+ Update prompts compare npm latest against the effective installed version from source metadata, PATH `sks --version`, and global npm package metadata. `sks update now` installs through npm global mode instead of mutating the current project's dependencies. If a global update succeeded but an old shim remains earlier on PATH, `sks doctor --fix` can remove duplicate global installs and refresh the managed setup.
638
659
 
639
660
  ### Zellij is missing
640
661
 
@@ -76,7 +76,7 @@ dependencies = [
76
76
 
77
77
  [[package]]
78
78
  name = "sks-core"
79
- version = "2.0.1"
79
+ version = "2.0.2"
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.1"
3
+ version = "2.0.2"
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.1"),
7
+ Some("--version") => println!("sks-rs 2.0.2"),
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.1",
5
- "source_digest": "fc6581fa4e92892f1de963685540cd8754dd02015459f80ded6c7271837a0197",
6
- "source_file_count": 1852,
7
- "built_at_source_time": 1780513745133
4
+ "package_version": "2.0.2",
5
+ "source_digest": "b1e08c53f5899ea762b2bb7a06ea6fab73ddfccac076d17c276685f2a8e12beb",
6
+ "source_file_count": 1861,
7
+ "built_at_source_time": 1780562040816
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.1';
2
+ const FAST_PACKAGE_VERSION = '2.0.2';
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.1",
4
- "package_version": "2.0.1",
3
+ "version": "2.0.2",
4
+ "package_version": "2.0.2",
5
5
  "typescript": true,
6
6
  "mjs_runtime_files": 0,
7
- "compiled_file_count": 929,
8
- "compiled_js_count": 929,
7
+ "compiled_file_count": 936,
8
+ "compiled_js_count": 936,
9
9
  "compiled_dts_count": 0,
10
- "source_digest": "fc6581fa4e92892f1de963685540cd8754dd02015459f80ded6c7271837a0197",
11
- "source_file_count": 1852,
12
- "source_files_hash": "92f47f9e5a2283d371d4ee267541e14ddbd9c9101e9db1ab8e46cede781f076b",
13
- "source_list_hash": "92f47f9e5a2283d371d4ee267541e14ddbd9c9101e9db1ab8e46cede781f076b",
10
+ "source_digest": "b1e08c53f5899ea762b2bb7a06ea6fab73ddfccac076d17c276685f2a8e12beb",
11
+ "source_file_count": 1861,
12
+ "source_files_hash": "c8eda2a67acc10058477afb1eb7963595dc9ba17273dd4fd396014d8862b277f",
13
+ "source_list_hash": "c8eda2a67acc10058477afb1eb7963595dc9ba17273dd4fd396014d8862b277f",
14
14
  "src_mjs_runtime_files": 0,
15
15
  "dist_stamp_schema": "sks.dist-build-stamp.v1",
16
16
  "files": [
@@ -135,6 +135,7 @@
135
135
  "core/agents/agent-roster.js",
136
136
  "core/agents/agent-runner-codex-exec.js",
137
137
  "core/agents/agent-runner-fake.js",
138
+ "core/agents/agent-runner-ollama.js",
138
139
  "core/agents/agent-runner-process.js",
139
140
  "core/agents/agent-runner-zellij.js",
140
141
  "core/agents/agent-scheduler.js",
@@ -159,6 +160,7 @@
159
160
  "core/agents/native-cli-worker.js",
160
161
  "core/agents/native-worker-backend-router.js",
161
162
  "core/agents/no-subagent-scaling-policy.js",
163
+ "core/agents/ollama-worker-config.js",
162
164
  "core/agents/real-codex-parallel-proof.js",
163
165
  "core/agents/route-collaboration-ledger.js",
164
166
  "core/agents/scout-policy.js",
@@ -259,6 +261,7 @@
259
261
  "core/commands/harness-command.js",
260
262
  "core/commands/hproof-command.js",
261
263
  "core/commands/image-ux-review-command.js",
264
+ "core/commands/local-model-command.js",
262
265
  "core/commands/mad-sks-command.js",
263
266
  "core/commands/naruto-command.js",
264
267
  "core/commands/paths-command.js",
@@ -792,6 +795,7 @@
792
795
  "scripts/loop-blocker-check.js",
793
796
  "scripts/mad-preflight-blocks-unreadable-config-check.js",
794
797
  "scripts/mad-sks-actual-executor-blackbox.js",
798
+ "scripts/mad-sks-app-ui-no-mutation-check.js",
795
799
  "scripts/mad-sks-audit-proof-check.js",
796
800
  "scripts/mad-sks-db-executor-check.js",
797
801
  "scripts/mad-sks-executor-proof-graph-check.js",
@@ -806,6 +810,7 @@
806
810
  "scripts/mad-sks-service-executor-check.js",
807
811
  "scripts/mad-sks-shell-executor-check.js",
808
812
  "scripts/mad-sks-write-guard-check.js",
813
+ "scripts/mad-sks-zellij-default-pane-worker-check.js",
809
814
  "scripts/mad-sks-zellij-launch-check.js",
810
815
  "scripts/mcp-0-134-modernization-check.js",
811
816
  "scripts/mcp-readonly-concurrency-check.js",
@@ -839,6 +844,7 @@
839
844
  "scripts/prepublish-release-check-or-fast.js",
840
845
  "scripts/priority-full-closure-check.js",
841
846
  "scripts/provider-badge-context-check.js",
847
+ "scripts/provider-context-config-toml-check.js",
842
848
  "scripts/python-tools-smoke-check.js",
843
849
  "scripts/qa-actual-route-backfill-check.js",
844
850
  "scripts/qa-backfill-route-blackbox.js",
@@ -943,6 +949,7 @@
943
949
  "scripts/zellij-spawn-on-demand-layout-check.js",
944
950
  "scripts/zellij-ui-design-check.js",
945
951
  "scripts/zellij-worker-pane-manager-check.js",
952
+ "scripts/zellij-worker-pane-manager-single-owner-check.js",
946
953
  "scripts/zellij-worker-pane-spawn-order-check.js",
947
954
  "vendor/openai-codex/latest/hooks/permission-request.command.input.schema.json",
948
955
  "vendor/openai-codex/latest/hooks/permission-request.command.output.schema.json",
@@ -80,6 +80,7 @@ export const COMMANDS = {
80
80
  run: entry('beta', 'Classify and execute a task through the SKS trust kernel', 'dist/core/commands/run-command.js', argsCommand(() => import('../core/commands/run-command.js'), 'runCommand', 'dist/core/commands/run-command.js')),
81
81
  status: entry('stable', 'Show concise active mission and trust status', 'dist/core/commands/status-command.js', argsCommand(() => import('../core/commands/status-command.js'), 'statusCommand', 'dist/core/commands/status-command.js')),
82
82
  root: entry('stable', 'Show active SKS root', 'dist/commands/root.js', directCommand(() => import('../commands/root.js'), 'dist/commands/root.js')),
83
+ update: entry('stable', 'Update the global SKS npm package', 'dist/core/commands/basic-cli.js', subcommand(() => import(basicModule), 'updateCommand', 'dist/core/commands/basic-cli.js', 'check')),
83
84
  'update-check': entry('stable', 'Check npm package freshness', 'dist/core/commands/basic-cli.js', basicArgs('updateCheckCommand')),
84
85
  wizard: entry('stable', 'Open setup wizard help', 'dist/core/commands/basic-cli.js', basicNoArgs('quickstartCommand')),
85
86
  usage: entry('stable', 'Show focused usage topic', 'dist/core/commands/basic-cli.js', basicArgs('usageCommand')),
@@ -117,6 +118,7 @@ export const COMMANDS = {
117
118
  dfix: entry('stable', 'Run DFix diagnose/plan/patch/verify loop', 'dist/core/commands/dfix-command.js', commandArgsCommand(() => import('../core/commands/dfix-command.js'), 'dfixCommand', 'dist/core/commands/dfix-command.js')),
118
119
  team: entry('beta', 'Create and observe Team missions', 'dist/core/commands/team-command.js', argsCommand(() => import('../core/commands/team-command.js'), 'team', 'dist/core/commands/team-command.js')),
119
120
  agent: entry('beta', 'Run native multi-session agent missions', 'dist/core/commands/agent-command.js', argsCommand(() => import('../core/commands/agent-command.js'), 'agentCommand', 'dist/core/commands/agent-command.js')),
121
+ 'with-local-llm': entry('beta', 'Enable or inspect local Ollama worker backend', 'dist/core/commands/local-model-command.js', argsCommand(() => import('../core/commands/local-model-command.js'), 'localModelCommand', 'dist/core/commands/local-model-command.js')),
120
122
  naruto: entry('labs', 'Run $Naruto shadow-clone swarm (up to 100 parallel sessions)', 'dist/core/commands/naruto-command.js', argsCommand(() => import('../core/commands/naruto-command.js'), 'narutoCommand', 'dist/core/commands/naruto-command.js')),
121
123
  'qa-loop': entry('beta', 'Run QA loop missions', 'dist/core/commands/qa-loop-command.js', subcommand(() => import('../core/commands/qa-loop-command.js'), 'qaLoopCommand', 'dist/core/commands/qa-loop-command.js')),
122
124
  research: entry('labs', 'Run research missions', 'dist/core/commands/research-command.js', subcommand(() => import('../core/commands/research-command.js'), 'researchCommand', 'dist/core/commands/research-command.js')),
@@ -96,12 +96,17 @@ export async function run(_command, args = []) {
96
96
  model_provider: null
97
97
  }
98
98
  }));
99
- const codexAppUi = await repairCodexAppFastUi(root, {
100
- apply: flag(args, '--fix') && flag(args, '--repair-codex-app-ui'),
101
- reportPath: `${root}/.sneakoscope/reports/codex-app-fast-ui-repair.json`
99
+ const doctorFix = flag(args, '--fix');
100
+ const explicitCodexAppUiRepair = flag(args, '--repair-codex-app-ui') || flag(args, '--yes');
101
+ const codexAppUiPlan = await repairCodexAppFastUi(root, {
102
+ apply: false,
103
+ reportPath: `${root}/.sneakoscope/reports/codex-app-fast-ui-repair-plan.json`
102
104
  }).catch((err) => ({
103
105
  schema: 'sks.codex-app-fast-ui-repair.v1',
104
106
  ok: false,
107
+ apply: false,
108
+ safe_auto_apply: false,
109
+ requires_confirmation: true,
105
110
  fast_selector: 'manual_action_required',
106
111
  provider_selector: 'ok',
107
112
  host_owned_config: 'diagnostic_failed',
@@ -109,6 +114,27 @@ export async function run(_command, args = []) {
109
114
  actions: [],
110
115
  blockers: [err?.message || String(err)]
111
116
  }));
117
+ const shouldApplyCodexAppUiRepair = doctorFix && (explicitCodexAppUiRepair ||
118
+ codexAppUiPlan.safe_auto_apply === true);
119
+ const codexAppUi = shouldApplyCodexAppUiRepair
120
+ ? await repairCodexAppFastUi(root, {
121
+ apply: true,
122
+ force: explicitCodexAppUiRepair,
123
+ reportPath: `${root}/.sneakoscope/reports/codex-app-fast-ui-repair.json`
124
+ }).catch((err) => ({
125
+ schema: 'sks.codex-app-fast-ui-repair.v1',
126
+ ok: false,
127
+ apply: true,
128
+ safe_auto_apply: false,
129
+ requires_confirmation: true,
130
+ fast_selector: 'manual_action_required',
131
+ provider_selector: 'ok',
132
+ host_owned_config: 'diagnostic_failed',
133
+ next_action: 'Review Codex App UI config manually.',
134
+ actions: [],
135
+ blockers: [err?.message || String(err)]
136
+ }))
137
+ : codexAppUiPlan;
112
138
  const zellij = await checkZellijCapability({ root, require: process.env.SKS_REQUIRE_ZELLIJ === '1' });
113
139
  const permissionProfiles = await inventoryCodexPermissionProfiles(root, { writeReport: true });
114
140
  const globalSksInstallCleanup = flag(args, '--fix') && !flag(args, '--local-only')
@@ -12,7 +12,10 @@ export function parseAgentCommandArgs(command, args = []) {
12
12
  const minimumWorkItems = Number(readOption(args, '--minimum-work-items', targetActiveSlots));
13
13
  const maxQueueExpansion = Number(readOption(args, '--max-queue-expansion', 10));
14
14
  const concurrency = Number(readOption(args, '--concurrency', Math.min(agents, 5)));
15
- const backend = String(readOption(args, '--backend', hasFlag(args, '--mock') ? 'fake' : 'codex-sdk'));
15
+ const useOllama = hasFlag(args, '--ollama') || hasFlag(args, '--local-model');
16
+ const noOllama = hasFlag(args, '--no-ollama') || hasFlag(args, '--no-local-model');
17
+ const backendExplicit = hasOption(args, '--backend');
18
+ const backend = String(readOption(args, '--backend', hasFlag(args, '--mock') ? 'fake' : useOllama && !noOllama ? 'ollama' : 'codex-sdk'));
16
19
  const route = String(readOption(args, '--route', '$Agent'));
17
20
  const mock = hasFlag(args, '--mock') || backend === 'fake';
18
21
  const real = hasFlag(args, '--real');
@@ -26,6 +29,10 @@ export function parseAgentCommandArgs(command, args = []) {
26
29
  const serviceTier = normalizeServiceTier(explicitServiceTier, null) || undefined;
27
30
  const fastMode = hasFlag(args, '--no-fast') || serviceTier === 'standard' ? false : hasFlag(args, '--fast') ? true : undefined;
28
31
  const noFast = hasFlag(args, '--no-fast');
32
+ const ollamaModel = String(readOption(args, '--ollama-model', readOption(args, '--local-model-model', '')) || '') || null;
33
+ const ollamaBaseUrl = String(readOption(args, '--ollama-base-url', readOption(args, '--local-model-base-url', '')) || '') || null;
34
+ const zellijSessionName = String(readOption(args, '--zellij-session-name', '') || '') || null;
35
+ const zellijPaneWorker = hasFlag(args, '--no-zellij-pane-worker') ? false : hasFlag(args, '--zellij-pane-worker') ? true : undefined;
29
36
  const apply = hasFlag(args, '--apply');
30
37
  const dryRun = hasFlag(args, '--dry-run') || hasFlag(args, '--dryrun');
31
38
  const drain = hasFlag(args, '--drain');
@@ -33,7 +40,7 @@ export function parseAgentCommandArgs(command, args = []) {
33
40
  const graceMs = Number(readOption(args, '--grace-ms', 750));
34
41
  const killEscalation = hasFlag(args, '--kill-escalation') || !hasFlag(args, '--no-kill-escalation');
35
42
  const codexApp = hasFlag(args, '--codex-app');
36
- const positionals = positionalArgs(rest, new Set(['--agents', '--target-active-slots', '--work-items', '--minimum-work-items', '--max-queue-expansion', '--concurrency', '--backend', '--route', '--mission', '--mission-id', '--agent', '--lane', '--stale-ms', '--grace-ms', '--profile', '--write-mode', '--max-write-agents', '--patch-entry-id', '--patch-entry', '--service-tier', '--intake', '--agent-root', '--artifact-dir', '--result-path', '--heartbeat-path', '--patch-envelope-path']));
43
+ const positionals = positionalArgs(rest, new Set(['--agents', '--target-active-slots', '--work-items', '--minimum-work-items', '--max-queue-expansion', '--concurrency', '--backend', '--route', '--mission', '--mission-id', '--agent', '--lane', '--stale-ms', '--grace-ms', '--profile', '--write-mode', '--max-write-agents', '--patch-entry-id', '--patch-entry', '--service-tier', '--zellij-session-name', '--intake', '--agent-root', '--artifact-dir', '--result-path', '--heartbeat-path', '--patch-envelope-path', '--ollama-model', '--local-model-model', '--ollama-base-url', '--local-model-base-url']));
37
44
  const missionDefault = action === 'run' || action === 'spawn' || action === 'plan' ? '' : 'latest';
38
45
  const positionalMission = action === 'run' || action === 'spawn' || action === 'plan' ? '' : (positionals[0] || '');
39
46
  const missionId = String(readOption(args, '--mission', readOption(args, '--mission-id', positionalMission || missionDefault)));
@@ -41,7 +48,7 @@ export function parseAgentCommandArgs(command, args = []) {
41
48
  const patchEntryId = String(readOption(args, '--patch-entry-id', readOption(args, '--patch-entry', '')));
42
49
  const promptPositionals = positionalMission ? positionals.slice(1) : positionals;
43
50
  const prompt = promptPositionals.join(' ').trim() || 'Native agent run';
44
- return { command, action, prompt, route, agents, targetActiveSlots, desiredWorkItemCount, minimumWorkItems, maxQueueExpansion, concurrency, backend, mock, real, readonly, profile, writeMode, applyPatches, dryRunPatches, maxWriteAgents, fastMode, serviceTier, noFast, apply, dryRun, drain, staleMs, graceMs, killEscalation, json, missionId, lane, codexApp, patchEntryId };
51
+ return { command, action, prompt, route, agents, targetActiveSlots, desiredWorkItemCount, minimumWorkItems, maxQueueExpansion, concurrency, backend, backendExplicit, mock, real, readonly, profile, writeMode, applyPatches, dryRunPatches, maxWriteAgents, fastMode, serviceTier, noFast, ollamaEnabled: useOllama && !noOllama, noOllama, ollamaModel, ollamaBaseUrl, zellijSessionName, zellijPaneWorker, apply, dryRun, drain, staleMs, graceMs, killEscalation, json, missionId, lane, codexApp, patchEntryId };
45
52
  }
46
53
  function hasFlag(args, flag) {
47
54
  return args.includes(flag);
@@ -53,6 +60,9 @@ function readOption(args, name, fallback) {
53
60
  const prefixed = args.find((arg) => String(arg).startsWith(name + '='));
54
61
  return prefixed ? prefixed.slice(name.length + 1) : fallback;
55
62
  }
63
+ function hasOption(args, name) {
64
+ return args.includes(name) || args.some((arg) => String(arg).startsWith(name + '='));
65
+ }
56
66
  function positionalArgs(args, valueFlags) {
57
67
  const out = [];
58
68
  for (let i = 0; i < args.length; i += 1) {
@@ -20,6 +20,8 @@ import { AgentPatchTransactionJournal } from './agent-patch-transaction-journal.
20
20
  import { normalizeAgentPatchEnvelope } from './agent-patch-schema.js';
21
21
  import { runFakeAgent } from './agent-runner-fake.js';
22
22
  import { runProcessAgent } from './agent-runner-process.js';
23
+ import { classifyOllamaWorkerSlice, runOllamaAgent } from './agent-runner-ollama.js';
24
+ import { resolveOllamaWorkerConfig } from './ollama-worker-config.js';
23
25
  import { validateAgentWorkerResult } from './agent-worker-pipeline.js';
24
26
  import { writeAgentCleanupReport } from './agent-cleanup.js';
25
27
  import { writeAgentTrustReport } from './agent-trust-report.js';
@@ -251,6 +253,8 @@ export async function runNativeAgentOrchestrator(opts = {}) {
251
253
  requestedAgents: Number(opts.agents || roster.agent_count || targetActiveSlots),
252
254
  targetActiveSlots,
253
255
  backend,
256
+ backendExplicit: opts.backendExplicit === true,
257
+ noOllama: opts.noOllama === true,
254
258
  route,
255
259
  fastModePolicy
256
260
  });
@@ -867,8 +871,11 @@ function buildProvidedAgentRoster(input, opts = {}) {
867
871
  };
868
872
  }
869
873
  async function runAgentByBackend(backend, agent, slice, opts) {
874
+ backend = await maybeSelectOllamaBackend(backend, agent, slice, opts);
870
875
  if (backend === 'process')
871
876
  return runProcessAgent(agent, slice, opts);
877
+ if (backend === 'ollama')
878
+ return runOllamaAgent(agent, slice, opts);
872
879
  if (backend === 'codex-sdk' || backend === 'zellij') {
873
880
  const ledgerRoot = path.resolve(opts.agentRoot || opts.cwd || process.cwd());
874
881
  const workerDir = path.join(ledgerRoot, 'codex-sdk-workers', String(agent.session_id || agent.id || 'agent'), String(slice?.id || 'slice'));
@@ -932,6 +939,21 @@ async function runAgentByBackend(backend, agent, slice, opts) {
932
939
  }
933
940
  return runFakeAgent(agent, slice, opts);
934
941
  }
942
+ async function maybeSelectOllamaBackend(backend, agent, slice, opts) {
943
+ if (backend !== 'codex-sdk')
944
+ return backend;
945
+ if (opts.backendExplicit === true || opts.backend_explicit === true || opts.noOllama === true || opts.no_ollama === true)
946
+ return backend;
947
+ const config = await resolveOllamaWorkerConfig({
948
+ ollamaEnabled: opts.ollamaEnabled === true || opts.ollama_enabled === true,
949
+ model: opts.ollamaModel || opts.ollama_model || null,
950
+ baseUrl: opts.ollamaBaseUrl || opts.ollama_base_url || null
951
+ }).catch(() => null);
952
+ if (!config?.ok || config.enabled !== true)
953
+ return backend;
954
+ const policy = classifyOllamaWorkerSlice(slice, { route: opts.route, agent });
955
+ return policy.ok ? 'ollama' : backend;
956
+ }
935
957
  function buildDirectSdkWorkerPrompt(slice) {
936
958
  const write = sdkWritePaths(slice, {});
937
959
  return [
@@ -33,7 +33,7 @@ export const AGENT_RESULT_RUNTIME_SCHEMA = {
33
33
  persona_id: { type: 'string' },
34
34
  task_slice_id: { type: 'string' },
35
35
  status: { enum: ['done', 'blocked', 'failed'] },
36
- backend: { enum: ['fake', 'process', 'codex-sdk', 'zellij'] },
36
+ backend: { enum: ['fake', 'process', 'codex-sdk', 'zellij', 'ollama'] },
37
37
  summary: { type: 'string' },
38
38
  findings: { type: 'array', items: { type: 'string' } },
39
39
  proposed_changes: { type: 'array', items: { type: 'string' } },
@@ -91,6 +91,7 @@ export const AGENT_RESULT_RUNTIME_SCHEMA = {
91
91
  worker_process_id: { type: 'number' },
92
92
  backend_child_process_id: { type: 'number' },
93
93
  backend_sdk_thread_id: { type: 'string' },
94
+ backend_ollama_request_id: { type: 'string' },
94
95
  fast_mode: { type: 'boolean' },
95
96
  service_tier: { enum: ['fast', 'standard'] },
96
97
  lease_id: { type: 'string' },
@@ -17,6 +17,7 @@ export function normalizeAgentPatchEnvelope(input) {
17
17
  ...(hasFiniteNumber(input?.worker_process_id) ? { worker_process_id: Number(input.worker_process_id) } : {}),
18
18
  ...(hasFiniteNumber(input?.backend_child_process_id) ? { backend_child_process_id: Number(input.backend_child_process_id) } : {}),
19
19
  ...(input?.backend_sdk_thread_id ? { backend_sdk_thread_id: String(input.backend_sdk_thread_id) } : {}),
20
+ ...(input?.backend_ollama_request_id ? { backend_ollama_request_id: String(input.backend_ollama_request_id) } : {}),
20
21
  ...(input?.fast_mode === undefined ? {} : { fast_mode: Boolean(input.fast_mode) }),
21
22
  ...(input?.service_tier === 'fast' || input?.service_tier === 'standard' ? { service_tier: input.service_tier } : {}),
22
23
  ...(input?.lease_id ? { lease_id: String(input.lease_id) } : {}),
@@ -50,7 +51,7 @@ export function validateAgentPatchEnvelope(envelope) {
50
51
  violations.push('operations_missing');
51
52
  if (envelope.source && !['fixture', 'model_authored', 'process_generated', 'zellij_generated'].includes(envelope.source))
52
53
  violations.push('source_invalid');
53
- if (envelope.source === 'model_authored' && !hasFiniteNumber(envelope.backend_child_process_id) && !envelope.backend_sdk_thread_id)
54
+ if (envelope.source === 'model_authored' && !hasFiniteNumber(envelope.backend_child_process_id) && !envelope.backend_sdk_thread_id && !envelope.backend_ollama_request_id)
54
55
  violations.push('model_authored_backend_proof_missing');
55
56
  if (envelope.source === 'fixture' && envelope.backend_child_process_id !== undefined)
56
57
  violations.push('fixture_backend_child_process_id_present');
@@ -29,7 +29,7 @@ export function systemSafeNarutoConcurrency(opts = {}) {
29
29
  const freeGb = freeBytes / (1024 * 1024 * 1024);
30
30
  const totalGb = totalBytes / (1024 * 1024 * 1024);
31
31
  const backend = String(opts.backend || 'codex-sdk');
32
- const heavy = backend === 'codex-sdk' || backend === 'zellij' || backend === 'process';
32
+ const heavy = backend === 'codex-sdk' || backend === 'zellij' || backend === 'process' || backend === 'ollama';
33
33
  const ceiling = MAX_NARUTO_AGENT_COUNT;
34
34
  // macOS reports very low freemem while reclaimable memory is still available, so
35
35
  // budget against a total-memory-derived floor rather than the instantaneous free.