model-orchestrator 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -1
- package/README.md +4 -4
- package/bin/cli-run.mjs +29 -5
- package/bin/cli.js +10 -4
- package/package.json +1 -1
- package/templates/agents/snippets/chat.md +8 -18
- package/templates/common/README.md +11 -3
- package/templates/intermediate/CLI-RUN.md +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,30 @@ All notable changes to this project are documented here. The format follows [Kee
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.1.7] - 2026-09-05
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Preserve unrelated subagents in uninstall guidance and explain manual activation cleanup.
|
|
12
|
+
- Provide a chat activation block below 1,500 characters and explain protocol uploads.
|
|
13
|
+
- Warn about zero-lane setups; doctor reports inactive with exit 13, including with --run.
|
|
14
|
+
- Add a first-task walkthrough and clarify agent-directed routing, connection checks and output contracts.
|
|
15
|
+
- Correct the contributor exit-code reference.
|
|
16
|
+
|
|
17
|
+
## [0.1.6] - 2026-09-05
|
|
18
|
+
|
|
19
|
+
Issues #16 to #19, filed against 0.1.5. Each reproduced before the fix; each fix has a test.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- `--dry-run` as an alias for `--dry`; the package script was already named `dry-run` (#16).
|
|
24
|
+
- `cli-run`: `killTree()` ends a lane's process tree with `taskkill /T /F` on Windows instead of killing only the root process. Windows is still not exercised by CI and stays documented as unsupported; the branch is unit-tested by argv capture (#18).
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- `cli-run --expect-json` accepts a response that is exactly one markdown code fence around JSON (`\`\`\`json ... \`\`\``, CRLF included). Prose before or after the fence still fails the contract, because then the deliverable is not the JSON (#17).
|
|
29
|
+
- `--yes` with several candidate agents and no `--primary` now prefers claude-code, then the first agent that can load subagent definitions, then the first listed. `--ais codex,agy` used to pick codex and write no subagents (#19).
|
|
30
|
+
|
|
7
31
|
## [0.1.5] - 2026-09-05
|
|
8
32
|
|
|
9
33
|
First release published by the workflow, with provenance.
|
|
@@ -97,7 +121,9 @@ First release.
|
|
|
97
121
|
- Tests: a case per fix, judges proven to go red, mutation checks; `npm test` prints the current count.
|
|
98
122
|
- Adversarial audit: two Codex rounds plus a two-engine review (Codex, Antigravity); findings and fixes in `docs/audit-brief.md`. After the review: subagents go to the project root (`--project`), snippet paths computed from `--dir`, lane sections rendered from the selection, a primary agent required, level 3 asks for API keys separately from CLIs, images and CLI installs pinned, an activation summary at the end of every install.
|
|
99
123
|
|
|
100
|
-
[Unreleased]: https://github.com/aunysillyme/model-orchestrator/compare/v0.1.
|
|
124
|
+
[Unreleased]: https://github.com/aunysillyme/model-orchestrator/compare/v0.1.7...HEAD
|
|
125
|
+
[0.1.7]: https://github.com/aunysillyme/model-orchestrator/compare/v0.1.6...v0.1.7
|
|
126
|
+
[0.1.6]: https://github.com/aunysillyme/model-orchestrator/compare/v0.1.5...v0.1.6
|
|
101
127
|
[0.1.5]: https://github.com/aunysillyme/model-orchestrator/compare/v0.1.4...v0.1.5
|
|
102
128
|
[0.1.4]: https://github.com/aunysillyme/model-orchestrator/compare/v0.1.3...v0.1.4
|
|
103
129
|
[0.1.3]: https://github.com/aunysillyme/model-orchestrator/compare/v0.1.2...v0.1.3
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/model-orchestrator) [](https://github.com/aunysillyme/model-orchestrator/actions/workflows/test.yml) [](LICENSE) [](package.json)
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**Routing instructions and a CLI runner for your AI tools.** One installer asks what you have access to and generates a matching setup, from one chat app to several agent CLIs or a virtual machine. Your primary agent follows the instructions to choose a tier or lane; the runner executes the lane it is given. It does not automatically compare prices or select models.
|
|
6
6
|
|
|
7
7
|
Built from a working system, not a diagram: the routing rules, the protocols and the lane runner here run in production, generalized so they transfer to any stack.
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@ Built from a working system, not a diagram: the routing rules, the protocols and
|
|
|
10
10
|
npx model-orchestrator
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
That runs the latest published release from the npm registry. To run a specific release or the current main straight from GitHub: `npx github:aunysillyme/model-orchestrator#v0.1.
|
|
13
|
+
That runs the latest published release from the npm registry. To run a specific release or the current main straight from GitHub: `npx github:aunysillyme/model-orchestrator#v0.1.7` (drop `#v0.1.7` for main).
|
|
14
14
|
|
|
15
15
|
The installer asks a few things, then writes a folder:
|
|
16
16
|
|
|
@@ -18,7 +18,7 @@ The installer asks a few things, then writes a folder:
|
|
|
18
18
|
2. **Which AIs do you have access to?** (it marks the ones already on your PATH)
|
|
19
19
|
3. **Which one is your primary agent?** (the one that runs the system)
|
|
20
20
|
|
|
21
|
-
It never writes a secret, never runs a vendor shell script for you, and never overwrites a document you already have unless you pass `--force`. Two exceptions, both stated when they happen: `MANIFEST.json` and `bin/lanes.json` are machine-owned and rewritten on every run so a changed selection applies; runtime files (`cli-run`, the audit job, compose, gateway config, setup script) are upgraded when the installed copy matches the hash a previous run recorded, kept and reported as a conflict when you edited them, and kept as unverifiable when no manifest exists (`--upgrade-runtime` replaces runtime files only). The same hash rule is available for documents on request: `--update-docs` regenerates the documents a previous run wrote and nobody edited, so a changed selection reaches `ROUTING.md` and the delegation matrix without `--force`; edited documents are kept and named. Docs and protocols go to `--dir` (default `./ai-orchestrator`); subagent definitions go to the project root your agent runs from (`--project`, default the current directory), because that is the only place Claude Code and Antigravity read them. It ends with an activation summary: what to copy where, which sign-ins, and one smoke command. Uninstall:
|
|
21
|
+
It never writes a secret, never runs a vendor shell script for you, and never overwrites a document you already have unless you pass `--force`. Two exceptions, both stated when they happen: `MANIFEST.json` and `bin/lanes.json` are machine-owned and rewritten on every run so a changed selection applies; runtime files (`cli-run`, the audit job, compose, gateway config, setup script) are upgraded when the installed copy matches the hash a previous run recorded, kept and reported as a conflict when you edited them, and kept as unverifiable when no manifest exists (`--upgrade-runtime` replaces runtime files only). The same hash rule is available for documents on request: `--update-docs` regenerates the documents a previous run wrote and nobody edited, so a changed selection reaches `ROUTING.md` and the delegation matrix without `--force`; edited documents are kept and named. Docs and protocols go to `--dir` (default `./ai-orchestrator`); subagent definitions go to the project root your agent runs from (`--project`, default the current directory), because that is the only place Claude Code and Antigravity read them. It ends with an activation summary: what to copy where, which sign-ins, and one smoke command. Uninstall: follow the generated README. Inspect the manifest and remove only the individual managed subagent files you no longer need, preserve edited or pre-existing files, and remove your manually pasted activation block. Never delete a shared subagent folder.
|
|
22
22
|
|
|
23
23
|
## The three levels
|
|
24
24
|
|
|
@@ -120,7 +120,7 @@ If you need a property in the third row to be enforced, that is a router, a poli
|
|
|
120
120
|
|
|
121
121
|
## Requirements
|
|
122
122
|
|
|
123
|
-
Node 18 or newer. No dependencies. Works on macOS and Linux; the level 3 box templates assume Ubuntu.
|
|
123
|
+
Node 18 or newer. No dependencies. Works on macOS and Linux; the level 3 box templates assume Ubuntu. Windows is untested: `cli-run` ends a lane's process tree there with `taskkill`, but nothing in CI runs on Windows, so treat it as unsupported until someone reports otherwise.
|
|
124
124
|
|
|
125
125
|
**Privacy.** The installer makes no network call of its own and sends no telemetry; the only network activity is the `npm install -g` you approve per package. `cli-run` talks to nothing but the vendor CLI you name.
|
|
126
126
|
|
package/bin/cli-run.mjs
CHANGED
|
@@ -244,6 +244,27 @@ export function judge(lane, rc, out, err, outFile) {
|
|
|
244
244
|
// an agent CLI that shelled out to a tool must not keep working after the
|
|
245
245
|
// wrapper has reported 12. A child that calls setsid() itself escapes this
|
|
246
246
|
// boundary; that is documented, not hidden.
|
|
247
|
+
// Models often wrap JSON in one markdown fence. --expect-json accepts exactly that shape:
|
|
248
|
+
// the whole trimmed response is one fenced block, optionally tagged json. Prose before or
|
|
249
|
+
// after the fence still fails, because then the deliverable is not the JSON (#17).
|
|
250
|
+
export function unfence(text) {
|
|
251
|
+
const t = String(text).trim();
|
|
252
|
+
const m = /^```(?:json|JSON)?[ \t]*\r?\n([\s\S]*?)\r?\n?```$/.exec(t);
|
|
253
|
+
return m ? m[1].trim() : t;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Kill a lane and everything it spawned. POSIX: the detached process group.
|
|
257
|
+
// Windows has no process groups a signal can reach, so taskkill walks the tree (#18).
|
|
258
|
+
// Windows is not exercised by CI; this branch is unit-tested by argv capture only.
|
|
259
|
+
export function killTree(pid, platform = process.platform, deps = { kill: (p, sig) => process.kill(p, sig), spawn }) {
|
|
260
|
+
if (platform === 'win32') {
|
|
261
|
+
deps.spawn('taskkill', ['/pid', String(pid), '/T', '/F'], { stdio: 'ignore', windowsHide: true });
|
|
262
|
+
return 'taskkill';
|
|
263
|
+
}
|
|
264
|
+
deps.kill(-pid, 'SIGKILL');
|
|
265
|
+
return 'group';
|
|
266
|
+
}
|
|
267
|
+
|
|
247
268
|
export function runBounded(argv, timeoutSec, maxBuffer = 16 * 1024 * 1024) {
|
|
248
269
|
return new Promise((resolveRun) => {
|
|
249
270
|
const t0 = Date.now();
|
|
@@ -257,8 +278,7 @@ export function runBounded(argv, timeoutSec, maxBuffer = 16 * 1024 * 1024) {
|
|
|
257
278
|
const killGroup = () => {
|
|
258
279
|
if (!child) return;
|
|
259
280
|
try {
|
|
260
|
-
|
|
261
|
-
else child.kill('SIGKILL');
|
|
281
|
+
killTree(child.pid);
|
|
262
282
|
} catch {
|
|
263
283
|
try {
|
|
264
284
|
child.kill('SIGKILL');
|
|
@@ -404,7 +424,11 @@ export async function doctor(run) {
|
|
|
404
424
|
let bad = 0;
|
|
405
425
|
console.log(`doctor: ${enabled.length} enabled lane(s): ${enabled.join(', ') || 'none'}`);
|
|
406
426
|
const primary = installedPrimary();
|
|
407
|
-
if (primary && !enabled.includes(primary)) console.log(` note: ${primary} is the primary agent
|
|
427
|
+
if (primary && !enabled.includes(primary)) console.log(` note: ${primary} is the primary agent and is not an executable lane`);
|
|
428
|
+
if (!enabled.length) {
|
|
429
|
+
console.error('doctor: inactive: no executable lanes enabled. Use level 1 for a single-agent setup, or re-run the installer with a supported CLI selected.');
|
|
430
|
+
return UNAVAILABLE;
|
|
431
|
+
}
|
|
408
432
|
for (const lane of LANES) {
|
|
409
433
|
const on = enabled.includes(lane);
|
|
410
434
|
const bin = which(lane);
|
|
@@ -452,9 +476,9 @@ export function checkContracts(opts, text, before) {
|
|
|
452
476
|
}
|
|
453
477
|
if (opts.expectJson) {
|
|
454
478
|
try {
|
|
455
|
-
JSON.parse(text);
|
|
479
|
+
JSON.parse(unfence(text));
|
|
456
480
|
} catch {
|
|
457
|
-
return '--expect-json: the response is not valid JSON';
|
|
481
|
+
return '--expect-json: the response is not valid JSON (a single ```json fence around the whole response is accepted; prose around it is not)';
|
|
458
482
|
}
|
|
459
483
|
}
|
|
460
484
|
return null;
|
package/bin/cli.js
CHANGED
|
@@ -17,7 +17,7 @@ import { planFiles, writeFiles, resolveSelection, resolveTools, resolveApis, dir
|
|
|
17
17
|
// turn a dry run into a real one.
|
|
18
18
|
const SPEC = {
|
|
19
19
|
level: 'value', ais: 'value', primary: 'value', dir: 'value', project: 'value', tools: 'value', apis: 'value',
|
|
20
|
-
yes: 'bool', force: 'bool', dry: 'bool', 'no-install': 'bool', 'no-tools': 'bool', 'no-apis': 'bool', 'upgrade-runtime': 'bool', 'update-docs': 'bool', list: 'bool', help: 'bool', h: 'bool'
|
|
20
|
+
yes: 'bool', force: 'bool', dry: 'bool', 'dry-run': 'bool', 'no-install': 'bool', 'no-tools': 'bool', 'no-apis': 'bool', 'upgrade-runtime': 'bool', 'update-docs': 'bool', list: 'bool', help: 'bool', h: 'bool'
|
|
21
21
|
};
|
|
22
22
|
export function parseArgs(argv) {
|
|
23
23
|
const out = {};
|
|
@@ -93,7 +93,7 @@ Flags
|
|
|
93
93
|
--update-docs regenerate the documents a previous run wrote and nobody edited since (hash-checked against
|
|
94
94
|
MANIFEST.json), so a changed selection reaches ROUTING.md and friends; edited documents are kept
|
|
95
95
|
and reported, and nothing happens without a manifest
|
|
96
|
-
--dry
|
|
96
|
+
--dry, --dry-run print the plan, write nothing
|
|
97
97
|
--no-install never offer to run npm installs
|
|
98
98
|
--list print the catalog
|
|
99
99
|
`);
|
|
@@ -178,7 +178,10 @@ async function main() {
|
|
|
178
178
|
} else if (candidates.length === 0) {
|
|
179
179
|
bad('pick at least one agent or chat app to be the orchestrator; a local model runtime on its own cannot run the system');
|
|
180
180
|
} else if (candidates.length > 1) {
|
|
181
|
-
|
|
181
|
+
// --yes picks for the user: claude-code if present, else the first agent that can load subagent
|
|
182
|
+
// definitions (it gets five files written for it), else the first candidate. #19: codex listed
|
|
183
|
+
// before agy used to win and nothing was written to the project root.
|
|
184
|
+
if (yes) primary = candidates.find((a) => a.id === 'claude-code') || candidates.find((a) => a.agentsDir) || candidates[0];
|
|
182
185
|
else {
|
|
183
186
|
console.log('\nWhich one is your primary agent (the one that runs the system)?');
|
|
184
187
|
candidates.forEach((a, i) => console.log(` ${i + 1} ${a.name}`));
|
|
@@ -250,7 +253,10 @@ async function main() {
|
|
|
250
253
|
const lvl = LEVELS.find((l) => l.id === level);
|
|
251
254
|
const agentFiles = files.filter((f) => f.root === 'project');
|
|
252
255
|
console.log(`\nPlan\n level ${lvl.id} ${lvl.name}\n access ${selected.map((a) => a.id).join(', ')}\n primary ${primary ? primary.id : 'none'}\n tools ${tools.map((t) => t.id).join(', ') || 'none'}` + (level >= 3 ? `\n api keys ${apis.map((p) => p.id).join(', ') || 'none'}` : '') + `\n folder ${dir}\n project ${project}${agentFiles.length ? ' (' + agentFiles.length + ' subagent files go here)' : ''}\n files ${files.length}`);
|
|
253
|
-
if (
|
|
256
|
+
if (level >= 2 && !selected.some((a) => a.cliRun)) {
|
|
257
|
+
console.log('\nWarning: no executable lanes selected; delegation is inactive. Use level 1 for a single-agent setup, or add a supported CLI. Doctor will exit 13 until a lane is enabled.');
|
|
258
|
+
}
|
|
259
|
+
if (flag('dry') || flag('dry-run')) {
|
|
254
260
|
for (const f of files) console.log(' - ' + (f.root === 'project' ? '[project] ' : '') + f.rel);
|
|
255
261
|
console.log('\n--dry: nothing written.');
|
|
256
262
|
rl && rl.close();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "model-orchestrator",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "A model orchestrator you can npm run: route every task to the cheapest AI that does it well, across one agent, many CLIs, or a whole virtual machine. Three levels, one installer that asks what you have access to.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -3,23 +3,13 @@
|
|
|
3
3
|
{{PRIMARY_NAME}} has no project instructions file, so the rules travel by paste. Put the block below into the custom instructions, a Project, a Gem, or the first message of a working session.
|
|
4
4
|
|
|
5
5
|
```
|
|
6
|
-
You
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
EVERY HAND-OFF to a fresh context carries a brief: purpose, task class (read_only / draft_only / mutating), granted scope, capabilities, denied actions, conventions it does not have, report contract (what was NOT done, what is unverified), exit parameters. Absence is denial.
|
|
15
|
-
|
|
16
|
-
AFTER ANY COMPREHENSIVE TASK: a second pass in a fresh turn that hunts for what is MISSING, not what is present.
|
|
17
|
-
|
|
18
|
-
NUMBERS AND LOGIC: any figure someone will act on, any comparison you state, any complexity or equivalence claim is computed with a tool (a code interpreter, a calculator), never estimated. Give the exact form and the decimal and name the tool. Trivial single-digit sums are exempt; nothing else is.
|
|
19
|
-
|
|
20
|
-
MEMORY AND RECORD: before writing anything durable, search for it; after writing, correct the index that lists it; one writer per session; mark inferred content as inferred.
|
|
21
|
-
|
|
22
|
-
A gate you cannot fail is not a gate. Exit 0 is not a deliverable.
|
|
6
|
+
You follow a model-orchestrator workflow inside this chat. Tiers describe effort, not automatic model switching or cost savings.
|
|
7
|
+
Route first: bulk/formatting -> fast; live data -> standard with tools; review -> standard, read-only; ambiguous/high-risk -> deep; otherwise standard. State the tier. Escalate on failure instead of silently retrying.
|
|
8
|
+
For builds: map affected parts; identify the biggest risk and any flaw in the request (none is valid with reasons); build and verify; use a fresh turn to challenge the result. Before irreversible actions, explain rollback and ask for approval.
|
|
9
|
+
For hand-offs: include purpose, scope, allowed and denied actions, required output, and stopping conditions. A fresh context has none of these instructions.
|
|
10
|
+
After comprehensive work, check for omissions. Compute consequential numbers and comparisons with a tool; report what was checked and what remains unverified.
|
|
11
|
+
Before durable writes, search existing records, update their index, use one writer, and label inferences.
|
|
12
|
+
Check the actual deliverable; exit 0 alone is not evidence of completion. Do not claim to have read local files that were not uploaded or pasted.
|
|
23
13
|
```
|
|
24
14
|
|
|
25
|
-
|
|
15
|
+
This compact block fits within 1,500 characters. For the full workflow, upload or paste the following files into your Project or working session; a local path alone does not give a chat access to them: `ORCHESTRATOR.md`, `TASK_BUNDLE.md`, `protocols/`.
|
|
@@ -11,7 +11,15 @@ Companion tools:
|
|
|
11
11
|
|
|
12
12
|
## The idea in one line
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
This folder gives your agent routing instructions and, at level 2+, a runner for explicitly selected CLI lanes. The agent chooses the tier or lane; the runner does not automatically compare prices or choose a model.
|
|
15
|
+
|
|
16
|
+
## Your first task
|
|
17
|
+
|
|
18
|
+
1. Activate the snippet using the instructions below. For a chat app, paste the block in `PASTE-INTO-YOUR-AGENT.md`; upload any full protocols you want it to read because local paths alone do not share files.
|
|
19
|
+
2. Start a fresh agent session and ask: "Read the orchestrator instructions. Quote the routing rule you will use, then sort pear, apple, banana alphabetically. Name the tier and whether you delegated."
|
|
20
|
+
3. Expect the fast tier and `apple, banana, pear`. If the agent cannot quote the routing rule, check the snippet location or chat instructions before continuing. This is a manual activation check, not proof that every future task follows the rules.
|
|
21
|
+
4. At level 2+, run `node bin/cli-run.mjs --doctor` from this folder. It checks binary presence, not authentication or loaded instructions. `--doctor --run` additionally uses a little quota to test live responses. No enabled lanes means delegation is inactive.
|
|
22
|
+
5. To test a real output contract, choose an enabled lane from `bin/lanes.json` and run `node bin/cli-run.mjs <lane> 'Return only {"sorted":["apple","banana","pear"]}' --expect-json`. This uses quota. Expect JSON and exit 0; inspect the array yourself. A non-JSON response exits 10, a missing binary exits 13, and an authentication failure reports the vendor error. The explicit lane tests execution; your primary agent still makes delegation decisions.
|
|
15
23
|
|
|
16
24
|
## What is in this folder
|
|
17
25
|
|
|
@@ -32,7 +40,7 @@ Level 2 adds `ROUTING.md`, `TIERS.md`, `DELEGATION_MATRIX.md`, `RESEARCH_TRIAGE.
|
|
|
32
40
|
|
|
33
41
|
## Load it into your agent
|
|
34
42
|
|
|
35
|
-
|
|
43
|
+
For a CLI primary, the project rules file is `{{PRIMARY_RULES_FILE}}`. Chat apps use pasted instructions instead. The installer wrote a snippet file next to this README (`*.snippet.md`, or `PASTE-INTO-YOUR-AGENT.md` for a chat app). Copy its contents into that file, or paste it into the agent's custom instructions. Nothing was appended to a file you already had.
|
|
36
44
|
|
|
37
45
|
## The three rules that carry everything
|
|
38
46
|
|
|
@@ -49,4 +57,4 @@ Your primary agent reads `{{PRIMARY_RULES_FILE}}` from a project root. The insta
|
|
|
49
57
|
|
|
50
58
|
## Uninstall
|
|
51
59
|
|
|
52
|
-
|
|
60
|
+
Before deleting anything, inspect `MANIFEST.json`: entries beginning with `[project] ` identify the subagent files managed by this installation. Review those individual files and remove only the ones you no longer want, preserving edited or pre-existing files. Never delete the shared `.claude/agents` or `.agents/agents` folder; it may contain unrelated agents. If the manifest is missing, inspect files individually rather than deleting a folder. Remove the orchestrator block you manually copied into your project rules file or chat instructions. Then delete this generated docs folder only after preserving any work you added to it. The optional log at `~/.ai-orchestrator/cli-run.log.jsonl` is shared across installations; remove it only if you no longer need that history.
|
|
@@ -30,6 +30,8 @@ node bin/cli-run.mjs --doctor # which lanes are enabled and which binar
|
|
|
30
30
|
node bin/cli-run.mjs --doctor --run # also sends each enabled lane one tiny prompt and judges the reply (uses a little quota)
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
With zero enabled lanes, doctor reports inactive and exits 13. Use level 1 or select a supported CLI. Binary presence does not verify authentication or that your primary loaded its instructions.
|
|
34
|
+
|
|
33
35
|
A lane that is enabled but not on PATH, or that answers with no deliverable, shows up here before it shows up mid-task.
|
|
34
36
|
|
|
35
37
|
## Why it exists
|