ΦΜΛ


A library that is also an operating system. Documents have margins that run when you read them.

Status

Working. Open source under MIT. The manual and documentation are at oma.ooo.

RoleYearKindTry it
Concept, world and language design, engineering2026Operating system, interactive fictionoma.ooo
3,497lines of Rust, in 10 modules
2dependencies
28commands, every one a word a reader would use

The problem

A command line asks you to learn its words: ls, cd, cat. The files it shows you are inert.

I wanted to find out what a system feels like when it uses the reader's words instead, and when the documents in it are allowed to do things.

What I built

  • A shell in a reader's vocabulary. browse instead of ls, walk instead of cd, inscribe instead of cat >. Rooms are directories, shelves are their contents, the journal is the system log written as prose.
  • Three registers on every document. Φ is where it is, Μ is what it says, Λ is what it does. read shows the text. inspect shows all three.
  • A small language for the margins. Λ has twelve instructions. A document can speak, ask the reader something, create other documents, delete them, and rewrite or erode its own text.
  • A founding collection. The documents on the shelves at first boot are the manual, and each one is also a program: one loses a line every time it is read, one deletes itself after a single reading, one writes the next lesson when you finish it.
  • Two daemons. A librarian tidies and writes to the journal every five minutes. A dreamer reads random fragments once an hour and inscribes new documents, which expire after a day.
  • A second language underneath. A two-dimensional grid language in which the three registers must agree before an instruction runs.

How it is structured

The reader only ever talks to the shell. Everything else is files in rooms.

Rust, with two dependencies (chrono for time, libc for the terminal). One binary, 37 commits.

How a document is stored

A document is an ordinary text file. If it has a margin, the file holds the text, then a line reading --- Λ ---, then the margin. Nothing else: no database, no hidden attributes. You can open any document in another editor and see exactly what it will do.

The Λ language

InstructionWhat it does
sayPrints text, with variables filled in
setSets a variable: to a value, a count of files, the number of times this document has been read, a random line, a random file, or the reader's answer to a question
if, loop whileRun the indented lines below, once or repeatedly
writeAdds a line to a file
inscribeCreates a document from the indented lines below
withdrawDeletes a document
erode selfRemoves lines from this document's own text
mutate selfReplaces words in this document's own text
waitPauses

In the code

From Beach-Bum/OMA-Library-OS, which is public.

shell.rs
library.rs
lambda.rs
grid.rs
daemon.rs
founding.rs
interpreter.py
SPEC.md
Makefile
src/library.rs
/// Document metadata separator
const META_SEPARATOR: &str = "\n--- Λ ---\n";

pub struct Document {
    pub name: String,
    pub mu: String,       // visible text (Μ)
    pub lambda: String,   // executable logic (Λ)
    pub is_process: bool,
}

impl Document {
    pub fn load(path: &Path) -> Option<Self> {
        let content = fs::read_to_string(path).ok()?;
        let name = path.file_name()?.to_string_lossy().to_string();
        let is_process = path.starts_with("east-wing/processes")
            || content.contains(META_SEPARATOR);

        let (mu, lambda) = if let Some(idx) = content.find(META_SEPARATOR) {
            let (m, l) = content.split_at(idx);
            (m.to_string(), l[META_SEPARATOR.len()..].to_string())
        } else {
            (content, String::new())
        };

        Some(Document { name, mu, lambda, is_process })
    }
}

The grid language

Under the readable margin language is a stranger one. A program is a grid of cells that wraps at its edges, and execution moves across it in four directions. Each instruction passes through three stages, one per register: declared, populated, activated. If the registers do not agree, the instruction does not run and the disagreement is written down as a schism, not raised as an error. A cell changes after it has been executed, so no program runs the same way twice.

I wrote it first as a reference interpreter in Python (970 lines) and then ported it to Rust (526 lines). The written specification is in the repository.

How it is built

cargo build --release, then the binary is stripped. The Makefile also cross-compiles for a Raspberry Pi and has a target for a bootable SD card image, so the library can be the only thing a small computer does.

How it is tested

There are no automated tests. The Python reference interpreter is the one cross-check for the grid language: the same program should produce the same log in both.

What it does not do

  • Margins are not confined. A margin's file paths are joined to the library's folder without checking them, so a document could write or delete outside the library. It is safe for documents you wrote yourself; it is not safe to read a stranger's.
  • as-archivist is a word, not a password. It marks intent. It does not check who you are.
  • One reader at a time.

More

Source on GitHub
Open ↗
The manual, at oma.ooo
Open ↗
Project notes on the weblog
Open ↗