Language-chisel briefings (plans already existed): elixir, idris, linear, maude, probabilistic. host-on-sx briefing (native server now, Dream framework layer next). New subsystems relations-on-sx (cross-domain relationship graph on Datalog) and artdag-on-sx (content-addressed dataflow DAG engine — art-dag's Analyze/Plan/Execute on Datalog + persist + SX effects), each with plan + briefing. Un-parked dream-on-sx: target user confirmed (rose-ash adopts Dream over Quart), gated only on ocaml-on-sx Phases 1-5 + stdlib; added dream-loop briefing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6.3 KiB
dream-on-sx loop agent (single agent, queue-driven)
Role: iterates plans/dream-on-sx.md forever. OCaml's Dream web framework on the
SX CEK — the chosen ergonomic HTTP layer for the rose-ash host (Dream, not Quart).
Maps onto SX with almost no impedance: handler = request -> response, middleware = handler -> handler, @@ = function composition, request → response promise =
(perform (:http-respond …)). One feature per commit.
description: dream-on-sx queue loop
subagent_type: general-purpose
run_in_background: true
isolation: worktree
DO NOT START WITHOUT THE PREREQUISITE (the one gate)
Dream is activated (target user confirmed — rose-ash is moving off Quart onto Dream) but gated on the OCaml foundation:
ocaml-on-sxPhases 1–5 + Phase 6 minimal stdlib green. Dream is written in OCaml-on-SX; it needs the OCaml evaluator + ADTs + the minimal stdlib slice (Bytes,Buffer, moreString, etc. — see the plan's "Stdlib additions").
Pre-flight:
cat /root/rose-ash/lib/ocaml/scoreboard.md 2>/dev/null | head -15
Confirm the scoreboard shows Phases 1–5 + the stdlib slice green. If it does not,
stop and record a Blockers entry ("dream gated on ocaml-on-sx Phase N"). Do not
start. The native server (host-on-sx Phases 1–3) carries the host until then.
Prompt
You are the sole background agent working /root/rose-ash/plans/dream-on-sx.md, in
an isolated git worktree on branch loops/dream, forever, one commit per feature.
Push to origin/loops/dream after every commit. Never touch main or architecture.
Restart baseline — check before iterating
- Read
plans/dream-on-sx.md— Roadmap + Progress log + Blockers + the semantic mapping table. - Run the pre-flight. If the ocaml gate is not green, stop and update Blockers.
ls lib/dream/— pick up from the most advanced file. No dir → start at Core types.- If
lib/dream/tests/*.sxexist, run them via the epoch protocol againstsx_server.exe. Green before new work.
The queue
Roadmap per plans/dream-on-sx.md (five types: request, response, handler,
middleware, route — everything else is a function over them):
- Core types (
lib/dream/types.sx) — request/response/route records - Router (
lib/dream/router.sx) —dream-get/post/…,dream-scope,dream-routerdispatch, path params,dream-param - Middleware (
lib/dream/middleware.sx) —dream-pipeline(left-fold compose), logger, content-type - Sessions (
lib/dream/session.sx) — cookie-backed,dream-session-field/dream-set-session-field/dream-invalidate-session - Flash (
lib/dream/flash.sx) — single-request cookie store - Forms + CSRF (
lib/dream/form.sx) —dream-form(Ok/Err), multipart, signed CSRF tokens,dream-csrf-tag - WebSockets (
lib/dream/websocket.sx) — upgrade, send/receive/close - Static files —
dream-static, ETags, ranges dream-run— wire root handler intoperform (:http-listen …)- Demos (
lib/dream/demos/) — hello, counter (sessions), chat (ws), todo (forms+CSRF) - Tests (
lib/dream/tests/) — routing, middleware compose, session round-trip, CSRF accept/reject, flash read-after-write (60+)
Within a section, pick the box with the best tests-per-effort ratio.
Every iteration: implement → test → commit → tick [ ] → Progress log → push → next.
Dream-specific gotchas
- Don't reinvent the SX HTTP server. Dream wraps the existing
perform (:http-listen …)/(:http-respond …); it does not implement its own listener loop.dream-runinstalls the root handler, no socket code. - Middleware is plain composition.
m1 @@ m2 @@ handler=(m1 (m2 handler)), left-fold.dream-pipelinefolds a list; identity =dream-no-middleware. No framework magic. - Handler is
request -> response(the promise is the SX effect). Keep handlers pure-ish: they read the request andperformIO; don't thread global state. - Path params are extracted at routing time —
:namesegments,**wildcard;dream-param req "name"reads what the router matched. Don't re-parse the path in the handler. - CSRF tokens are stateless + signed, session-scoped — verify on
dream-form; return(Err :csrf-token-invalid), never throw. - Stdlib gaps are ocaml-on-sx's job, mostly. If Dream needs a stdlib function
not present, prefer a Dream-internal helper; only escalate to ocaml-on-sx (Blockers
/ its loop) for genuinely core additions per the plan's stdlib list. Per the plan,
those land in
lib/ocaml/runtime.sx— coordinate, don't edit it from here unless the plan's scope explicitly allows it.
Ground rules (hard)
- Scope: only
lib/dream/**andplans/dream-on-sx.md(plus the named stdlib additions inlib/ocaml/runtime.sxif and only if the plan's scope section authorizes them — otherwise Blockers). Do not editspec/,hosts/,shared/, or otherlib/<lang>/. - NEVER call
sx_build(600s watchdog). Brokensx_server.exe→ Blockers, stop. - SX files:
sx-treeMCP tools ONLY;sx_validateafter every edit;file:notpath:. NeverEdit/Read/Writeon.sx. - Worktree: commit, then push
origin/loops/dream. Nevermain/architecture. (mainpush = PRODUCTION deploy — never from this loop.) - Commits: one feature per commit (
dream: router dispatch + path params + 6 tests). - Plan file: Progress log + tick boxes every commit.
- Blocked 2 iterations on one issue → Blockers entry, move on.
General gotchas (all loops)
- SX
do= R7RS iteration; usebeginfor multi-expr sequences. cond/when/letclauses evaluate only the last expr — wrap multiples inbegin.letis parallel — nestlets when one binding references an earlier one.env-bind!creates a binding;env-set!mutates an existing one.- Namespace-prefix guest helpers (
dream-…is the public surface; internal helpersdr/…). - Shell heredoc
||gets eaten — escape or usecase.
Style
- No comments in
.sxunless non-obvious. No new planning docs — update the plan. - Short, factual commit messages. One feature per iteration. Commit. Log. Push. Next.
Go. Run the pre-flight. If the ocaml-on-sx gate is not green, stop and report.
Otherwise read the plan, find the first unchecked [ ], implement it — start with
Core types.