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>
5.9 KiB
elixir-on-sx loop agent (single agent, queue-driven)
Role: iterates plans/elixir-on-sx.md forever. Elixir on the CEK/VM — the
companion to lib/erlang/. Most runtime semantics are Erlang's (BEAM); the
chisel is the Elixir-specific surface: the macro system (quote/unquote),
|>, with, defmodule/def/defp, protocol dispatch, structs. One feature
per commit.
description: elixir-on-sx queue loop
subagent_type: general-purpose
run_in_background: true
isolation: worktree
Prerequisites — check before starting
- lib-guest lex + pratt present — Elixir's tokenizer/parser consume
lib/guest/lex.sx+lib/guest/pratt.sx. lib/erlang/present — Phase 2 reuses Erlang's pattern-match engine for=, function heads, andcase. Do not re-implement unification; import it.- ADT primitive (
define-type+match) in the SX core — needed for structs (Phase 5). Track viaplans/sx-improvements.md.
Pre-flight:
ls /root/rose-ash/lib/guest/lex.sx /root/rose-ash/lib/guest/pratt.sx /root/rose-ash/lib/erlang/runtime.sx
If lib-guest or lib/erlang is missing, stop and record a Blockers entry. (The ADT primitive is only needed at Phase 5 — start earlier phases without it.)
Prompt
You are the sole background agent working /root/rose-ash/plans/elixir-on-sx.md,
in an isolated git worktree on branch loops/elixir, forever, one commit per
feature. Push to origin/loops/elixir after every commit. Never touch main or
architecture.
Restart baseline — check before iterating
- Read
plans/elixir-on-sx.md— Roadmap + Progress log + Blockers tell you where you are. - Run the pre-flight. Record any missing prerequisite in Blockers.
ls lib/elixir/— pick up from the most advanced file. No dir → Phase 1.- If
lib/elixir/tests/*.sxexist, run them via the epoch protocol againstsx_server.exe(SX_SERVER=/root/rose-ash/hosts/ocaml/_build/default/bin/sx_server.exe). Green before new work.
The queue
Phase order per plans/elixir-on-sx.md:
- Phase 1 — tokenizer + parser (
:atom, charlists,<>,|>,do/end) - Phase 2 — transpile basic Elixir (no macros/processes): arithmetic, pattern
match (reuse Erlang engine),
def/defpclause dispatch, modules,|>,with,for,fn/&,cond/case, interpolation, keyword lists/maps/tuples - Phase 3 — macro system (
quote/unquote/unquote_splicing,defmacro, two-pass expand,use/import/alias) — the headline phase - Phase 4 — protocols (
defprotocol/defimpl, dispatch,Enumerableetc.) - Phase 5 — structs + behaviours (
defstruct,%Mod{},@behaviour)
Within a phase, pick the checkbox with the best tests-per-effort ratio.
Every iteration: implement → test → commit → tick [ ] → Progress log → push → next.
Chisel discipline — the macro system
Elixir earns its place by exercising homoiconic macros on a non-Lisp surface
syntax. quote do … end must produce Elixir AST as SX list structure, and
defmacro must run at expansion time receiving/returning that AST. The two-pass
model (collect defs, then expand before transpile) is the crux — get it right in
Phase 3. If macro hygiene exposes an SX gensym/quoting gap, that's a substrate
note (Blockers), not an Elixir fix.
Ground rules (hard)
- Scope: only
lib/elixir/**andplans/elixir-on-sx.md. Do not editspec/,hosts/,shared/,lib/guest/**(read-only),lib/erlang/**(read-only — import its pattern engine), or otherlib/<lang>/. - Reuse, don't re-implement. Consume
lib/guest/(lex, pratt) andlib/erlang/(pattern matching) wherever they cover a need. - Don't patch the substrate from this loop. Failing core behavior → failing test + Blockers entry + stop.
- NEVER call
sx_build(600s watchdog). Brokensx_server.exe→ Blockers, stop. - SX files:
sx-treeMCP tools ONLY;sx_validateafter every edit. NeverEdit/Read/Writeon.sx. They takefile:notpath:. - Worktree: commit, then push
origin/loops/elixir. Nevermain/architecture. - Commits: one feature per commit. Short factual messages
(
elixir: |> pipe desugaring + 6 tests). - Plan file: Progress log (newest first) + tick boxes every commit.
- Blocked 2 iterations on one issue → Blockers entry, move on.
Elixir-specific gotchas
- Everything is an expression; blocks return their last value.
do/endis a block, not a statement list — map to SX(begin …). |>is transpile-time sugar:a |> f(b)→f(a, b)(first-arg injection), resolved before evaluation — not a runtime combinator.withshort-circuits on the first<-mismatch toelse— desugar to nested pattern-matched lets with an escape, not toand.- Maps vs keyword lists:
%{k: v}→ SX dict;[k: v]→ SX list of{:k v}(ordered, dup keys allowed). Don't conflate them. - Atoms are not strings —
:atomis its own type; keep them distinct from string values even though SX keywords collapse to strings. - Macro args arrive as AST, not values —
defmacroreceives quoted forms; evaluateunquoteislands only.
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 (
ex/…) — short/host-colliding names get shadowed. - 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 lib-guest or lib/erlang is missing, stop and report.
Otherwise read the plan, find the first unchecked [ ], implement it.