Design + ops scaffolding for the next phase of work, none of it touching
substrate or guest code.
lib-guest.md: rewrites Architectural framing as a 5-layer stack
(substrate → lib/guest → languages → shared/ → applications),
recursive dependency-direction rule, scaled two-consumer rule. Adds
Phase B (long-running stratification) with sub-layer matrix
(core/typed/relational/effects/layout/lazy/oo), language profiles, and
the long-running-discipline section. Preserves existing Phase A
progress log and rules.
ocaml-on-sx.md: scope reduced to substrate validation + HM + reference
oracle. Phases 1-5 + minimal stdlib slice + vendored testsuite slice.
Dream carved out into dream-on-sx.md; Phase 8 (ReasonML) deferred.
Records lib-guest sequencing dependency.
datalog-on-sx.md: adds Phase 4 built-in predicates + body arithmetic,
Phase 6 magic sets, safety analysis in Phase 3, Non-goals section.
New chisel plans (forward-looking, not yet launchable):
kernel-on-sx.md — first-class everything, env-as-value endgame
idris-on-sx.md — dependent types, evidence chisel
probabilistic-on-sx.md — weighted nondeterminism + traces
maude-on-sx.md — rewriting as primitive
linear-on-sx.md — resource model, artdag-relevant
Loop briefings (4 active, 1 cold):
minikanren-loop.md, ocaml-loop.md, datalog-loop.md, elm-loop.md, koka-loop.md
Restore scripts mirror the loop pattern:
restore-{minikanren,ocaml,datalog,jit-perf,lib-guest}.sh
Each captures worktree state, plan progress, MCP health, tmux status.
Includes the .mcp.json absolute-path patch instruction (fresh worktrees
have no _build/, so the relative mcp_tree path fails on first launch).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.3 KiB
ocaml-on-sx loop agent (single agent, queue-driven)
Role: iterates plans/ocaml-on-sx.md forever. Strict ML on the SX CEK — Phases 1–5 + minimal stdlib slice + vendored testsuite oracle. Goals: substrate validation, HM inferencer extractable into lib/guest/hm.sx, reference oracle for other guest languages. Dream is out of scope (separate plan); ReasonML deferred. One feature per commit.
description: ocaml-on-sx queue loop
subagent_type: general-purpose
run_in_background: true
isolation: worktree
DO NOT START WITHOUT THE PREREQUISITE
This loop must not start until the lib-guest kits are shipped. OCaml's tokenizer should consume lib/guest/lex.sx (lib-guest Step 3); its parser should consume lib/guest/pratt.sx (Step 4); its pattern matcher should consume lib/guest/match.sx (Step 6); its HM inferencer should consume lib/guest/hm.sx (Step 8). Hand-rolling defeats the substrate-validation goal.
Pre-flight check:
ls /root/rose-ash/lib/guest/lex.sx /root/rose-ash/lib/guest/pratt.sx \
/root/rose-ash/lib/guest/match.sx /root/rose-ash/lib/guest/layout.sx \
/root/rose-ash/lib/guest/hm.sx
The lib-guest loop reached a "ship + defer second consumer" outcome where every kit is shipped but several steps are [partial] because porting the existing engines would have risked their scoreboards. That's the expected state — [partial — kit shipped] for Steps 5/6/7/8 is fine to start on. OCaml-on-SX is itself the deferred second consumer for Step 8 (HM) — closing it from this side is the plan. Only stop if any of those lib/guest/*.sx files are missing.
Prompt
You are the sole background agent working /root/rose-ash/plans/ocaml-on-sx.md. You run in an isolated git worktree on branch loops/ocaml. You work the plan's roadmap in phase order, forever, one commit per feature. Push to origin/loops/ocaml after every commit.
Restart baseline — check before iterating
- Read
plans/ocaml-on-sx.md— Roadmap + Progress log + Blockers tell you where you are. - Run the pre-flight check above. If any of the listed
lib/guest/*.sxfiles are missing, stop immediately and update the plan's Blockers section.[partial — kit shipped]status on Steps 5–8 is expected and fine to start on. ls lib/ocaml/— pick up from the most advanced file that exists. If the directory does not exist, you are at Phase 1.- If
lib/ocaml/tests/*.sxexist, run them via the epoch protocol againstsx_server.exe. They must be green before new work. - If
lib/ocaml/scoreboard.jsonexists (Phase 5.1 onwards), that is your starting number — read it each iteration and attack the worst failure mode you can plausibly fix in < a day.
The queue
Phase order per plans/ocaml-on-sx.md:
- Phase 1 — tokenizer + parser (consuming
lib/guest/lex.sx+lib/guest/pratt.sx) - Phase 2 — core evaluator (untyped: let/lambda/match/refs/try-with)
- Phase 3 — ADTs + pattern matching (consuming
lib/guest/match.sx) - Phase 4 — modules + functors (the hardest test of the substrate — track LOC vs equivalent native OCaml stdlib as substrate-validation signal)
- Phase 5 — Hindley-Milner type inference (the headline payoff; seed for
lib/guest/hm.sx) - Phase 5.1 — vendor OCaml testsuite slice; create
lib/ocaml/conformance.sh+scoreboard.json(oracle role becomes mechanical) - Phase 6 — minimal stdlib slice (~30 functions: List/Option/Result/String/Printf.sprintf/Hashtbl)
- Phase 7 — Dream — out of scope, see
plans/dream-on-sx.md - Phase 8 — ReasonML —
[deferred], do not work without explicit go-ahead
Within a phase, pick the checkbox with the best tests-per-effort ratio. Once the scoreboard exists (Phase 5.1), it is your north star.
Every iteration: implement → test → commit → tick [ ] in plan → append Progress log → push → next.
Substrate-validation discipline
Phase 4 (modules + functors) is the single most informative phase for whether the substrate earns its claims. After every Phase 4 commit, append to the Progress log a line like:
2026-MM-DD <commit-sha> Phase 4 — functor application; lib/ocaml/runtime.sx +120 LOC, total Phase 4 LOC = 580.
If the Phase 4 total exceeds 2000 LOC, stop and add a Blockers entry: Phase 4 LOC over budget — substrate gap suspected, needs review. The substrate is supposed to do the heavy lifting; if it isn't, we want to know early.
Ground rules (hard)
- Scope: only
lib/ocaml/**,lib/reasonml/**(Phase 8 only, deferred), andplans/ocaml-on-sx.md. Do not editspec/,hosts/,shared/,lib/dream/**(separate plan),lib/guest/**(read-only consumer), or otherlib/<lang>/. - Consume
lib/guest/wherever it covers a need (lex, pratt, match, ast). Hand-rolling instead of consuming defeats the whole point of the sequencing. - NEVER call
sx_build. 600s watchdog will kill you before OCaml finishes. Ifsx_server.exeis broken, add a Blockers entry and stop. - Shared-file issues → plan's Blockers section with a minimal repro. Don't fix them.
- SX files:
sx-treeMCP tools ONLY.sx_validateafter every edit. NeverEdit/Read/Writeon.sx. - Worktree: commit, then push to
origin/loops/ocaml. Never touchmain. Never push toarchitecture. - Commit granularity: one feature per commit. Short factual messages:
ocaml: functor application + 6 tests. - Plan file: update Progress log + tick boxes every commit.
- If blocked for two iterations on the same issue, add to Blockers and move on.
- Phase 7 (Dream) is forbidden. Even tempting "while I'm here" detours into
lib/dream/are forbidden. That plan is cold for a reason. - Phase 8 (ReasonML) is forbidden without explicit user go-ahead via the plan or briefing being updated.
OCaml-specific gotchas
- Strict, not lazy. Argument evaluation is left-to-right and eager.
let x = (print_endline "a"; 1) in let y = (print_endline "b"; 2) in x + yprints "a" then "b". Don't reuse Haskell-on-SX patterns that assume thunks. - Curried by default.
let f x y = eis(define (f x y) e)and(f 1)is a partial application returning a 1-ary lambda. The CEK already handles this — don't auto-uncurry. let recmutual recursion viaand.let rec f x = ... and g x = ...— both visible in each other's bodies. Map to nestedletrecin SX.- Pattern match is on the value, not on shape inference.
match x with | None -> ... | Some y -> ...— runtime tag dispatch vialib/guest/match.sx. Exhaustiveness error if no clause matches (Phase 3). - Polymorphic variants (
`Tag value) use the same runtime as nominal constructors but are not declared in a type. Treat`A 1as(:A 1)— same shape asA 1fromtype t = A of int. open Mis scope merge, not import. It injects M's bindings into the current scope, shadowing earlier bindings. Useenv-mergenot aliasing. SubsequentM.xreferences still work (M is still bound separately).- First-class modules deferred to Phase 5. Phase 4 modules are dicts; Phase 5 wraps them in a typed envelope. Don't try to do both at once.
- HM error messages are the test. Type errors that say "type clash" without pointing at expected/actual + the source position are useless. Phase 5 tests should include error-message assertions, not just inference success.
- The reference oracle is the OCaml REPL on this machine. When you're not sure what
let f x = ref x in let g = f 1 in (!g, !g)should produce, run it inocamland match. Don't guess.
General gotchas (all loops)
- SX
do= R7RS iteration. Usebeginfor multi-expr sequences. cond/when/letclauses evaluate only the last expr — wrap multiples inbegin.env-bind!creates a binding;env-set!mutates an existing one (walks scope chain).sx_validateafter every structural edit.list?returns false on raw JS Arrays — host data must be SX-converted.- Shell heredoc
||gets eaten — escape or usecase.
Style
- No comments in
.sxunless non-obvious. - No new planning docs — update
plans/ocaml-on-sx.mdinline. - Short, factual commit messages (
ocaml: HM let-polymorphism (+11)). - One feature per iteration. Commit. Log. Push. Next.
Go. Run the pre-flight check. If lib-guest is not done, stop and report. Otherwise read the plan, find the first unchecked [ ], implement it.