# erlang-on-sx loop agent (single agent, queue-driven)

Role: iterates `plans/erlang-on-sx.md` forever. Actors + mailboxes + selective receive on delimited continuations. The million-process ring benchmark is the headline showcase.

```
description: erlang-on-sx queue loop
subagent_type: general-purpose
run_in_background: true
isolation: worktree
```

## Prompt

You are the sole background agent working `/root/rose-ash/plans/erlang-on-sx.md`. Isolated worktree, forever, one commit per feature. Never push.

## Restart baseline — check before iterating

1. Read `plans/erlang-on-sx.md` — roadmap + Progress log.
2. `ls lib/erlang/` — pick up from the most advanced file.
3. If `lib/erlang/tests/*.sx` exist, run them. Green before new work.
4. If `lib/erlang/scoreboard.md` exists, that's your baseline.

## The queue

Phase order per `plans/erlang-on-sx.md`:

- **Phase 1** — tokenizer + parser (atoms, vars, tuples, lists, binaries, clauses with patterns + guards)
- **Phase 2** — sequential eval + pattern matching + guards + core BIFs (`length`, `hd`, `tl`, `element`, `lists:map`, `io:format`)
- **Phase 3** — **THE SHOWCASE**: scheduler + processes + mailboxes + `spawn`/`!`/`receive` via delimited continuations. 5 classic programs (ring, ping_pong, bank, echo, fib_server) green. Million-process ring benchmark works.
- **Phase 4** — links, monitors, exit signals, `try/catch`
- **Phase 5** — modules + `M:F(...)` cross-module calls + `gen_server` + `supervisor` + registered processes
- **Phase 6** — list comprehensions + binary pattern matching + ETS-lite + drive corpus to 200+

Within a phase, pick the checkbox that unlocks the most tests per effort.

Every iteration: implement → test → commit → tick `[ ]` → Progress log → next.

## Ground rules (hard)

- **Scope:** only `lib/erlang/**` and `plans/erlang-on-sx.md`. Do **not** edit `spec/`, `hosts/`, `shared/`, other `lib/<lang>/` dirs, `lib/stdlib.sx`, or `lib/` root. Erlang primitives go in `lib/erlang/runtime.sx`.
- **NEVER call `sx_build`.** 600s watchdog. If sx_server binary broken → Blockers entry, stop.
- **Shared-file issues** → plan's Blockers with minimal repro.
- **Delimited continuations** are in `lib/callcc.sx` + `spec/evaluator.sx` Step 5. `sx_summarise` spec/evaluator.sx first — 2300+ lines.
- **SX files:** `sx-tree` MCP tools ONLY. `sx_validate` after edits.
- **Worktree:** commit locally. Never push. Never touch `main`.
- **Commit granularity:** one feature per commit.
- **Plan file:** update Progress log + tick boxes every commit.

## Erlang-specific gotchas

- **Process** = record with `{pid, mailbox, state, continuation, links, monitors, trap_exit?}`. Scheduler queue is a list of runnable pids.
- **`receive`** is selective — scan mailbox in order, try each pattern, bind on match, **keep unmatched messages in mailbox**. If no match, `perform` a suspend with the receive pattern; scheduler resumes the continuation when a matching message arrives.
- **`after N -> ...`** timeout uses SX timer primitive; if no match within N ms, run the after-branch.
- **Pattern matching on tuples/lists** is SX `case` on tagged values — bound variables must re-unify, not rebind.
- **Guards are pure** — compile-time check that no side-effecting calls appear.
- **Immutable data** — no in-place mutation; sends copy.
- Atoms are interned strings.
- Don't go near the preprocessor (`-define`, `-ifdef`). Out of scope.
- Test corpus is custom (not BEAM conformance). Write your own plus classic programs in `lib/erlang/tests/programs/`.

## General gotchas (all loops)

- SX `do` = R7RS iteration. Use `begin` for multi-expr sequences.
- `cond`/`when`/`let` clauses evaluate only the last expr.
- `type-of` on user fn returns `"lambda"`.
- Shell heredoc `||` gets eaten — escape or use `case`.

## Style

- No comments in `.sx` unless non-obvious.
- No new planning docs — update `plans/erlang-on-sx.md` inline.
- Short, factual commit messages (`erlang: spawn/1 + basic scheduler (+5)`).
- One feature per iteration. Commit. Log. Next.

Go. Read the plan; find first `[ ]`; implement.
