snappy-jcode skill
$ npx snappy-skills install snappy-jcode
$ npx snappy-skills install --all
$ npx snappy-skills update
Dispatch GPT 5.6 Luna/Sol lane workers via the local jcode CLI
(v0.76.0+, validated 2026-08-14). Work happens THERE (agent in a git
worktree, commits + pushes its branch); integration happens HERE (the
orchestrator merges/installs/verifies). Files travel only via git.
Proven invocation:
bash_ZO_DOCTOR=0 jcode run --quiet --no-update --json \
-p openai -m gpt-5.6-luna \
--tools bash,read,write,apply_patch \
-C <worktree> "<brief>"
→ JSON {model, provider, session_id, text, usage}. Resume a lane with
--resume <session_id>. --tool-profile none for text-only probes. The
--tools allow-list is the permission. Effort: HIS level, read from the
Providers tab through snappy-settings/providers-choice.ts and passed as
JCODE_OPENAI_REASONING_EFFORT / JCODE_ANTHROPIC_REASONING_EFFORT in the
child's env (measured v0.78.1: no CLI flag exists; openrouter and gemini have
no knob and refuse effort_not_applicable). NEVER edit ~/.jcode/config.toml.
Provider defaults to his saved default. Auth check:
jcode auth status (openai = ChatGPT Pro OAuth). Log each dispatch to
~/.claude/logs/agent-runs.ndjson. Lanes never install, never touch the
runtime state root, never git stash. Typed interface: api.ts
(jcodeRun, jcodeResume).
<!-- SKILL-INDEX-START -->
[snappy-jcode Index]|root: ~/.claude/skills/snappy-jcode|IMPORTANT: Prefer these files over pre-training assumptions for this domain. Read the relevant file when the AGENTS.md summary is insufficient.|root:{SKILL.md}|references:{fleet-control-playbook.md}
<!-- SKILL-INDEX-END -->
Nothing in the collection names this skill.
<!-- SNAPPY-CONTRACT-VERBS-START -->
Generated from api.ts HAND_CONTRACT. Do not hand-edit this block.
This skill declares no executable verbs. Its instruction-only label is intentional.
When an answer carries face_hint, show it with one snappy_present(<answer>) call.
See /snappy-faces for face selection. Human-facing images must crop to the
element, render at 2x on Retina, and fill the destination channel instead of
placing a small card in a full-page screenshot.
<!-- SNAPPY-CONTRACT-VERBS-END -->
# snappy-jcode (agent loader)
Dispatch GPT 5.6 Luna/Sol lane workers via the local `jcode` CLI
(v0.76.0+, validated 2026-08-14). Work happens THERE (agent in a git
worktree, commits + pushes its branch); integration happens HERE (the
orchestrator merges/installs/verifies). Files travel only via git.
Proven invocation:
```bash
_ZO_DOCTOR=0 jcode run --quiet --no-update --json \
-p openai -m gpt-5.6-luna \
--tools bash,read,write,apply_patch \
-C <worktree> "<brief>"
```
→ JSON `{model, provider, session_id, text, usage}`. Resume a lane with
`--resume <session_id>`. `--tool-profile none` for text-only probes. The
`--tools` allow-list is the permission. Effort: HIS level, read from the
Providers tab through `snappy-settings/providers-choice.ts` and passed as
`JCODE_OPENAI_REASONING_EFFORT` / `JCODE_ANTHROPIC_REASONING_EFFORT` in the
child's env (measured v0.78.1: no CLI flag exists; openrouter and gemini have
no knob and refuse `effort_not_applicable`). NEVER edit `~/.jcode/config.toml`.
Provider defaults to his saved default. Auth check:
`jcode auth status` (openai = ChatGPT Pro OAuth). Log each dispatch to
`~/.claude/logs/agent-runs.ndjson`. Lanes never install, never touch the
runtime state root, never `git stash`. Typed interface: `api.ts`
(`jcodeRun`, `jcodeResume`).
<!-- SKILL-INDEX-START -->
[snappy-jcode Index]|root: ~/.claude/skills/snappy-jcode|IMPORTANT: Prefer these files over pre-training assumptions for this domain. Read the relevant file when the AGENTS.md summary is insufficient.|root:{SKILL.md}|references:{fleet-control-playbook.md}
<!-- SKILL-INDEX-END -->
## Used by
Nothing in the collection names this skill.
<!-- SNAPPY-CONTRACT-VERBS-START -->
## Contract verbs
Generated from `api.ts` `HAND_CONTRACT`. Do not hand-edit this block.
This skill declares no executable verbs. Its `instruction-only` label is intentional.
## Show the result
When an answer carries `face_hint`, show it with one `snappy_present(<answer>)` call.
See `/snappy-faces` for face selection. Human-facing images must crop to the
element, render at 2x on Retina, and fill the destination channel instead of
placing a small card in a full-page screenshot.
<!-- SNAPPY-CONTRACT-VERBS-END -->
Validated 2026-08-14 on jcode v0.76.0 with two live smokes (text round-trip
+ agentic file write, both green on the first try). This skill is the
hardened road for the orchestrator (Fable, HERE) to dispatch **GPT 5.6
Luna/Sol agents (THERE)** as sandboxed lane workers, with integration kept
centralized.
worktree (the sandbox). It edits files, runs scoped tests, commits, and
pushes on ITS branch.
--only` / merge with scoped verify), installs, walks the glass, keeps
the board. Decisions never leave this seat.
the only transport. Unpushed work does not exist.
writable file with another lane. Same laws as every fleet.
bash_ZO_DOCTOR=0 jcode run --quiet --no-update --json \
-p openai -m gpt-5.6-luna \
--tools bash,read,write,apply_patch \
-C <worktree-abs-path> \
"<the lane brief>"
model, provider, session_id, text, usage(input_tokens/output_tokens/cache fields).
--tools allow-list IS the permission system in run mode — nointeractive approval; grant only what the lane needs. `--tool-profile
none` = pure text (cheap probes/judging).
jcode run --resume <session_id> "<follow-up>"reopens the same agent with its context — nudge, don't respawn.
--ndjson streams events; --trace logs tool I/O to stderr — use fordebugging a misbehaving lane.
gpt-5.6-luna, gpt-5.6-sol (plus -pro,-terra, -sol-wm variants). Provider openai rides Robert's ChatGPT
Pro OAuth (auto-refresh, jcode auth status to check). claude and
openrouter providers are also authed — the same road can run other
brains.
He sets it on the bar's Providers tab — a level per provider, saved to
~/.snappy-skills/providers.json. jcodeRun reads it through
snappy-settings/providers-choice.ts (the kernel's one reader of that
document) and passes it to jcode. Nothing to do by hand.
MEASURED on jcode v0.78.1, 2026-09-09:
jcode run --help lists --json,-p, -C, --ndjson, --remote-working-dir, --no-update,
--auto-update, --trace, --quiet, --resume, --no-selfdev,
--socket, --debug-socket, -m, --provider-profile, --tool-profile,
--tools, --disabled-tools, --disable-base-tools — and nothing else.
Grepping the whole help (run and top level) for effort/reason/think returns
nothing.
JCODE_OPENAI_REASONING_EFFORT and JCODE_ANTHROPIC_REASONING_EFFORT,
both in the v0.78.1 binary's env table beside the [provider] keys
openai_reasoning_effort / anthropic_reasoning_effort. jcodeRun puts
the chosen word in the CHILD's environment for that one run.
them is refused by name — effort_not_applicable, the typed refusal from
snappy-settings/refusal-codes.ts — and the run does not happen. A level he
can see on his panel that the run silently ignored is the same lie as a
status truer than its artifact.
Never edit ~/.jcode/config.toml. (This SKILL.md used to say: set
openai_reasoning_effort = "xhigh", run the window, restore it after. That
advice is retired — it mutates the effort of every jcode window he has open,
and a lane that dies between the set and the restore leaves his global
changed.) The per-run env override does the same job and touches nothing of
his.
typescript// his level, automatically:
await jcodeRun(brief, { cwd });
// this one run only, overriding his level:
await jcodeRun(brief, { cwd, effort: "xhigh" });
git worktree add + npm run worktree:bootstrap(repo-specific; links node_modules/venv/.env.cache in snappy-os-app).
inventory-first, laws, "commit early, push every commit, NEVER
git stash").
session_id.git fetch +branch freshness. Nudge stalled lanes via --resume.
session_id → branch.
~/.claude/logs/agent-runs.ndjson (shared schema with snappy-shell /
snappy-dispatch) for cost + latency audit.
Smoke runs: ~10.8k input tokens for a bare one-shot (jcode's system
harness is the floor), 10-27 output. Subscription-backed (ChatGPT Pro),
not per-token billed — the constraint is the account's usage limits
(jcode usage), not dollars.
The M1 crashed the Claude Code harness repeatedly under 12+ concurrent
xhigh Lunas (resource exhaustion). The always-on Mac mini (Host mini =
100.93.55.2 in ~/.ssh/config, Apple M4 / 16GB) is the proper heavy-fleet
sandbox:
/opt/homebrew/bin/jcode (non-login ssh PATH misses it —always use the absolute path). openai OAuth is authenticated ON the mini
(its own ~/.jcode/openai-auth.json); smoke proof MINI-M4-ROAD-OK in
7.5s round-trip; harness floor there ~4k tokens vs 10.8k local.
design (never provision keys there): `git remote add mini
robertboulos@100.93.55.2:Projects/snappy-os-app, git push mini
<branches>, lanes COMMIT but never push, collect with git fetch mini`.
~/lanes/<name> on the mini; dep drift from the stale cloneis real — npm install fresh in ONE worktree, ln -sfn its
node_modules into the others. Briefs get a MINI ADAPTATIONS footer: no
push, no live daemon (the daemon binds 127.0.0.1 on the M1 — live-daemon
lanes MUST run locally), merge the local integration/... ref first.
/opt/homebrew/bin/jcode run … > ~/lanes/X-result.json 2> …stderr.log &'`
— survives M1 crashes entirely. Effort: pass effort to jcodeRun, or set
it once on the Providers tab; nothing edits the mini's
~/.jcode/config.toml; restore after.
vm_stat freepages + uptime load before sizing; ~8-9 Lunas is the 16GB ceiling
(12 pinched it to 57MB free). Keep a ~/lanes/QUEUED.txt and refill
slots as lanes finish. Local cap ~3 (live-daemon lanes only).
other dirs (codex threads, agent-mail, Desktop, Application Support);
pre-existing checkout WIP gets parked on a branch first; worktrees
removed + branches pruned after collection.
~/lanes/fleetctl.sh)#One ssh call per operation; this is HOW control is exercised there:
fleetctl.sh status — procs, load, free disk, free mem, and per-lane:LIVE/done · result bytes · dirty count · last commit. The whole fleet's
truth in one round-trip; run it before every decision.
fleetctl.sh launch <lane> — GUARDED launch: refuses under 3GB freedisk or at the 8-proc cap; appends an audit line to
~/lanes/dispatches.ndjson (collect periodically into the local
agent-runs log).
fleetctl.sh pause <lane> / fleetctl.sh sweep (removes worktrees whosebranches are ancestors of integration — merged means swept).
references/fleet-control-playbook.md; READ IT before running a fleet)#LAW ZERO — THE ORCHESTRATOR'S MACHINE RUNS NOTHING HEAVY. EVER.
2026-08-15, third crash of the night, self-inflicted: the full 8,479-test
web suite was launched ON the M1 while orchestrating — the exact
resource-exhaustion class already named twice that session. The M1 is the
merge/install/decide seat plus at most 2-3 LIGHT live-daemon lanes. Full
test suites, storybook builds, broad batteries: ALWAYS on the mini — and
the mini earns trustworthy full-suite COUNTS by provisioning ONE
full-environment worktree (complete npm install incl. vitest, python venv,
rebuilt native bindings) kept for exactly this. If a number can only be
measured with a heavy run, the heavy run happens THERE, detached.
Verified control, not assumed control. The five laws that replace guessing:
heartbeats a file/row every 30s; the controller reads heartbeat AGE.
pgrep-by-name is ABOLISHED (titles rewrite; ssh quoting mangles
patterns). Interim: per-lane liveness by lsof +D <worktree>.
ps -o lstart= fingerprint, recorded at spawn.zsystem flock) held for the lane'slife; double-launch structurally impossible.
KeepAlive reaper expires 90s-stale leases with evidence and kills
PROCESS GROUPS. Ship SCRIPTS over ssh, never quoted command strings.
[ "$a" -ef "$b" ] (APFS iscase-insensitive — ~/projects ate ~/Projects once), never rm -rf a
worktree, and a VERIFIED git bundle precedes anything destructive —
the rule that already saved 915 refs.
a full disk kills lanes SILENTLY (0-byte results, empty stderr). The
fleetctl launch guard exists because of this night.
cycles and CSS elision; esbuild refuses them. Lanes touching import
graphs run bash apps/snappy-os/scripts/build-web.sh — exit 0 IS the
finish line for web work. (Cycle class: ambiguous .ts/.tsx basename
self-resolution — extract the pure leaf.)
finds deps missing runs its own npm install (1.4GB × N). Verify the
links, don't assume them.
bindings and absent tsc on stale clones produce test failures the
code doesn't have. Lanes report them; the orchestrator re-verifies
locally before judging.
by design, so a lane whose only miss is "could not push" is DONE —
read the report body, not just the verdict. Batteries likewise report
FALSE while any single check fails; that is the honesty working.
sizes (mini over ssh + local scratchpad) that EXITS when work lands —
the exit notification is the orchestrator's wake-up. Detached lanes
never notify by themselves.
Scoped tests + typecheck + web build gate each merge (fast). The FULL
web suite runs ON THE MINI, detached, at every install window — a
trailing signal (~15-30 min), never a blocking gate. Drift is caught
one window late instead of forty merges late. The ratchet only
ratchets when the full battery watches continuously: scoped-only
gating accumulated 49→291 invisibly in one night.
deliberately rewrite surfaces, every story pinning the old truth WILL
fail — that is the workshop working. Plan the repair wave as part of
the feature wave, not as a surprise.
area → one fix lane per cluster with its EXACT file list inline + the
law: update tests to the new intended truth WITH per-change
justification; fix real defects at owners; NEVER weaken an assertion.
Each lane reruns exactly its cluster and pastes counts.
LANDED → WORKSHOP (story exercises real states incl. the defect state)
→ GLASS (dogfooded on the installed app, evidence captured) →
ITERATED → ACCEPTED, in a ledger (docs/GAUNTLET-*.md). A dedicated
glass-prosecutor lane drives the live daemon (tunnel) assuming
everything is broken; sb-audit fills the workshop column. Founder's
eyes outrank every column.
conflict aborts and goes back to the lane worktree with a reconcile
brief ("both sides fully survive"); the orchestrator hand-resolves
only trivial import unions.
an undesigned button strip reach the founder's glass. Per-class
structural gates (e.g. nothing renders above a page's h1) are the
mechanism; a mounted element with no designed story is a defect.
ssh -f -N -R 3147:127.0.0.1:3147 mini) lets minilanes drive the live daemon at their own localhost — batteries and
prosecutors run THERE too. Mint keys via a 600-perm file, never argv.
snappy-dispatch (pi): sub-penny mechanical grunt work, 2-4s.snappy-shell (pi REPL): full interactive fallback session.snappy-jcode: real BUILD lanes on a second brain (GPT 5.6),sandboxed in worktrees, integration kept here. The peer-fleet road.
fleetctl launch <lane> <brief-file> now COPIES the brief into the
worktree as LANE-BRIEF.md and REFUSES to launch when the worktree has no
LANE-BRIEF.md (the agent's fixed prompt reads that file; an argv brief
path was silently ignored for hours and two lanes executed a stale
wave-30 brief they found by hunting). Corollary: before merging ANY lane,
verify its result describes the work its brief assigned — mismatched work
gets parked on a branch, never merged. Resume a merged-but-PARTIAL lane
via its recorded session_id with the on-glass wire evidence; rename the
old result file so sentinels see the fresh one.
"Is 'Say Keep' even backed by research?" — it wasn't, and it was broken.
Any lane brief that touches an INTERACTION PATTERN (a save/commit moment,
a progress display, a confirmation flow, an editing gesture, an
approval surface) MUST order research-first: survey ≥2 named world-class
references (Zapier, n8n, Linear, Cursor, Notion, Raycast, Figma...),
cite what was taken and what was rejected in the result JSON. A pattern
that exists only because we shipped it that way is a finding, not a
tradition.
"Designed but not mounted" anatomy: leaf stories prove components in
isolation; route tests prove the wire; NOBODY proved the JOIN — the
parent conditional that mounts the leaf from live-shaped data. The Keep
button shipped green-storied and never rendered because of exactly this.
LAW: any UI lane touching a flow must add/extend the PAGE story per
snappy-storybook §8b — withAppShell + MSW handlers whose fixtures are
CAPTURED FROM THE REAL WIRE (probe-keys law), asserting the new leaf
mounts in the composed page. A leaf story without its page story is half
a proof and does not close a UI brief.
lanes reparent to PPID 1, so a PPID==1 heuristic + command-pattern kill hit
lane luna-h27's own jcode process mid-work (its commits survived; ~30 min
lost to relaunch). Orphan cleanup must EXCLUDE anything holding a lane
worktree open (lsof +D ~/lanes/<L> first, build an allow-list of lane
pids, then kill only non-lane test tooling) — or simpler, restart lanes at
a quiet boundary and let their children die with them. Law 1's lease model
is the real fix; until it exists, no pattern-matched kills at all.
work" queues BEHIND X's merge — never parallel (krisp/skool built the
same owner twice with different names). Shared-owner extraction is its
own tiny lane FIRST when two consumers need it.
work; a lane whose base predates a hot-file landing produces guard-r1/r2
class collisions. The relaunch/continue preamble always includes
git fetch origin && git merge origin/<branch>.
or build/route.tsx per wave. These two files ate most merge churn.
log): reboots are KERNEL PANICS — "userspace watchdog timeout: no
successful checkins from WindowServer in 161 seconds" — memory
starvation, not CPU. The lanes' vitest/tsc bursts fill the compressor
(~7.6G) and swap (5G/6G) until WindowServer starves. Four reboots total:
two at 8-10 agents, one at 7, one at 4-5 during concurrent test phases.
Queue runners guard on (live < 4 && free_disk > 8GB && swap_used <
4500M via sysctl -n vm.swapusage) and are idempotent (skip if result
exists or process live). ONE runner is the launch authority at a time —
two runners racing the same check both launch and bust the cap.
as masters, get scp'd to /tmp at launch, AND fleetctl installs
LANE-BRIEF.md in the worktree. Recovery = re-push briefs + relaunch with
the continuation preamble (worktree diffs survive; work is never lost).
merge (each ~2GB; 20 stale worktrees = 37GB = the disk death spiral).
NEVER rm ~/.jcode/scratch of live agents (killed the whole fleet once).
suites) runs BEFORE push, as its own command, push only after reading
green. Conflict taxonomy: additive collisions → union; parallel
invention of one owner → single name, rename leftovers; double redesign
of one file → HEAD side + renote the dropped half as a follow-up lane.
from web main with dynamic imports included) names any web→server leak
chain in seconds — use it before any bisect of a web build failure.
<!-- SNAPPY-NEAR-NEIGHBOURS-START -->
A model confuses this hand with snappy-agent-host, snappy-ai-models, snappy-ax, snappy-browse, snappy-cleanshot, snappy-deploy, snappy-desktop, snappy-dispatch, snappy-ffmpeg, snappy-github, snappy-hands, snappy-image, snappy-maintenance, snappy-nightshift, snappy-os-operator, snappy-resident, snappy-telegram, snappy-video, snappy-voice-control, snappy-watchtower, snappy-xano-mcp. Open one of those when its job is the job.
<!-- SNAPPY-NEAR-NEIGHBOURS-END -->
---
name: snappy-jcode
instruction-only: true
description: "Dispatch GPT 5.6 (Luna/Sol) agents as sandboxed lane workers via the local jcode CLI, on this Mac or the Mac mini: work happens THERE (a headless agent in its own git worktree, editing, testing, committing on its branch), integration happens HERE in the orchestrator. Use when Robert says: /snappy-jcode, 'use gpt 5.6 LUNA agents on EXTRA HIGH using JCODE', 'when you switch to jcode', 'we need to be doing 10 on the mini with jcode', 'continue the agents on the MAC MINI, sonnet 5 agents over there on extra high', 'you have to be slamming that mac mini but keeping it landing CLEAN', 'use the mac mini as a workhorse'. Triggers on: jcode, lane worker, gpt 5.6, luna, sol, mac mini agent, sandboxed worktree agent. NOT the in-app user seats (see snappy-resident). NOT cheap pi sub-agent dispatch (see snappy-dispatch). NOT the overnight orchestration OS (see snappy-nightshift)."
---
# snappy-jcode — GPT 5.6 lane workers via the local jcode CLI
Validated 2026-08-14 on jcode v0.76.0 with two live smokes (text round-trip
+ agentic file write, both green on the first try). This skill is the
hardened road for the orchestrator (Fable, HERE) to dispatch **GPT 5.6
Luna/Sol agents (THERE)** as sandboxed lane workers, with integration kept
centralized.
## The architecture contract (Robert's ruling, 2026-08-14)
- **Work happens THERE**: a jcode agent runs headlessly inside a git
worktree (the sandbox). It edits files, runs scoped tests, commits, and
pushes on ITS branch.
- **Integration happens HERE**: the orchestrator merges (`git commit
--only` / merge with scoped verify), installs, walks the glass, keeps
the board. Decisions never leave this seat.
- **Files come back via git**, never via copy-paste: the lane branch is
the only transport. Unpushed work does not exist.
- Lanes NEVER install, never touch the runtime state root, never share a
writable file with another lane. Same laws as every fleet.
## The proven invocation (copy exactly)
```bash
_ZO_DOCTOR=0 jcode run --quiet --no-update --json \
-p openai -m gpt-5.6-luna \
--tools bash,read,write,apply_patch \
-C <worktree-abs-path> \
"<the lane brief>"
```
- Result JSON keys: `model`, `provider`, `session_id`, `text`, `usage`
(`input_tokens`/`output_tokens`/cache fields).
- The `--tools` allow-list IS the permission system in run mode — no
interactive approval; grant only what the lane needs. `--tool-profile
none` = pure text (cheap probes/judging).
- **Continuation**: `jcode run --resume <session_id> "<follow-up>"`
reopens the same agent with its context — nudge, don't respawn.
- `--ndjson` streams events; `--trace` logs tool I/O to stderr — use for
debugging a misbehaving lane.
- Models proven present: `gpt-5.6-luna`, `gpt-5.6-sol` (plus `-pro`,
`-terra`, `-sol-wm` variants). Provider `openai` rides Robert's ChatGPT
Pro OAuth (auto-refresh, `jcode auth status` to check). `claude` and
`openrouter` providers are also authed — the same road can run other
brains.
## Reasoning effort: HIS CHOICE, PER RUN, IN THE ENVIRONMENT
**He sets it on the bar's Providers tab** — a level per provider, saved to
`~/.snappy-skills/providers.json`. `jcodeRun` reads it through
`snappy-settings/providers-choice.ts` (the kernel's one reader of that
document) and passes it to jcode. Nothing to do by hand.
MEASURED on **jcode v0.78.1**, 2026-09-09:
- **There is still NO per-run CLI flag.** `jcode run --help` lists `--json`,
`-p`, `-C`, `--ndjson`, `--remote-working-dir`, `--no-update`,
`--auto-update`, `--trace`, `--quiet`, `--resume`, `--no-selfdev`,
`--socket`, `--debug-socket`, `-m`, `--provider-profile`, `--tool-profile`,
`--tools`, `--disabled-tools`, `--disable-base-tools` — and nothing else.
Grepping the whole help (run and top level) for effort/reason/think returns
nothing.
- **The knob is jcode's env override of its own config key:**
`JCODE_OPENAI_REASONING_EFFORT` and `JCODE_ANTHROPIC_REASONING_EFFORT`,
both in the v0.78.1 binary's env table beside the `[provider]` keys
`openai_reasoning_effort` / `anthropic_reasoning_effort`. `jcodeRun` puts
the chosen word in the CHILD's environment for that one run.
- **openrouter and gemini have no such override.** An effort chosen for one of
them is refused by name — `effort_not_applicable`, the typed refusal from
`snappy-settings/refusal-codes.ts` — and the run does not happen. A level he
can see on his panel that the run silently ignored is the same lie as a
status truer than its artifact.
**Never edit `~/.jcode/config.toml`.** (This SKILL.md used to say: set
`openai_reasoning_effort = "xhigh"`, run the window, restore it after. That
advice is retired — it mutates the effort of every jcode window he has open,
and a lane that dies between the set and the restore leaves his global
changed.) The per-run env override does the same job and touches nothing of
his.
```typescript
// his level, automatically:
await jcodeRun(brief, { cwd });
// this one run only, overriding his level:
await jcodeRun(brief, { cwd, effort: "xhigh" });
```
## Fleet pattern (when Robert orders a jcode fleet)
1. Worktree per lane: `git worktree add` + `npm run worktree:bootstrap`
(repo-specific; links node_modules/venv/.env.cache in snappy-os-app).
2. Brief = the standard lane brief (finish line, territory pathspec,
inventory-first, laws, "commit early, push every commit, NEVER
git stash").
3. Launch each lane with the proven invocation; capture `session_id`.
4. Poll by GIT EVIDENCE (branch commits), not by chat: `git fetch` +
branch freshness. Nudge stalled lanes via `--resume`.
5. Merge/install/walk stays HERE. The board file records lane →
session_id → branch.
6. Log every dispatch as one ndjson line to
`~/.claude/logs/agent-runs.ndjson` (shared schema with snappy-shell /
snappy-dispatch) for cost + latency audit.
## Cost observed
Smoke runs: ~10.8k input tokens for a bare one-shot (jcode's system
harness is the floor), 10-27 output. Subscription-backed (ChatGPT Pro),
not per-token billed — the constraint is the account's usage limits
(`jcode usage`), not dollars.
## The mini (M4) variant — VALIDATED 2026-08-15, the crash-proof heavy fleet
The M1 crashed the Claude Code harness repeatedly under 12+ concurrent
xhigh Lunas (resource exhaustion). The always-on Mac mini (Host `mini` =
100.93.55.2 in ~/.ssh/config, Apple M4 / 16GB) is the proper heavy-fleet
sandbox:
- jcode lives at `/opt/homebrew/bin/jcode` (non-login ssh PATH misses it —
always use the absolute path). openai OAuth is authenticated ON the mini
(its own `~/.jcode/openai-auth.json`); smoke proof `MINI-M4-ROAD-OK` in
7.5s round-trip; harness floor there ~4k tokens vs 10.8k local.
- **The M1 is the git hub** — the mini's clone has NO github credentials by
design (never provision keys there): `git remote add mini
robertboulos@100.93.55.2:Projects/snappy-os-app`, `git push mini
<branches>`, lanes COMMIT but never push, collect with `git fetch mini`.
- Worktrees at `~/lanes/<name>` on the mini; dep drift from the stale clone
is real — `npm install` fresh in ONE worktree, `ln -sfn` its
node_modules into the others. Briefs get a MINI ADAPTATIONS footer: no
push, no live daemon (the daemon binds 127.0.0.1 on the M1 — live-daemon
lanes MUST run locally), merge the local `integration/...` ref first.
- Launch detached ON the mini: `ssh mini 'cd ~/lanes/X && nohup
/opt/homebrew/bin/jcode run … > ~/lanes/X-result.json 2> …stderr.log &'`
— survives M1 crashes entirely. Effort: pass `effort` to `jcodeRun`, or set
it once on the Providers tab; nothing edits the mini's
`~/.jcode/config.toml`; restore after.
- **Resource governance is measured, not assumed**: check `vm_stat` free
pages + `uptime` load before sizing; ~8-9 Lunas is the 16GB ceiling
(12 pinched it to 57MB free). Keep a `~/lanes/QUEUED.txt` and refill
slots as lanes finish. Local cap ~3 (live-daemon lanes only).
- Proper-use walls: lanes touch ONLY their worktree; never the mini's
other dirs (codex threads, agent-mail, Desktop, Application Support);
pre-existing checkout WIP gets parked on a branch first; worktrees
removed + branches pruned after collection.
### fleetctl — the mini control plane (installed at `~/lanes/fleetctl.sh`)
One ssh call per operation; this is HOW control is exercised there:
- `fleetctl.sh status` — procs, load, free disk, free mem, and per-lane:
LIVE/done · result bytes · dirty count · last commit. The whole fleet's
truth in one round-trip; run it before every decision.
- `fleetctl.sh launch <lane>` — GUARDED launch: refuses under 3GB free
disk or at the 8-proc cap; appends an audit line to
`~/lanes/dispatches.ndjson` (collect periodically into the local
agent-runs log).
- `fleetctl.sh pause <lane>` / `fleetctl.sh sweep` (removes worktrees whose
branches are ancestors of integration — merged means swept).
### THE CONTROL DOCTRINE (researched, 2026-08-15 — full design in
### `references/fleet-control-playbook.md`; READ IT before running a fleet)
**LAW ZERO — THE ORCHESTRATOR'S MACHINE RUNS NOTHING HEAVY. EVER.**
2026-08-15, third crash of the night, self-inflicted: the full 8,479-test
web suite was launched ON the M1 while orchestrating — the exact
resource-exhaustion class already named twice that session. The M1 is the
merge/install/decide seat plus at most 2-3 LIGHT live-daemon lanes. Full
test suites, storybook builds, broad batteries: ALWAYS on the mini — and
the mini earns trustworthy full-suite COUNTS by provisioning ONE
full-environment worktree (complete npm install incl. vitest, python venv,
rebuilt native bindings) kept for exactly this. If a number can only be
measured with a heavy run, the heavy run happens THERE, detached.
Verified control, not assumed control. The five laws that replace guessing:
1. **Liveness = lease, never process detection.** The lane's wrapper
heartbeats a file/row every 30s; the controller reads heartbeat AGE.
pgrep-by-name is ABOLISHED (titles rewrite; ssh quoting mangles
patterns). Interim: per-lane liveness by `lsof +D <worktree>`.
2. **Identity = pid + `ps -o lstart=` fingerprint**, recorded at spawn.
3. **One worktree = one kernel lock** (`zsystem flock`) held for the lane's
life; double-launch structurally impossible.
4. **launchd owns lane processes** (per-lane LaunchAgent), not nohup; a
KeepAlive reaper expires 90s-stale leases with evidence and kills
PROCESS GROUPS. Ship SCRIPTS over ssh, never quoted command strings.
5. **Deletes prove non-identity** with `[ "$a" -ef "$b" ]` (APFS is
case-insensitive — ~/projects ate ~/Projects once), never rm -rf a
worktree, and a VERIFIED `git bundle` precedes anything destructive —
the rule that already saved 915 refs.
### Hard-won operational laws (each cost real wall-clock, 2026-08-15)
- **DISK is checked before RAM is** — 13 worktrees + fresh deps ≈ 10GB;
a full disk kills lanes SILENTLY (0-byte results, empty stderr). The
fleetctl launch guard exists because of this night.
- **The bundler is part of lane verification**: vitest tolerates import
cycles and CSS elision; esbuild refuses them. Lanes touching import
graphs run `bash apps/snappy-os/scripts/build-web.sh` — exit 0 IS the
finish line for web work. (Cycle class: ambiguous `.ts`/`.tsx` basename
self-resolution — extract the pure leaf.)
- **Symlinked node_modules must exist BEFORE lanes start** — a lane that
finds deps missing runs its own npm install (1.4GB × N). Verify the
links, don't assume them.
- **Mini-environment failures ≠ code failures**: missing better-sqlite3
bindings and absent `tsc` on stale clones produce test failures the
code doesn't have. Lanes report them; the orchestrator re-verifies
locally before judging.
- **A FALSE finish line can be a success report**: mini lanes cannot push
by design, so a lane whose only miss is "could not push" is DONE —
read the report body, not just the verdict. Batteries likewise report
FALSE while any single check fails; that is the honesty working.
- Sentinel pattern: a harness-TRACKED background loop polling result-file
sizes (mini over ssh + local scratchpad) that EXITS when work lands —
the exit notification is the orchestrator's wake-up. Detached lanes
never notify by themselves.
## THE INTEGRATION METHOD (2026-08-16 — bought with a 291-failure surprise)
1. **Scoped gates per merge, full battery TRAILING every install window.**
Scoped tests + typecheck + web build gate each merge (fast). The FULL
web suite runs ON THE MINI, detached, at every install window — a
trailing signal (~15-30 min), never a blocking gate. Drift is caught
one window late instead of forty merges late. The ratchet only
ratchets when the full battery watches continuously: scoped-only
gating accumulated 49→291 invisibly in one night.
2. **Surface-rewrite waves BUDGET a story-ratification wave.** When lanes
deliberately rewrite surfaces, every story pinning the old truth WILL
fail — that is the workshop working. Plan the repair wave as part of
the feature wave, not as a surprise.
3. **Cluster-repair pattern**: full-suite report → group failing files by
area → one fix lane per cluster with its EXACT file list inline + the
law: update tests to the new intended truth WITH per-change
justification; fix real defects at owners; NEVER weaken an assertion.
Each lane reruns exactly its cluster and pastes counts.
4. **THE GAUNTLET**: merged ≠ working. Every landing carries states
LANDED → WORKSHOP (story exercises real states incl. the defect state)
→ GLASS (dogfooded on the installed app, evidence captured) →
ITERATED → ACCEPTED, in a ledger (docs/GAUNTLET-*.md). A dedicated
glass-prosecutor lane drives the live daemon (tunnel) assuming
everything is broken; sb-audit fills the workshop column. Founder's
eyes outrank every column.
5. **Conflicts reconcile ON THE BRANCH, never at the seat**: a merge
conflict aborts and goes back to the lane worktree with a reconcile
brief ("both sides fully survive"); the orchestrator hand-resolves
only trivial import unions.
6. **Workshop parity ≠ composition designed**: "55/55 route stories" let
an undesigned button strip reach the founder's glass. Per-class
structural gates (e.g. nothing renders above a page's h1) are the
mechanism; a mounted element with no designed story is a defect.
7. **Reverse tunnel** (`ssh -f -N -R 3147:127.0.0.1:3147 mini`) lets mini
lanes drive the live daemon at their own localhost — batteries and
prosecutors run THERE too. Mint keys via a 600-perm file, never argv.
## When to use which runner
- `snappy-dispatch` (pi): sub-penny mechanical grunt work, 2-4s.
- `snappy-shell` (pi REPL): full interactive fallback session.
- **`snappy-jcode`**: real BUILD lanes on a second brain (GPT 5.6),
sandboxed in worktrees, integration kept here. The peer-fleet road.
## Brief-install law (2026-08-15, bought with a two-lane hijack)
`fleetctl launch <lane> <brief-file>` now COPIES the brief into the
worktree as LANE-BRIEF.md and REFUSES to launch when the worktree has no
LANE-BRIEF.md (the agent's fixed prompt reads that file; an argv brief
path was silently ignored for hours and two lanes executed a stale
wave-30 brief they found by hunting). Corollary: before merging ANY lane,
verify its result describes the work its brief assigned — mismatched work
gets parked on a branch, never merged. Resume a merged-but-PARTIAL lane
via its recorded session_id with the on-glass wire evidence; rename the
old result file so sentinels see the fresh one.
## Research mandate for interaction patterns (founder law 2026-08-15)
"Is 'Say Keep' even backed by research?" — it wasn't, and it was broken.
Any lane brief that touches an INTERACTION PATTERN (a save/commit moment,
a progress display, a confirmation flow, an editing gesture, an
approval surface) MUST order research-first: survey ≥2 named world-class
references (Zapier, n8n, Linear, Cursor, Notion, Raycast, Figma...),
cite what was taken and what was rejected in the result JSON. A pattern
that exists only because we shipped it that way is a finding, not a
tradition.
## The page-story law (founder root-cause session 2026-08-15)
"Designed but not mounted" anatomy: leaf stories prove components in
isolation; route tests prove the wire; NOBODY proved the JOIN — the
parent conditional that mounts the leaf from live-shaped data. The Keep
button shipped green-storied and never rendered because of exactly this.
LAW: any UI lane touching a flow must add/extend the PAGE story per
snappy-storybook §8b — withAppShell + MSW handlers whose fixtures are
CAPTURED FROM THE REAL WIRE (probe-keys law), asserting the new leaf
mounts in the composed page. A leaf story without its page story is half
a proof and does not close a UI brief.
## ORCHESTRATION LAWS (2026-08-16 wave — each bought with a real failure)
0. **NEVER pattern-kill "orphans" (2026-08-26, killed a live Luna).** Detached
lanes reparent to PPID 1, so a PPID==1 heuristic + command-pattern kill hit
lane luna-h27's own jcode process mid-work (its commits survived; ~30 min
lost to relaunch). Orphan cleanup must EXCLUDE anything holding a lane
worktree open (`lsof +D ~/lanes/<L>` first, build an allow-list of lane
pids, then kill only non-lane test tooling) — or simpler, restart lanes at
a quiet boundary and let their children die with them. Law 1's lease model
is the real fix; until it exists, no pattern-matched kills at all.
1. **Dependency-sequenced dispatch.** A brief that says "reuse lane X's
work" queues BEHIND X's merge — never parallel (krisp/skool built the
same owner twice with different names). Shared-owner extraction is its
own tiny lane FIRST when two consumers need it.
2. **Base freshness.** Every lane merges origin/integration HEAD before
work; a lane whose base predates a hot-file landing produces guard-r1/r2
class collisions. The relaunch/continue preamble always includes
`git fetch origin && git merge origin/<branch>`.
3. **Hot-file serialization.** At most ONE live lane touching builder-turn.ts
or build/route.tsx per wave. These two files ate most merge churn.
4. **Cap 4 on the mini, swap-guarded.** Root-caused 2026-08-16 (panic-full
log): reboots are KERNEL PANICS — "userspace watchdog timeout: no
successful checkins from WindowServer in 161 seconds" — memory
starvation, not CPU. The lanes' vitest/tsc bursts fill the compressor
(~7.6G) and swap (5G/6G) until WindowServer starves. Four reboots total:
two at 8-10 agents, one at 7, one at 4-5 during concurrent test phases.
Queue runners guard on (live < 4 && free_disk > 8GB && swap_used <
4500M via `sysctl -n vm.swapusage`) and are idempotent (skip if result
exists or process live). ONE runner is the launch authority at a time —
two runners racing the same check both launch and bust the cap.
5. **Reboot survival.** /tmp dies on reboot: briefs live in the scratchpad
as masters, get scp'd to /tmp at launch, AND fleetctl installs
LANE-BRIEF.md in the worktree. Recovery = re-push briefs + relaunch with
the continuation preamble (worktree diffs survive; work is never lost).
6. **Worktree hygiene.** Sweep MERGED lanes' worktrees immediately after
merge (each ~2GB; 20 stale worktrees = 37GB = the disk death spiral).
NEVER rm ~/.jcode/scratch of live agents (killed the whole fleet once).
7. **Integration wall.** Battery (workflow-builder-turn battery + touched
suites) runs BEFORE push, as its own command, push only after reading
green. Conflict taxonomy: additive collisions → union; parallel
invention of one owner → single name, rename leftovers; double redesign
of one file → HEAD side + renote the dropped half as a follow-up lane.
8. **The graph walker** (scratchpad/trace-graph.mjs pattern: es-import walk
from web main with dynamic imports included) names any web→server leak
chain in seconds — use it before any bisect of a web build failure.
<!-- SNAPPY-NEAR-NEIGHBOURS-START -->
## Near neighbours
A model confuses this hand with `snappy-agent-host`, `snappy-ai-models`, `snappy-ax`, `snappy-browse`, `snappy-cleanshot`, `snappy-deploy`, `snappy-desktop`, `snappy-dispatch`, `snappy-ffmpeg`, `snappy-github`, `snappy-hands`, `snappy-image`, `snappy-maintenance`, `snappy-nightshift`, `snappy-os-operator`, `snappy-resident`, `snappy-telegram`, `snappy-video`, `snappy-voice-control`, `snappy-watchtower`, `snappy-xano-mcp`. Open one of those when its job is the job.
<!-- SNAPPY-NEAR-NEIGHBOURS-END -->
// snappy-jcode/api.ts — typed programmatic interface for dispatching
// GPT 5.6 lane workers via the local jcode CLI. Validated 2026-08-14 on
// jcode v0.76.0 (two green smokes: text round-trip + agentic file write).
//
// Contract: work happens THERE (the agent inside a worktree, pushing its
// own branch); integration happens HERE. Files travel only via git.
import { execFile } from "node:child_process";
import { appendFile } from "node:fs/promises";
import { homedir } from "node:os";
import { join } from "node:path";
import { refuse, refusalTable, type Refusal } from "../snappy-settings/refusal-codes.ts";
import { defaultProvider, effortFor, type Effort } from "../snappy-settings/providers-choice.ts";
export interface JcodeRunOptions {
/** Absolute path the agent works in (a git worktree for build lanes). */
cwd: string;
/** Default "gpt-5.6-luna". Sol/pro/terra variants proven present. */
model?: string;
/**
* jcode's own provider word. Default: the provider the owner chose on the
* bar's Providers tab, mapped through PROVIDER_ROADS; "openai" (ChatGPT Pro
* OAuth) when he has chosen none. "claude"/"openrouter" also authed.
*/
provider?: string;
/**
* Override the reasoning effort for this one run. Default: the level he set
* for this provider on the Providers tab. `null` is not "medium" — it is
* "he expressed no preference", and jcode is then left on its own config.
*/
effort?: Effort;
/**
* Explicit tool allow-list — this IS the permission system in run mode.
* Default full build set. Pass [] for a text-only (no-tools) run.
*/
tools?: string[];
/** Resume an existing session with its context instead of starting fresh. */
resumeSessionId?: string;
/** Kill the child after this many ms. Default 20 minutes. */
timeoutMs?: number;
}
export interface JcodeRunResult {
ok: boolean;
text: string;
model: string;
provider: string;
session_id: string;
usage: { input_tokens: number; output_tokens: number } & Record<string, unknown>;
durationMs: number;
/** Raw stderr tail when ok=false — the diagnosis, never swallowed. */
error?: string;
/** The level this run was launched with, or null when none was chosen. */
effort?: Effort | null;
/** Set when the run never happened because his choice could not be honoured. */
refusal?: Refusal;
}
/**
* ── HIS CHOICE → WHAT THIS LANE ACTUALLY SPENDS ──────────────────────────────
*
* ⟨owner, 2026-09-09 10:25⟩ he picks a Default provider, a Fallback order and
* an Effort per provider on the bar's Providers tab. The choices land in
* `~/.snappy-skills/providers.json`; `snappy-settings/providers-choice.ts` is
* the kernel's ONE reader of them. THIS table is the only place the ids in that
* document meet jcode's own `-p` words, so no other file in the collection
* writes the map a second time.
*
* THE EFFORT KNOB, MEASURED — NOT REMEMBERED ⟨jcode v0.78.1, 2026-09-09⟩:
*
* `jcode run --help` lists --json, -p, -C, --ndjson, --remote-working-dir,
* --no-update, --auto-update, --trace, --quiet, --resume, --no-selfdev,
* --socket, --debug-socket, -m, --provider-profile, --tool-profile, --tools,
* --disabled-tools, --disable-base-tools. There is NO effort flag — grepping
* the whole help for effort/reason/think returns nothing, on `run` and on the
* top level both. (The SKILL.md said the same of v0.76; it is still true.)
*
* The knob is jcode's ENVIRONMENT OVERRIDE of its own config key. The binary
* carries `JCODE_OPENAI_REASONING_EFFORT` and `JCODE_ANTHROPIC_REASONING_EFFORT`
* in its env table, beside the `[provider]` keys `openai_reasoning_effort` /
* `anthropic_reasoning_effort` that `~/.jcode/config.toml` sets by hand. So
* the effort travels in the CHILD's environment, per run, and this hand never
* edits his config file — a lane that rewrote `~/.jcode/config.toml` would
* change the effort of every jcode window he has open.
*
* openrouter and gemini have NO such override. An effort chosen for one of
* them is REFUSED by name (`effort_not_applicable`), never dropped: a level
* shown on his panel that the run silently ignored is the same lie as a
* status truer than its artifact.
*/
interface ProviderRoad {
/** The id the runner mints from `jcode usage --json` (providers-choice.ts). */
choice: string;
/** jcode's own `-p` words for that provider. The FIRST is the one passed. */
jcode: string[];
/** jcode's env override for reasoning effort, or null when it has none. */
effortEnv: string | null;
}
export const PROVIDER_ROADS: readonly ProviderRoad[] = [
{ choice: "chatgpt", jcode: ["openai"], effortEnv: "JCODE_OPENAI_REASONING_EFFORT" },
{ choice: "openai-api", jcode: ["openai-api"], effortEnv: "JCODE_OPENAI_REASONING_EFFORT" },
{ choice: "claude", jcode: ["claude", "anthropic-api"], effortEnv: "JCODE_ANTHROPIC_REASONING_EFFORT" },
{ choice: "openrouter", jcode: ["openrouter"], effortEnv: null },
{ choice: "gemini", jcode: ["gemini", "gemini-api", "google"], effortEnv: null },
] as const;
function roadForChoice(id: string | null): ProviderRoad | undefined {
return id === null ? undefined : PROVIDER_ROADS.find((road) => road.choice === id);
}
function roadForJcode(provider: string): ProviderRoad | undefined {
return PROVIDER_ROADS.find((road) => road.jcode.includes(provider));
}
export interface JcodePlan {
/** The argv, in order, exactly as it is handed to jcode. */
args: string[];
/** The environment additions this run carries — never the whole process env. */
env: Record<string, string>;
provider: string;
model: string;
effort: Effort | null;
/** Present when the run must not happen; `jcodeRun` returns it without spawning. */
refusal?: Refusal;
}
/**
* THE ARGV AND THE ENVIRONMENT, DECIDED WITHOUT SPAWNING ANYTHING.
*
* Separated from `jcodeRun` so the owner's choices can be driven by a test on a
* machine with no jcode session at all: the thing that was wrong before was the
* ARGV (two hard-coded strings), and an argv that only a real 20-minute lane
* can prove is an argv nothing checks.
*/
export function jcodePlan(brief: string, opts: JcodeRunOptions): JcodePlan {
const provider = opts.provider ?? roadForChoice(defaultProvider())?.jcode[0] ?? "openai";
const model = opts.model ?? "gpt-5.6-luna";
const road = roadForJcode(provider);
const effort = opts.effort ?? (road === undefined ? null : effortFor(road.choice));
const args = ["run", "--quiet", "--no-update", "--json", "-p", provider, "-m", model, "-C", opts.cwd];
const tools = opts.tools ?? DEFAULT_TOOLS;
if (tools.length === 0) args.push("--tool-profile", "none");
else args.push("--tools", tools.join(","));
if (opts.resumeSessionId) args.push("--resume", opts.resumeSessionId);
args.push(brief);
if (effort !== null && (road === undefined || road.effortEnv === null)) {
return {
args, env: {}, provider, model, effort,
refusal: refuse("effort_not_applicable",
`The effort "${effort}" is set for ${road?.choice ?? provider}, and jcode v0.78.1 has no effort knob for that provider — only openai and anthropic take one (JCODE_OPENAI_REASONING_EFFORT / JCODE_ANTHROPIC_REASONING_EFFORT).`),
};
}
const env = effort !== null && road?.effortEnv ? { [road.effortEnv]: effort } : {};
return { args, env, provider, model, effort };
}
const LOG_PATH = join(homedir(), ".claude", "logs", "agent-runs.ndjson");
const DEFAULT_TOOLS = ["bash", "read", "write", "apply_patch"];
export async function jcodeRun(brief: string, opts: JcodeRunOptions): Promise<JcodeRunResult> {
const started = Date.now();
const plan = jcodePlan(brief, opts);
const { args } = plan;
// A CHOICE THAT CANNOT BE HONOURED STOPS THE RUN. Spending twenty minutes of
// a provider at a level he did not ask for is worse than answering now.
if (plan.refusal !== undefined) {
return {
ok: false, text: "", model: plan.model, provider: plan.provider, session_id: "",
usage: { input_tokens: 0, output_tokens: 0 }, durationMs: Date.now() - started,
effort: plan.effort, refusal: plan.refusal, error: plan.refusal.message,
};
}
const result = await new Promise<JcodeRunResult>((resolvePromise) => {
execFile("jcode", args, {
cwd: opts.cwd,
env: { ...process.env, _ZO_DOCTOR: "0", ...plan.env },
timeout: opts.timeoutMs ?? 20 * 60_000,
maxBuffer: 32 * 1024 * 1024,
}, (err, stdout, stderr) => {
const durationMs = Date.now() - started;
try {
const parsed = JSON.parse(stdout.slice(stdout.indexOf("{")));
resolvePromise({ ok: !err, durationMs, effort: plan.effort, ...parsed });
} catch {
resolvePromise({
ok: false, text: "", model: plan.model,
provider: plan.provider, session_id: "",
usage: { input_tokens: 0, output_tokens: 0 }, durationMs,
effort: plan.effort,
error: (stderr || String(err)).slice(-2000),
});
}
});
});
await appendFile(LOG_PATH, JSON.stringify({
ts: new Date(started).toISOString(), runner: "snappy-jcode",
model: result.model, provider: result.provider, effort: plan.effort, cwd: opts.cwd,
session_id: result.session_id, ok: result.ok, duration_ms: result.durationMs,
input_tokens: result.usage?.input_tokens, output_tokens: result.usage?.output_tokens,
brief_head: brief.slice(0, 120),
}) + "\n").catch(() => {});
return result;
}
/** Nudge a previously launched lane with its context intact. */
export function jcodeResume(sessionId: string, followUp: string, opts: JcodeRunOptions): Promise<JcodeRunResult> {
return jcodeRun(followUp, { ...opts, resumeSessionId: sessionId });
}
/** WHAT THIS HAND ANSWERS: NOTHING, AND IT SAYS SO ⟨lane CONTRACTS, 2026-09-07⟩.
* This file is a library other skills import — it has no CLI dispatch, so it
* implements no verb a person or an AI could call. Declaring `verbs: {}` is
* the honest reading: the census counts it as a skill with a contract and zero
* callable verbs, rather than as a hand whose contract could not be read,
* which is a different fact and would send someone looking for a bug. */
export const HAND_CONTRACT = {
skill: "snappy-jcode",
description: "Dispatch GPT 5.6 (Luna/Sol) agents as sandboxed lane workers via the local jcode CLI, on this Mac or the Mac mini: work happens THERE (a headless agent in its own git worktree, editing, testing, committing on its branch), integration happens HERE in the orchestrator. Use when Robert says: /snappy-jcode, 'use gpt 5.6 LUNA agents on EXTRA HIGH using JCODE', 'when you switch to jcode', 'we need to be doing 10 on the mini with jcode', 'continue the agents on the MAC MINI, sonnet 5 agents over there on extra high', 'you have to be slamming that mac mini but keeping it landing CLEAN', 'use the mac mini as a workhorse'. Triggers on: jcode, lane worker, gpt 5.6, luna, sol, mac mini agent, sandboxed worktree agent. NOT the in-app user seats (see snappy-resident). NOT cheap pi sub-agent dispatch (see snappy-dispatch). NOT the overnight orchestration OS (see snappy-nightshift).",
managed: false,
requires: [] as string[],
refusals: refusalTable("unknown_verb", "effort_not_applicable"),
verbs: {},
} as const;
if (process.argv[1] !== undefined && process.argv[2] === "contract") {
try {
const { realpathSync } = await import("node:fs");
const { fileURLToPath } = await import("node:url");
if (realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url))) {
console.log(JSON.stringify(HAND_CONTRACT, null, 2));
process.exit(0);
}
} catch { /* not invoked directly */ }
}
// snappy-jcode/api.ts — typed programmatic interface for dispatching
// GPT 5.6 lane workers via the local jcode CLI. Validated 2026-08-14 on
// jcode v0.76.0 (two green smokes: text round-trip + agentic file write).
//
// Contract: work happens THERE (the agent inside a worktree, pushing its
// own branch); integration happens HERE. Files travel only via git.
import { execFile } from "node:child_process";
import { appendFile } from "node:fs/promises";
import { homedir } from "node:os";
import { join } from "node:path";
import { refuse, refusalTable, type Refusal } from "../snappy-settings/refusal-codes.ts";
import { defaultProvider, effortFor, type Effort } from "../snappy-settings/providers-choice.ts";
export interface JcodeRunOptions {
/** Absolute path the agent works in (a git worktree for build lanes). */
cwd: string;
/** Default "gpt-5.6-luna". Sol/pro/terra variants proven present. */
model?: string;
/**
* jcode's own provider word. Default: the provider the owner chose on the
* bar's Providers tab, mapped through PROVIDER_ROADS; "openai" (ChatGPT Pro
* OAuth) when he has chosen none. "claude"/"openrouter" also authed.
*/
provider?: string;
/**
* Override the reasoning effort for this one run. Default: the level he set
* for this provider on the Providers tab. `null` is not "medium" — it is
* "he expressed no preference", and jcode is then left on its own config.
*/
effort?: Effort;
/**
* Explicit tool allow-list — this IS the permission system in run mode.
* Default full build set. Pass [] for a text-only (no-tools) run.
*/
tools?: string[];
/** Resume an existing session with its context instead of starting fresh. */
resumeSessionId?: string;
/** Kill the child after this many ms. Default 20 minutes. */
timeoutMs?: number;
}
export interface JcodeRunResult {
ok: boolean;
text: string;
model: string;
provider: string;
session_id: string;
usage: { input_tokens: number; output_tokens: number } & Record<string, unknown>;
durationMs: number;
/** Raw stderr tail when ok=false — the diagnosis, never swallowed. */
error?: string;
/** The level this run was launched with, or null when none was chosen. */
effort?: Effort | null;
/** Set when the run never happened because his choice could not be honoured. */
refusal?: Refusal;
}
/**
* ── HIS CHOICE → WHAT THIS LANE ACTUALLY SPENDS ──────────────────────────────
*
* ⟨owner, 2026-09-09 10:25⟩ he picks a Default provider, a Fallback order and
* an Effort per provider on the bar's Providers tab. The choices land in
* `~/.snappy-skills/providers.json`; `snappy-settings/providers-choice.ts` is
* the kernel's ONE reader of them. THIS table is the only place the ids in that
* document meet jcode's own `-p` words, so no other file in the collection
* writes the map a second time.
*
* THE EFFORT KNOB, MEASURED — NOT REMEMBERED ⟨jcode v0.78.1, 2026-09-09⟩:
*
* `jcode run --help` lists --json, -p, -C, --ndjson, --remote-working-dir,
* --no-update, --auto-update, --trace, --quiet, --resume, --no-selfdev,
* --socket, --debug-socket, -m, --provider-profile, --tool-profile, --tools,
* --disabled-tools, --disable-base-tools. There is NO effort flag — grepping
* the whole help for effort/reason/think returns nothing, on `run` and on the
* top level both. (The SKILL.md said the same of v0.76; it is still true.)
*
* The knob is jcode's ENVIRONMENT OVERRIDE of its own config key. The binary
* carries `JCODE_OPENAI_REASONING_EFFORT` and `JCODE_ANTHROPIC_REASONING_EFFORT`
* in its env table, beside the `[provider]` keys `openai_reasoning_effort` /
* `anthropic_reasoning_effort` that `~/.jcode/config.toml` sets by hand. So
* the effort travels in the CHILD's environment, per run, and this hand never
* edits his config file — a lane that rewrote `~/.jcode/config.toml` would
* change the effort of every jcode window he has open.
*
* openrouter and gemini have NO such override. An effort chosen for one of
* them is REFUSED by name (`effort_not_applicable`), never dropped: a level
* shown on his panel that the run silently ignored is the same lie as a
* status truer than its artifact.
*/
interface ProviderRoad {
/** The id the runner mints from `jcode usage --json` (providers-choice.ts). */
choice: string;
/** jcode's own `-p` words for that provider. The FIRST is the one passed. */
jcode: string[];
/** jcode's env override for reasoning effort, or null when it has none. */
effortEnv: string | null;
}
export const PROVIDER_ROADS: readonly ProviderRoad[] = [
{ choice: "chatgpt", jcode: ["openai"], effortEnv: "JCODE_OPENAI_REASONING_EFFORT" },
{ choice: "openai-api", jcode: ["openai-api"], effortEnv: "JCODE_OPENAI_REASONING_EFFORT" },
{ choice: "claude", jcode: ["claude", "anthropic-api"], effortEnv: "JCODE_ANTHROPIC_REASONING_EFFORT" },
{ choice: "openrouter", jcode: ["openrouter"], effortEnv: null },
{ choice: "gemini", jcode: ["gemini", "gemini-api", "google"], effortEnv: null },
] as const;
function roadForChoice(id: string | null): ProviderRoad | undefined {
return id === null ? undefined : PROVIDER_ROADS.find((road) => road.choice === id);
}
function roadForJcode(provider: string): ProviderRoad | undefined {
return PROVIDER_ROADS.find((road) => road.jcode.includes(provider));
}
export interface JcodePlan {
/** The argv, in order, exactly as it is handed to jcode. */
args: string[];
/** The environment additions this run carries — never the whole process env. */
env: Record<string, string>;
provider: string;
model: string;
effort: Effort | null;
/** Present when the run must not happen; `jcodeRun` returns it without spawning. */
refusal?: Refusal;
}
/**
* THE ARGV AND THE ENVIRONMENT, DECIDED WITHOUT SPAWNING ANYTHING.
*
* Separated from `jcodeRun` so the owner's choices can be driven by a test on a
* machine with no jcode session at all: the thing that was wrong before was the
* ARGV (two hard-coded strings), and an argv that only a real 20-minute lane
* can prove is an argv nothing checks.
*/
export function jcodePlan(brief: string, opts: JcodeRunOptions): JcodePlan {
const provider = opts.provider ?? roadForChoice(defaultProvider())?.jcode[0] ?? "openai";
const model = opts.model ?? "gpt-5.6-luna";
const road = roadForJcode(provider);
const effort = opts.effort ?? (road === undefined ? null : effortFor(road.choice));
const args = ["run", "--quiet", "--no-update", "--json", "-p", provider, "-m", model, "-C", opts.cwd];
const tools = opts.tools ?? DEFAULT_TOOLS;
if (tools.length === 0) args.push("--tool-profile", "none");
else args.push("--tools", tools.join(","));
if (opts.resumeSessionId) args.push("--resume", opts.resumeSessionId);
args.push(brief);
if (effort !== null && (road === undefined || road.effortEnv === null)) {
return {
args, env: {}, provider, model, effort,
refusal: refuse("effort_not_applicable",
`The effort "${effort}" is set for ${road?.choice ?? provider}, and jcode v0.78.1 has no effort knob for that provider — only openai and anthropic take one (JCODE_OPENAI_REASONING_EFFORT / JCODE_ANTHROPIC_REASONING_EFFORT).`),
};
}
const env = effort !== null && road?.effortEnv ? { [road.effortEnv]: effort } : {};
return { args, env, provider, model, effort };
}
const LOG_PATH = join(homedir(), ".claude", "logs", "agent-runs.ndjson");
const DEFAULT_TOOLS = ["bash", "read", "write", "apply_patch"];
export async function jcodeRun(brief: string, opts: JcodeRunOptions): Promise<JcodeRunResult> {
const started = Date.now();
const plan = jcodePlan(brief, opts);
const { args } = plan;
// A CHOICE THAT CANNOT BE HONOURED STOPS THE RUN. Spending twenty minutes of
// a provider at a level he did not ask for is worse than answering now.
if (plan.refusal !== undefined) {
return {
ok: false, text: "", model: plan.model, provider: plan.provider, session_id: "",
usage: { input_tokens: 0, output_tokens: 0 }, durationMs: Date.now() - started,
effort: plan.effort, refusal: plan.refusal, error: plan.refusal.message,
};
}
const result = await new Promise<JcodeRunResult>((resolvePromise) => {
execFile("jcode", args, {
cwd: opts.cwd,
env: { ...process.env, _ZO_DOCTOR: "0", ...plan.env },
timeout: opts.timeoutMs ?? 20 * 60_000,
maxBuffer: 32 * 1024 * 1024,
}, (err, stdout, stderr) => {
const durationMs = Date.now() - started;
try {
const parsed = JSON.parse(stdout.slice(stdout.indexOf("{")));
resolvePromise({ ok: !err, durationMs, effort: plan.effort, ...parsed });
} catch {
resolvePromise({
ok: false, text: "", model: plan.model,
provider: plan.provider, session_id: "",
usage: { input_tokens: 0, output_tokens: 0 }, durationMs,
effort: plan.effort,
error: (stderr || String(err)).slice(-2000),
});
}
});
});
await appendFile(LOG_PATH, JSON.stringify({
ts: new Date(started).toISOString(), runner: "snappy-jcode",
model: result.model, provider: result.provider, effort: plan.effort, cwd: opts.cwd,
session_id: result.session_id, ok: result.ok, duration_ms: result.durationMs,
input_tokens: result.usage?.input_tokens, output_tokens: result.usage?.output_tokens,
brief_head: brief.slice(0, 120),
}) + "\n").catch(() => {});
return result;
}
/** Nudge a previously launched lane with its context intact. */
export function jcodeResume(sessionId: string, followUp: string, opts: JcodeRunOptions): Promise<JcodeRunResult> {
return jcodeRun(followUp, { ...opts, resumeSessionId: sessionId });
}
/** WHAT THIS HAND ANSWERS: NOTHING, AND IT SAYS SO ⟨lane CONTRACTS, 2026-09-07⟩.
* This file is a library other skills import — it has no CLI dispatch, so it
* implements no verb a person or an AI could call. Declaring `verbs: {}` is
* the honest reading: the census counts it as a skill with a contract and zero
* callable verbs, rather than as a hand whose contract could not be read,
* which is a different fact and would send someone looking for a bug. */
export const HAND_CONTRACT = {
skill: "snappy-jcode",
description: "Dispatch GPT 5.6 (Luna/Sol) agents as sandboxed lane workers via the local jcode CLI, on this Mac or the Mac mini: work happens THERE (a headless agent in its own git worktree, editing, testing, committing on its branch), integration happens HERE in the orchestrator. Use when Robert says: /snappy-jcode, 'use gpt 5.6 LUNA agents on EXTRA HIGH using JCODE', 'when you switch to jcode', 'we need to be doing 10 on the mini with jcode', 'continue the agents on the MAC MINI, sonnet 5 agents over there on extra high', 'you have to be slamming that mac mini but keeping it landing CLEAN', 'use the mac mini as a workhorse'. Triggers on: jcode, lane worker, gpt 5.6, luna, sol, mac mini agent, sandboxed worktree agent. NOT the in-app user seats (see snappy-resident). NOT cheap pi sub-agent dispatch (see snappy-dispatch). NOT the overnight orchestration OS (see snappy-nightshift).",
managed: false,
requires: [] as string[],
refusals: refusalTable("unknown_verb", "effort_not_applicable"),
verbs: {},
} as const;
if (process.argv[1] !== undefined && process.argv[2] === "contract") {
try {
const { realpathSync } = await import("node:fs");
const { fileURLToPath } = await import("node:url");
if (realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url))) {
console.log(JSON.stringify(HAND_CONTRACT, null, 2));
process.exit(0);
}
} catch { /* not invoked directly */ }
}
import { test } from "node:test";
import assert from "node:assert/strict";
import { HAND_CONTRACT } from "./api.ts";
import { REFUSAL_CODES, type RefusalCode } from "../snappy-settings/refusal-codes.ts";
/** RULE 33 COVERAGE, AGAINST THE ONE CLOSED TABLE ⟨lane r30, 2026-09-09⟩.
* This file used to restate a refusal row's own properties — that it has a
* `contract_slice`, that it has a `fix`, that it leaks no token — once per
* hand, 48 times, over rows that all come from the SAME object. Forty-eight
* copies of one check is the duplicate road the closed table exists to end:
* `snappy-settings/refusal-codes.test.ts` runs those checks ONCE over every
* row, and the second test below proves this hand carries THE ROW ITSELF and
* not a copy — an identity a drifted duplicate cannot fake. Before this, each
* hand hand-wrote its own row, and the wording had already drifted: the
* inline `unknown_verb` said "Call one of the verbs named in
* HAND_CONTRACT.verbs" while the closed table says "Call one of the verbs the
* contract declares; the refusal lists them."
*
* DECLARED stays a literal list, deliberately. It is this hand's coverage
* manifest and it is what rule 33's lint reads out of the test SOURCE to ask
* "did a person look at this code" — deriving it from Object.keys would make
* the test pass for a hand with no refusals at all. `satisfies readonly
* RefusalCode[]` makes the compiler refuse a name the one table does not
* have. It NAMES codes; it no longer DEFINES them. */
const DECLARED = [
// Added by 122c9ed (2026-09-09), which made effort_not_applicable a typed
// refusal on this hand and did not touch its coverage manifest — nothing
// ran this file, so nothing said so. Phase 8 is the gate that now does.
"effort_not_applicable",
"unknown_verb",
] as const satisfies readonly RefusalCode[];
test("snappy-jcode: the refusal table declares exactly the codes this test names", () => {
assert.deepEqual(Object.keys(HAND_CONTRACT.refusals ?? {}).sort(), [...DECLARED].sort());
});
test("snappy-jcode: every declared refusal is the one closed table's own row, never a copy", () => {
const declared = Object.entries(HAND_CONTRACT.refusals ?? {});
assert.ok(declared.length > 0, "HAND_CONTRACT.refusals is empty");
for (const [code, row] of declared) {
assert.ok(code in REFUSAL_CODES, `${code} is not a row of snappy-settings/refusal-codes.ts`);
assert.equal(row, REFUSAL_CODES[code as RefusalCode], `${code} is a copy of the closed table's row, not the row itself`);
}
});
import { test } from "node:test";
import assert from "node:assert/strict";
import { HAND_CONTRACT } from "./api.ts";
import { REFUSAL_CODES, type RefusalCode } from "../snappy-settings/refusal-codes.ts";
/** RULE 33 COVERAGE, AGAINST THE ONE CLOSED TABLE ⟨lane r30, 2026-09-09⟩.
* This file used to restate a refusal row's own properties — that it has a
* `contract_slice`, that it has a `fix`, that it leaks no token — once per
* hand, 48 times, over rows that all come from the SAME object. Forty-eight
* copies of one check is the duplicate road the closed table exists to end:
* `snappy-settings/refusal-codes.test.ts` runs those checks ONCE over every
* row, and the second test below proves this hand carries THE ROW ITSELF and
* not a copy — an identity a drifted duplicate cannot fake. Before this, each
* hand hand-wrote its own row, and the wording had already drifted: the
* inline `unknown_verb` said "Call one of the verbs named in
* HAND_CONTRACT.verbs" while the closed table says "Call one of the verbs the
* contract declares; the refusal lists them."
*
* DECLARED stays a literal list, deliberately. It is this hand's coverage
* manifest and it is what rule 33's lint reads out of the test SOURCE to ask
* "did a person look at this code" — deriving it from Object.keys would make
* the test pass for a hand with no refusals at all. `satisfies readonly
* RefusalCode[]` makes the compiler refuse a name the one table does not
* have. It NAMES codes; it no longer DEFINES them. */
const DECLARED = [
// Added by 122c9ed (2026-09-09), which made effort_not_applicable a typed
// refusal on this hand and did not touch its coverage manifest — nothing
// ran this file, so nothing said so. Phase 8 is the gate that now does.
"effort_not_applicable",
"unknown_verb",
] as const satisfies readonly RefusalCode[];
test("snappy-jcode: the refusal table declares exactly the codes this test names", () => {
assert.deepEqual(Object.keys(HAND_CONTRACT.refusals ?? {}).sort(), [...DECLARED].sort());
});
test("snappy-jcode: every declared refusal is the one closed table's own row, never a copy", () => {
const declared = Object.entries(HAND_CONTRACT.refusals ?? {});
assert.ok(declared.length > 0, "HAND_CONTRACT.refusals is empty");
for (const [code, row] of declared) {
assert.ok(code in REFUSAL_CODES, `${code} is not a row of snappy-settings/refusal-codes.ts`);
assert.equal(row, REFUSAL_CODES[code as RefusalCode], `${code} is a copy of the closed table's row, not the row itself`);
}
});
/**
* COVERAGE FOR THE ARGV AND THE ENVIRONMENT A LANE IS LAUNCHED WITH.
*
* THE DEFECT THIS FILE EXISTS FOR ⟨2026-09-09⟩: the owner set a Default
* provider and a per-provider Effort on the bar's Providers tab, and `jcodeRun`
* built `-p openai -m gpt-5.6-luna` from two hard-coded strings — his choice
* reached nothing. MEASURED the same hour on jcode v0.78.1: `jcode run --help`
* carries NO effort flag, and the knob is the env override
* `JCODE_OPENAI_REASONING_EFFORT` / `JCODE_ANTHROPIC_REASONING_EFFORT` (both
* present in the binary's env table beside the `[provider]` config keys).
* So the effort travels in the CHILD'S ENVIRONMENT, and for a provider with no
* such knob it is REFUSED BY NAME rather than dropped on the floor.
*
* `jcodePlan` is pure, so every case here is decided without spawning jcode.
* The scratch home is `SNAPPY_SKILLS_HOME`; no case reads the real document.
*/
import { strict as assert } from "node:assert";
import { test } from "node:test";
import { mkdtempSync, writeFileSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { jcodePlan } from "./api.ts";
const HOMES: string[] = [];
function choices(document: Record<string, unknown>): void {
const home = mkdtempSync(join(tmpdir(), "jcode-plan-"));
HOMES.push(home);
process.env.SNAPPY_SKILLS_HOME = home;
writeFileSync(join(home, "providers.json"), JSON.stringify(document));
}
function noDocument(): void {
const home = mkdtempSync(join(tmpdir(), "jcode-plan-"));
HOMES.push(home);
process.env.SNAPPY_SKILLS_HOME = home;
}
test.after(() => { for (const home of HOMES) rmSync(home, { recursive: true, force: true }); });
const CWD = "/tmp/lane-shape";
test("with no saved document the argv is what it always was: -p openai -m gpt-5.6-luna", () => {
noDocument();
const plan = jcodePlan("brief-shape", { cwd: CWD });
assert.equal(plan.refusal, undefined);
assert.deepEqual(plan.args.slice(0, 8),
["run", "--quiet", "--no-update", "--json", "-p", "openai", "-m", "gpt-5.6-luna"]);
assert.equal(plan.effort, null);
assert.equal(plan.env.JCODE_OPENAI_REASONING_EFFORT, undefined);
});
test("his Default provider becomes the -p word, mapped to jcode's own spelling", () => {
choices({ default: "claude", fallback: [], effort: {} });
assert.equal(jcodePlan("brief-shape", { cwd: CWD }).args[5], "claude");
choices({ default: "openai-api", fallback: [], effort: {} });
assert.equal(jcodePlan("brief-shape", { cwd: CWD }).args[5], "openai-api");
choices({ default: "chatgpt", fallback: [], effort: {} });
assert.equal(jcodePlan("brief-shape", { cwd: CWD }).args[5], "openai",
"the runner's `chatgpt` id is jcode's `openai` provider — the subscription road");
});
test("an explicit provider on the call outranks the saved default", () => {
choices({ default: "claude", fallback: [], effort: {} });
assert.equal(jcodePlan("brief-shape", { cwd: CWD, provider: "openrouter" }).args[5], "openrouter");
});
test("his Effort reaches jcode in the child's environment, per provider family", () => {
choices({ default: "chatgpt", fallback: [], effort: { chatgpt: "xhigh" } });
const openai = jcodePlan("brief-shape", { cwd: CWD });
assert.equal(openai.effort, "xhigh");
assert.equal(openai.env.JCODE_OPENAI_REASONING_EFFORT, "xhigh");
assert.equal(openai.env.JCODE_ANTHROPIC_REASONING_EFFORT, undefined);
choices({ default: "claude", fallback: [], effort: { claude: "low" } });
const claude = jcodePlan("brief-shape", { cwd: CWD });
assert.equal(claude.effort, "low");
assert.equal(claude.env.JCODE_ANTHROPIC_REASONING_EFFORT, "low");
assert.equal(claude.env.JCODE_OPENAI_REASONING_EFFORT, undefined);
});
test("an effort for a provider jcode has no knob for REFUSES; it is never dropped in silence", () => {
choices({ default: "openrouter", fallback: [], effort: { openrouter: "high" } });
const plan = jcodePlan("brief-shape", { cwd: CWD });
assert.equal(plan.refusal?.outcome, "refused");
assert.equal(plan.refusal?.code, "effort_not_applicable");
assert.match(String(plan.refusal?.message), /openrouter/);
assert.match(String(plan.refusal?.message), /high/);
assert.ok(String(plan.refusal?.fix).length > 20);
});
test("an effort saved for a provider this run is not using changes nothing", () => {
choices({ default: "chatgpt", fallback: [], effort: { openrouter: "high" } });
const plan = jcodePlan("brief-shape", { cwd: CWD });
assert.equal(plan.refusal, undefined, "the openrouter level is not this run's business");
assert.equal(plan.effort, null);
});
test("the tool words and the brief keep their places around the new argv", () => {
choices({ default: "chatgpt", fallback: [], effort: { chatgpt: "medium" } });
const withTools = jcodePlan("brief-shape", { cwd: CWD, tools: ["bash", "read"] });
assert.deepEqual(withTools.args.slice(-3), ["--tools", "bash,read", "brief-shape"]);
const noTools = jcodePlan("brief-shape", { cwd: CWD, tools: [] });
assert.deepEqual(noTools.args.slice(-3), ["--tool-profile", "none", "brief-shape"]);
const resumed = jcodePlan("brief-shape", { cwd: CWD, resumeSessionId: "session-shape" });
assert.deepEqual(resumed.args.slice(-3), ["--resume", "session-shape", "brief-shape"]);
});
/**
* COVERAGE FOR THE ARGV AND THE ENVIRONMENT A LANE IS LAUNCHED WITH.
*
* THE DEFECT THIS FILE EXISTS FOR ⟨2026-09-09⟩: the owner set a Default
* provider and a per-provider Effort on the bar's Providers tab, and `jcodeRun`
* built `-p openai -m gpt-5.6-luna` from two hard-coded strings — his choice
* reached nothing. MEASURED the same hour on jcode v0.78.1: `jcode run --help`
* carries NO effort flag, and the knob is the env override
* `JCODE_OPENAI_REASONING_EFFORT` / `JCODE_ANTHROPIC_REASONING_EFFORT` (both
* present in the binary's env table beside the `[provider]` config keys).
* So the effort travels in the CHILD'S ENVIRONMENT, and for a provider with no
* such knob it is REFUSED BY NAME rather than dropped on the floor.
*
* `jcodePlan` is pure, so every case here is decided without spawning jcode.
* The scratch home is `SNAPPY_SKILLS_HOME`; no case reads the real document.
*/
import { strict as assert } from "node:assert";
import { test } from "node:test";
import { mkdtempSync, writeFileSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { jcodePlan } from "./api.ts";
const HOMES: string[] = [];
function choices(document: Record<string, unknown>): void {
const home = mkdtempSync(join(tmpdir(), "jcode-plan-"));
HOMES.push(home);
process.env.SNAPPY_SKILLS_HOME = home;
writeFileSync(join(home, "providers.json"), JSON.stringify(document));
}
function noDocument(): void {
const home = mkdtempSync(join(tmpdir(), "jcode-plan-"));
HOMES.push(home);
process.env.SNAPPY_SKILLS_HOME = home;
}
test.after(() => { for (const home of HOMES) rmSync(home, { recursive: true, force: true }); });
const CWD = "/tmp/lane-shape";
test("with no saved document the argv is what it always was: -p openai -m gpt-5.6-luna", () => {
noDocument();
const plan = jcodePlan("brief-shape", { cwd: CWD });
assert.equal(plan.refusal, undefined);
assert.deepEqual(plan.args.slice(0, 8),
["run", "--quiet", "--no-update", "--json", "-p", "openai", "-m", "gpt-5.6-luna"]);
assert.equal(plan.effort, null);
assert.equal(plan.env.JCODE_OPENAI_REASONING_EFFORT, undefined);
});
test("his Default provider becomes the -p word, mapped to jcode's own spelling", () => {
choices({ default: "claude", fallback: [], effort: {} });
assert.equal(jcodePlan("brief-shape", { cwd: CWD }).args[5], "claude");
choices({ default: "openai-api", fallback: [], effort: {} });
assert.equal(jcodePlan("brief-shape", { cwd: CWD }).args[5], "openai-api");
choices({ default: "chatgpt", fallback: [], effort: {} });
assert.equal(jcodePlan("brief-shape", { cwd: CWD }).args[5], "openai",
"the runner's `chatgpt` id is jcode's `openai` provider — the subscription road");
});
test("an explicit provider on the call outranks the saved default", () => {
choices({ default: "claude", fallback: [], effort: {} });
assert.equal(jcodePlan("brief-shape", { cwd: CWD, provider: "openrouter" }).args[5], "openrouter");
});
test("his Effort reaches jcode in the child's environment, per provider family", () => {
choices({ default: "chatgpt", fallback: [], effort: { chatgpt: "xhigh" } });
const openai = jcodePlan("brief-shape", { cwd: CWD });
assert.equal(openai.effort, "xhigh");
assert.equal(openai.env.JCODE_OPENAI_REASONING_EFFORT, "xhigh");
assert.equal(openai.env.JCODE_ANTHROPIC_REASONING_EFFORT, undefined);
choices({ default: "claude", fallback: [], effort: { claude: "low" } });
const claude = jcodePlan("brief-shape", { cwd: CWD });
assert.equal(claude.effort, "low");
assert.equal(claude.env.JCODE_ANTHROPIC_REASONING_EFFORT, "low");
assert.equal(claude.env.JCODE_OPENAI_REASONING_EFFORT, undefined);
});
test("an effort for a provider jcode has no knob for REFUSES; it is never dropped in silence", () => {
choices({ default: "openrouter", fallback: [], effort: { openrouter: "high" } });
const plan = jcodePlan("brief-shape", { cwd: CWD });
assert.equal(plan.refusal?.outcome, "refused");
assert.equal(plan.refusal?.code, "effort_not_applicable");
assert.match(String(plan.refusal?.message), /openrouter/);
assert.match(String(plan.refusal?.message), /high/);
assert.ok(String(plan.refusal?.fix).length > 20);
});
test("an effort saved for a provider this run is not using changes nothing", () => {
choices({ default: "chatgpt", fallback: [], effort: { openrouter: "high" } });
const plan = jcodePlan("brief-shape", { cwd: CWD });
assert.equal(plan.refusal, undefined, "the openrouter level is not this run's business");
assert.equal(plan.effort, null);
});
test("the tool words and the brief keep their places around the new argv", () => {
choices({ default: "chatgpt", fallback: [], effort: { chatgpt: "medium" } });
const withTools = jcodePlan("brief-shape", { cwd: CWD, tools: ["bash", "read"] });
assert.deepEqual(withTools.args.slice(-3), ["--tools", "bash,read", "brief-shape"]);
const noTools = jcodePlan("brief-shape", { cwd: CWD, tools: [] });
assert.deepEqual(noTools.args.slice(-3), ["--tool-profile", "none", "brief-shape"]);
const resumed = jcodePlan("brief-shape", { cwd: CWD, resumeSessionId: "session-shape" });
assert.deepEqual(resumed.args.slice(-3), ["--resume", "session-shape", "brief-shape"]);
});
(Full agent report; commissioned by Robert after the night the fleet's control
signals lied. Direct mapping to our five real failures at the bottom.)
worker ASSERTS liveness by renewing a lease/heartbeat; the controller only
reads heartbeat age. A lane is alive iff its lease is unexpired. Abolish
pgrep-by-name entirely.
ps -p $pid -o lstart=at spawn; later checks compare both. PIDs recycle; argv/titles lie.
$WT/.lane.lock` held for the lane's life — double-launch becomes
structurally impossible; stale locks impossible (kernel releases on death).
Plus git worktree lock so pruning can't eat a live tree.
(ProgramArguments, StandardOut/ErrPath under ~/Library/Logs/fleet/,
ThrottleInterval 30); launchctl print gui/$UID/<label> is authoritative
liveness. nohup only shields SIGHUP — no restart, no logs, no limits.
lane attempt = one worktree; retry is a NEW launch, never a reused process.
30s; a KeepAlive reaper (60s sweep) marks rows with heartbeat older than
90s DEAD(lease_expired), snapshots ps/stderr/df evidence, kills the
process GROUP, requeues (attempt<3) or dead-letters.
the wrapper stamps attempt into the worktree and refuses to push/merge if
superseded; launches are INSERT OR IGNORE on the idempotency key.
heartbeat carries disk_free; alarm under 5GB; the liveness probe is a
BOUNDED DURABLE WRITE (write+fsync+read a nonce), not kill -0 — the check
that catches ENOSPC while it happens.
terminator record {"exit":N,"done":true}. 0-byte/unterminated = infra
death BY DEFINITION, never "the agent said nothing".
what mangled our pgrep): scp the script, run ssh host 'zsh script args';
base64 structured payloads; ControlMaster/ControlPersist for the fleet
connection.
kill -TERM -$pgid → 10s → kill -KILL -$pgid. Never kill by name.
[ "$a" -ef "$b" ] (inode check —APFS is case-insensitive; ~/projects == ~/Projects), `git worktree
remove` never rm -rf, trash-dir with 48h cooling, MANDATORY verified
git bundle before any repo-destructive act. Optional: case-sensitive
APFS volume for the fleet area (one diskutil command, ends the class).
SQLite WAL db ~/fleet/fleet.db: jobs(lane, attempt, status, pid, pgid,
lstart, worktree, heartbeat_at, seq, disk_free, result_path, reason,
PK(lane,attempt)). Writers with strict ownership: WRAPPER (per lane,
launchd-owned: flock claim → RUNNING row → spawn pgroup → 30s heartbeats →
atomic result → exit); REAPER (KeepAlive agent, 60s: expire 90s-stale leases
with evidence, kill pgroups, requeue/DLQ, disk alarms); CONTROLLER (laptop:
inserts idempotent launch requests, reads rows, NEVER pgreps/kills/decides
death). Intervals: hb 30s · TTL 90s · sweep 60s · TERM→KILL 10s · gate 20GB
· attempts 3 → DLQ. The one BLOCKED-to-founder condition: the reaper itself
dead per launchctl print.
Build it on the tasks extension (io.modelcontextprotocol/tasks, spec
2026-07-28, experimental): fleet_launch returns CreateTaskResult
{taskId=lane:attempt, ttlMs, pollIntervalMs}; tasks/get reads the SQLite row
(terminal states carry the result); tasks/cancel marks CANCELLING and the
REAPER kills. MCP server = thin stateless face over fleet.db; launchd owns
processes; truth survives every crash. FastMCP ships a reference impl
(task=True). input_required is the future mid-run-decision door.
Depot (Actions runner internals) · Kleppmann fencing tokens · MCP tasks ext
(modelcontextprotocol.io/extensions/tasks) · FastMCP tasks · Temporal
activity heartbeats · Buildkite agent lifecycle · Salsify reaper ·
launchd.info · SQS visibility timeout · claude_code_agent_farm +
claude-tmux-orchestration + awesome-agent-orchestrators.
proc-title lies → 1,2,4. Silent disk death → 8,9. APFS case aliasing → 12.
Harness-crash orphaning → 4. No leases/supervisor → the liveness design + MCP face.
# Fleet Control Playbook — distilled from 33-search research sweep, 2026-08-15
(Full agent report; commissioned by Robert after the night the fleet's control
signals lied. Direct mapping to our five real failures at the bottom.)
## The twelve patterns
1. LEASE-AND-RENEW, NEVER PROCESS DETECTION (GitHub Actions runner): the
worker ASSERTS liveness by renewing a lease/heartbeat; the controller only
reads heartbeat age. A lane is alive iff its lease is unexpired. Abolish
pgrep-by-name entirely.
2. PID IDENTITY = pid + start-time fingerprint: record `ps -p $pid -o lstart=`
at spawn; later checks compare both. PIDs recycle; argv/titles lie.
3. KERNEL-HELD LOCK PER WORKTREE: `zmodload zsh/system; zsystem flock -t 0
$WT/.lane.lock` held for the lane's life — double-launch becomes
structurally impossible; stale locks impossible (kernel releases on death).
Plus `git worktree lock` so pruning can't eat a live tree.
4. LAUNCHD IS THE SUPERVISOR, NOT NOHUP: per-lane LaunchAgent plist
(ProgramArguments, StandardOut/ErrPath under ~/Library/Logs/fleet/,
ThrottleInterval 30); `launchctl print gui/$UID/<label>` is authoritative
liveness. nohup only shields SIGHUP — no restart, no logs, no limits.
5. ONE-SHOT EPHEMERAL WORKERS (Buildkite --acquire-job): one launch = one
lane attempt = one worktree; retry is a NEW launch, never a reused process.
6. HEARTBEAT + REAPER: worker updates heartbeat_at + seq + disk_free every
30s; a KeepAlive reaper (60s sweep) marks rows with heartbeat older than
90s DEAD(lease_expired), snapshots ps/stderr/df evidence, kills the
process GROUP, requeues (attempt<3) or dead-letters.
7. FENCING TOKENS + IDEMPOTENCY KEYS (Kleppmann): job row = (lane, attempt);
the wrapper stamps attempt into the worktree and refuses to push/merge if
superseded; launches are INSERT OR IGNORE on the idempotency key.
8. PREFLIGHT RESOURCE GATE + LOUD RESOURCE DEATH: refuse launch under 20GB;
heartbeat carries disk_free; alarm under 5GB; the liveness probe is a
BOUNDED DURABLE WRITE (write+fsync+read a nonce), not kill -0 — the check
that catches ENOSPC while it happens.
9. ATOMIC RESULT PROTOCOL: result.json.tmp → fsync → mv, ending with a
terminator record {"exit":N,"done":true}. 0-byte/unterminated = infra
death BY DEFINITION, never "the agent said nothing".
10. SHIP SCRIPTS, NOT QUOTED COMMANDS, OVER SSH (the two-shells problem —
what mangled our pgrep): scp the script, run `ssh host 'zsh script args'`;
base64 structured payloads; ControlMaster/ControlPersist for the fleet
connection.
11. OWN THE PROCESS GROUP: spawn via setsid/launchd, record pgid, teardown =
`kill -TERM -$pgid` → 10s → `kill -KILL -$pgid`. Never kill by name.
12. SAFE DELETE: prove NON-identity with `[ "$a" -ef "$b" ]` (inode check —
APFS is case-insensitive; ~/projects == ~/Projects), `git worktree
remove` never rm -rf, trash-dir with 48h cooling, MANDATORY verified
`git bundle` before any repo-destructive act. Optional: case-sensitive
APFS volume for the fleet area (one diskutil command, ends the class).
## Liveness design (adopt as-is)
SQLite WAL db ~/fleet/fleet.db: jobs(lane, attempt, status, pid, pgid,
lstart, worktree, heartbeat_at, seq, disk_free, result_path, reason,
PK(lane,attempt)). Writers with strict ownership: WRAPPER (per lane,
launchd-owned: flock claim → RUNNING row → spawn pgroup → 30s heartbeats →
atomic result → exit); REAPER (KeepAlive agent, 60s: expire 90s-stale leases
with evidence, kill pgroups, requeue/DLQ, disk alarms); CONTROLLER (laptop:
inserts idempotent launch requests, reads rows, NEVER pgreps/kills/decides
death). Intervals: hb 30s · TTL 90s · sweep 60s · TERM→KILL 10s · gate 20GB
· attempts 3 → DLQ. The one BLOCKED-to-founder condition: the reaper itself
dead per launchctl print.
## MCP control plane verdict
Build it on the tasks extension (io.modelcontextprotocol/tasks, spec
2026-07-28, experimental): fleet_launch returns CreateTaskResult
{taskId=lane:attempt, ttlMs, pollIntervalMs}; tasks/get reads the SQLite row
(terminal states carry the result); tasks/cancel marks CANCELLING and the
REAPER kills. MCP server = thin stateless face over fleet.db; launchd owns
processes; truth survives every crash. FastMCP ships a reference impl
(task=True). input_required is the future mid-run-decision door.
## Sources kept
Depot (Actions runner internals) · Kleppmann fencing tokens · MCP tasks ext
(modelcontextprotocol.io/extensions/tasks) · FastMCP tasks · Temporal
activity heartbeats · Buildkite agent lifecycle · Salsify reaper ·
launchd.info · SQS visibility timeout · claude_code_agent_farm +
claude-tmux-orchestration + awesome-agent-orchestrators.
## Mapping to the five failures of 2026-08-15
proc-title lies → 1,2,4. Silent disk death → 8,9. APFS case aliasing → 12.
Harness-crash orphaning → 4. No leases/supervisor → the liveness design + MCP face.