diff --git a/DEV.md b/DEV.md index e76e345..9e7d1ad 100644 --- a/DEV.md +++ b/DEV.md @@ -23,7 +23,7 @@ and [`project.md`](project.md). ## Workspace layout -Six workspace crates (`benches/` exists but is excluded from the workspace — +Seven workspace crates (`benches/` exists but is excluded from the workspace — it depends on the external `execution_tape` crate; see the root `Cargo.toml` comments): @@ -40,6 +40,7 @@ comments): - `fmpl-web/` — Axum server with HTMX frontend, per-user sessions, approval queue, storylet system - `fmpl-tui/` — Ratatui TUI with DAG-based conversation management (Ctrl+L for chat mode) - `fmpl-bootstrap/` — Minimal interpreter for build-time parser generation (avoids circular deps) +- `fmpl-wasm/` — wasm-bindgen bindings for the browser REPL **FMPL standard library** (`lib/`): @@ -85,8 +86,8 @@ comments): ## Documentation map -- `docs/known-gaps.md` — current limitations, grouped by root cause (the ~185 - `#[ignore]`d tests each carry a reason pointing here) +- `docs/known-gaps.md` — current limitations, grouped by root cause (74 + `#[ignore]`d tests; the integration-suite ones carry a reason pointing here) - `docs/design-principles.md` — durable invariants (DESIGN-001…005) - `docs/STANDARDS.md` — documentation standards for design docs, plans, specs - `specs/README.md` — spec index and crate overview diff --git a/README.md b/README.md index cb34792..2e5e133 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,10 @@ that grammar (see [`fmpl.ebnf`](fmpl.ebnf)) seeded this project. The syntax is only lightly similar to the 1992 language, and everything beyond the grammar — the streaming model, first-class PEG grammars, the indexed-RPN VM, capability security, the metacircular bootstrap — is new design. The MUD lineage is -first-hand: Nunley also co-wrote cool++, a C++ rewrite of Stephen White's -CoolMUD (White created MOO, from which LambdaMOO was forked). See -[`project.md`](project.md) for the full north star. +first-hand: Nunley was one of the developers on cool++/coldmud; ColdStore — a +C++ persistent object store and VM toolkit from that era — is the better +reference for what he was doing then. See [`project.md`](project.md) for the +full north star. ## A taste @@ -110,7 +111,8 @@ Source → Lexer (logos) → Parser → AST → Compiler → Indexed RPN bytecod - [Engineering tour](https://mparrett.github.io/fmpl/fmpl-tour.html) — one-page overview: architecture, what works, what doesn't - [Browser REPL](https://mparrett.github.io/fmpl/repl.html) — fmpl-core as WebAssembly, live on GitHub Pages -- Field logs — engineering retrospectives: [revitalizing the agent-written codebase](https://mparrett.github.io/fmpl/fmpl-rehab-log.html) and [closing the metacircular-parser gap](https://mparrett.github.io/fmpl/fmpl-field-log.html) +- Field logs — engineering retrospectives: [Opening the Door](https://mparrett.github.io/fmpl/fmpl-revival-log.html) (revitalizing the agent-written codebase) and [Closing the Loop](https://mparrett.github.io/fmpl/fmpl-field-log.html) (closing the metacircular-parser gap) +- [The Layer Underneath](https://mparrett.github.io/fmpl/fmpl-process.html) — the agent process that wrote FMPL: requirement lattice, hook-enforced state machine, adversarial review, read out of `archive/agent-harness` - [`project.md`](project.md) — north star, principles, design lineage - [`docs/design-principles.md`](docs/design-principles.md) — durable design invariants - [`AGENTS.md`](AGENTS.md) — workflow rules and gotchas for agents and humans diff --git a/docs/fmpl-field-log.html b/docs/fmpl-field-log.html index ec2c267..c061fc7 100644 --- a/docs/fmpl-field-log.html +++ b/docs/fmpl-field-log.html @@ -381,7 +381,7 @@

Closing the Loop, in three moves

§1

The setup

-

After the public-release rehabilitation (the 24-commit sweep reviewed in PR #1 and chronicled in its own field log), the repo had a working build, CI, and an honest ledger of what didn’t work: docs/known-gaps.md, dominated by one bucket of ~120 ignored tests labeled metacircular parser not yet complete. FMPL’s flagship commitment (DESIGN-001) is that the canonical parser is written in FMPL and the Rust parser is stage-0 scaffolding — so this bucket wasn’t a feature gap, it was the language not yet being what it claims to be.

+

After the public-release revitalization (the 24-commit sweep reviewed in PR #1 and chronicled in Opening the Door), the repo had a working build, CI, and an honest ledger of what didn’t work: docs/known-gaps.md, dominated by one bucket of ~120 ignored tests labeled metacircular parser not yet complete. FMPL’s flagship commitment (DESIGN-001) is that the canonical parser is written in FMPL and the Rust parser is stage-0 scaffolding — so this bucket wasn’t a feature gap, it was the language not yet being what it claims to be.

The plan ordered three workstreams deliberately. First a documentation test harness, because the parser work would change language behavior and we wanted the docs to break loudly when it did. Then a WebAssembly build — independent of parser internals, safe to do while thinking. Then the critical path. The sequencing mattered: by the time the grammar changed, every code block in the tutorial was executing in CI and would have caught a regression the unit suite missed.

@@ -477,7 +477,7 @@

Closing the Loop, in three moves

1,398 → 1,519
tests passing, zero failures throughout — every slice landed on a green suite
185 → 74
ignored tests; the metacircular-parser bucket itself went ~120 → 0
6 → 9
parser-generator epoch — three postlude-affecting changes, each with a history entry
-
#5, #6
advisory review PRs, one per phase, each based on the previous phase’s frozen tip
+
advisory PRs
one per phase, each based on the previous phase’s frozen tip — still the house convention
@@ -487,7 +487,7 @@

Closing the Loop, in three moves

diff --git a/docs/fmpl-process.html b/docs/fmpl-process.html new file mode 100644 index 0000000..3933f54 --- /dev/null +++ b/docs/fmpl-process.html @@ -0,0 +1,591 @@ + + + + + +The Layer Underneath: FMPL’s Agent Process + + + + +
+ +
+

Process archaeology · github.com/mparrett/fmpl

+

The Layer Underneath, read out of the archive

+

FMPL’s autonomous loop carried a requirements lattice, a hook-enforced state machine, adversarial review rounds, and an iteration log that recorded its own failures. None of it was legible from the surface of the repo. Here it is.

+
+ 253 commits, 2025-12-21–2026-05-12 + 31 epics / 100 stories / 331 ACs + 88 scenarios + 22 logged iterations + ~30k lines on archive/agent-harness +
+ + +

Diagram from PROMPT.md on the archive branch; block messages from ralph-gate.py at 2a6db48, abridged. A companion to the field logs Opening the Door and Closing the Loop.

+
+ + + +
+
§1

Why this page exists

+
+

Most published writing about autonomous coding agents describes either the prompt or the output. This is the middle: what a loop looks like when someone has been running it long enough to know where it lies to itself. Norman Nunley ran one against FMPL for five months, and the arrangement he assembled to keep it honest is more interesting than most of what gets written about the practice.

+

It reached us as thirty thousand lines to triage before we had read enough to understand them, because that is how a process layer arrives when you fork someone’s solo project — legible to its participants, opaque from outside. Sidelining it to an archive branch was the right call for a repo with different tooling, and it made the layer invisible rather than merely unfamiliar. This page opens it back up.

+

Everything here is quoted from primary sources on archive/agent-harness: the prompt the loop ran under, the hooks that gated it, the requirement documents, the iteration log, the memory store. All of it predates the cleanup this fork performed — the state of the project as its author left it, not as we rearranged it.

+
+
+ +
+
§2

Where the evidence lives

+
+

All of it sits on one branch, archive/agent-harness, at the commit this fork found on arrival. Nothing was deleted to make the main branch legible; the harness was moved intact in a single commit, and the branch is the “before” snapshot. Four bodies of material matter:

+
+ +
+
+
docs/superpowers/
+
The planning layer — 41 files + A roadmap, 31 epic requirement documents, a dated iteration log, a coverage ledger mapping specs to stories, a behavior corpus, and design study notes.
+
+
+
.agent/
+
The memory system — 107 files + Episodic capture, a clustering “dream cycle,” a candidate lifecycle with graduation and rejection, semantic and team memory files, and a review queue.
+
+
+
PROMPT.md
+
The loop contract + A single-iteration headless prompt: state machine, pre-flight context, budget rules, and a one-line output format the driver parses.
+
+
+
.claude/hooks/
+
The enforcement + A PreToolUse gate that blocks tool calls not permitted in the current state, and a PostToolUse transition hook that advances it.
+
+
+ +
+ Field note · adopted and aimed +

Some of this is off-the-shelf and some is written for FMPL. The memory system arrived as an installed stack (agentic_stack_version 0.15.0, 2026-05-09, with adapters for both Claude Code and Codex); the loop driver lives in a ralph-loop/ directory shared across the author’s projects; docs/superpowers/ takes its name from an existing methodology. PROMPT.md, the roadmap, the requirement documents, and the iteration log are this project’s own. Nunley assembled all of it and aimed it at a language implementation for five months, which is the part that produced the artifact.

+
+ +
+ Field note · a caveat about the tip +

Do not expect to open the archive branch and read the hooks. At the tip, ralph.sh and every file under .claude/hooks/ is a symlink into /Users/ndn/development/ralph-loop/ — a path that existed only on the author’s machine. The loop driver was shared across projects and was never repo-resident.

+

The real sources survive earlier in history, before the symlink conversion. git show 2a6db48:.claude/hooks/ralph-gate.py is the full gate; git show 38b551c:.claude/settings.json is the wiring. Every hook quotation on this page comes from those commits.

+
+
+ +
+
§3

The requirement lattice

+
+

The planning layer is a five-level structure, and each level is machine-checkable against the one above it:

+
+ +
EPIC-010  Bootstrap Parity                       31 epic documents
+  └─ STORY-0043  as a language implementor…      100 stories
+       └─ AC-1 … AC-5   impact:correctness       331 acceptance criteria
+                        seam:integration
+            └─ SCENARIO-0030  proof seam,        88 scenarios
+                 preconditions, observables,
+                 execution command
+                 └─ ITER-0001  delivered         22 logged iterations
+ +
+

Two properties make this more than paperwork. First, every acceptance criterion carries an impact and a seam — where the claim must be proven. The distribution is a fair summary of the project’s testing philosophy: 246 integration, 61 unit, 12 app-level, 7 process-level, 5 end-to-end. This is a codebase that decided early that its interesting failures live between components, and staffed its acceptance criteria accordingly.

+

Second, scenarios carry an execution command. A scenario begins life with Automation status: pending and Execution command: TBD, and is “promoted to sentinel” when a real command exists that proves it:

+
+ +
SCENARIO-0030: promoted to sentinel,
+  command = `cargo test -p fmpl-core --test ast_to_ir_parity parity_integer`
+SCENARIO-0031 through SCENARIO-0037: marked BLOCKED:ITER-0002
+ +
+

A blocked scenario names the iteration that will unblock it. The coverage ledger closes the loop in the other direction, classifying each source spec by how much of it has been lifted into stories and scenarios — specs/grammar-system.md at 18 stories and 14 scenarios, specs/vm.md at 15 and 9, each marked covered. Requirements trace down to commands; commands trace back up to specs.

+

The idiom outlived the harness. docs/behavior-scenarios.md on the main branch is a direct descendant, and it is a literal build input: fmpl-core’s build script generates a test suite from it, so moving the file breaks the build rather than silently orphaning the corpus.

+
+
+ +
+
§4

The state machine that couldn’t be skipped

+
+

An LLM told to run tests before committing will usually run tests before committing. Usually is the problem. The loop was configured so that the instruction was not advice: a PreToolUse hook read the current state from .ralph-state.json and returned exit code 2 — a hard block, with the reason fed back to the agent — for any tool call the state did not permit.

+
+ +
+
+
HEALTH_CHECK
+
Only cargo test + The iteration starts by proving the tree is green. Every other tool is blocked until it is.
+
+
+
PICK_TASK
+
Only the issue tracker + jj issue ready, then jj issue show. No reading, no editing, no exploring.
+
+
+
TRIAGE
+
Is this already done? + Tracker and tests only. Three close-and-pick loops maximum, counted in the state file — the fourth jj issue close is blocked, forcing the agent to commit to a task.
+
+
+
IMPLEMENT
+
Write, under two conditions + The first Write is blocked until docs/codebase/ has been read. Unfiltered cargo output is blocked — commands must pipe through grep/head, which is context budgeting enforced at the tool boundary. Re-picking a task is blocked: “you are committed to the current task.”
+
+
+
VERIFY
+
Tests, then edits — not the reverse + Editing is blocked outright unless verification already failed, in which case the same edit demotes the state back to IMPLEMENT. Failure is a transition, not an exception.
+
+
+
REVIEW
+
Review tools only + Diffs, logs, review skills and subagents. An attempted edit here means review found something: the state drops to IMPLEMENT and clears tests_passed, clippy_passed, and health_check_passed. Passing the gates once buys nothing after a change.
+
+
+
COMMIT
+
Green suite or no commit + jj describe is blocked while health_check_passed is false, with an explicit reason: the VERIFY step may have run a filtered subset, so run the full suite now.
+
+
+ +
+

A second arc — RESEARCH → DOCUMENT → COMMIT — handles work that needs discovery first, and gates differently: RESEARCH allows reads and dispatched subagents but blocks Bash outside the issue tracker, and DOCUMENT permits writes only to docs/codebase/ and AGENTS.md. Attempting to write code from either state silently transitions to IMPLEMENT rather than failing, so the machine bends where the work genuinely changed shape and holds where it did not.

+

The details are where the operating experience shows. The gate refuses to read ~/.cargo/registry and points at a documentation tool instead. It refuses cargo doc --open, which does nothing headless. It refuses rustc on a file in /tmp, because a throwaway compile is how a loop convinces itself something works without adding a test. It honors a list of protected files, so edits a human made outside the loop cannot be reverted by it. And it checks whether the process that wrote the state file is still alive — if the driver died, the stale state is ignored rather than blocking an interactive session forever. Each of those is a scar.

+

The prompt carries the same texture: research budget under 40% of context and implementation under 60%; “the issue description IS your research”; a three-strike rule that converts a repeated error into a written spec and a stop; and a flat prohibition on the agent’s own to-do tool, because the issue tracker is the task list and two task lists means neither is true. Each iteration ends by printing exactly one line — COMPLETED:<id> or BLOCKED:<id> — which is what makes the loop a loop.

+
+
+ +
+
§5

PAR: review by adversary

+
+

PAR — parallel adversarial review — is the load-bearing reviewer in this system. Rounds run against a plan or a diff and return a verdict with numbered findings. It is the answer to the question the first field log failed to ask: who reviews a solo agent’s work?

+

ITER-0004c shows it working. Three PAR rounds ran against the iteration’s scope before implementation began and surfaced 26 actionable findings. What they changed:

+
    +
  • An acceptance criterion asserted optimizer behavior that does not exist — the optimizer never recurses into Lambda, Let, Match, Call, List, Map, or Block. Verified against the source and corrected before anything was built against it.
  • +
  • A citation named the wrong optimization pass for the observable being tested.
  • +
  • The build order was rewritten to put cleanup deletions first, shrinking the migration target set before the migration started.
  • +
  • A scope item was split out into its own iteration rather than carried.
  • +
+

Then the harder result. The iteration’s plan called for a code transformer written in FMPL. It was built — grammar plus a Rust driver — and a PAR spec-compliance review failed it: three of six rules were implementable cleanly, and the other three needed left-hand-side context tracking the grammar engine cannot express. The transformer was abandoned, the change dropped, and the work continued by hand. Round one had already flagged hand-migration as viable, so the fallback was on record before the attempt.

+

An adversarial review that only ever approves is a formality. This one killed a piece of finished work on spec-compliance grounds and sent the iteration down its own second-choice path.

+
+
+ +
+
§6

A log that records being wrong

+
+

The iteration log runs to 22 entries across six days, 2026-05-08 to 2026-05-13. Most entries are what you would expect: stories delivered, tasks executed, scenarios promoted, test counts. The interesting one is ITER-0004b, whose heading carries (PARTIAL) and whose dates read completed 2026-05-08; reconciled 2026-05-09.

+

The iteration’s goal was a single canonical representation for structured values. A commit landed claiming “Final step of ITER-0004b.” A day later the reconciliation says why that was false, under its own heading — Why the gap wasn’t caught at commit time:

+
+

The Phase C commit message claims “Final step of ITER-0004b — single canonical representation,” and that claim is true at the Rust runtime level but false at the FMPL stdlib and AST/parser-surface level. The 16 #[ignore]’d tests in optimizer_integration.rs were the canary that should have failed loudly to catch the gap; instead they sit silent. Workspace tests pass because nothing currently exercises a path that would surface the parser-shape mismatch.

+
+

The entry then enumerates exactly what was skipped — a transformer never built, five standard-library files still in the old syntax with per-file counts, an optimizer wiring step passed over, parser surfaces still present — and reschedules all of it into a named successor iteration under a rule the process calls deferring-work-must-reschedule. Three lessons are recorded, including one that reads as a direct rebuke of the commit that caused it: a commit message that says “final step of X” should be checked against X’s stated acceptance criteria.

+

A green test suite said the iteration was done. The requirements lattice said otherwise, someone checked, and the disagreement went into the permanent log rather than getting resolved by moving the goalposts. That is the whole argument for keeping requirements separate from tests: the tests can only tell you about the code you wrote.

+ +
+ Field note · the ignored test as a contract +

The third lesson from that entry is the one worth stealing: #[ignore]’d tests are a deferred-acceptance contract. The 16 silent optimizer tests were the iteration’s own acceptance criteria, written down and then not run. They should be un-ignored by whichever iteration delivers their preconditions, or tracked as scheduled work with an owner.

+

This fork arrived at 185 ignored tests and turned them into docs/known-gaps.md — a ledger grouped by root cause, with each ignore carrying a machine-readable reason. Same idea, reached from the outside.

+
+
+
+ +
+
§7

Memory, and its honest yield

+
+

The most ambitious piece of the harness is the memory system, installed as a versioned stack on 2026-05-09, two days into the documented sprint. Hooks capture episodic entries as the agent works. A “dream cycle” runs unattended: cluster the episodes, extract structured patterns, stage them as candidates with lifecycle metadata, apply a heuristic prefilter that drops obvious junk, decay old entries, and write a review queue for the next session. Its docstring is explicit about the boundaries it will not cross:

+
+

Never: subjective validation (host agent reviews via CLI tools) · promotion to LESSONS.md (graduate.py does that) · git commit (unattended repo writes are dangerous on a host hook).

+
+

A mechanical process stages; a reasoning process judges; neither writes to the repository unattended. That separation is the right one, and it is drawn in code rather than in a README.

+

The yield is smaller than the machinery, though the clock is a fair defense: the stack had four days between installation and the archive tip. In that window it accumulated 1,648 episodic entries, 23 candidates awaiting review, 2 graduated, 9 rejected, and 4 lessons in the semantic store. Read the queue and the reason is plain — the top-priority candidates are mostly failure telemetry (“this skill has failed 10 times in 14 days, flag for rewrite”), which is useful operational signal and not the durable engineering lesson the pipeline was built to distill. One graduated lesson is genuinely good, about enumerating rename targets after a compiler-checked deletion rather than before. The ratio of infrastructure to insight is roughly 107 files to 4 lessons.

+

Two things follow. The first is a caution for anyone reading this as a template: the review queue graduates lessons, not code. It is not a code review mechanism, and reading it as one would put the reviewer in the wrong place entirely — PAR is where code gets adjudicated. The second is chronological. The pre-agentic archive inside .agent/ is dated January 2026 and records a 100-iteration, three-hour loop run against the terminal UI, tasks checked off and 222 tests passing. The commit history agrees: 131 commits in January against 48 in May. The memory stack is a late addition to a loop that had already been running for months.

+
+
+ +
+
§8

What a fork keeps

+
+

This fork sidelined the harness for a reason that has nothing to do with its quality: we drive the repo with different agents on a different loop, and a process encoded for someone else’s tooling sitting where a visitor looks first is misleading in both directions. That decision stands. It also had a cost, and the cost is specific.

+

Invariants the loop enforced in code — full suite green before commit, design docs read before the first write, filtered output — became prose in AGENTS.md that an agent is trusted to remember. Trust is weaker than a hook returning exit code 2. specs/portable-invariant-enforcement.md audits that gap and concludes it is narrower than it first appears: CI and the build script already enforce most of it, and the house idiom for the rest is a repo-resident test that asserts the invariant. Git hooks are rejected as a tier for the same reason they would fail here — this repo is driven with jj, which skips them.

+

What survived the move without argument, because it was portable to begin with: the specs directory and its curated index pairing each spec with the code implementing it; the behavior corpus, now a build input; the habit of an ignored test carrying its reason; and the discipline of a ledger that makes “burn down the bucket” a measurable goal rather than a sentiment.

+
+ +
+
31 / 100 / 331
epic documents, stories, and acceptance criteria — each AC tagged with an impact and the seam where it must be proven
+
88
behavior scenarios, promoted to “sentinel” only when a real execution command proves them
+
22
logged iterations over six days, one carrying a written reconciliation of its own false completion claim
+
3 rounds, 26 findings
PAR scope review on ITER-0004c alone — which then failed and killed the transformer that iteration had built
+
1,648 → 4
episodic entries to graduated lessons in the memory stack’s four days on the project; 23 candidates still queued, 9 rejected
+
253 commits
2025-12-21 to 2026-05-12, of which January alone accounts for 131 — the loop long predates the process stack documenting it
+
+
+ + + +
+ + + diff --git a/docs/fmpl-rehab-log.html b/docs/fmpl-rehab-log.html index e424418..d345d21 100644 --- a/docs/fmpl-rehab-log.html +++ b/docs/fmpl-rehab-log.html @@ -3,482 +3,30 @@ -Revitalizing an Agent-Written Codebase: An FMPL Field Log +Moved — Opening the Door + + - -
- -
-

Engineering field log · github.com/mparrett/fmpl

-

The Revival, Revived, in four tiers

-

Revitalizing an agent-written codebase: 24 commits from a repo that wouldn’t build on a fresh clone to a published fork with CI, executable claims, and an honest ledger of its own gaps.

-
- 2 days, 2026-07-20–21 - 24 commits (PR #1) - 4 tiers - ~30k lines sidelined, 0 deleted - build broken → CI green -
- - -

This log is the prequel to Closing the Loop and the making-of behind the engineering tour. FMPL itself is Norman Nunley’s Rust-built descendant of a 1992 MUD language; this is the log of reviving his revival.

-
- - - -
-
§1

What the machine left behind

-
-

The repo we inherited was written almost entirely by an autonomous agent loop — “ralph,” set up and steered by the project’s creator, Norman Nunley, iterating against a roadmap for months. What it produced is genuinely impressive: a working language with a bytecode VM, a PEG grammar engine, an object system, and a parser that generates itself. What it also produced is the sediment of its own process: a 107-file .agent/ memory system, 41 files of “superpowers” process documentation, ralph driver scripts, run logs, a bespoke .git-issue/ tracker, and prompt files — roughly 30,000 lines of machinery about building the thing, interleaved with the thing.

-

And the repo did not build. Not subtly: cargo build failed at manifest resolution, before compiling a line, because one workspace member had a path dependency on execution_tape — a “verified bytecode VM” crate that existed on exactly one machine, and this wasn’t it. Cargo resolves every member’s manifest before building any of them, so the missing path failed everything, including cargo build -p fmpl-cli. The agent never noticed because the agent never had to do a fresh clone.

-

The first day was recon before surgery: a static read plus live runs of the REPL, TUI, and web app, written up as findings before any code changed. That ordering was deliberate. With an inherited codebase — especially an agent-inherited one — the temptation is to start fixing what you see; the discipline is to first record what is actually true, because you will not get a second chance to observe the artifact undisturbed.

-
-
- -
-
§2

Keep, sideline, delete

-
-

The central judgment call of the whole rehabilitation: what to do with the agent’s machinery. Deleting it would have been clean and irreversible — and wrong twice over. The harness is part of the project’s story (the tour says plainly that the implementation is agent-written), and it may be useful again if an autonomous loop resumes. Keeping it in place was also wrong: a public repo where the first thing a visitor meets is the scaffolding, not the building.

-

The answer was a third category. Everything the agent needed and a human doesn’t was moved — intact, in one commit — to an archive/agent-harness branch. Nothing was deleted; the main branch simply stopped carrying it. The same commit unified the agent’s CLAUDE.md into a single human-and-agent AGENTS.md, later split again into lean workflow rules plus a DEV.md inventory. The test of the triage: months later, nobody has needed anything back from the archive — but it costs nothing to keep, and it makes the history honest.

-
- -
- Field note · nothing is deleted -

“Sideline, don’t delete” became the arc’s standing rule, and it echoes forward: the pre-rehab branch freezes the untouched inherited tip as PR #1’s base, the advisory-PR convention pins every later phase boundary the same way, and the dormant cross_compile feature keeps the execution_tape integration described in comments rather than erased. A revitalization you can diff against its “before” is one you can trust.

-
-
- -
-
§3

Four tiers, one stack

-
-

The work was planned as tiers with a deliberate order — each one meaningless without the one below it — and built as a stack of branches, each on the previous, so the whole thing could be reviewed bottom-up and landed as one fast-forward:

-
- -
-
Tier 0/1
Build hygiene: a fresh clone must build - Drop the phantom execution_tape dependency (the cross_compile feature goes dormant, documented in Cargo.toml comments), untrack build artifacts, add README, LICENSE, a justfile, and a CI workflow. Everything else assumes this floor exists.
-
Tier 2
Sideline the harness - The ~30k-line move to archive/agent-harness (§2). Done early so every later diff is about the language, not the scaffolding.
-
Tier 3
Ergonomics: fix what bites in the first five minutes - Accept if as a guard alias for when (the docs’ own idiom didn’t parse), universal type predicates on every value, a targeted hint when @{…} misroutes, and a DEMO.md sweep against a live REPL.
-
Tier 4
Test quality: make the suite tell the truth - Checked integer arithmetic (overflow is an error, not a process abort), and a reason on every one of ~185 ignored tests — the beginning of the gap ledger (§5).
-
- -
-

The ordering encodes a belief about inherited code: credibility is restored outside-in. A stranger’s first five minutes are clone, build, run an example from the README, hit an edge. Ergonomic polish on a repo that doesn’t build is decoration; deep test work before the harness is sidelined gets tangled in machinery that’s about to move.

-
-
- -
-
§4

First contact with CI

-
-

The repo had never had CI — the agent ran its own checks, on its own machine, in its own environment. The very first CI run failed twice, and both failures were the same lesson wearing different clothes: properties nobody asserts are properties nobody has.

-

The first failure was the determinism check: regenerate the parser twice, byte-compare. The outputs differed every run — grammar rules travel through a HashMap, so each generator process emitted the parser’s functions in a different random order. Rust doesn’t care about definition order, so ~1,390 tests had been green for months over a nondeterministic build. The fix was one sort; the point is that the assertion had existed the whole time as an ignored test nobody ran.

-

The second was humbler: CI installs the latest stable toolchain, and its clippy was newer than the local one, with new lints. A locally-clean build is only evidence about the local toolchain. That became a standing rule in AGENTS.md — keep local Rust current, because a clean local clippy is not proof of a green CI.

-

A third repair completed the set: the checked-arithmetic work from Tier 4 had moved a panic rather than removing it — the generated parser’s digit-fold actions were emitted with .unwrap() on the newly-fallible ops. Threading Result through generated grammar actions (and rejecting the tempting catch_unwind shortcut, which would have poisoned VM mutexes) is the change that started the parser-generator epoch history at 6 — the same counter the next arc drove to 9.

-
-
- -
-
§5

The ledger is born

-
-

The suite we inherited had ~185 ignored tests with no stated reasons — indistinguishable from neglect, and unusable as a map. The Tier 4 pass read every one, grouped them by root cause, wrote a machine-readable reason into each #[ignore], and distilled the result into docs/known-gaps.md: metacircular parser (~120), pattern matching (~50), pending design decisions, odds and ends.

-

This was the quiet keystone of the whole revitalization. An agent-written test suite encodes months of intent — tests written ahead of features, aspirational behavior pinned before it exists — but intent you can’t read is indistinguishable from cruft. Turning the ignore pile into a ledger did two things: it made the repo honest to visitors (the count reads as roadmap, not rot), and it made progress measurable. The payoff came fast: the next arc picked the ~120 bucket off the top of the ledger, burned it to zero in two days, and could prove it — because the ledger defined what zero meant.

-
-
- -
-
§6

Going public

-
-

Publishing had its own fork points. The upstream repo wasn’t pushable (403 — no access), which settled the topology: a fork carries the work, upstream remains the lineage. The rehabilitated history needed to be reviewable without being mergeable — the fork’s main already contained everything — which produced the advisory-PR convention: freeze a pre-rehab branch at the inherited tip, open a PR from main against it, mark it review-only, close it when read. The frozen base is the “before” snapshot; merging would destroy it. That convention outlived the rehab — every phase since gets an advisory PR based on the previous phase’s frozen tip.

-

The last mile was the engineering tour: a single page that says what the thing is, what provably works, and what honestly doesn’t — every claim in it verified against a fresh REPL, like the TUTORIAL sweep before it. GitHub Pages hosting came with one classic paper cut: Jekyll choked on the design docs, so .nojekyll ships in docs/. (Pages later moved to Actions-based deploys in the wasm arc; the file remains as a fossil of this one.)

-
- -
-
FORK-1Sideline the harness, or delete it
-
Sidelined to an archive branch, zero lines deleted. The harness is provenance, not garbage — and reversibility was the theme of the whole arc.
-
FORK-2Vendor the phantom crate, or go dormant
-
execution_tape could have been vendored to keep cross_compile alive. Dormancy won: a fresh clone must build with zero external state, and the feature’s seam is documented for whenever the crate returns.
-
FORK-3Fix the suite, or make it legible
-
Tier 4 deliberately did not try to make ignored tests pass. It made them mean something — the fixing came two arcs later, guided by exactly that legibility.
-
FORK-4Review PR, or merge PR
-
A merge PR was impossible (main already had the work) and an upstream PR premature. The review-only PR against a frozen base got the visibility without the fiction — and became the house convention.
-
-
- -
-
§7

What carried forward

-
-

Revitalizing an agent-written codebase turned out to differ from ordinary legacy work in one repeated way: the artifact is strong where humans are weak, and weak where humans are strong. The agent never got tired, so the language core is deep and the test suite vast. The agent never changed machines, so the build was broken for everyone else on earth. It never had a reviewer, so nothing distinguished roadmap from rot. Every tier addressed some version of that asymmetry — and the fixes were mostly social artifacts, not code: a README, a ledger, a review convention, an archive, CI as an outside observer.

-

What the later arcs inherited from this one: a build a stranger can run, a ledger that made “burn down the bucket” a measurable goal, an advisory-PR convention still in use at #5 and #6, the epoch discipline for generated-parser changes, and the habit — docs verified against a live REPL — that grew into the doctest harness in the very next phase.

-
- -
-
broken → green
fresh-clone build; CI added and passing from the second run onward
-
~30,000 → 0 lines
agent machinery on main — moved to archive/agent-harness, none deleted
-
185 unexplained → 185 cataloged
ignored tests, each with a reason, grouped by root cause in known-gaps.md
-
0 → 3
published surfaces: repo, engineering tour, review PR — the browser REPL followed one arc later
-
-
- - - -
- +
+

This field log is now “Opening the Door,” at fmpl-revival-log.html.

+

Redirecting…

+
diff --git a/docs/fmpl-revival-log.html b/docs/fmpl-revival-log.html new file mode 100644 index 0000000..a1ebd64 --- /dev/null +++ b/docs/fmpl-revival-log.html @@ -0,0 +1,492 @@ + + + + + +Opening the Door: An FMPL Field Log + + + + +
+ +
+

Engineering field log · github.com/mparrett/fmpl

+

Opening the Door, in four tiers

+

Revitalizing an agent-written codebase: 24 commits from a repo that wouldn’t build on a fresh clone to a published fork with CI, executable claims, and an honest ledger of its own gaps.

+
+ 2 days, 2026-07-20–21 + 24 commits (PR #1) + 4 tiers + ~30k lines sidelined, 0 deleted + build broken → CI green +
+ + +

This log is the prequel to Closing the Loop and the making-of behind the engineering tour. FMPL itself is Norman Nunley’s Rust-built descendant of a 1992 MUD language; this is the log of preparing it for readers other than its author.

+
+ + + +
+
§1

What a fresh clone met

+
+

FMPL is Norman Nunley’s project, and most of its implementation was written by an autonomous agent loop — “ralph” — that he set up and steered against a roadmap for months. What that produced is genuinely impressive: a working language with a bytecode VM, a PEG grammar engine, an object system, and a parser that generates itself. It arrived with its development process attached, in the tree: a 107-file .agent/ memory system, 41 files under docs/superpowers/ (a roadmap, 31 EPIC requirement documents, a dated iteration log, a coverage ledger, a behavior corpus), ralph driver scripts and run logs, a bespoke .git-issue/ tracker, and the prompt files that drove the loop. Roughly 30,000 lines — a real process, written down in the shape its tooling wanted, living beside the language it built.

+

And a fresh clone did not build. Not subtly: cargo build failed at manifest resolution, before compiling a line, because one workspace member had a path dependency on execution_tape — a “verified bytecode VM” crate developed alongside FMPL but outside the repo. Cargo resolves every member’s manifest before building any of them, so the missing path failed everything, including cargo build -p fmpl-cli. Nothing in the loop’s environment could have surfaced this: the crate was there, so the build was green every time it ran. A project with one machine can be correct on that machine indefinitely.

+

The first day was recon before surgery: a static read plus live runs of the REPL, TUI, and web app, written up as findings before any code changed. That ordering was deliberate. Arriving at someone else’s working project, the temptation is to start fixing what you see; the discipline is to first record what is actually true — partly because you get one chance to observe the repo undisturbed, and partly because a fair amount of what looks like a defect from outside is a decision you haven’t read yet. We held to the first half of that better than the second (§7).

+
+
+ +
+
§2

Keep, sideline, delete

+
+

The central judgment call of the whole arc: what to do with the development harness. Deleting it would have been clean, irreversible, and wrong — it is how the project was actually built, and it may build it again. Keeping it on main was wrong for a narrower and more specific reason: our tooling is not ralph. We drive this repo with different agents on a different loop, so the harness’s memory system, hooks, and state machine encoded a process we would not be following — sitting in the place a visitor looks first.

+

So the answer was a third category. Everything specific to the ralph loop was moved — intact, in one commit — to an archive/agent-harness branch. Nothing was deleted; the main branch simply stopped carrying it. The same commit unified the agent’s CLAUDE.md into a single human-and-agent AGENTS.md, later split again into lean workflow rules plus a DEV.md inventory. What stayed on main is the part of the process that outlives the tooling change: specs/, the curated index that pairs each spec with the code implementing it, and docs/behavior-scenarios.md, which is a literal build input. Two days on, nobody has needed the process machinery back from the archive — though agent-era feature work off the same lineage (the ITER-0005 persistence arc — durable TupleSpace, content-addressed recovery, bytecode persistence — on branches this fork predated) was since grafted onto main and now underpins active design. The scaffolding was disposable; the code beneath it was not. Keeping the archive costs nothing, and it keeps the history honest.

+
+ +
+ Field note · nothing is deleted +

“Sideline, don’t delete” became the arc’s standing rule, and it echoes forward: the pre-rehab branch (named before this rename) freezes the untouched upstream tip as PR #1’s base, the advisory-PR convention pins every later phase boundary the same way, and the dormant cross_compile feature keeps the execution_tape integration described in comments rather than erased. A revitalization you can diff against its “before” is one you can trust.

+
+
+ +
+
§3

Four tiers, one stack

+
+

The work was planned as tiers with a deliberate order — each one meaningless without the one below it — and built as a stack of branches, each on the previous, so the whole thing could be reviewed bottom-up and landed as one fast-forward:

+
+ +
+
Tier 0/1
Build hygiene: a fresh clone must build + Drop the phantom execution_tape dependency (the cross_compile feature goes dormant, documented in Cargo.toml comments), untrack build artifacts, add README, LICENSE, a justfile, and a CI workflow. Everything else assumes this floor exists.
+
Tier 2
Sideline the harness + The ~30k-line move to archive/agent-harness (§2). Done early so every later diff is about the language, not the harness.
+
Tier 3
Ergonomics: fix what bites in the first five minutes + Accept if as a guard alias for when (the docs’ own idiom didn’t parse), universal type predicates on every value, a targeted hint when @{…} misroutes, and a DEMO.md sweep against a live REPL.
+
Tier 4
Test quality: make the suite tell the truth + Checked integer arithmetic (overflow is an error, not a process abort), and a reason on every one of ~185 ignored tests — the beginning of the gap ledger (§5).
+
+ +
+

The ordering encodes a belief about arriving at someone else’s code: credibility is restored outside-in. A stranger’s first five minutes are clone, build, run an example from the README, hit an edge. Ergonomic polish on a repo that doesn’t build is decoration; deep test work before the harness is sidelined gets tangled in files that are about to move.

+
+
+ +
+
§4

First contact with CI

+
+

The repo had never had CI; the loop ran its checks locally, which is what a solo project does right up until someone else needs to run them. The first CI contact taught the same lesson twice in quick succession: properties nobody asserts are properties nobody has.

+

The first failure was the determinism check: regenerate the parser twice, byte-compare. The outputs differed every run — grammar rules travel through a HashMap, so each generator process emitted the parser’s functions in a different random order. Rust doesn’t care about definition order, so ~1,390 tests had been green for months over a nondeterministic build. The fix was one sort. The part worth keeping is that the assertion already existed, as an ignored test: the property had been identified and written down long before anything was in a position to check it. CI didn’t find a blind spot — it was the first machine other than the author’s to run the check, which is the only thing the check had ever been missing.

+

The second was humbler: CI installs the latest stable toolchain, and its clippy was newer than the local one, with new lints. A locally-clean build is only evidence about the local toolchain. That became a standing rule in AGENTS.md — keep local Rust current, because a clean local clippy is not proof of a green CI.

+

A follow-up repair completed the set: the checked-arithmetic work from Tier 4 had moved a panic rather than removing it — the generated parser’s digit-fold actions were emitted with .unwrap() on the newly-fallible ops. Threading Result through generated grammar actions (and rejecting the tempting catch_unwind shortcut, which would have poisoned VM mutexes) is the change that started the parser-generator epoch history at 6 — the same counter the next arc drove to 9.

+
+
+ +
+
§5

The ledger is born

+
+

The suite carried ~185 ignored tests, and none of the #[ignore] attributes said why. The reasons were not missing, though — they were one system over, in the iteration log, where ITER-0000 records that “22 full-pipeline tests remain ignored — these are the bootstrap bottleneck that ITER-0002/0003 will address.” That is a stated reason. It just lived in the process layer, which is exactly the layer §2 had moved off main. The Tier 4 pass read every ignore, grouped them by root cause, wrote a machine-readable reason into the attribute itself, and distilled the result into docs/known-gaps.md: metacircular parser (~120), pattern matching (~50), pending design decisions, odds and ends.

+

This was the quiet keystone of the whole revitalization, and it is better described as a relocation than a discovery: intent moved from the process docs into the code, where it survives a change of tooling. A suite written ahead of its features encodes months of planning, but planning a reader can’t reach from the test is planning they will misread as abandonment — we nearly did. Putting the reason inside the #[ignore] did two things: it made the count legible to a visitor as a roadmap, and it made progress measurable. The payoff came fast: the next arc picked the ~120 bucket off the top of the ledger, burned it to zero in two days, and could prove it — because the ledger defined what zero meant.

+
+
+ +
+
§6

Going public

+
+

Publishing had its own fork points. The upstream repo wasn’t pushable (403 — no access), which settled the topology: a fork carries the work, upstream remains the lineage. The revitalized history needed to be reviewable without being mergeable — the fork’s main already contained everything — which produced the advisory-PR convention: freeze a pre-rehab branch at the upstream tip, open a PR from main against it, mark it review-only, close it when read. The frozen base is the “before” snapshot; merging would destroy it. That convention outlived this arc — every phase since gets an advisory PR based on the previous phase’s frozen tip.

+

The last mile was the engineering tour: a single page that says what the thing is, what provably works, and what honestly doesn’t — every claim in it verified against a fresh REPL, like the TUTORIAL sweep before it. GitHub Pages hosting came with one classic paper cut: Jekyll choked on the design docs, so .nojekyll ships in docs/. (Pages later moved to Actions-based deploys in the wasm arc; the file remains as a fossil of this one.)

+
+ +
+
FORK-1Sideline the harness, or delete it
+
Sidelined to an archive branch, zero lines deleted. It is how the project was built and may build it again; ours is simply a different loop. Reversibility was the theme of the whole arc.
+
FORK-2Vendor the phantom crate, or go dormant
+
execution_tape could have been vendored to keep cross_compile alive. Dormancy won: a fresh clone must build with zero external state, and the feature’s seam is documented for whenever the crate returns.
+
FORK-3Fix the suite, or make it legible
+
Tier 4 deliberately did not try to make ignored tests pass. It made them mean something — the fixing came two arcs later, guided by exactly that legibility.
+
FORK-4Review PR, or merge PR
+
A merge PR was impossible (main already had the work) and an upstream PR premature. The review-only PR against a frozen base got the visibility without the fiction — and became the house convention.
+
+
+ +
+
§7

What carried forward

+
+

Joining an agent-built solo project turned out to differ from ordinary legacy work in one repeated way: almost nothing we fixed was a quality problem. It was the absence of an independent second party. The loop never got tired, so the language core is deep and the suite is vast. It also never changed machines, so a dependency living outside the repo stayed invisible; never opened a pull request, so a nondeterministic build had nobody to fail in front of; and kept its review and roadmap inside its own process layer — PAR adversarial audits, an iteration log, a behavior-scenario corpus — so to an outside reader who never opened that layer, nothing on the surface distinguished roadmap from rot. Every tier here is a version of adding that second party — and the fixes were mostly social artifacts rather than code: a README, a ledger, a review convention, an archive, CI as an outside observer.

+

What the later arcs kept from this one: a build a stranger can run, a ledger that made “burn down the bucket” a measurable goal, an advisory-PR convention still in use several phases later, the epoch discipline for generated-parser changes, and the habit — docs verified against a live REPL — that grew into the doctest harness in the very next phase.

+

One honest caveat for the work that followed: sidelining the harness did not only swap tooling. Several invariants the loop had enforced in code — full suite green before jj describe, design docs read before the first write, filtered cargo output — became prose in AGENTS.md that an agent is merely trusted to remember. That cost is real for forward work; restoring those gates in a form that is not bolted to one machine is sketched in specs/portable-invariant-enforcement.md.

+
+ +
+ Field note · the correction +

Nunley corrected this claim, and the one in §2, on the published draft — by pull request, keeping our structure and changing two sentences. The framing that replaced them, review and roadmap living inside the loop’s own process layer, is his. Thanks for both. That layer is now documented on its own page, read out of the archive branch: The Layer Underneath.

+

An earlier version of this log said the project “never had a reviewer, so nothing distinguished roadmap from rot.” That was wrong, and wrong in the way outsiders usually are. The process layer carried PAR (parallel adversarial review) — documented rounds that returned APPROVE / REVISE with numbered findings — plus a roadmap, 31 EPIC requirement documents, and a dated iteration log. PROMPT.md describes a state machine whose implementation arc runs IMPLEMENT → VERIFY → REVIEW → COMMIT (the research arc is RESEARCH → DOCUMENT → COMMIT, with no REVIEW); a directive early in that prompt sends the loop to study specs/README.md; and specs/ stayed on main as a curated index pairing each spec with the code implementing it.

+

We read the absence of our process as the absence of a process, and we did it while holding the evidence: §2 of this log moved those files with our own hands. The body above is corrected. The note stays, because it is the most generalizable thing in here — when you fork someone’s solo project, the undocumented part is the part that was obvious to its participants, and it is the first thing you will get wrong.

+
+ +
+
broken → green
fresh-clone build; CI added and passing from the second run onward
+
~30,000 → 0 lines
ralph-specific harness on main — moved to archive/agent-harness, none deleted
+
~185 cataloged
ignored tests — reasons moved out of the process docs and into the integration-suite #[ignore] attributes, grouped by root cause in known-gaps.md
+
0 → 3
published surfaces: repo, engineering tour, review PR — the browser REPL followed one arc later
+
+
+ + + +
+ + + diff --git a/docs/fmpl-tour.html b/docs/fmpl-tour.html index f8d253d..b10dbdc 100644 --- a/docs/fmpl-tour.html +++ b/docs/fmpl-tour.html @@ -443,16 +443,16 @@

FMPL, “of Accardi”

§1

Lineage and thesis

The original FMPL (“of Accardi”) came out of UC Berkeley’s Experimental Computing Facility around 1992 — a MUD server language in the LambdaMOO / ColdMUD tradition, with an interpreter written by Jon Blow. Those systems shared a distinctive shape: a live image of prototype-based objects, edited from inside, serving many users at once, persisting across restarts. The program wasn’t a file you ran; it was a world you inhabited.

-

This FMPL is Norman Nunley’s — a descendant of the original, not a restoration of it. The surviving link to the 1992 language is an EBNF grammar Nunley extracted from its sources back in the late 1990s; decades later, that grammar became the seed of this project. The syntax is only lightly similar to the original, and everything beyond the grammar — the streaming model, the PEG grammar system, the indexed-RPN VM, the metacircular bootstrap — is new design. The MUD lineage is first-hand, too: Nunley co-wrote cool++, a C++ rewrite of Stephen White’s CoolMUD (White also created MOO, the server LambdaMOO grew from).

+

This FMPL is Norman Nunley’s — a descendant of the original, not a restoration of it. The surviving link to the 1992 language is an EBNF grammar Nunley extracted from its sources back in the late 1990s; decades later, that grammar became the seed of this project. The syntax is only lightly similar to the original, and everything beyond the grammar — the streaming model, the PEG grammar system, the indexed-RPN VM, the metacircular bootstrap — is new design. The MUD lineage is first-hand, too: Nunley was one of the developers on cool++/coldmud; ColdStore — a C++ persistent object store and VM toolkit from that era — is the better reference for what he was doing then.

The project bets that the MUD shape is the right shape for AI agents. A modern agent system wants exactly what a MUD had: long-lived stateful objects, many concurrent actors (now LLMs as well as humans), capability-scoped access between them, and durable state that survives a crash mid-conversation. FMPL adds the modern half: streaming as a first-class concern, OMeta-style PEG grammars as the universal tool for parsing any stream — text, bytes, or structured values — and an async runtime for tool calls.

-

One more thing worth saying plainly, because it shapes the codebase: most of this implementation was written by an autonomous LLM agent loop that Nunley set up and steered, iterating against a roadmap for months. It was recently rehabilitated for public release in much the same mode it was built — Claude doing the grinding, steered by a couple dozen human prompts over a few hours — the agent harness sidelined to an archive branch (~30,000 lines), a build that works on a fresh clone, CI, and a documentation pass in which every claim in the tutorial was re-verified against a live REPL. The result is unusually honest about itself: the test suite encodes where the language is and, via 74 deliberately-ignored tests, where it is going.

+

One more thing worth saying plainly, because it shapes the codebase: most of this implementation was written by an autonomous LLM agent loop that Nunley set up and steered, iterating against a roadmap for months. It was recently revitalized for public release in much the same mode it was built — Claude doing the grinding, steered by a couple dozen human prompts over a few hours — with the ralph harness sidelined to an archive branch (~30,000 lines, nothing deleted, since this fork runs a different loop), a build that works on a fresh clone, CI, and a documentation pass in which every claim in the tutorial was re-verified against a live REPL. The result is unusually honest about itself: the test suite encodes where the language is and, via 74 deliberately-ignored tests, where it is going.

§2

Architecture

-

FMPL is a Cargo workspace of six crates around one core. The execution pipeline is conventional in outline and unconventional in detail:

+

FMPL is a Cargo workspace of seven crates around one core. The execution pipeline is conventional in outline and unconventional in detail:

-
~50
+
54
Pattern-matching completeness Pattern unification, list-as-stream tree matching, and compilation of specific pattern shapes aren’t wired end-to-end.
-
~9
+
9
Design decisions pending For-loop bodies can’t mutate outer bindings; recursive scoped let and mutable closure capture need a strategy (Y-combinator, let rec, or cells); yield.
-
~5
+
5
Optimizer wiring and web storylets - The FMPL AST optimizer isn’t in the bootstrap compile path; the web REPL’s storylet route is mid-build.
+ The FMPL AST optimizer isn’t in the bootstrap compile path (2); the web REPL’s storylet route is mid-build (3).
+ +
+
6
+
Unbucketed remainder + Five rustdoc ignore-fences plus one unit-test ignore outside the gap buckets above.
@@ -657,14 +662,14 @@

Objects, images, and durable state

just tui # terminal UI (Ctrl+L for LLM chat)
-

Start with the language guide — the web rendering of TUTORIAL.md and DEMO.md, every snippet of which runs as documented, verified line-by-line against the REPL. specs/ holds the implementation specs (VM, grammars, objects, persistence, tuplespace); docs/known-gaps.md is the honest map of the frontier. If you want to contribute, the metacircular-parser bucket is the critical path: pick a file from the ledger, run it with -- --ignored, and land the feature its tests describe.

+

Start with the language guide — the web rendering of TUTORIAL.md and DEMO.md, every snippet of which runs as documented, verified line-by-line against the REPL. specs/ holds the implementation specs (VM, grammars, objects, persistence, tuplespace); docs/known-gaps.md is the honest map of the frontier. If you want to contribute, the pattern-matching bucket is the largest lever: pick a file from the ledger, run it with -- --ignored, and land the feature its tests describe.

diff --git a/docs/index.html b/docs/index.html index 0bd36aa..01285e2 100644 --- a/docs/index.html +++ b/docs/index.html @@ -130,14 +130,18 @@

FMPL, “of Accardi”

try it The browser REPLThe same VM compiled to WebAssembly, rebuilt from source on every deploy. No install. - + field log 1 - The Revival, RevivedRevitalizing an agent-written codebase: from a repo that wouldn’t build to a published fork with CI. + Opening the DoorRevitalizing an agent-written codebase: from a repo that wouldn’t build to a published fork with CI. field log 2 Closing the LoopHow the metacircular-parser ledger went to zero — five stacked bugs behind one error message. + + how it was built + The Layer UnderneathThe agent process that wrote FMPL — requirement lattice, hook-enforced state machine, adversarial review — read out of the archive branch. +