# Lispex full current documentation This bundle contains the 69 canonical English pages for Lispex v1.20. Individual Markdown pages are available at https://www.lispex.com/v1.20/en/docs/*.md. The concise index is https://www.lispex.com/llms.txt. --- Source: https://www.lispex.com/v1.20/en/docs/introduction.md # Introduction > Meet Lispex through one complete decision rule, then choose a six-step learning path, the Playground, or the precise manuals. Canonical page: https://www.lispex.com/v1.20/en/docs/introduction Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. Lispex is a Lisp for decisions that should be easy to read again. A rule is ordinary text. The same source and input produce the same observable answer, and the result can stay shaped like data instead of disappearing inside an application. ### Start here You do not need to know Lisp or Scheme. If you can recognize a function call and a true-or-false question, the six-step course will take you from your first expression to a complete decision rule. ## See the shape first A Lispex program is built from values and parenthesized forms. In an evaluated form, the first name says what to do and the remaining expressions supply the inputs. ```lispex (+ 2 3) ``` **Result** ```text 5 ``` Nesting reads from the inside out. Below, `define` puts a name on a value, `>=` answers a question, and `if` selects one of two data values. ```lispex (define total 62) (if (>= total 50) '(decision free-shipping) '(decision standard-shipping)) ``` **Result** ```text (decision free-shipping) ``` The leading quote in `'(decision free-shipping)` means “keep this list as data.” Without it, Lispex would try to call a procedure named `decision`. That central distinction, that forms can be executed or preserved as data, is one of the useful ideas you will learn gradually. ## What Lispex is good at Lispex fits rules such as eligibility checks, refund windows, pricing boundaries, routing choices, and repeatable transformations. Its reference runtime relies on deterministic evaluation rules, exact arithmetic where possible, and stable diagnostics. These properties make a rule easier to rerun and compare. Lispex is a dedicated language for deterministic decision logic. It evaluates self-contained rules with no hidden network calls, clocks, random values, or package imports. Your application supplies the input and decides what to do with the returned value. ## Choose your entrance | If you want to… | Go here | | --- | --- | | learn the language in six steps | [Learning Path](/en/docs/learn) | | run code without installing anything | [Playground](/en/play) | | study SICP chapter by chapter by reading, editing, and running code | [Lispex · SICP course](https://sicp.io) | | scan the everyday syntax on one page | [Syntax at a Glance](/en/docs/language-tour) | | install a local runtime | [First Program](/en/docs/getting-started) | | build and run a verified Native artifact | [Run Verified Bytecode](/en/docs/guides/verified-bytecode) | | look up an exact form or procedure | [Syntax Reference](/en/docs/reference/core-forms) or [Procedure Index](/en/docs/reference/procedure-index) | Exact Lispex Images, verified Native bytecode, and Lispex Vouch are real product features, but none is a prerequisite for learning the language. Images carry exact source. Bytecode gives you an explicit local route through a virtual machine. Lispex Vouch checks a recorded decision later. It authenticates who signed a rule, binds your own copy of the source and input, and can require one exact local decision. Learn the language first. Those paths will make more sense afterward. ## Running a rule you do not trust Standard Lispex execution runs trusted source directly in memory. This direct model powers the multi-route tools and the authoring evaluation offered by `lispex mcp serve`. For rules that use a configured resource profile, the downloadable program offers `lispex embed`. It evaluates the decision profile under deterministic CPU fuel and memory values within the host process and produces a portable core record when execution completes. ## A useful promise The manual presents exact product capabilities and verified boundaries. Rust is the reference runtime. Topaz is a companion language and compiler used for a Topaz virtual machine and an AOT toolchain that compiles a rule ahead of time into a standalone program. LIL (Lispex in Lispex) and LIT (Lispex in Topaz) operate as differential verification backends. You can explore these components in [Runtime and Backends](/en/docs/reference/runtime-backends) when deployment or cross-checking matters. ## Words this documentation reuses A handful of words repeat across the manual, the guides, and the release history. You do not need any of them for the course. | Word | What it means | | --- | --- | | evaluator | the program that runs the rule | | tree | the built-in interpreter that reads your source directly | | VM | a virtual machine, a program that runs prepared instructions instead of reading your source | | AOT | ahead-of-time compilation, which turns a rule into a program before anyone runs it | | canonical | written the same way every time, so the same input gives the same bytes | | resource profile | the exact work and memory values assigned to a run | | meter | the counter that measures how much work a run used | | route | one way of running a rule | | route lock | a file that records which route was chosen independently from where that product sits on the machine | | portable core | the record that binds the rule, the input, the limits, and the outcome of one run | | receipt | a written record of what one run or one installation produced | | court | one run of checks gathered into a single verdict | | surface | a place where Lispex is offered, such as Native, npm, the WebAssembly build, or the Playground, while the surface of the language means the part of the language that is covered | | Topaz | A separate language and its compiler. Lispex uses it as a Topaz virtual machine that runs prepared instructions and as an AOT toolchain that compiles a rule ahead of time into a standalone program | | LIL | A Lispex interpreter written in Lispex | | LIT | A Lispex interpreter written in Topaz | | WASM | the WebAssembly build | Ready? Open the [Learning Path](/en/docs/learn), or go straight to the [First Program](/en/docs/getting-started) if you prefer to learn by running code. --- Source: https://www.lispex.com/v1.20/en/docs/learn.md # Learning Path > Learn Lispex in six runnable steps covering a first program, values and procedures, quoted data, conditions, and one complete decision rule. Canonical page: https://www.lispex.com/v1.20/en/docs/learn Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. This course is the shortest complete route from zero Lispex experience to writing and testing a complete decision rule. It has six lessons, and the sidebar walks through them in the order below. Each lesson builds on the previous one, ends with a practical exercise, and tells you when you are ready to move on. ### What you will finish You will run a `.lspx` program, define and call a procedure, and build a data-shaped answer. You will also test the exact boundary of a refund rule and name the engine that produced your answer. No Scheme background, image tooling, backend knowledge, or Vouch setup is required. ## Before you begin Use any modern browser for the Playground. Local installation is optional in the first lesson. When you install, the page gives both npm and Native paths. Every lesson is short, and you can stop after any of them. The course uses one reading rule repeatedly. ```text (operation input1 input2 ...) ``` Parentheses do not mean mysterious Lisp punctuation. They show a form. Most forms call a procedure. Core forms such as `define`, `if`, and `quote` controls evaluation. If the parentheses still feel unfamiliar, spend five minutes with [Reading the Parentheses](/en/docs/learn/reading-parentheses) before Step 1. It has no prerequisites and returns you directly to the first program. ## The six steps ### 1. First Program Run one complete expression in the Playground, save it as a `.lspx` file, and learn how a diagnostic points back to where the unfinished form begins. [Start the first program →](/en/docs/getting-started) ### 2. Values, Names, and Procedures Read literals, bind names with `define` and `let`, and create a reusable procedure. This lesson turns nested parentheses into a predictable evaluation order. [Learn values and procedures →](/en/docs/learn/values-procedures) ### 3. Code Is Data See why a quoted list and a call share the same shape. Learn why an answer that stays shaped like data is useful in ordinary code. [Read Code Is Data →](/en/docs/learn/code-is-data) ### 4. Data, Conditions, and Decisions Preserve symbols and lists as data, choose with `if` and `cond`, and remember that only `#f` is false. You will return a labelled decision instead of an unexplained boolean. [Learn data and decisions →](/en/docs/learn/data-decisions) ### 5. First Decision Rule Combine the earlier pieces into a refund-window rule. Test day 14, day 15, and an opened item so the boundary is visible rather than assumed. [Build the first decision rule →](/en/docs/guides/first-project) ### 6. Where Your Program Runs Name the engine that has been running everything so far, meet the other three, and see why a missing route stops the run instead of quietly switching to another one. [See where your program runs →](/en/docs/learn/where-your-program-runs) ## Keep this map beside the course [Syntax at a Glance](/en/docs/language-tour) shows literals, calls, bindings, procedures, conditions, quoted data, aggregates, and higher-order procedures on one page. Use it when you recognize a shape but cannot remember its name. The map links into the full manual. It is the last page in the Learn group. Because it is a reference sheet rather than an exercise, nothing on it needs finishing. ## After the course Choose the path that matches your next question. - **Write more Lispex.** Continue with [Source Text and Reader](/en/docs/manual/source-reader), then the language guides. - **Ship a local rule.** Read [Choosing Where to Run](/en/docs/guides/choosing-runtime) and [Downloads](/en/downloads). - **Make source visual and reversible.** Try [Lispex Images](/en/docs/guides/lispex-images). - **Authenticate and recheck a decision.** Enter the advanced [Lispex Vouch overview](/en/docs/vouch). You do not need to read the manual in page-number order after this course. Use the navigation numbers for orientation, then follow the question you actually have. --- Source: https://www.lispex.com/v1.20/en/docs/learn/reading-parentheses.md # Reading the Parentheses > The parentheses are one rule applied everywhere, and once you see the rule the syntax stops being an obstacle. Canonical page: https://www.lispex.com/v1.20/en/docs/learn/reading-parentheses Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. **Result.** Find the first item inside a pair of parentheses, separate it from the pieces that follow, and tell whether the expression is an ordinary call or a special form. **What you need first.** Nothing. This page is for a reader who has never written a program, and for a reader who has written many but bounced off the parentheses. ## One main shape, reused everywhere Most languages have a large syntax. There are function calls, operators with precedence, statements, and blocks, and each has its own shape to memorize. This language reuses one main shape. ```text (operation input1 input2 ...) ``` In an ordinary call, the first item inside a pair of parentheses says what procedure to call. Everything after it supplies the arguments. This reading rule covers most of the expressions you meet first. ```lispex (+ 2 3) ``` Read it aloud as add two and three. It produces `5`. The plus sign is not a special operator sitting between two numbers. It is the first item, the procedure being called. A small set of forms, including `define`, `if`, `quote`, and `lambda`, uses the same parenthesized shape but controls evaluation instead of calling a procedure. For these special forms, the first item names the form and the remaining pieces are the syntax it controls. ## Nesting is the same rule inside itself An inner expression is evaluated first, and its value takes its place. ```lispex (+ 10 (* 2 3)) ``` Read from the inside out. Multiply two and three, giving six. Then add ten and six, giving sixteen. This is why the parentheses look heavy at first and become light later. There is no precedence to remember, and no question of whether multiplication happens before addition. The shape of the parentheses already says the order, unambiguously, every time. ## What you can now read Look at this and, without knowing what any of these names do, say what is being applied to what. ```lispex (define (price-with-fee price fee) (+ price fee)) ``` The outer form is `define`, a special form rather than a procedure call. Its first piece is `(price-with-fee price fee)`, the name being defined together with the names it expects. Its second piece is the body. The body `(+ price fee)` is an ordinary call, so it adds those two values. You just separated a definition into its meaningful pieces before learning every detail of `define`. That is the payoff of a small, repeated shape. ## Try this Read this expression and predict the value before running it. ```lispex (+ 1 (* 2 (+ 3 4))) ```
Show answer Fifteen. Innermost first, add three and four giving seven. Then multiply two and seven giving fourteen. Then add one, giving fifteen. Nothing about operator precedence entered the reasoning, because the parentheses said the order.
## Ready to move on when You can look at an unfamiliar expression, point at the first item inside each pair of parentheses, and say what is being applied to what, even when you do not know what the names mean. Continue to [First Program](/en/docs/getting-started), where you will run this shape before learning its pieces in detail. --- Source: https://www.lispex.com/v1.20/en/docs/getting-started.md # First Program > Run a Lispex program in the Playground or from a `.lspx` file, understand its output, fix one reader error, and add the official editor extension. Canonical page: https://www.lispex.com/v1.20/en/docs/getting-started Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. The fastest way to understand Lispex is to modify a program and watch its value update. Start in the browser. Install a local runtime only when you want to keep a file. ### Step 1 outcome By the end of this lesson, you can run a complete Lispex file, explain its printed result, and recognize a reader diagnostic caused by an unfinished form. ## Run it in the Playground Open the [Playground](/en/play), replace the editor contents with this program, and choose **Run**. ```lispex (define language "Lispex") (list 'hello language (+ 2 3)) ``` **Result** ```text (hello "Lispex" 5) ``` The first form gives the string `"Lispex"` the name `language`. The final form builds a list from a quoted symbol, that string, and the result of `(+ 2 3)`. The Playground prints the value of every top-level expression that produces one or more values. `define` itself produces no printed value. Change `3` to `8` and run again. If the final element becomes `10`, you have completed the browser part of the lesson. ## Keep it as a local file Save the same source as `hello.lspx`. Choose either local product. ```shell npx lispex hello.lspx ``` Or download the Native binary for your platform and run it. ```shell lispex hello.lspx ``` Both commands run the same reference implementation written in Rust. The npm package delivers it through WebAssembly. The Native binary runs it directly. See [Downloads](/en/downloads) for platform-specific installation and checksum steps. That is all a first program needs. Native users who later want a compiled file that comes out the same way every time from the same source can continue to [Run Verified Bytecode](/en/docs/guides/verified-bytecode). The beginner course remains source-first. ## Add editor color, the file icon, and formatting The official extension recognizes `.lspx` files, highlights Lispex syntax, supplies the Lispex file icon for light and dark themes, and formats a document through the installed Native CLI. - [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=studiohaze.lispex) - [Open VSX Registry](https://open-vsx.org/extension/studiohaze/lispex) The exact identifier is `studiohaze.lispex`. Once you install the Native binary, format files with **Format Document** or format-on-save. The extension runs `lispex fmt -`. Set `lispex.format.executable` if the binary is not on `PATH`. The extension does not bundle a runtime, language server, autocomplete, hover types, or editor diagnostics. Formatting is unavailable through npm, the public WebAssembly build, or the Playground. ## Read one diagnostic Now remove the closing parenthesis from the first `define`. ```lispex (define total 10 (+ total 5) ``` The command exits unsuccessfully and reports an `E100` reader diagnostic. The important part is the stage. Lispex could not finish reading one source form, so no expression ran. Restore the `)` after `10` before looking for a runtime problem. Lispex writes diagnostics to standard error, and a failed run returns a non-zero exit status. Later, [Diagnostics](/en/docs/manual/diagnostics) separates reader, normalization, runtime, and resource failures. ## Exercise Change the successful program so it prints this. ```text (hello "Lispex" 12) ```
Show one answer Change the final expression to `(list 'hello language (* 3 4))`. Lispex evaluates the nested call `(* 3 4)` before `list` receives its three values.
## Ready for Step 2? Continue when you can point to the name, the string, the nested call, and the final list in the first program. Next comes [Values, Names, and Procedures](/en/docs/learn/values-procedures). --- Source: https://www.lispex.com/v1.20/en/docs/learn/values-procedures.md # Values, Names, and Procedures > Learn how Lispex reads literals and calls, then bind names with `define` and `let` and create reusable procedures with `lambda`. Canonical page: https://www.lispex.com/v1.20/en/docs/learn/values-procedures Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. Step 1 showed a complete program. This lesson takes apart the small set of shapes inside it. A value is one thing, a name that refers to a value is another, and a procedure call that computes a value is a third. Keeping those three apart is most of the work. ### Step 2 outcome You will be able to read a nested call in evaluation order, define a reusable procedure, create local names with `let`, and predict the final printed value. ## Values can stand alone Numbers, booleans, strings, characters, and quoted data are values. ```lispex 42 #t "Lispex" #\L 'ready ``` To write a single character as a value, put `#\` in front of it. The `#\L` above is one capital L. That is a different kind of value from a string in double quotes. A bare symbol such as `ready` behaves differently. Written without a quote, `ready` is a name that Lispex looks up. Writing `'ready` instead preserves the symbol as data. ## A list in call position asks for work You can read this one by starting at the innermost call and working outward. ```lispex (+ 10 (* 2 3)) ``` First Lispex finds `+`, then evaluates `10`, then evaluates `(* 2 3)` from left to right. The inner call produces `6`, so the outer call becomes the equivalent of `(+ 10 6)`. **Result** ```text 16 ``` Some parenthesized forms are not ordinary calls. `define`, `lambda`, `let`, and `if` control which parts are evaluated and where names are visible. The syntax map calls out each of these forms explicitly. ## Give a value a name `define` creates or updates a top-level binding, meaning a name the rest of the file can use. ```lispex (define fee 3) (+ 20 fee) ``` **Result** ```text 23 ``` The definition itself prints nothing. The final addition prints one value. Reach for `let` when a name is needed only inside one body. ```lispex (let ((base 7)) (* base 2)) ``` **Result** ```text 14 ``` The binding `base` is visible inside the body and disappears afterward. That small scope makes a temporary calculation easier to inspect. ## Create a reusable procedure Function-definition shorthand lets you name both the procedure and its inputs at once. ```lispex (define (price-with-fee price fee) (+ price fee)) (price-with-fee 20 3) ``` **Result** ```text 23 ``` Writing out the equivalent long form makes the procedure value visible. ```lispex (define price-with-fee (lambda (price fee) (+ price fee))) ``` A procedure checks how many arguments it was given. Calling `price-with-fee` with one or three arguments is a runtime error rather than an implicit default. ## Put the pieces together ```lispex (define (price-with-fee price fee) (+ price fee)) (list (price-with-fee 20 3) (let ((base 7)) (* base 2))) ``` **Result** ```text (23 14) ``` Notice the order here. The first list element is computed, then the second. `list` receives the two resulting values and constructs `(23 14)`. ## Exercise Define a procedure named `triple` that multiplies its input by `3`, then return `(12 21)` by calling it twice inside `list`.
Show one answer ```lispex (define (triple n) (* n 3)) (list (triple 4) (triple 7)) ```
## Ready for Step 3? Continue when you can explain why a quoted symbol is data, why `(* 2 3)` runs before the outer addition uses it, and where a `let` name is visible. Next comes [Code Is Data](/en/docs/learn/code-is-data). --- Source: https://www.lispex.com/v1.20/en/docs/learn/code-is-data.md # Code Is Data > A quoted list and a call are the same shape, and understanding that one fact explains most of what makes this family of languages different. Canonical page: https://www.lispex.com/v1.20/en/docs/learn/code-is-data Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. **Result.** Explain why a program in this language is made of the same lists that it manipulates, and why that is useful rather than a curiosity. **What you need first.** [Reading the Parentheses](/en/docs/learn/reading-parentheses). Nothing else. ## The same shape means two things You already know this shape. ```lispex (+ 2 3) ``` When run, it produces five. Now put a quote mark in front of it. ```lispex '(+ 2 3) ``` That returns a list of three items, the symbol `+`, the number two, and the number three. Nothing was added or evaluated. The quote says to treat this as data rather than something to do. The same text is a call or a list, depending only on whether you ask it to run. In most languages, a function call and a list of three items are unrelated concepts that happen to share punctuation. Here, they are one thing seen two ways. ## Why that matters in ordinary code You do not need to write a compiler for this to pay off. It shows up the first time a program returns a decision instead of a number. Say you put a two item list under the name `answer`. Two names pull values back out of a list. `car` returns the first item, and `cdr` returns everything after the first item, still as a list. Neither name tells you what it does, because both came straight from register names on the machine Lisp first ran on. Do not try to decode them. Just learn the two. ```lispex (define answer '(decision allow)) (car (cdr answer)) ``` `cdr` hands back the one item list `(allow)`, and `car` takes the item out of it, so the result is `allow`. The program built a small piece of structured data using the exact notation it is written in, and pulled the piece it needed back out with ordinary list operations. There was no separate syntax for literals, no extra format to convert data into before saving or sending it, and no object model to define first. That is the everyday version of the idea. A program that produces structure creates the same kind of thing it is built from, so the tools for one work on the other. ## Quote, and the family around it Quote has relatives you will meet later. The four marks below are notation, so read them rather than run them. ```text 'x `x ,x ,@xs ``` The first is `quote`, treat as data. The second is `quasiquote`, treat as data but allow holes. The third is `unquote`, which fills a hole with a computed value, and the fourth is `unquote-splicing`, which fills a hole by splicing in a list. They exist so a program can build a structure that is mostly fixed, with a few parts filled in. You do not need them yet. Knowing they exist keeps you from being surprised when a backtick appears that is not a string. ## The honest caveat The famous consequence of code being data is that programs can write programs. That is real, and it is also not what most working code does. Most working code benefits in the smaller way shown above, with uniform notation and one set of tools. Treat the grand version as a door that is open rather than a room you must enter. ## Try this Predict both results before running them. ```lispex (list (+ 1 2) '(+ 1 2)) ```
Show answer `(3 (+ 1 2))`. The first element was evaluated and became three. The second was quoted, so it stayed a three item list. The same text, two outcomes, decided entirely by the quote mark.
## Ready to move on when You can explain what the quote mark does, and give an example of a program returning structured data. You can also explain why using the same notation for data and calls is convenient rather than confusing. Continue to [Data, Conditions, and Decisions](/en/docs/learn/data-decisions), which builds real rules out of exactly these pieces. --- Source: https://www.lispex.com/v1.20/en/docs/learn/data-decisions.md # Data, Conditions, and Decisions > Preserve symbols and lists as data, choose with `if` and `cond`, use short-circuit logic, and return a labelled decision value. Canonical page: https://www.lispex.com/v1.20/en/docs/learn/data-decisions Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. When programs can distinguish code from data and select one result, they perform useful work. Lispex keeps both ideas visible. Quote preserves data, while conditionals decide which expression is evaluated. ### Step 4 outcome You will build a labelled decision, choose among three outcomes with `cond`, and explain why only `#f` counts as false. ## Quote keeps a form as data Without a quote, Lispex treats a non-empty list as something to evaluate. ```lispex (+ 1 2) ``` With a quote, Lispex returns the same shape as data. ```lispex '(+ 1 2) ``` **Result** ```text (+ 1 2) ``` You can also construct a fresh list from evaluated values. ```lispex (list 'decision 'allow) ``` **Result** ```text (decision allow) ``` Use quote for fixed literal data. Use `list` when one or more elements must be computed. ## `if` makes one two-way choice `if` takes a test, a result for true, and a result for false. ```lispex (if (>= 62 50) '(decision free-shipping) '(decision standard-shipping)) ``` Only the selected branch runs. Only `#f` is false. The values `0`, `""`, and `()` are all true values. When you mean “non-empty,” “positive,” or another domain condition, use an explicit predicate, a test that answers true or false. ## `and` and `or` stop early `and` evaluates from left to right and stops on `#f`. `or` stops on its first true value. `not` flips the true or false it is given. Stopping evaluation early makes a compound eligibility test readable. ```lispex (and (<= 9 14) (not #f)) ``` **Result** ```text #t ``` Short-circuiting is part of the evaluation rule. An expression to the right is not evaluated after the result is already known. The value it stopped on is the value you get back. It is not turned into a boolean. ```lispex (or #f 'standard) ``` **Result** ```text standard ``` ## `cond` names several cases ```lispex (define (shipping-decision total member?) (cond ((>= total 50) '(decision free-shipping)) (member? '(decision discounted-shipping)) (else '(decision standard-shipping)))) (shipping-decision 42 #t) ``` **Result** ```text (decision discounted-shipping) ``` The clauses are tested from top to bottom. A high total wins before membership is considered. `else` is the fallback. The labelled list shows a reader what the answer means without requiring them to know the procedure that produced it. ## Inspect a list when you need to For an ordinary list, one that ends with the empty list, `car` returns the first value and `cdr` returns the remaining list. ```lispex (define answer '(decision allow)) (list (car answer) (car (cdr answer))) ``` **Result** ```text (decision allow) ``` Prefer direct construction and predicates in ordinary rules. Manual `car`/`cdr` chains are useful for learning and low-level access, but named helpers often communicate intent better. ## Exercise Write `age-decision` so ages 18 and above return `(decision allow)` and lower ages return `(decision deny under-age)`.
Show one answer ```lispex (define (age-decision age) (if (>= age 18) '(decision allow) '(decision deny under-age))) (age-decision 17) ``` The result is `(decision deny under-age)`.
## Ready for Step 5? Continue when you can explain the difference between `'(decision allow)` and `(decision allow)`, name the three positions in `if`, and say why `0` is not false. Next comes [First Decision Rule](/en/docs/guides/first-project). --- Source: https://www.lispex.com/v1.20/en/docs/guides/first-project.md # First Decision Rule > Combine procedures, conditions, quoted data, and boundary tests into a complete refund-window decision rule. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/first-project Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. This step combines the earlier pieces into one complete rule. The policy is deliberately direct. An unopened item may be refunded through day 14. Build the habit of making both the decision and its boundary visible. ### Step 5 outcome You will write the rule, run one allowed case, test the exact edge and first rejected value, and return a labelled answer that another part of an application can inspect. ## State the inputs before the code The procedure receives two inputs. - `days` is the number of days since delivery. - `opened?` is `#t` when the item has been opened, otherwise `#f`. This lesson assumes the caller already supplied a valid non-negative day count and a boolean. Input validation is a separate decision boundary covered in [Handling Errors Deterministically](/en/docs/guides/errors). ## Write the rule ```lispex (define (refund-decision days opened?) (if (and (<= days 14) (not opened?)) '(decision allow) '(decision deny outside-refund-window))) (refund-decision 9 #f) ``` **Result** ```text (decision allow) ``` Read the test from left to right. `days` must be at most `14`, and `opened?` must be false. `and` stops immediately if the first condition fails. `if` evaluates only the selected quoted decision. The denied label is intentionally conservative. In a real policy you may want separate reasons for “too late” and “already opened.” That is a product choice, not a hidden behavior of Lispex. ## Test the boundary, not just the happy path ```lispex (list (refund-decision 14 #f) (refund-decision 15 #f) (refund-decision 9 #t)) ``` **Result** ```text ((decision allow) (decision deny outside-refund-window) (decision deny outside-refund-window)) ``` | Case | Why it matters | Decision | | --- | --- | --- | | day 14, unopened | the inclusive edge | allow | | day 15, unopened | the first value outside the window | deny | | day 9, opened | the second condition independently fails | deny | If someone later changes `<=` to `<`, the first row changes. A boundary table makes that change reviewable. ## Keep the rule deterministic The rule reads its arguments. The caller calculates `days` from its clock and application state, then passes that value explicitly. Given the same two Lispex values under the same documented runtime values, the rule follows the same evaluation path and produces the same observable result. Lispex makes the computation inspectable. Policy review owns fairness and legal requirements, the input pipeline owns real-world data provenance, and the surrounding application owns the external action. ## Exercise Change the rule so an unopened item is allowed through day 30. Add the two boundary calls that show the last accepted and first rejected values.
Show one answer Change `(<= days 14)` to `(<= days 30)`, then run the two boundary calls. ```lispex (list (refund-decision 30 #f) (refund-decision 31 #f)) ``` The expected result is `((decision allow) (decision deny outside-refund-window))`.
## Ready for Step 6? You can now read calls, define a procedure, preserve a list as data, choose a branch, and test a boundary. The next step is [Where Your Program Runs](/en/docs/learn/where-your-program-runs). You can also branch out from the course here. - Deepen your language knowledge with [Source Text and Reader](/en/docs/manual/source-reader). - Keep the exact record of one run and check it with [Running and Checking Decision Records](/en/docs/guides/decision-rules). - Turn exact source into a reversible visual artifact with [Lispex Images](/en/docs/guides/lispex-images). - When you need to authenticate who signed a rule and re-check it against your own exact request, enter the advanced [Lispex Vouch workflow](/en/docs/vouch). --- Source: https://www.lispex.com/v1.20/en/docs/learn/where-your-program-runs.md # Where Your Program Runs > One program can run on four engines, with a built-in reference route and three explicitly selected Native routes. Canonical page: https://www.lispex.com/v1.20/en/docs/learn/where-your-program-runs Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. **Result.** You will name the four routes, which are the four engines that can run one program. You will explain which one you have been using all along and predict what happens when a requested route is not available. **What you need first.** You should know how to run a `.lspx` file. The [First Program](/en/docs/getting-started) lesson covers that, and nothing on this page requires installing anything new. ## You have been using a route all along Every time you ran a program like this ```sh lispex rule.lspx ``` you used the tree route. This built-in interpreter is written in Rust and reads your source directly. It ships inside the ordinary Lispex product as the default. It serves as the reference for what the language means and implements the complete language profile. ## The four routes The browser Playground, npm package, and downloadable Native program are Lispex products. A route is the engine that runs your program inside a product. The Playground and npm package use the tree route. Native can use all four routes. The same program can run on four engines. 1. **Tree.** The built-in interpreter that reads your source directly and evaluates it. Always present, no setup. 2. **Rust virtual machine.** Also built in. A virtual machine is a program that runs prepared instructions instead of source text. Native builds those instructions from your source, writing them the same way every time, and checks them before running. You ask for this route explicitly with `--engine vm`. Topaz is a separate language from Lispex and has a compiler of its own. The two routes below borrow those tools. A Lispex rule is written out as Topaz and then run or compiled by the Topaz side, so this is borrowing a toolchain rather than mixing the languages. 3. **Topaz virtual machine.** An exact Topaz 5.11 virtual machine installed as a separate macOS ARM64 product. You pass its absolute product location to the Native command. 4. **Ahead-of-time build, or AOT.** An executable built ahead of time from your program, which then needs no source to run. Building one requires the exact installed Topaz compiler and a Rust tool directory. The installed product then runs without any source tree. Every route implements the same Lispex language rather than a separate dialect. These routes are designed to preserve the same meaning. Comparison commands record their observations for one exact request together with the source, input, products, and resource values. ## Two route identity rules Two rules preserve the producer identity of every route result. **Use the exact location.** Execution, inventory, diagnosis, and comparison commands use the external product location you provide. The separate `routes fetch` command acquires one exact official companion, and route selection happens when you supply that installed product. **Preserve the selected engine.** Every run records the requested route in its result or error. A Topaz VM result carries the exact Topaz virtual-machine product identity. Together these rules identify exactly which route produced the answer. ## Checking that routes agree After installing the exact Topaz virtual machine and building a matching ahead-of-time product, Native can run all four routes for one exact request and write one diagnostic receipt, a report file it never writes over an existing file. ```sh lispex compare-routes \ --topaz-vm /absolute/tools/lispex-topaz-vm/product \ --aot-product /absolute/products/rule-aot \ --receipt route-comparison.json \ rule.lspx ``` This command takes both exact external products and reports all four observations. Agreement records the result for that source, input, product set, and resource profile. The receipt names each field directly. ## Try this Suppose a teammate's script requests the Topaz virtual machine route, and the machine it runs on has no Topaz virtual machine installed. Predict what happens before opening the answer.
Show answer The run returns an error naming the missing route and preserves the requested route label. Install the exact companion and pass its location, or change the script to select an installed route.
## Ready to move on when You are ready when you can name the four routes, state which one runs with no setup, and explain both honesty rules in your own words. When you want to choose a route for real work, continue with [Choosing Where to Run](/en/docs/guides/choosing-runtime). When you want to install a companion, follow [Install an Optional Extra Engine](/en/docs/guides/portable-routes). --- Source: https://www.lispex.com/v1.20/en/docs/language-tour.md # Syntax at a Glance > Scan the everyday Lispex syntax on one page, with tiny examples, observed results, and direct links to the full manual. Canonical page: https://www.lispex.com/v1.20/en/docs/language-tour Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. Treat this page as a map. Each card answers “what shape am I looking at?” and links to the page explaining its exact behavior. You do not need to memorize the cards before starting the course. ### Literals and comments **Syntax:** `value ; comment` Numbers, booleans, strings, characters, and quoted symbols evaluate to predictable values. A semicolon starts a line comment. ```lispex (list 42 #t "tea" #\T 'ready) ; the comment is ignored ``` [Read the source and reader manual](/en/docs/manual/source-reader) ### Calls and nesting **Syntax:** `(procedure argument ...)` The first expression selects a procedure. Operator and arguments are evaluated from left to right. A nested call finishes before the outer form uses its value. ```lispex (+ 10 (* 2 3)) ``` [Learn evaluation order](/en/docs/manual/evaluation-order) ### Names and local bindings **Syntax:** `define · let · let* · letrec` Choose `define` for a top-level name, `let` for parallel local inputs, `let*` when a later binding needs an earlier one, and `letrec` for recursive local names. ```lispex (let ((price 20) (fee 3)) (+ price fee)) ``` [Learn bindings and scope](/en/docs/manual/bindings) ### Named procedures and lambda **Syntax:** `(define (name x) body) · (lambda (x) body)` A procedure is a value. Give it a top-level name with definition shorthand or create it inline with `lambda`. ```lispex (define (double n) (* n 2)) (double 6) ``` [Learn procedures and arity](/en/docs/manual/procedures) ### Conditions **Syntax:** `if · cond · case · and · or` `if` chooses between two expressions. `cond` names several tests. `and` and `or` stop as soon as the result is known. Only `#f` is false. ```lispex (if (>= 62 50) 'free 'standard) ``` [Choose a conditional form](/en/docs/manual/conditionals) ### Quoted data and lists **Syntax:** `'datum · (list value ...)` A quote preserves a form as data. The `list` procedure evaluates its inputs and constructs a new proper list. ```lispex (list 'decision 'allow) ``` [Learn data and aggregates](/en/docs/manual/data-types) ### Strings, vectors, and bytes **Syntax:** `"text" · #(value ...) · #u8(byte ...)` Strings hold Unicode text. Vectors store ordered elements you reach by index and are mutable in the current profile. Bytevectors hold bytes from 0 through 255 and remain immutable. Below, `string-length` counts the characters in a string and `vector-ref` takes one element out by a zero based index. ```lispex (list (string-length "Lispex") (vector-ref #(red green blue) 1)) ``` [Open the text and byte reference](/en/docs/reference/string-char-bytevector) ### Recursion and higher-order work **Syntax:** `recur · map · filter · fold · apply` Decompose data structures with a shrinking recursive call, or pass a procedure to `map`, `filter`, and folds. Proper tail calls support loop-shaped recursion. ```lispex (map (lambda (n) (* n 10)) '(1 2 3)) ``` [Build a data pipeline](/en/docs/guides/higher-order) ## Advanced next | Question | Continue with | | --- | --- | | How can closures share a changing binding? | [Bindings, Cells, and Mutation](/en/docs/manual/bindings) and [Closures](/en/docs/guides/closures) | | Why does `1/3` stay exact while `(/ 1.0 3)` is inexact? | [Exact and Inexact Numbers](/en/docs/manual/numbers) | | How can one computation return two results? | [Multiple Values](/en/docs/manual/multiple-values) | | Which recursive calls use constant stack? | [Proper Tail Calls](/en/docs/manual/tail-calls) | | When is an escape continuation appropriate? | [Continuations and dynamic-wind](/en/docs/manual/continuations) | | How are infinite work and huge output stopped? | [Determinism and Resources](/en/docs/manual/determinism-resources) | Consult [Reader Grammar](/en/docs/reference/reader-grammar) and [Core Forms](/en/docs/reference/core-forms) for exact accepted tokens and form shapes. Revisit the [Learning Path](/en/docs/learn) when you want a guided sequence. --- Source: https://www.lispex.com/v1.20/en/docs/guides/recursion.md # Recursion > Express loops as named `let` or mutually recursive procedures whose recursive calls are in documented tail positions. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/recursion Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Express loops as named `let` or mutually recursive procedures whose recursive calls are in documented tail positions. Three words come up throughout this page, so start with those. A **continuation** is the work left to do once the current computation finishes. In `(+ 1 (f x))`, the moment you call `f`, the promise to add 1 on the way back is the continuation. Promises take room while they wait. A **tail position** is a place where no such promise is left. When a call's result becomes the result of the enclosing expression directly, there is nothing to do on the way back, so the current continuation is handed over instead of a new one being stacked. That is why a recursive call in tail position costs no extra room however long it runs. A **named `let`** is a `let` with a name written right after it. That name becomes the name you call to run the loop again. Below, that name is `loop`. ## See it run ```lispex (let loop ((xs (list 1 2 3 4)) (sum 0)) (if (null? xs) sum (loop (cdr xs) (+ sum (car xs))))) ``` **Observed result** ```text 10 ``` `null?` asks whether a list is empty. It is true for the empty list. The same loop can be written with `do`. For each variable, `do` takes a starting value and the value it becomes next, and then a stopping test with the value to hand back when it stops. ```lispex (do ((rest (list 1 2 3 4) (cdr rest)) (sum 0 (+ sum (car rest)))) ((null? rest) sum)) ``` **Observed result** ```text 10 ``` `do` settles into the same loop as a named `let`, so take whichever reads better. Leave out the value after the stopping test and the loop hands nothing back. ## Walk through the pattern 1. **Find the base case.** When `xs` is empty, the answer already sits in `sum`. 2. **Shrink the remaining work.** `(cdr xs)` removes exactly one item, so every finite proper list reaches the base case. 3. **Carry the answer forward.** The next accumulator is computed before `loop`, leaving the recursive call as the final action. ## How to reason about it - Carry accumulators as parameters instead of combining work after the recursive return. - Tail position survives final `if`, `begin`, `and`/`or`, `cond`, `case`, `do`, `call-with-values`, and `apply` paths. - Keep the test input finite and representative, and distinguish continuation depth from runtime cost. ## Check yourself Add `5` to the input list. What result should the program produce, and does the recursive call remain in tail position?
Answer The result is `15`. Only the input data changes, and `loop` is still the selected branch’s final action.
## A common mistake Tail safety does not make an infinite loop terminate or remove resource budgets. ## Keep going The tail-call manual covers converting a non-tail function and which places stay in tail position. Use the procedure reference when choosing a fold instead. [Proper tail calls](/en/docs/manual/tail-calls) · [Higher-order procedures](/en/docs/reference/higher-order-procedures) --- Source: https://www.lispex.com/v1.20/en/docs/guides/closures.md # Closures and Shared Mutable State > A closure captures lexical cells, not frozen value copies, so related procedures can coordinate through one private binding. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/closures Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you A closure captures lexical cells, not frozen value copies, so related procedures can coordinate through one private binding. ## See it run ```lispex (define counter (let ((n 0)) (lambda () (set! n (+ n 1)) n))) (list (counter) (counter)) ``` **Observed result** ```text (1 2) ``` ## Walk through the pattern 1. **Create the private cell.** The enclosing `let` allocates `n` once while constructing `counter`. 2. **Return behavior, not the cell.** The lambda is the only value that can reach that binding after `let` finishes. 3. **Observe shared updates.** Both calls invoke the same closure, so the second call sees the first call’s `set!`. ## How to reason about it - Create the state in an enclosing `let`, return procedures that read or mutate it, and keep the cell unreachable except through those procedures. - Shadowed bindings allocate different cells. `set!` updates the nearest resolved binding. - Top-level redefinition updates the original global cell seen by earlier closures. ## Check yourself Construct `counter-a` and `counter-b` by evaluating the enclosing `let` twice. Does calling `counter-a` change `counter-b`?
Answer No. Each evaluation allocates a different lexical cell. Calls share state only when their closures capture the same cell.
## A common mistake Shared mutation is deterministic here, but it still deserves narrow ownership and explicit tests. ## Keep going Bindings covers the exact cell and shadowing rules. Use the decision-rule guide if state can instead be explicit input. [Bindings and scope](/en/docs/manual/bindings) · [Decision records](/en/docs/guides/decision-rules) --- Source: https://www.lispex.com/v1.20/en/docs/guides/higher-order.md # Working with map, filter, fold, and apply > Build deterministic pipelines from left-to-right collection traversal and keep callback arity and result contexts explicit. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/higher-order Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Build deterministic pipelines from left-to-right collection traversal and keep callback arity and result contexts explicit. ## See it run ```lispex (reduce + 0 (map (lambda (x) (* x x)) (filter odd? (list 1 2 3 4)))) ``` **Observed result** ```text 10 ``` ## Walk through the pattern 1. **Select.** `filter` keeps `1` and `3` because `odd?` is true for them. 2. **Transform.** `map` squares the retained values, producing `(1 9)` in the same order. 3. **Combine.** `reduce` starts at `0` and adds each square, producing `10`. ## How to reason about it - Use `map` for one result per element, `filter` for truth-valued selection, and folds for one accumulated result. - Use `all?` or `any?` when a strict boolean answer can stop the traversal early. - Callbacks execute as guest procedures, so errors, escapes, warnings, and value-context rules remain active. - `string-map` and `vector-map` produce fresh collections, and their `for-each` variants run only for effects and return zero values. - These procedures take one collection, not the multi-list variants some Scheme systems offer. - Use `apply` when a final proper list should become positional arguments. It preserves tail application. ## Check yourself Replace `odd?` with `even?`. What does the same pipeline return?
Answer It keeps `2` and `4`, squares them to `(4 16)`, and returns `20`.
## A common mistake A callback that yields zero or multiple values in a single-value traversal position raises E320. ## Keep going Use the reference for exact callback arities. Use recursion when traversal needs a shape that no maintained combinator expresses clearly. [Higher-order reference](/en/docs/reference/higher-order-procedures) · [Recursion guide](/en/docs/guides/recursion) --- Source: https://www.lispex.com/v1.20/en/docs/guides/multiple-values.md # Producing and Consuming Multiple Values > Use `values` to return a value packet and `call-with-values` to connect that packet to a consumer with matching arity. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/multiple-values Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Use `values` to return a value packet and `call-with-values` to connect that packet to a consumer with matching arity. ## See it run ```lispex (call-with-values (lambda () (values 3 4)) (lambda (a b) (+ (* a a) (* b b)))) ``` **Observed result** ```text 25 ``` ## Walk through the pattern 1. **Produce the packet.** The first lambda returns two values, `3` and `4`, and does not construct a list. 2. **Match the consumer.** The second lambda has two parameters, so its arity matches the packet exactly. 3. **Compute normally.** Inside the consumer, `a` and `b` are ordinary single values and the final arithmetic returns `25`. ## How to reason about it - Place the producer in the dedicated producer context, not in a call operand, test, binding initializer, or the right-hand side of an assignment. - The consumer receives each produced value as one argument and is arity-checked normally. - Use `(values)` deliberately to return zero values in control paths that can discard them. ## Check yourself Replace the consumer with `list`. What result is stored, and why does it differ from the producer packet?
Answer The result is the ordinary list `(3 4)`. `call-with-values` passed two arguments, and `list` deliberately constructed one storable value.
## A common mistake Do not encode semantic multiple values as an ordinary list when the caller expects value arity. ## Keep going The manual defines every value context. Procedure arity explains what happens when the consumer expects the wrong count. [Multiple-value contexts](/en/docs/manual/multiple-values) · [Procedures and arity](/en/docs/manual/procedures) --- Source: https://www.lispex.com/v1.20/en/docs/guides/sicp.md # SICP Study Guide > Select the Lispex SICP profile explicitly in the course site, browser, CLI, or JavaScript, and keep its product and measurement boundaries visible. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/sicp Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. SICP teaches computation through Scheme. Lispex provides a separate SICP profile with the Scheme-compatible surface needed for that study. The ordinary Lispex core profile remains its own runtime product. ### What this page gives you Run one `.scm` exercise through the explicit profile, choose between the course site, CLI, and JavaScript runtime, and read the exact dimensions in the published product measurement. ## Choose how to study 1. Use [sicp.io](https://sicp.io) for a chapter-organized read-edit-run-see loop, Korean lessons, the coverage map, and the browser workbench. 2. Use the [Lispex SICP Playground](https://www.lispex.com/en/play?profile=sicp) for one explicit browser run. The ordinary Playground remains on the core profile. 3. Use `lispex sicp run` for local `.scm` files. Native runs the Rust SICP profile built into its binary. The `lispex@1.20.0` npm CLI uses its separate `@lispex/sicp@1.0.0` Wasm dependency. 4. Use `@lispex/sicp` directly when a Node or browser application needs typed observations and exact execution traces. Install the direct JavaScript API separately when you are not using the `lispex` CLI package. ```sh npm install @lispex/sicp@1.0.0 ``` ## Run one file Select the profile in the command, whether the source comes from a file or standard input. ```sh lispex sicp run exercise.scm cat exercise.scm | lispex sicp run - ``` `lispex run exercise.scm` is rejected. A `.scm` suffix never changes the active profile by itself, and a failed SICP run never falls back to another engine. The CLI prints the stdout and final value needed for a learning loop. Use the JavaScript API when you need structured observations and traces. ## Embed the runtime Node can load the package directly. ```js const { run } = require('@lispex/sicp'); const result = run('(define (square x) (* x x)) (square 12)'); console.log(result); ``` The browser entry point loads the same dedicated runtime. ```js const { createSicpRuntime } = await import('@lispex/sicp/browser'); const runtime = await createSicpRuntime(); const result = runtime.run('(define (square x) (* x x)) (square 12)'); console.log(result); ``` The WebAssembly module has no external imports. It accepts at most 1 MiB of UTF-8 source and applies fixed logical heap, fuel, output, and trace limits. After loading, it executes entirely in memory on the selected engine. The host deployment owns process and network isolation. The result contains a typed `sicp-observation/v1` document and a `lispex-trace/v1` document with limits of 1,024 events and 1 MiB. These are educational execution observations. Native Vouch adds producer authentication, recipient policy, current replay, and the local gate, while the host application owns external action. ## Read the product measurement The machine-readable [SICP measurement claim](/sicp/claim.json) binds the shipped Wasm identity to a versioned representative corpus of 26 fixtures. It separately records four pinned external Scheme-oracle measurements, their disagreements, limits, and exclusions. The measurement unit is the shipped Wasm artifact running the named 26-fixture corpus under the recorded limits. The four oracle records preserve each producer identity and disagreement category. SICP book text and corpus source remain separately licensed content artifacts. ## Keep the profiles separate | | Ordinary Lispex core | Lispex SICP profile | | --- | --- | --- | | Selection | default `lispex run` | explicit `lispex sicp run` or `?profile=sicp` | | Source suffix | `.lspx` | `.scm` | | Purpose | general Lispex programs | SICP study and exercises | | Runtime | Lispex core engine | built-in Rust profile in Native; `@lispex/sicp` Wasm in npm and JavaScript | ## Keep going [Open the SICP course](https://sicp.io) · [Run the SICP Playground](https://www.lispex.com/en/play?profile=sicp) · [Review Current and Deferred Scope](/en/docs/reference/current-scope) --- Source: https://www.lispex.com/v1.20/en/docs/manual/source-reader.md # Source Text, Tokens, and Reader > The reader accepts a pinned UTF-8 S-expression grammar and reports deterministic reader-phase diagnostics before normalization. Canonical page: https://www.lispex.com/v1.20/en/docs/manual/source-reader Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ## When this matters Start here when source text is rejected before evaluation, or when you are unsure whether parentheses describe a call or data. The reader owns spelling and structure, and evaluation has not yet begun. ## See it run ```lispex '(alpha 1 2/3 #u8(4 5)) ``` **Observed result** ```text (alpha 1 2/3 #u8(4 5)) ``` ## Read the example The leading quote keeps the whole form as data. The reader still recognizes a symbol, integer, rational, and bytevector, but none of them is called or computed. Removing the quote would put `alpha` in procedure position. ## How to reason about it - Integer, rational, and real token grammars are disjoint, and leading-zero and non-finite numeric spellings are rejected. - Lists, dotted pairs, vectors, bytevectors, strings, characters, quote, quasiquote, and comments have pinned forms. - Reader failures are E1xx diagnostics with source spans, and invalid UTF-8 is rejected at the invocation boundary. ## Choose quickly | You want | Write | What the reader creates | | --- | --- | --- | | a name | `alpha` | a symbol token that may later be looked up | | text | `"alpha"` | an immutable string | | a proper list as data | `'(alpha 1)` | a quoted pair chain ending in `()` | | a dotted pair as data | `'(alpha . 1)` | one pair whose tail is `1` | | indexed values | `#(1 2)` | a vector | | bytes | `#u8(1 2)` | an immutable bytevector | ## A common mistake Radix and exactness prefixes such as `#x` and `#e` are outside the current profile. ## Current boundaries - The language does not silently normalize newlines, paths, or host encodings. ## Keep going Continue with evaluation order to see what happens after reading, or open Reader Grammar for every accepted token shape. [Evaluation order](/en/docs/manual/evaluation-order) · [Reader Grammar](/en/docs/reference/reader-grammar) --- Source: https://www.lispex.com/v1.20/en/docs/manual/evaluation-order.md # Expressions and Evaluation Order > Evaluation order is observable and fixed. The operator runs first, then the operands left to right, then arity checking and procedure entry. Canonical page: https://www.lispex.com/v1.20/en/docs/manual/evaluation-order Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ## When this matters Evaluation order matters whenever expressions mutate a cell, print output, raise an error, or may be skipped. Lispex fixes the order so the same source never depends on a host language’s operand convention. ## See it run ```lispex (define x 0) (list (begin (set! x 1) x) (begin (set! x (+ x 1)) x)) ``` **Observed result** ```text (1 2) ``` ## Read the example The first `begin` changes `x` from `0` to `1` and returns `1`. Only then does the second operand read that new value, add one, store `2`, and return it. `list` therefore receives `1` followed by `2`. ## How to reason about it - `let` initializers use the enclosing environment left to right. `let*` extends one binding at a time, and `letrec` allocates all cells first. - Sequences evaluate left to right and discard non-final value packets. - `and` and `or` short-circuit left to right, and only `#f` is false. ## Choose quickly | Context | Order | What may be skipped | | --- | --- | --- | | procedure call | operator, then operands left to right | nothing | | `begin` | forms left to right | nothing, and only earlier values are discarded | | `if` | test, then one selected branch | the unselected branch | | `and` / `or` | operands left to right | the remaining operands after the answer is known | | `let` | initializers left to right in the outer scope | nothing | | `let*` | bind and extend after each initializer | nothing | ## A common mistake Lispex does not inherit an unspecified operand order from another Scheme implementation. ## Current boundaries - Arity errors occur after the required operator and operand evaluation has already happened. ## Keep going Bindings explains the different `let` scopes. Conditionals shows which forms deliberately stop early. [Bindings and scope](/en/docs/manual/bindings) · [Conditionals](/en/docs/manual/conditionals) --- Source: https://www.lispex.com/v1.20/en/docs/manual/bindings.md # Bindings, Scope, Cells, and Mutation > Every lexical binding is a mutable cell. Closures capture frames and therefore share later `set!` updates to the same cell. Canonical page: https://www.lispex.com/v1.20/en/docs/manual/bindings Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ## When this matters Use bindings to give a result a name, create a local scope, or deliberately keep state between calls. Most code needs only `define` and `let`. Reach for `set!` only when shared mutation is part of the model. ## See it run ```lispex (define x 1) (define get (lambda () x)) (set! x 2) (get) ``` **Observed result** ```text 2 ``` ## Read the example `get` closes over the global cell named `x`, not a frozen copy of the number `1`. `set!` writes `2` into that same cell, so the later call observes `2`. A new inner `x` would instead shadow the cell. `let*` creates its names one after another from the top, so a later initializer can see the name just created. ```lispex (let* ((x 6) (y (+ x 1))) (* x y)) ``` **Observed result** ```text 42 ``` `letrec` allocates every cell before it evaluates any initializer, which is what lets a name call itself. ```lispex (letrec ((f (lambda (n) (if (= n 0) 1 (* n (f (- n 1))))))) (f 5)) ``` **Observed result** ```text 120 ``` ## How to reason about it - Lookup chooses the nearest lexical cell, and shadowing does not mutate an outer binding. - `letrec` allocates cells before initializers and raises E321 when an uninitialized cell is read. - A duplicate top-level `define` updates the existing global cell, preserving earlier closure references. ## Choose quickly | Form | Use it for | Visibility of initializers | | --- | --- | --- | | `define` | a top-level name or named procedure | current top-level environment | | `let` | independent local values | outer environment | | `let*` | locals that depend on earlier locals | each earlier binding | | `letrec` | mutually recursive local procedures | all allocated cells, though early reads fail | | `set!` | updating an existing cell | no new binding is created | ## A common mistake `set!` on an unbound name is E303. It never creates a binding. ## Current boundaries - The internal marker for an uninitialized cell cannot be represented as a guest value. ## Keep going Procedures shows how closures capture these cells. The closures guide turns that rule into a complete stateful example. [Procedures](/en/docs/manual/procedures) · [Closures guide](/en/docs/guides/closures) --- Source: https://www.lispex.com/v1.20/en/docs/manual/procedures.md # Procedures, Arity, Application, and apply > Fixed and dotted-arity closures use lexical scope, deterministic argument evaluation, and one application dispatcher shared by direct calls and `apply`. Canonical page: https://www.lispex.com/v1.20/en/docs/manual/procedures Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ## When this matters Create a procedure when one transformation has a name or must be passed to another procedure. Named shorthand is easiest to read. `lambda` is useful when the behavior is local. ## See it run ```lispex (define (sum first . rest) (apply + first rest)) (sum 1 2 3 4) ``` **Observed result** ```text 10 ``` ## Read the example `sum` requires at least one argument. `first` receives `1`, while `rest` receives the fresh list `(2 3 4)`. `apply` combines the explicit `first` argument with that list and invokes `+` once. A run of `define` forms at the very start of a procedure body creates names visible only inside that procedure. They can call each other. ```lispex (define (g) (define a 1) (define b 2) (+ a b)) (g) ``` **Observed result** ```text 3 ``` Only the unbroken run at the start is grouped this way. A `define` that comes after some other expression means something different, so keep the definitions together at the top. ## How to reason about it - Arity mismatch is E302 before the procedure body starts. - A dotted rest parameter receives a fresh proper list of remaining arguments. - A `lambda` parameter list has exactly two shapes, `(x ...)` and `(x ... . rest)`. A bare name with no parentheses, as in `(lambda args ...)`, is E130. - `apply` accepts explicit leading arguments plus one final proper list and preserves tail position. ## Choose quickly | Shape | Best use | Arity | | --- | --- | --- | | `(define (f x) body)` | a named reusable procedure | fixed | | `(lambda (x y) body)` | an anonymous procedure value | fixed | | `(define (f . xs) body)` | a named procedure that gathers its arguments | zero or more | | `(lambda (x . rest) body)` | required arguments plus a remainder | at least the fixed prefix | | `(apply f a final-list)` | arguments assembled as data | checked by `f` | ## A common mistake Applying a non-procedure is E301. An improper final `apply` list is a list-domain error. ## Current boundaries - Host `apply` is not used to execute guest closures. ## Keep going Higher-order procedures explains passing behavior to `map`, `filter`, and `fold`. Bindings explains the cells a closure captures. [Higher-order procedures](/en/docs/reference/higher-order-procedures) · [Bindings and scope](/en/docs/manual/bindings) --- Source: https://www.lispex.com/v1.20/en/docs/manual/conditionals.md # Conditionals and Derived Forms > The core of `if`, sequencing, binding, lambda, application, assignment, and quotation receives derived forms rewritten without capturing the names you chose. Canonical page: https://www.lispex.com/v1.20/en/docs/manual/conditionals Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ## When this matters Choose a conditional by the shape of the question. It may be one yes/no test, several predicates, one value compared with fixed datums, or a side effect that should run only in one case. Remember that only `#f` is false. ## See it run ```lispex (case 2 ((1) 'one) ((2) 'two) (else 'other)) ``` **Observed result** ```text two ``` ## Read the example `case` evaluates `2` once, compares it with each listed datum using `eqv?`, and selects the second clause. The quoted symbol `two` is the result, and the `else` clause is not evaluated. `when` runs its body in order only when the test is true and gives back the last value. `unless` does the opposite and runs when the test is false. So `(when #t 42)` is 42 and `(unless #f 7)` is 7. The path the test rules out produces no value at all. `guard` is written `(guard (variable clause ...) body ...)`. When the body raises, the error object is bound to the variable and the clauses are tried in order the way `cond` tries them. A clause head may be `else`. ## How to reason about it - `cond`, `case`, `and`, `or`, `when`, `unless`, `let*`, named `let`, `do`, and quasiquote preserve pinned evaluation and tail positions. - Generated temporary names and hidden built-in operations cannot be captured or shadowed by user names. - `case` compares datums with `eqv?`, and the false paths of `when` and `unless` produce zero values. - `if` needs all three parts. Drop the false arm and write `(if #t 1)` and you get E130. - A `cond` or `case` with no `else` clause produces no value at all when nothing matches. Put that result where a value is required and you get E320. - `else` is not a reserved word. It only means something at the head of a `cond`, `case`, or `guard` clause, so `(define else 5)` is accepted. - The `cond` arrow clause `=>` is not supported and raises E130. The `case` arrow clause has no diagnostic at all, so `=>` reads as a name and raises E300. ## Choose quickly | Form | Use it when | Result behavior | | --- | --- | --- | | `if` | there are exactly two branches | returns the selected branch | | `cond` | different predicates name several cases | returns the first matching clause | | `case` | one value is compared with fixed datums | evaluates the key once | | `and` / `or` | tests form a short-circuit chain | returns an operand value, not a coerced boolean | | `when` / `unless` | a one-sided effect is clearer | false path returns zero values | ## A common mistake There is no `define-syntax` or user macro expansion. ## Current boundaries - Bare `unquote` and `unquote-splicing` outside quasiquote are static errors. ## Keep going The data-and-decisions lesson teaches the everyday forms. Derived Forms gives their exact normalization shapes. [Data and decisions](/en/docs/learn/data-decisions) · [Derived Forms](/en/docs/reference/derived-forms) --- Source: https://www.lispex.com/v1.20/en/docs/manual/data-types.md # Data and Aggregate Types > The value space has booleans, exact and inexact numbers, characters, symbols, strings, pairs, vectors, bytevectors, procedures, and escape continuations. Canonical page: https://www.lispex.com/v1.20/en/docs/manual/data-types Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ## When this matters Choose the value shape that communicates the job directly. Use an atom for one fact, a proper list for sequential data, a vector for indexed mutable slots, or a bytevector for a fixed-length block of bytes. ## See it run ```lispex (list (vector? #(1 2)) (bytevector? #u8(1 2)) (pair? (cons 1 2))) ``` **Observed result** ```text (#t #t #t) ``` ## Read the example The example asks three predicates about three different aggregate values. Each constructor creates the documented kind of value, so the result is a list of three true booleans. `cons` joins two values into one pair. Put a list on the right and the list grows by one, so `(cons 1 (list 2 3))` is `(1 2 3)`. Put anything else there and you get a pair that is not a list, so `(cons 1 2)` is `(1 . 2)`. `pair?` is the question of whether a value is that pair. When the shape is mostly fixed and only a few slots need filling, use quasiquote. Write the template after a backtick and put a comma where a value goes. One comma drops a single value into that slot, and `,@` opens a list out across several slots. ```lispex (define x 7) (define ys (list 2 3)) `(a ,x ,@ys b) ``` **Observed result** ```text (a 7 2 3 b) ``` `,@` only works where list elements go. Alone anywhere else it is E130. ## How to reason about it - Pairs, strings, and bytevectors are immutable in the current profile, while vectors and lexical cells are mutable. - Quoted aggregate data is immutable, and constructors create runtime aggregates with the documented identity rules. - Improper and cyclic structures are distinguished from proper lists, and deep equality terminates on cycles. ## Choose quickly | Value family | Typical spelling | Mutation in the current profile | | --- | --- | --- | | atoms | `#t`, `42`, `2/3`, `name`, `#\\a` | not applicable | | list / pair | `(list 1 2)`, `(cons 1 2)` | immutable | | string | `"hello"` | immutable | | vector | `#(1 2)` or `(vector 1 2)` | mutable slots | | bytevector | `#u8(1 2)` | immutable | | procedure | `(lambda (x) x)` | a callable value whose body is not data | ## A common mistake Complex numbers, ports, records, and mutable pairs or strings are outside the current profile. ## Current boundaries - Internal outcomes, signals, and internal markers for uninitialized cells are not guest values. ## Keep going List and Aggregate Procedures gives constructors and accessors. Equality explains identity versus structural comparison. [List and aggregate procedures](/en/docs/reference/list-aggregate-procedures) · [Equality](/en/docs/manual/equality) --- Source: https://www.lispex.com/v1.20/en/docs/manual/numbers.md # Exact and Inexact Numbers > Lispex has arbitrary-precision exact integers, reduced exact rationals, and finite IEEE-754 reals that always print in the same positional form. Canonical page: https://www.lispex.com/v1.20/en/docs/manual/numbers Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ## When this matters Use exact integers and rationals when the mathematical result must stay exact. Introduce a real only when an inexact measurement or explicitly inexact operation is part of the problem. ## See it run ```lispex (list (/ 1 3) (+ 1 2.0) (number->string -0.0)) ``` **Observed result** ```text (1/3 3.0 "-0.0") ``` ## Read the example `1/3` stays an exact reduced rational. Adding exact `1` to inexact `2.0` produces inexact `3.0`. Rendering preserves the sign of negative zero, so `number->string` returns `"-0.0"`. ## How to reason about it - Exact arithmetic stays exact, while `+ - * /` become inexact if any operand is inexact. Comparisons use exact mixed-number comparison. - No infinity or NaN value can enter the runtime. Division by zero is E313 and non-finite production is E314. - Finite real output is the shortest round-trip form, positional only, with a forced `.0` and preserved `-0.0`. ## Choose quickly | Kind | Examples | Key rule | | --- | --- | --- | | exact integer | `0`, `-12`, `999999999999` | arbitrary precision | | exact rational | `1/3`, `-5/2` | stored reduced with positive denominator | | finite real | `2.0`, `-0.0`, `0.125` | finite IEEE-754, always printed in the same positional form | | mixed arithmetic | `(+ 1 2.0)` | one inexact operand makes arithmetic inexact | | mixed comparison | `(= 2 2.0)` | compared mathematically without lossy coercion | ## A common mistake Complex numbers and platform-libm transcendentals are excluded. ## Current boundaries - Exact/inexact contagion for arithmetic must not be generalized to selection or comparison semantics. ## Keep going Numeric Procedures lists domains and signatures. Equality explains why numeric equality differs from exactness-sensitive equality. [Numeric procedures](/en/docs/reference/numeric-procedures) · [Equality](/en/docs/manual/equality) --- Source: https://www.lispex.com/v1.20/en/docs/manual/equality.md # Equality and Identity > Lispex separates atom/identity equality (`eq?`, `eqv?`), deep structural equality (`equal?`), and numeric equality (`=`). Canonical page: https://www.lispex.com/v1.20/en/docs/manual/equality Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ## When this matters Pick equality by intent, not habit. Use mathematical equality for numbers, identity-style equality for atoms or the same aggregate object, and deep equality for data structures. ## See it run ```lispex (list (= 2 2.0) (eqv? 2 2.0) (equal? (list 1 2) (list 1 2))) ``` **Observed result** ```text (#t #f #t) ``` ## Read the example `=` treats exact `2` and inexact `2.0` as the same mathematical number. `eqv?` preserves the exactness distinction. Two separately constructed lists are not the same object, but `equal?` sees the same contents. ## How to reason about it - `eq?` and `eqv?` agree on atoms in this profile and compare aggregates by identity. - `eqv?` and `equal?` are exactness-sensitive, so exact `2` and inexact `2.0` are different. - `equal?` descends through pairs, vectors, bytevectors, and strings with cycle detection. ## Choose quickly | Predicate | Use it for | Aggregate behavior | | --- | --- | --- | | `=` | numbers with mathematical equality | non-numbers are a domain error | | `eq?` | atoms and object identity | same aggregate object only | | `eqv?` | exactness-sensitive atoms and identity | same aggregate object only | | `equal?` | nested data contents | recursive, cycle-safe structural comparison | | `==` / `!=` | readable structural aliases | `equal?` and its negation | ## A common mistake `=` accepts numbers only. `==` and `!=` are structural aliases. ## Current boundaries - Procedure equality never compares procedure bodies structurally. ## Keep going Data Types explains which values have identity. Aggregate Procedures shows the constructors that create separate objects. [Data types](/en/docs/manual/data-types) · [Aggregate procedures](/en/docs/reference/list-aggregate-procedures) --- Source: https://www.lispex.com/v1.20/en/docs/manual/tail-calls.md # Proper Tail Calls and Recursion > Lispex runs tail applications in a loop that replaces the current interpreter frame, so self and mutual tail recursion never grow the logical continuation. Canonical page: https://www.lispex.com/v1.20/en/docs/manual/tail-calls Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ## When this matters Tail calls matter when a loop is naturally written as recursion. The place the recursion guide named, where a call's result becomes the result of the enclosing expression directly, is tail position. When the recursive call sits there, Lispex replaces the current continuation instead of stacking another one. ## See it run ```lispex (let loop ((n 10000) (acc 0)) (if (= n 0) acc (loop (- n 1) (+ acc 1)))) ``` **Observed result** ```text 10000 ``` ## Read the example Named `let` creates `loop`. Each branch either returns `acc` or immediately calls `loop` with smaller `n` and updated `acc`, so there is no pending addition after the call. Ten thousand iterations therefore finish as one logical loop. ## How to reason about it - Tail positions include final bodies, both `if` branches, normalized `cond`/`case`, final `and`/`or`, `do`, `call-with-values`, and `apply`. - Proper tail behavior keeps continuation growth flat while the selected resource profile controls execution. - Resource limits remain deterministic and profile-specific even for tail-recursive programs. ## Choose quickly | Shape | Tail call? | Why | | --- | --- | --- | | `(if done? answer (loop next))` | yes | the selected branch result is returned directly | | `(begin (display x) (loop next))` | yes | the call is the final form | | `(+ x (loop next))` | no | addition remains after the recursive result | | `(map loop items)` | no for the callback | `map` still owns the callback result | | `(apply loop args)` in tail position | yes | `apply` preserves the caller’s tail position | ## A common mistake Non-tail recursion may reach the declared resource limit. ## Current boundaries - A resource fault records the executor identity, profile values, and threshold reached by that route. ## Keep going The recursion guide shows base cases and accumulator conversion. Determinism and Resources explains how tail-safe execution works with configured resource profiles. [Recursion guide](/en/docs/guides/recursion) · [Determinism and resources](/en/docs/manual/determinism-resources) --- Source: https://www.lispex.com/v1.20/en/docs/manual/multiple-values.md # Multiple Values and Value Contexts > Multiple values are an evaluation outcome, never a storable guest value. Every continuation position declares how many values it accepts. Canonical page: https://www.lispex.com/v1.20/en/docs/manual/multiple-values Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ## When this matters Use multiple values when one computation naturally produces several coordinated results and immediately hands them to a known consumer. Use a list or vector instead when the group must be stored as data. ## See it run ```lispex (call-with-values (lambda () (floor/ 17 5)) list) ``` **Observed result** ```text (3 2) ``` ## Read the example `floor/` produces quotient `3` and remainder `2` as two values. `call-with-values` passes them as two arguments to `list`, which deliberately turns the transient packet into the storable list `(3 2)`. ## How to reason about it - Single-value contexts require exactly one value and raise E320 for zero or at least two. - Discard contexts accept any count, and `call-with-values` passes the producer packet as consumer arguments. - The operands of `values` are themselves single-value contexts evaluated left to right. ## Choose quickly | Context | Accepted count | Example | | --- | --- | --- | | ordinary operand or binding initializer | exactly one | `(+ (values 1) 2)` | | `begin` before the final form | any count, discarded | `(begin (values 1 2) 3)` | | producer of `call-with-values` | any count | `(lambda () (values 1 2))` | | consumer of `call-with-values` | must accept produced arity | `(lambda (a b) ...)` | | stored aggregate | one list/vector value | `(list 1 2)` | ## A common mistake Multiple values are not boxed into a list or vector. ## Current boundaries - Using `(values)` where one value is required is an error, not an unspecified sentinel. ## Keep going The practical guide builds a producer and consumer. Procedure arity explains the consumer-side failure. [Multiple-values guide](/en/docs/guides/multiple-values) · [Procedures and arity](/en/docs/manual/procedures) --- Source: https://www.lispex.com/v1.20/en/docs/manual/diagnostics.md # Errors, Warnings, and Diagnostics > Reader, normalization, runtime, warning, and resource outcomes have distinct phases and deterministic channels. Canonical page: https://www.lispex.com/v1.20/en/docs/manual/diagnostics Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ## When this matters Read the diagnostic phase before changing code. A reader error asks you to repair spelling, a normalization error asks you to repair form shape, and a runtime error describes a valid form that failed while running. ## See it run ```lispex (guard (e (else (error-object-message e))) (car 1)) ``` **Observed result** ```text "car: expected a pair, got 1" ``` ## Read the example `car` receives `1` instead of a pair and raises a catchable runtime error. `guard` catches the error object and returns its stable message. The program therefore succeeds with a string rather than printing a host stack trace. ## How to reason about it - Runtime errors use E3xx codes, stable templates, deterministic rendering of the values they report, and the enclosing call-site span. - Warnings are ordered observations. A genuine `%` call emits W330 before using `modulo`. Genuine `list-first` and `list-rest` calls emit W331 before using `car` and `cdr`. Each source call site warns once, a shadowing binding does not warn, and a warning remains recorded if the operation then fails. - The first uncaught error aborts without a host stack trace, and resource exhaustion remains outside catchable E3xx. ## Choose quickly | Class | When it appears | First action | | --- | --- | --- | | E100 · E140 · E150 reader | source cannot become a datum | repair the highlighted token or delimiter | | E110 · E120 · E130 normalization | a form has an invalid static shape | check form spelling, placement, and arity | | E3xx runtime | evaluation reaches an invalid operation | inspect the named procedure and the values it reports | | W3xx warning | execution continues with a name that is being retired | move to the named replacement | | resource outcome | a profile ceiling is reached | reduce work or choose the correct declared profile | ## A common mistake A warning is not stdout and must not be reordered or merged into a diagnostic. Use `modulo`, `first`, and `rest` in new code. The deprecated spellings remain executable only for compatibility. ## Current boundaries - Platform panic, blank crash, and nondeterministic host text are not valid guest diagnostics. ## Keep going Diagnostic Catalog is the exact code lookup. The errors guide shows how to validate before producing a decision. [Diagnostic Catalog](/en/docs/reference/diagnostic-catalog) · [Errors guide](/en/docs/guides/errors) --- Source: https://www.lispex.com/v1.20/en/docs/manual/continuations.md # One-Shot Continuations and dynamic-wind > The current `call/cc` is an upward, escape-only, non-reentrant one-shot continuation built from explicit signals inside the interpreter that runs your program. Canonical page: https://www.lispex.com/v1.20/en/docs/manual/continuations Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ## When this matters Use ordinary `if`, `cond`, and procedures first. Reach for `call/cc` only when a deeply nested computation needs one explicit upward escape, and add `dynamic-wind` when entry and cleanup must bracket that escape. ## See it run ```lispex (call/cc (lambda (escape) (escape 'done) 'unreachable)) ``` **Observed result** ```text done ``` ## Read the example `call/cc` passes an escape procedure to the lambda. Calling it with `done` immediately transfers that value to the enclosing `call/cc`. The later symbol `unreachable` is never evaluated, and the escape is consumed by this transfer. `dynamic-wind` takes three procedures. One for going in, one for the work in the middle, and one for coming out. ```lispex (dynamic-wind (lambda () (display "before ")) (lambda () (display "during ")) (lambda () (display "after"))) ``` **Observed result** ```text before during after ``` The last procedure still runs when an escape in the middle carries you out. That is where cleanup belongs. ## How to reason about it - The first invocation atomically consumes the continuation before transfer, and every later invocation is E340. - `dynamic-wind` runs `before`, then `thunk`, then `after`. Unwinding runs pending `after` thunks innermost first. - A new error or escape from an `after` thunk replaces the signal already in flight. ## Choose quickly | Need | Prefer | Why | | --- | --- | --- | | ordinary choice | `if` or `cond` | local control stays visible | | return from a helper | normal procedure result | no non-local transfer | | leave several nested calls once | `call/cc` escape | one explicit upward exit | | cleanup around a possible escape | `dynamic-wind` | `after` runs during unwind | | resume the same point repeatedly | redesign the flow | continuations are one-shot and non-reentrant | ## A common mistake Multi-shot continuation reuse and dynamic-context re-entry are deferred. ## Current boundaries - Host exceptions and host continuations do not implement guest transfer. ## Keep going Conditionals covers ordinary control flow. Diagnostics explains how errors travel along those same explicit interpreter signals. [Conditionals](/en/docs/manual/conditionals) · [Diagnostics](/en/docs/manual/diagnostics) --- Source: https://www.lispex.com/v1.20/en/docs/manual/io-capabilities.md # I/O, Capabilities, and Explicit Effects > Use deterministic Lispex output procedures and connect files, network, time, randomness, and external actions through the host application. Canonical page: https://www.lispex.com/v1.20/en/docs/manual/io-capabilities Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. Lispex separates the rule observation from application effects. Guest output is part of the deterministic transcript, while the host application owns its operational environment. ## Output procedures ```lispex (begin (display "answer=") (write 42) (newline) 0) ``` **Observed result** ```text answer=42 0 ``` `display` writes human-facing text, `write` uses readable guest notation, `newline` writes one line break, and `println` combines `display` with that line break. All four return zero values. Explicit output remains ordered with CLI auto-print, and receipts record completed root values separately. The named resource profile sets the output-byte cap. A later diagnostic keeps the output already written in the observation. ## Capability owners | Operation | Owner | | --- | --- | | readable value output | Lispex `write` | | human-facing text output | Lispex `display`, `newline`, and `println` | | source file and stdin selection | CLI invocation | | files and network | host application adapter | | clock and randomness | explicit application input | | database and transaction | host application state machine | | payment, deployment, or other external action | application policy after the local gate | Native MCP carries source and optional datum through local stdio and returns an observation under its declared byte and time values. Application adapters pass reviewed data into the rule and consume the returned decision. [Choosing Where to Run](/en/docs/guides/choosing-runtime) · [Decision Rules](/en/docs/guides/decision-rules) --- Source: https://www.lispex.com/v1.20/en/docs/manual/determinism-resources.md # Determinism and Resource Profiles > Lispex ties deterministic observations to exact source, input, executor identity, resource values, and output channels. Canonical page: https://www.lispex.com/v1.20/en/docs/manual/determinism-resources Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. Determinism in Lispex is a concrete execution contract. A comparison names the exact source bytes, input bytes, executor, resource profile, and observable channels. Repeating that tuple produces the same result, stdout, warnings, and diagnostic record. ## Resource profiles Each execution route publishes its input, output, transition, control, and allocation values. The report records which values were selected and what the run consumed. Programs continue until they finish, raise a runtime condition, or reach one of those values. | Contract field | What it fixes | Observable result | | --- | --- | --- | | source and input | exact program and request bytes | value or runtime diagnostic | | executor and profile | named language support and resource values | terminal status and resource report | | observation set | stdout, warnings, values, and diagnostics | exact channel order | | corpus and baseline | inputs selected before execution | agreement, mismatch, or not-comparable | | artifact identity | exact product bytes used for the run | receipt or engine fingerprint | Wall-clock duration remains an operational measurement. Semantic resource reports use the counters published by the selected execution route. ## Choosing an execution route The reference interpreter and verified Rust VM run trusted rule source for authoring, local automation, and route comparison. `lispex embed` runs supplied decision rules with configured work and memory values and a fresh instance. A comparison receipt applies to its named corpus, executors, profiles, and observations. Engine faults record their terminal status separately from guest values and runtime diagnostics. ## Keep going Read Proper Tail Calls for continuation behavior and the embed guide for a resource-controlled application workflow. [Proper Tail Calls](/en/docs/manual/tail-calls) · [Embed Lispex](/en/docs/guides/bounded-embedding) --- Source: https://www.lispex.com/v1.20/en/docs/vouch.md # Lispex Vouch > Check a recorded decision later in four steps. Authenticate the signature, pin source and input, rerun the rule on Native, and require one exact match. Canonical page: https://www.lispex.com/v1.20/en/docs/vouch Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### Know this first Vouch is an **advanced workflow for checking a decision later**. If you are learning the language, you can finish the [six-step Learning Path](/en/docs/learn) first. ## The decision being checked Every Vouch workflow protects one concrete, repeatable decision. A reviewed Lispex rule reads one exact input and returns one result that is ordinary data, such as a refund approval. The party who ran the decision is the **issuer**, and the party who checks it later is the **consumer**. Vouch connects those roles across people, machines, and points in time. Instead of answering the broad question “should I trust this JSON?”, Vouch asks four precise questions, each with its own check and its own failure. 1. **Authentication.** Did an allowed key sign these exact bytes? 2. **Request binding.** Do those bytes describe the exact source and input chosen by this consumer? 3. **Current execution agreement.** Does the current Native interpreter reproduce the same complete result? 4. **Local decision.** Does that live result exactly match the decision required by this call? Each stage consumes the named result of the preceding stage. That separation is the core of Vouch. ## The evidence a decision leaves behind When the issuer runs Native `vouch issue`, the run is captured as evidence rather than as a bare answer. Here is what the signed context pins. - the exact **rule source bytes** - the exact **input bytes** the rule read - the fixed **checked profile** (`csk.checked-profile/v1`) under which the rule ran and whose forms participate in Vouch - the **complete execution transcripts**. Native evaluates the rule twice, once on the built-in interpreter that reads your source directly and once through the Meaning path, the lowered form that same source is first converted into. These docs write that pair as tree/Meaning, and issuance keeps both full transcripts, not just the final value - the **issuer engine identity**, a short fingerprint of the bytes of the exact Native executable Issuance signs this context with the issuer's Ed25519 key, producing a signed container in the DSSE format called the *envelope*. With `--emit-bundle`, Native also packs the envelope together with the source and input bytes into one transport file that has a fixed size limit, the **bundle**. ## What the portable artifacts record A bundle transports the envelope with its exact source and input bytes between machines. `lispex vouch inspect` checks the file's schema, hashes, and internal bindings. The consumer's trust policy supplies the allowed key, engine identity, and reviewed source for authentication. The first real claim is authentication. `lispex vouch verify` checks the envelope against a **trust policy**, a file written the same way every time, which the consumer creates from a public key, a short fingerprint of the exact program that runs the rule, and rule source they reviewed independently. A successful verify records this result. *A key allowed by my policy signed exactly this context.* Request binding, current re-execution, and the local gate answer the next three questions in order. ## Why the request must come from you A bundle carries the source and input selected by the issuer. The consumer selects the request by supplying their own exact source and input. For that second question, the request must arrive from outside the bundle. You supply your own `--source` and `--input`, and Vouch checks that the signed context is byte-for-byte equal to them. The bundle is the **authentication target**. Native re-execution and gate take both external paths as the consumer-owned request and reject an incomplete pair before reading the file. A fully validated Lispex Image may supply the exact source bytes through `--source-image`. It changes only how the source is carried. Input choice, trust policy, re-execution, and gate remain separate. ## How each tool consumes the evidence Choose the operation by the question you actually need answered. The table also names the verified Rust VM, a virtual machine that runs compiled instructions instead of reading your source directly. | What you need to know | Operation | What you receive | | --- | --- | --- | | Is the file structurally consistent? | `lispex vouch inspect` | Unsigned structural inspection | | Did an allowed key sign it? | `lispex vouch verify` | Authentication report | | Does it match my source and input? | Add `--source` and `--input` to `vouch verify` | Request-bound authentication report | | Does it still execute the same way? | Native `vouch verify --reexecute` | Separate authentication and current tree/Meaning results | | Does an exact source-derived compiled artifact agree too? | Add `--compiled-artifact` to Native re-execution | Exact derivation, bytecode verifier, and current Rust VM results | | Is the live result the decision I require? | Native `vouch gate --require-decision`, optionally with `--compiled-artifact` | A local pass or denial, from the source-only or the compiled route | | Did the stored set of example cases change? | npm `lispex vouch replay` | Fixed-case comparison | | Is this an external-engine report? | Bridge checker | Checks for a separate kind of file | Re-execution answers the third question. Native runs the rule again *now* and compares the current complete transcripts with the signed ones. The gate answers the fourth. Within one Native call, the live re-executed result must exactly equal the decision the caller names with `--require-decision`. That local pass, the **grant**, lives inside that process and reaches the calling application as the gate result. The report records the decision and its checked context. The safe default journey uses the pieces in this order. 1. Build a trust policy from a public key, the exact program that runs the rule, and rule source that the consumer reviewed independently. 2. Let the issuer create a bundle for exact source and input bytes with Native. 3. Supply the consumer's own `--source` and `--input` as the request. 4. Authenticate with Native or npm. 5. Add Native re-execution only when current execution agreement matters. 6. If you also require the verified Rust VM, build and validate a compiled artifact from that exact source, then add `--compiled-artifact`. 7. Use the Native gate only when the application requires one exact decision in that same call. The [end-to-end Vouch workflow](/en/docs/guides/vouch) gives the commands in that order. ## The optional compiled route Vouch can additionally require agreement from the verified Rust VM. The compiled route starts from the same externally supplied exact source and input, re-derives a canonical `lispex.vouch-compiled-artifact/v1` container, checks the bytecode, and runs the verified Rust VM. The source request, authentication, current tree/Meaning agreement, compiled observation, and live gate transition remain named stages of one chain. The Topaz bytecode VM provides a separate diagnostic comparison route. Its installed product emits request and result JSON, execution output, resource observation, and a `compare-vms` receipt. The Native Vouch route owns the process-local gate grant. ## Vouch authority and scope - A valid signature authenticates an approved key over the exact checked bytes. The recipient trust policy maps that key to its organization and deployment. - Exact request equality binds the supplied source and input. The calling application manages freshness, expiry, revocation, and replay policy. - Tree/Meaning and VM agreement records two execution routes within one shared Rust lineage and the exact profile checked by this call. - Compiled agreement verifies the exact artifact, source, input, transcript, and limits checked by this call. - A gate grant lives inside the current Native call and reaches the calling application as one local decision. - Reports, bundles, images, bytecode, VM results, and Bridge artifacts remain inputs to the live verification chain. - The calling application owns approval and side-effect control for payments, refunds, deployments, and every other external action. ## Keep going Run the [end-to-end workflow](/en/docs/guides/vouch), or use [Artifacts and Reports](/en/docs/reference/vouch-receipts) to look up the exact role of each file. --- Source: https://www.lispex.com/v1.20/en/docs/guides/vouch.md # Use Lispex Vouch > Create recipient policy, issue signed evidence, authenticate an exact request, observe current Native execution, and require one local decision. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/vouch Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Follow one decision from recipient-owned trust configuration to a live local decision gate. Each stage records its exact input, result, and owner. ## The six stages | Stage | Command | Result | Owner | | --- | --- | --- | --- | | 1. Describe trust | `vouch policy create`, then `policy check` | canonical policy for reviewed key, engine, profile, and source identities | recipient | | 2. Issue | `vouch issue --emit-bundle` | Native-signed source, input, profile, and complete transcript context | issuer | | 3. Authenticate | `vouch verify --bundle ...` | signature and policy match | recipient | | 4. Bind the request | add `--source-image` or `--source`, plus `--input` | authenticated context matches the separately supplied request | recipient | | 5. Observe current execution | add `--reexecute` | current Native execution matches the signed complete transcript | Native | | 6. Require one decision | `vouch gate --require-decision ...` | live authenticated result matches the required decision | host application | The host application supplies caller identity, freshness, replay prevention, business authorization, and the external action. ## Prepare exact inputs Prepare these values independently. - reviewed `refund-window.lspx.png` or `refund-window.lspx` - exact checked input file `INPUT` - Ed25519 public key `issuer.spki.der` - absolute local PKCS#8 key URI for issuance - reviewed SHA-256 of the exact Native executable - new paths for `POLICY`, `OUTPUT`, and each report Print the exact identities through the shared Rust core. ```sh lispex vouch key-id --public-key issuer.spki.der lispex vouch engine-id --executable /exact/path/to/lispex lispex vouch source-id --source-image refund-window.lspx.png lispex vouch input-id --input INPUT ``` ## 1. Create recipient policy ```sh lispex vouch policy create \ --public-key issuer.spki.der \ --engine-sha256 sha256: \ --source-image refund-window.lspx.png \ --out POLICY lispex vouch policy check --trust-policy POLICY ``` The policy records the recipient's reviewed key, engine, profile, and source allowlist in canonical bytes. ## 2. Issue signed evidence ```sh ISSUER_KEY_URI="pkcs8-file:///absolute/path/to/private.pkcs8.der" lispex vouch issue \ --source-image refund-window.lspx.png \ --input INPUT \ --profile csk.checked-profile/v1 \ --key-handle "$ISSUER_KEY_URI" \ --out-dir OUTPUT \ --emit-bundle ``` Native executes the rule and signs the exact source, input, profile, engine, result, and complete transcript context. The bundle carries those canonical bytes under its configured byte budget. ## 3. Authenticate the bundle ```sh lispex vouch verify \ --bundle OUTPUT/vouch-input-bundle.json \ --trust-policy POLICY \ --report-out AUTH-REPORT ``` The report records signature verification and the exact policy match. ## 4. Bind the current request ```sh lispex vouch verify \ --bundle OUTPUT/vouch-input-bundle.json \ --trust-policy POLICY \ --source-image refund-window.lspx.png \ --input INPUT \ --profile csk.checked-profile/v1 \ --report-out PINNED-REPORT ``` The report now binds the authenticated context to the source and input supplied by this invocation. ## 5. Observe current Native execution ```sh lispex vouch verify \ --bundle OUTPUT/vouch-input-bundle.json \ --trust-policy POLICY \ --source-image refund-window.lspx.png \ --input INPUT \ --profile csk.checked-profile/v1 \ --reexecute \ --report-out REEXECUTION-REPORT ``` Native creates a fresh execution observation and compares both complete transcripts. ## 6. Require the decision ```sh lispex vouch gate \ --bundle OUTPUT/vouch-input-bundle.json \ --trust-policy POLICY \ --source-image refund-window.lspx.png \ --input INPUT \ --profile csk.checked-profile/v1 \ --require-decision approve \ --report-out GATE-REPORT ``` Exit `0` records the required live local decision. Exit `10` records a gate refusal. The application consumes that result together with its freshness, replay, identity, and action policy. ## Compiled evidence Native can derive `lispex.vouch-compiled-artifact/v1` from the same exact source and add verified Rust VM agreement to the tree and Meaning chain. The compiled workflow re-derives Core IR and bytecode after request authentication. ## Keep going [Vouch Receipts](/en/docs/reference/vouch-receipts) · [Application Handoff](/en/docs/guides/application-handoff) --- Source: https://www.lispex.com/v1.20/en/docs/reference/vouch-receipts.md # Vouch Receipts and Reports > Map every receipt, authentication report, re-execution report, compiled artifact, gate report, replay report, and Bridge report to its command and consumer. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/vouch-receipts Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you You will identify every Vouch artifact, the command that creates it, and the next product that consumes it. ## Differential receipt `csk.differential-receipt/v0` records one decision-profile rule, exact input, tree and lowered observations, hashes, and contract version. Native creates it with `lispex diff-receipt`; Native and npm inspect it with `lispex verify` and compare corpora with `lispex replay`. ## Artifact roles | Artifact | Records | Consumer | | --- | --- | --- | | `csk.differential-receipt/v0` | exact rule, input, lowering, observations, versions, and hashes | structural `verify` and corpus `replay` | | `csk.vouch-input-bundle/v0` | exact envelope, source, and input bytes | authenticated `vouch verify` | | trust policy v1 | recipient-selected keys, engines, profiles, and source identities | authentication | | authentication report | signature and policy result for the exact bound context | operator diagnostics and Native re-execution | | `lispex.vouch-compiled-artifact/v1` | source identity, Core IR, verified bytecode, verifier, VM, and resource profile | compiled validation and Native compiled re-execution | | `csk.native-reexecution-report/v0` | authentication plus current tree and Meaning agreement | local gate | | `csk.native-compiled-reexecution-report/v1` | request-bound authentication, current tree and Meaning agreement, exact derivation, and current verified Rust VM agreement | compiled local gate | | Topaz VM request, result, and comparison | installed-product lineage and exact bytecode observation | engineering inspection and comparison | | Topaz AOT product and reports | installed executable lineage, source map, resource request, and observation | AOT inspect, validate, run, and route comparison | | four-route report | one source, input, Core IR, bytecode, four observations, semantic axes, resource axes, and lineage | engineering inspection | | `csk.native-gate-report/v0` | current local grant or denial for the required decision | host application | | `csk.native-compiled-gate-report/v1` | current compiled local grant or denial | host application | | Bridge report | external-engine artifact bindings, identities, and declared gates | `lispex verify-bridge` and recipient policy | | replay report | agreement, mismatch, and comparison status for the selected corpus | rule review workflow | ## Live decision chain ```text signed envelope → authentication under recipient policy → exact external request binding → current tree and Meaning re-execution → optional exact derivation and verified Rust VM agreement → required-decision local gate → host application action ``` Each transition consumes the typed result from the previous step in the same Native process. Reports record the transition for inspection and application logging. ## Commands ```sh lispex diff-receipt --input input.datum rule.lspx > receipt.json lispex verify receipt.json --source rule.lspx lispex replay corpus --against receipts lispex vouch verify ... --report-out authenticated.json lispex vouch verify ... --reexecute --report-out current.json lispex vouch gate ... --require-decision approve --report-out gate.json lispex vouch compiled build --source rule.lspx --out rule.lpxvca lispex vouch compiled validate --artifact rule.lpxvca --source rule.lspx lispex vouch verify ... --reexecute --compiled-artifact rule.lpxvca ``` The recipient policy owns accepted identity and source. Native owns current re-execution and the local gate. The host application owns actor, time, request uniqueness, transaction state, and external action. [Using Lispex Vouch](/en/docs/guides/vouch) · [Vouch Replay](/en/docs/guides/vouch-replay) · [Vouch Bridge](/en/docs/guides/vouch-bridge) --- Source: https://www.lispex.com/v1.20/en/docs/guides/vouch-replay.md # Replaying a Decision Corpus > Replay compares a frozen set of pinned decision cases against a new rule or receipt set, and classifies every case as agree, mismatch, or not-comparable. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/vouch-replay Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Replay answers one question. Did any decision in a fixed corpus change? You will freeze a corpus, compare it against a baseline, and read the three possible outcomes together with their product role. ## The decision set being compared A replay corpus is a declared set of pinned decision cases. Each case holds the exact rule bytes, the exact input bytes, and the expected receipt lineage. Replay compares each case's recorded evidence against the baseline you name, either a version or a directory of receipts, and reports whether the recorded behavior changed. `vouch replay` re-checks recorded decisions. The host application owns replay protection for grants and reports through its freshness and one-time-use policy. ## Freeze the evidence before comparing - Freeze the corpus inventory before comparison. The report classifies every case as agree, mismatch, or not-comparable. - Preserve runner identity, rule bytes, input bytes, and result observations so the comparison can be reproduced. - Review mismatch cases as behavior changes and preserve historical receipts as the earlier baseline. ## Compare with a baseline ```sh lispex vouch replay gallery \ --against ``` The npm CLI provides this command. Read every reported mismatch and not-comparable case. A clean summary is useful only when the corpus and baseline were chosen before the outcome was known. ## Comparison statuses `not-comparable` records that the named executors produced no comparison for that case. It remains distinct from both agreement and mismatch in the report. ## Keep going Keep the Vouch overview nearby. It separates authentication, request binding, current execution agreement, and a local grant. [Lispex Vouch overview](/en/docs/vouch) · [Choosing Where to Run](/en/docs/guides/choosing-runtime) --- Source: https://www.lispex.com/v1.20/en/docs/guides/vouch-bridge.md # Using Vouch Bridge > Check how an external engine binds source bytes, target bytes, engine identity, declared gates, and linked evidence in a Vouch Bridge report. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/vouch-bridge Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you You will verify that an external engine's report is structurally valid and bound to the exact source, target, context, and linked evidence you selected. ## What a Bridge report carries An external engine runs its own pipeline and emits `vouch.bridge-report/v0`. The report binds - exact source and target bytes by hash and byte length - engine name, version, and commit - the declared execution route and capability identifiers - declared gate results as `pass`, `fail`, or `not-run` - hashes of linked proof or gate artifacts - an `attests` and `excludes` boundary that records the observation supplied by the engine and the responsibilities it retains This format lets an engine publish inspectable evidence while keeping its implementation private. ## Verify a report Run the external engine, preserve the source and target bytes, and pass the report and named artifacts to Lispex. ```sh lispex verify-bridge \ --source source.lspx \ --target translated.output \ bridge-report.json ``` Add `--linked =` to bind a linked artifact. Add `--expect-context ` to select the expected profile, subject, and route through `vouch.bridge-context-manifest/v0`. Exit `0` returns `vouch.bridge-verify-report/v0` with successful structure, byte, boundary, and requested-context checks. Exit `1` returns a verification report with the failed check. Exit `2` identifies usage, input/output, or JSON parsing errors. ## Artifact roles | Product | Role | | --- | --- | | External engine | Creates the target and runs its declared gates | | Bridge report | Binds that run to exact artifacts, identities, and results | | `lispex verify-bridge` | Validates report structure and receiver-selected bindings | | Recipient policy | Decides which external engine, route, and evidence to accept | Bridge reports and native differential receipts remain distinct artifact classes. `vouch.bridge-report/v0` enters `lispex verify-bridge`, while `csk.differential-receipt/v0` records reference-interpreter agreement and enters `lispex verify`. ## Keep going The Vouch overview connects authentication, request binding, current execution agreement, and a local grant. [Lispex Vouch overview](/en/docs/vouch) · [Choosing Where to Run](/en/docs/guides/choosing-runtime) --- Source: https://www.lispex.com/v1.20/en/docs/guides/decision-rules.md # Run and Check Decision Records > Run a reviewed refund rule with strict JSON, keep its exact decision record, authenticate an issuer, and replay the request. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/decision-rules Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Run one decision from reviewed source and explicit input, then inspect, verify, authenticate, and replay its exact record. ## Run the refund rule. Keep what was checked. ### Rule ```lispex (let ((days (cdr (car input))) (opened (cdr (car (cdr input))))) (if (< days 15) (if opened "deny" "allow") "deny")) ``` ### Strict JSON input ```json { "days": 14, "opened": false } ``` ### Run and check ```shell lispex rule run \ --source refund-window.lspx \ --input day-14-unopened.json \ --prepare-limits prepare-limits.json \ --eval-limits evaluation-limits.json \ --out decision lispex rule inspect --dir decision lispex rule verify --dir decision lispex rule replay --dir decision ``` **Decision:** `allow` ### Checkable record The portable core binds the semantic rule, canonical input, exact limits, evaluator artifact, and deterministic outcome. It does not establish issuer identity, freshness, policy correctness, replay prevention, or external-action authority. ## Read the decision first The rule asks how many days have passed and whether the item was opened. The application passes both values explicitly and owns the business meaning of `allow` and `deny`. | Input | Decision | Why | | --- | --- | --- | | day 14, unopened | `allow` | the order is still inside the window | | day 15, unopened | `deny` | the order is outside the window | | day 14, opened | `deny` | an opened item is not admitted | ## Four local commands | Command | Product behavior | | --- | --- | | `rule run` | prepares the rule, evaluates strict JSON under configured resource values, and atomically writes a five-member decision directory | | `rule inspect` | reads and summarizes the directory | | `rule verify` | checks the exact member set, identities, hashes, and bindings | | `rule replay` | evaluates the recorded request in a fresh evaluator instance and matches the result and portable core | The directory contains: | Member | Role | | --- | --- | | prepared artifact | canonical executable rule material | | canonical input | exact request value | | result artifact | deterministic result and request binding | | portable core | rule, input, resources, evaluator, transcript, and result identity | | summary | human-readable projection of the canonical members | The authoring workspace retains the source. New output paths preserve every completed record, and malformed or tampered members receive an explicit refusal. ## Authenticate an issuer The recipient creates policy for one reviewed public key. Native can sign the decision material and write a canonical `.lpxdecision` under the configured byte budget. ```text lispex rule issue --dir decision \ --private-key issuer.pkcs8.der \ --issuer-label "Refund desk A" \ --out issuer-envelope.json lispex rule policy create --dir decision \ --public-key issuer.spki.der \ --consumer-label "Refund receiver" \ --out recipient-policy.json lispex rule authenticate --dir decision \ --envelope issuer-envelope.json \ --policy recipient-policy.json lispex decision issue --dir decision \ --private-key issuer.pkcs8.der \ --issuer-label "Refund desk A" \ --out refund.lpxdecision lispex decision inspect --bundle refund.lpxdecision lispex decision authenticate --bundle refund.lpxdecision \ --policy recipient-policy.json lispex decision replay --bundle refund.lpxdecision \ --policy recipient-policy.json ``` The bundle has seven canonical members: input, manifest, issuer envelope, prepared artifact, portable core, result artifact, and summary. Native issues, inspects, authenticates, and replays the bundle. npm inspects and authenticates it offline. ## Product roles Decision authentication records package integrity, issuer signature, recipient policy admission, and request binding. Replay adds a fresh evaluator result. Vouch adds its own signed complete transcripts, consumer-pinned request, current Native observation, and local decision gate. The host application owns freshness, replay prevention, business authorization, and the external action. ## Keep going [Use Lispex Vouch](/en/docs/guides/vouch) · [Application Handoff](/en/docs/guides/application-handoff) --- Source: https://www.lispex.com/v1.20/en/docs/guides/errors.md # Handling Errors Deterministically > Use `with-exception-handler` for procedural handling and `guard` for condition-style matching over catchable error objects. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/errors Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Use `with-exception-handler` for procedural handling and `guard` for condition-style matching over catchable error objects. ## See it run ```lispex (guard (e ((error-object? e) (error-object-message e))) (error "bad input")) ``` **Observed result** ```text "bad input" ``` ## Walk through the pattern 1. **Raise a guest error.** `(error "bad input")` creates a catchable error object with a stable message. 2. **Match structured data.** `guard` tests `error-object?` rather than parsing rendered text. 3. **Return a recovery value.** The selected clause extracts the message, so the whole form evaluates to `"bad input"`. ## How to reason about it - `raise-continuable` returns the handler result to the raise site. A non-continuable `raise` cannot return normally. - Inspect error objects with the documented predicates and accessors rather than parsing rendered diagnostic text. - When no `guard` clause matches, the original error is reraised unchanged. ## Check yourself What happens if no `guard` clause matches the error object?
Answer The original error is raised again unchanged. A missing match is not converted into a generic success value.
## A common mistake ResourceLimit is not catchable, and host crashes are never converted into friendly guest errors. ## Keep going Diagnostics explains phases and codes. The decision-record guide shows what one recorded run refuses and what it still leaves to the application. [Diagnostics](/en/docs/manual/diagnostics) · [Decision records](/en/docs/guides/decision-rules) --- Source: https://www.lispex.com/v1.20/en/docs/guides/practical-decision-workspace.md # The Ready-Made Refund Example > Run one fixed refund example through the decision exchange under declared limits, recipient authentication, Image-backed Vouch, and a request-bound local gate. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/practical-decision-workspace Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you You will run one decision through two deliberately separate evidence paths. The first path produces and authenticates a portable `.lpxdecision` bundle. The second path uses an exact Lispex Image and a fresh Vouch gate for one explicit checked input. Neither path performs a refund or grants permission to perform one. ## Choose the fixed refund example Start from the ready-made refund example listed on [Downloads](/en/downloads#practical-decision-workspace), or use `examples/refund-workspace` in the Lispex repository. The archive and the repository directory have the same fixed member inventory. Keep every key and generated artifact outside that immutable directory. The example contains two different refund rules. | Lane | Source | Input shape | Result | | --- | --- | --- | --- | | Decision exchange | `generated/exchange/refund-window.lspx` | ordinary JSON records | `allow` or `deny` | | Vouch | `generated/vouch/refund-window-native.lspx.png` | checked input values | `approve` or `deny` | The exchange result is not Vouch evidence. The Vouch result is not an exchange result. They share a business example without sharing an identity, receipt, policy, or authority. ## Check the example before doing any work Enter the extracted example root or the repository directory. Create one separate caller-owned work root and ask Native to check the fixed inventory. ```sh mkdir -p ../refund-work lispex workspace status --dir . --work-dir ../refund-work ``` `workspace status` checks the exact member inventory before it reports any work slot. A reported `present-unchecked` slot is only present. It is not verified, trusted, fresh, or authorized. ## Run the decision exchange under declared limits The exchange lane uses separate preparation and evaluation limits. It writes a five-member decision directory without storing the raw rule source. ```sh mkdir -p ../refund-work/exchange lispex rule run \ --source ./generated/exchange/refund-window.lspx \ --input ./generated/exchange/inputs/day-14-unopened.json \ --prepare-limits ./generated/exchange/prepare-limits.json \ --eval-limits ./generated/exchange/evaluation-limits.json \ --out ../refund-work/exchange/decision lispex rule inspect --dir ../refund-work/exchange/decision lispex rule verify --dir ../refund-work/exchange/decision lispex rule replay --dir ../refund-work/exchange/decision ``` Inspect and verify do not execute the rule. Replay creates one fresh instance of the built-in program that runs the rule, and requires the same result. The portable result remains `vouch_eligible` false. ## Prepare a local issuer and an independent recipient Generate the private key under a caller-owned directory outside both the example directory and the work root. ```sh mkdir -p ../refund-issuer ../refund-recipient lispex key generate --out-dir ../refund-issuer/key lispex key inspect --public-key ../refund-issuer/key/public.spki.der ``` For this one-machine exercise, copy only the reviewed public SPKI into the recipient directory and inspect the copied bytes again. ```sh cp ../refund-issuer/key/public.spki.der \ ../refund-recipient/reviewed-issuer.spki.der lispex key inspect \ --public-key ../refund-recipient/reviewed-issuer.spki.der ``` A real issuer and recipient need a separately chosen transfer and review channel. A local copy is a walkthrough convenience, not a trust procedure. Never place `private.pkcs8.der` in the example directory, work root, recipient directory, source control, or a bundle. The recipient now creates a decision policy from four independently reviewed facts. None of them comes from the bundle that will be authenticated. ```sh lispex decision policy create \ --public-key ../refund-recipient/reviewed-issuer.spki.der \ --semantic-rule-sha256 14bb6f2e43cee011aedbeafc71d3716789bea8117e8331cd6a7feb1858d7418f \ --semantic-profile-id lispex/r7rs-rule-embedded-core/1 \ --engine-artifact-sha256 fa6e52559e1f5a43e50a3b7ac0cc5add6930cff0aed8aaff462cff4609362870 \ --portable-core-schema lispex.embed-receipt-core/v1 \ --consumer-label refund-recipient \ --out ../refund-recipient/decision-policy.json lispex decision policy check \ --policy ../refund-recipient/decision-policy.json ``` Policy creation records the accepted issuer key, semantic profile, evaluator, and portable-core schema. The surrounding application maps that key to an issuer organization and owns reuse and action policy. ## Issue and authenticate the portable decision The portable core is the part that holds the rule, its input, its limits, and its result together. The issuer signs the already verified portable core and writes one canonical `.lpxdecision` under the configured byte budget. ```sh lispex decision issue \ --dir ../refund-work/exchange/decision \ --private-key ../refund-issuer/key/private.pkcs8.der \ --issuer-label refund-issuer \ --out ../refund-work/exchange/refund.lpxdecision ``` The recipient uses its own policy and names the received bundle explicitly. ```sh lispex decision inspect \ --bundle ../refund-work/exchange/refund.lpxdecision lispex decision authenticate \ --bundle ../refund-work/exchange/refund.lpxdecision \ --policy ../refund-recipient/decision-policy.json lispex decision replay \ --bundle ../refund-work/exchange/refund.lpxdecision \ --policy ../refund-recipient/decision-policy.json ``` Authentication proves that an admitted exact key signed the exact decision material. Replay adds a fresh evaluation. Neither one supplies freshness, replay prevention, organizational identity, or permission for an external action. The files under `samples/recipient` are permanently marked `sample-do-not-trust`. They are useful for command practice only and must not become a real recipient policy or trust root. ## Start the separate Image-backed Vouch lane This lane starts again from the checked input and exact Lispex Image. It does not consume the exchange result, decision directory, decision policy, or `.lpxdecision` bundle. Inspect the four Vouch identity inputs first. ```sh mkdir -p ../refund-work/vouch lispex vouch source-id \ --source-image ./generated/vouch/refund-window-native.lspx.png lispex vouch input-id \ --input ./generated/vouch/inputs/day-14-unopened.checked.json lispex vouch key-id \ --public-key ../refund-recipient/reviewed-issuer.spki.der lispex vouch engine-id \ --executable /absolute/path/to/lispex ``` Review the exact engine output, then use that complete printed value as `ENGINE_ID`. The Vouch policy is separate from the decision policy even when both refer to the same reviewed public key. ```sh ENGINE_ID="sha256:" lispex vouch policy create \ --public-key ../refund-recipient/reviewed-issuer.spki.der \ --engine-sha256 "$ENGINE_ID" \ --source-image ./generated/vouch/refund-window-native.lspx.png \ --out ../refund-work/vouch/policy.json lispex vouch policy check \ --trust-policy ../refund-work/vouch/policy.json ``` Issue the retained walkthrough input from the exact Image. The `--profile` value `csk.checked-profile/v1` names the fixed checked profile whose forms participate in Vouch. ```sh ISSUER_KEY_URI="pkcs8-file:///absolute/path/outside-workspace/refund-issuer/key/private.pkcs8.der" lispex vouch issue \ --source-image ./generated/vouch/refund-window-native.lspx.png \ --input ./generated/vouch/inputs/day-14-unopened.checked.json \ --profile csk.checked-profile/v1 \ --key-handle "$ISSUER_KEY_URI" \ --out-dir ../refund-work/vouch/issued \ --emit-bundle ``` The retained checked input contains only `[14, false]`. Its issued bundle is a walkthrough bundle only. It cannot be reused by the application handoff because it does not bind a request ID, actor, action, or expiry. ## Issue a dedicated six-value current-request bundle Create a caller-owned file with exactly these bytes and one final line feed. The `input` field value `csk.checked-input/v1` names the fixed form of a checked input file, and `value` carries the input itself. ```json { "input": "csk.checked-input/v1", "value": [ 14, false, "request-123", "operator-7", "refund", 1785600000 ] } ``` Store it as `../refund-work/app/current-request.checked.json`. Issue a new bundle that binds all six values. ```sh mkdir -p ../refund-work/app lispex vouch issue \ --source-image ./generated/vouch/refund-window-native.lspx.png \ --input ../refund-work/app/current-request.checked.json \ --profile csk.checked-profile/v1 \ --key-handle "$ISSUER_KEY_URI" \ --out-dir ../refund-work/app/current-request-issued \ --emit-bundle ``` The refund rule reads the first two values. The Vouch input identity and signed context bind all six exact values. The surrounding application authenticates the actor and reserves a unique request from its trusted server state. ## Run a fresh gate for that exact request The recipient supplies the dedicated bundle, its policy, the exact Image, and the same six-value checked input independently. The gate creates a fresh local execution observation and requires `approve`. ```sh lispex vouch gate \ --bundle ../refund-work/app/current-request-issued/vouch-input-bundle.json \ --trust-policy ../refund-work/vouch/policy.json \ --source-image ./generated/vouch/refund-window-native.lspx.png \ --input ../refund-work/app/current-request.checked.json \ --profile csk.checked-profile/v1 \ --require-decision approve \ --report-out ../refund-work/app/current-request-gate.json ``` A stored verification or gate report names the request it observed. Every new request starts a fresh gate with its own source, input, policy, and report. ## Complete the application handoff An exit-zero gate establishes one local match between live authenticated current execution and the required decision. The application supplies caller authentication, actor and action policy, server time, request reservation, and exactly-once transaction handling. The application handoff example binds those server-owned facts and atomically publishes a `would_act` record before the business adapter performs the external action. [Application handoff](/en/docs/guides/application-handoff) · [Using Lispex Vouch](/en/docs/guides/vouch) · [Lispex Images](/en/docs/guides/lispex-images) --- Source: https://www.lispex.com/v1.20/en/docs/guides/application-handoff.md # Application Handoff > Bind one authenticated server request to a dedicated Vouch bundle, a fresh Native gate, and an idempotent local would-act record for the host application. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/application-handoff Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you You will see the exact boundary between a Vouch gate and an application. The included `handoff/would-act.mjs` example validates server-owned request facts, runs one fresh Native gate, and publishes one local record for the host application's transaction step. ## Know what the example is `handoff/would-act.mjs` is the local handoff reference. It validates the closed request and context, runs the absolute Native executable supplied by the caller, and publishes the `would_act` record. The host application owns authentication, transaction state, and the external-action connector. Its one durable effect is a local `would_act` record. The record says that this invocation reached an exact fresh gate and that no external action was performed. ## Authenticate before constructing server context The surrounding application authenticates the caller and then creates the server-context file from server-owned facts. After authentication, the application owns all of these facts. - the authenticated actor - the allowed actor set - the allowed action set - the trusted current Unix time - the request ID and its storage rule - the expiry chosen by the server - the business facts `days` and `opened` Only the server-owned context sets the authenticated actor, trusted current time, and expiry. ## Keep request data and trusted context separate The request record uses the closed schema `lispex.example-refund-request/v1`. ```json { "action": "refund", "actor": "operator-7", "days": 14, "expires_at_unix_seconds": 1785600000, "opened": false, "request_id": "request-123", "schema": "lispex.example-refund-request/v1" } ``` The independently trusted server context uses the closed schema `lispex.example-refund-server-context/v1`. ```json { "allowed_actions": [ "refund" ], "allowed_actors": [ "operator-7" ], "authenticated_actor": "operator-7", "now_unix_seconds": 1785599900, "schema": "lispex.example-refund-server-context/v1" } ``` Store the first block as `../refund-work/app/request.json` and the second as `../refund-work/app/server-context.json`. Preserve the exact two-space indentation and one terminal line feed in both files. The actor must match the authenticated actor byte for byte and must appear in the actor allowlist. The action must appear in the action allowlist. Expiry must be strictly later than the trusted current time. Both files must already be closed JSON in the one fixed byte form shown above. Unknown or duplicate keys, invalid UTF-8, controls, unsafe numbers, oversized values, and trailing bytes are refused before Native starts. Strings are not normalized or case-folded. The exact admitted scalar bytes are preserved. ## Bind all six current-request values The application reconstructs one exact checked input from the accepted request and server context. The `input` field value `csk.checked-input/v1` names the fixed form of a checked input file, and `value` carries the input itself. ```json { "input": "csk.checked-input/v1", "value": [ 14, false, "request-123", "operator-7", "refund", 1785600000 ] } ``` The values are `days`, `opened`, `request_id`, `actor`, `action`, and `expires_at_unix_seconds` in that order. Store exactly these bytes, with two-space indentation and one terminal line feed, as `CURRENT_REQUEST_CHECKED_JSON`. The retained `[14, false]` walkthrough has its own bundle. The handoff uses a dedicated bundle whose signed context binds all six current-request values. ## Issue the dedicated bundle separately The issuer creates the current-request bundle before the recipient application runs the handoff. This command is separate from the handoff and uses an issuer-owned key outside the example directory and the application work root. The `--profile` value `csk.checked-profile/v1` names the fixed checked profile whose forms participate in Vouch. ```sh mkdir -p ../refund-work/app ISSUER_KEY_URI="pkcs8-file:///absolute/path/outside-workspace/refund-issuer/key/private.pkcs8.der" lispex vouch issue \ --source-image ./generated/vouch/refund-window-native.lspx.png \ --input ../refund-work/app/current-request.checked.json \ --profile csk.checked-profile/v1 \ --key-handle "$ISSUER_KEY_URI" \ --out-dir ../refund-work/app/current-request-issued \ --emit-bundle ``` The application authenticates the caller before issuance. The recipient then supplies its independently reviewed policy, Image, and checked input to a fresh gate, and the host application owns the requested action. ## Prepare the local ledger namespace Create one caller-owned real directory with two existing real direct-child directories. Keep this namespace stable for the complete invocation. ```sh mkdir -p ../refund-work/app/request-ledger mkdir -p ../refund-work/app/request-staging ``` The example creates neither child directory implicitly. It uses the fixed sibling `.would-act-ledger-admission.lock` as one ledger-wide exclusive lock. An existing lock or a nonempty staging directory requires operator review and causes refusal. The lock is never reclaimed only because it looks old. ## Run the exact eight-flag handoff From the example root, invoke the script with every flag exactly once. The Native path must be absolute. The other paths are resolved once from the invocation directory. ```sh node handoff/would-act.mjs \ --native-bin /absolute/path/to/lispex \ --bundle ../refund-work/app/current-request-issued/vouch-input-bundle.json \ --trust-policy ../refund-work/vouch/policy.json \ --source-image ./generated/vouch/refund-window-native.lspx.png \ --checked-input ../refund-work/app/current-request.checked.json \ --request-record ../refund-work/app/request.json \ --server-context ../refund-work/app/server-context.json \ --app-work-dir ../refund-work/app ``` The child call is fixed to `lispex vouch gate`. It pins the bundle, policy, Image, six-value checked input, exact checked profile, required `approve` decision, and a fresh caller-owned report path. It uses an argv array with no shell, a closed child environment, a 30-second timeout, and a configured captured-output cap. The caller supplies the exact executable path and keeps child stdout and stderr in the local record. ## Read the exact local record Only an accepted fresh gate can reach publication. The final filename is the ordinary lowercase SHA-256 of the raw UTF-8 request ID followed by `.json`. The request ID is not repeated inside the record. The record has exactly these ten fields in this fixed order. ```json { "action": "refund", "actor": "operator-7", "authority": "informative-local-example", "checked_input_sha256": "sha256:<64-lowercase-hex>", "expires_at_unix_seconds": "1785600000", "external_action_performed": false, "gate_report_sha256": "sha256:<64-lowercase-hex>", "required_decision": "approve", "schema": "lispex.example-would-act-record/v1", "would_act": true } ``` `checked_input_sha256` is the ordinary SHA-256 of the exact checked-input file bytes. The Native gate report uses a different domain-separated input identity inside its context. `gate_report_sha256` is the ordinary SHA-256 of the exact accepted report bytes. Neither hash turns a stored report into reusable authority. `expires_at_unix_seconds` is a decimal string in one fixed form in this record. It is a safe integer inside a fixed range in the request and server context. ## Understand the idempotency boundary The script locks the whole ledger before scanning capacity, running Native, and publishing the record. It rejects any existing record for the same request without running the gate again. Exclusive hard-link publication lets only one concurrent caller win the final path. Different request IDs also share the ledger-wide admission lock so that they cannot race past total count or byte limits. This gives the example one atomically published local record per accepted request ID. The application transaction state machine uses that record to provide exactly-once payment or refund behavior. A record published before the business transaction keeps `external_action_performed` set to false. ## Put the real transaction in an application-owned state machine A production application keeps the gate and the external transaction as separate steps. A practical integration usually needs all of the following. 1. Authenticate the caller and load the server-owned request. 2. Authorize the actor and action and reject expired work. 3. Bind the exact request to a dedicated bundle and run a fresh local gate. 4. Atomically reserve the request in application storage under a unique request ID. 5. Submit the external transaction through an application-owned connector. 6. Store the external system response and mark the reservation complete. 7. Reconcile timeout or unknown outcomes before any retry. 8. Keep the checked-input hash, the accepted gate-report hash, the transaction identity, and the final state in the application audit trail. The local example intentionally stops before step 4. The application must design reservation, completion, retry, and reconciliation around the actual external system. A provider idempotency key can help only when that provider's contract is independently understood and the application stores the key and outcome durably. ## Know the closed refusals The example fails closed before an external action in every negative case. - Missing, duplicate, unknown, or positional arguments cause usage exit `2` before filesystem access. - A relative Native path is refused. The request, context, checked-input, work directory, staging, and ledger paths that the handoff reads or writes also refuse unsafe path kinds, symlinks, hardlinks, junctions, and reparse points. Native separately validates the decision bundle, recipient policy, and Image. - Request or context bytes that are not in that fixed form, wrong schemas, unknown fields, duplicate keys, bad strings, unsafe times, and resource-limit excess are refused. - Actor mismatch, disallowed actor, disallowed action, and expired or invalid time are refused before the child starts. - Any byte difference between the supplied checked input and the reconstructed six-value input is refused. - An existing admission lock, nonempty staging directory, unsafe ledger, existing same-request record, or exhausted ledger capacity is refused. - Spawn failure, timeout, signal, output overflow, nonzero child exit, missing report, and unexpected child output are refused. - An authentication failure, old or malformed report, wrong profile, wrong input identity, execution disagreement, decision mismatch, or nongranted gate is refused. - Record serialization, staging, publication, or cleanup failure returns a refusal. A record already published before cleanup failure remains for operator review. Application and local refusals exit `3` with empty stdout. Diagnostic stderr uses the configured byte budget. An earlier refusal remains final for that invocation. ## Record fields and application policy The handoff record means one exact current invocation can proceed to an application-owned decision point. The server context supplies caller identity, policy review supplies correctness criteria, the ledger supplies request uniqueness, expiry supplies freshness, and the host application records the external transaction and action authority. [The ready-made refund example](/en/docs/guides/practical-decision-workspace) · [Using Lispex Vouch](/en/docs/guides/vouch) · [Vouch receipts](/en/docs/reference/vouch-receipts) --- Source: https://www.lispex.com/v1.20/en/docs/reference/core-forms.md # Core Forms > The core forms are quotation, variable reference, `if`, sequencing, lambda, application, assignment, definition, lexical binding, and fixed control nodes. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/core-forms Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Settle the exact shape of a core form, what it evaluates and in what order, and which diagnostic it raises when the shape is wrong. ## See it run ```lispex ((lambda (x) (if #t x 0)) 42) ``` **Observed result** ```text 42 ``` ## How to reason about it - `if` has a mandatory else arm, and `begin` and procedure bodies preserve left-to-right order. - `lambda` supports fixed and dotted formals. `set!` mutates an existing cell, and `define` updates or creates a top-level cell. - `quote` returns immutable literal data, and the runtime does not evaluate quoted elements. - `module` is written `(module name (export id ...) (import name ...) body ...)` and may only sit at top level. Nest it inside another form and you get E130. The `export` and `import` clauses come before the body. - A `module` header is checked and then discarded, and the body is flattened outward. **It does not create a namespace.** Do not expect it to hide anything. That is why `(f 21)` below is called from outside the module. ```lispex (module doubling (export twice) (define (twice x) (* x 2))) (twice 21) ``` **Observed result** ```text 42 ``` ## Form contracts | Form | Arguments / evaluation | Result or fault | | --- | --- | --- | | quote | 1 datum, no element evaluation | immutable datum | | if | test, consequent, alternate, with the test first | the values from the selected branch. E320 if the test is not one value | | lambda | formals plus 1..N body forms | closure. E302 when applied with the wrong number of arguments | | set! | a name and a single-value expression on the right | zero values. E303 if the name is unbound | | let / letrec | binding list plus 1..N body forms | the values from the last body form. E321 on an uninitialized letrec read | | module | a name, 0..2 header clauses, 1..N body forms | the body, flattened outward. E130 anywhere but top level | ## A common mistake Convenience forms written as shorthand belong to the derived-form reference. ## Keep going Derived Forms holds the shorthand that normalizes into these shapes, and the manual explains when each subexpression runs. [Derived Forms](/en/docs/reference/derived-forms) · [Expressions and Evaluation Order](/en/docs/manual/evaluation-order) --- Source: https://www.lispex.com/v1.20/en/docs/reference/derived-forms.md # Derived Forms > `cond`, `case`, `and`, `or`, `when`, `unless`, `let*`, `do`, quasiquote, and `guard` are built into the normalizer rather than written as user macros. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/derived-forms Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you See exactly which core forms each shorthand becomes, and that no user macro can change that rewriting. The normalizer is the built-in step that rewrites these shorthand forms into core forms before anything runs. ## See it run ```lispex (let* ((x 6) (y (+ x 1))) (* x y)) ``` **Observed result** ```text 42 ``` ## How to reason about it - Expansion uses fresh names and hidden built-in helpers, so shadowing a name in your own code cannot change what an expansion means. - Normalization preserves defined tail positions and source diagnostics. - `guard` is a fixed core-facing construct for catchable errors, not a general macro facility. ## What each written form becomes | Written form | Core strategy | Pinned boundary | | --- | --- | --- | | cond / case | nested if with fresh temporaries, and case uses a hidden eqv? | tail clause preserved, and no cond => | | and / or | short-circuit nested if | single final operand remains tail | | when / unless | if plus begin or zero-value values | false path returns zero values | | named let / do | hygienic letrec loop | recursive application is tail | | quasiquote | quote plus hidden constructors | bare unquote outside quasiquote is static E1xx | ## A common mistake `define-syntax`, syntax objects, and arbitrary expansion are rejected. ## Keep going Core Forms holds the shapes these rewrite into, and the manual helps you choose between the conditionals. [Core Forms](/en/docs/reference/core-forms) · [Conditionals and Derived Forms](/en/docs/manual/conditionals) --- Source: https://www.lispex.com/v1.20/en/docs/reference/reserved-and-forbidden.md # Reserved and Forbidden Names > Twenty-seven names cannot be bound and twelve forms cannot be used. Some notations other Lisps have are simply absent here. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/reserved-and-forbidden Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you You can tell whether the name you just wrote will be rejected, and which code rejects it. ## See it run ```lispex (define else 5) else ``` **Observed result** ```text 5 ``` `else` is not a reserved word. It only means something at the head of a `cond`, `case`, or `guard` clause, so using it as a name is accepted. `(define include 1)`, on the other hand, is rejected with E120. `include` is an ordinary English word that invites use as a variable, and it sits on the forbidden list. ## How to reason about it - Binding a reserved word is E110. Rename the variable. - A forbidden form in code position is E120, whether you bind it or call it. Quoted data is not code, so `'include` is an ordinary symbol. - Notations the reader rejects never reach normalization. - Some notations you learned in another Lisp are simply absent here. A few have no diagnostic, so read the list below. ## The twenty-seven names you cannot bind Put any of these in a `define`, a `let`, or a parameter list and you get E110. | Group | Names | | --- | --- | | quoting | quote quasiquote unquote unquote-splicing | | core | lambda if begin set! define | | binding | let let\* letrec | | branching | cond case guard and or when unless do | | modules | module export import | | values and control | values call-with-values call/cc dynamic-wind | The four on the last row are reserved words and procedures at once, so they can be referenced as values. The other twenty-three name forms only, and standing alone in value position they are an error. ## The twelve forms you cannot use | Form | What to use instead | | --- | --- | | define-syntax syntax-rules syntax-case let-syntax letrec-syntax | there are no user macros. Solve it with procedures | | define-values let-values let\*-values | `call-with-values` | | define-library include include-ci include-library-declarations | `module`, and joining the files yourself | The name in code position is enough for E120. Quoted data is not code, so `'include` is an ordinary symbol. ## Notations the reader rejects outright | Notation | Result | | --- | --- | | `#;` datum comment | E120 | | `#lang` directive | E120 | | `[` `]` `{` `}` | E100, with a message of its own | ## Notations that do not exist - The `cond` arrow clause `=>` is unsupported and raises E130. The `case` arrow clause has no diagnostic at all, so `=>` reads as a name and raises E300. - A parameter list written as a bare name with no parentheses, as in `(lambda args ...)`, is E130. To gather arguments, write `(lambda (x . rest) ...)` or `(define (f . xs) ...)`. - Datum labels `#0=` and `#0#` do not exist. E100. - There are no `#!` reader directives. E100. There is no notation at all for declaring something at the top of a file. - The radix and exactness prefixes `#x` `#b` `#o` `#e` `#i` do not exist. E100. - Pipe-quoted symbols like `|a b|` do not exist. `|` is an ordinary character, so that reads as the two names `|a` and `b|`. ## A common mistake E110 and E120 both come from names, but they mean different things. E110 means you tried to cover something that exists. E120 means you called for something that does not. ## Next steps The exact shapes live in the core and derived form references, and the meaning of each code lives in the diagnostic catalog. [Core forms](/en/docs/reference/core-forms) · [Errors and warnings](/en/docs/reference/diagnostic-catalog) --- Source: https://www.lispex.com/v1.20/en/docs/reference/reader-grammar.md # Reader Grammar > The reader grammar defines whitespace/comments, identifiers, booleans, characters, strings, numeric tokens, lists, vectors, bytevectors, and quotation prefixes. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/reader-grammar Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Decide whether a token you have written is accepted, and see exactly which spellings the reader rejects rather than quietly drops. ## See it run ```lispex (list #\a #\x41 "\x41;" #true) ``` **Observed result** ```text (a A A #t) ``` The base spelling of a character is `#\` followed by one scalar, as in `#\a`. Hexadecimal works too, and there it carries no semicolon. Named characters are only the fourteen listed below. The escapes a string accepts are a closed set as well. There are six, `\"`, `\\`, `\n`, `\t`, `\r`, and the hexadecimal `\xHEX;`, which does carry the semicolon. Any other letter after the backslash is E150. There is no `\a` here, common as it is elsewhere. `#true` and `#false` are the same values as `#t` and `#f`. ## How to reason about it - An integer is written `-?(0|[1-9][0-9]*)`. A rational is an integer numerator over a positive denominator in the one accepted spelling, and a real requires a fraction or an exponent. - Dotted-list placement, escape spelling, byte range, and delimiter closure are checked before normalization. - Strings spell a hexadecimal scalar as `\xHEX;`, while characters spell it as `#\xHEX` without the semicolon. - Source spans use the reader input identity and deterministic positions. - A leading plus sign makes a name, not a number. Only a minus sign is accepted there, so `(define +5 7)` simply works. - An empty fraction, as in `1.`, is E100. One of the fraction or the exponent has to actually be written. - The only brackets are `(` and `)`. Write `[` or `{` and you get E100 with a message of its own. - A dot marks a dotted pair only when a delimiter follows it, so `...` and `.foo` are ordinary names. A vector accepts no dot at all, so `#(1 . 2)` is E100. - Bytevector elements are integers from 0 through 255 written out literally. Even `#u8(4/2)`, which would compute to 2, is rejected. ## Pinned token grammar | Token | Accepted shape | Rejected boundary | | --- | --- | --- | | integer | -?(0\|[1-9][0-9]*) | leading zero, radix/exactness prefix | | rational | <integer>/[1-9][0-9]*, reduced after read | zero/negative denominator spelling, leading-zero denominator | | real | decimal with fraction and/or exponent | bare integer ambiguity, non-finite literal | | string | quoted UTF-8 with pinned escapes, including `\xHEX;` | unterminated escape or missing hexadecimal semicolon | | character | #\\<scalar>, `#\xHEX`, or pinned named form | invalid scalar or a semicolon after the hexadecimal character | | bytevector | #u8(<byte> ...) | element outside 0..255 | The named characters are exactly `space`, `newline`, `linefeed`, `tab`, `return`, `null`, `nul`, `delete`, `rubout`, `escape`, `esc`, `backspace`, `alarm`, and `page`. Line comments begin with `;`. Block comments use nested `#| ... |#`. `#;` datum comments and `#lang` directives are rejected with `E120` rather than quietly dropped the way whitespace and comments are. ## A common mistake Reader extensions not listed in the profile fail loudly. ## Keep going The manual walks the same grammar as a reading process, and the catalog lists the code a rejected token produces. [Source Text, Tokens, and Reader](/en/docs/manual/source-reader) · [Error and Warning Catalog](/en/docs/reference/diagnostic-catalog) --- Source: https://www.lispex.com/v1.20/en/docs/reference/diagnostic-catalog.md # Error and Warning Catalog > Stable diagnostics are indexed by phase and code so callers can distinguish reader, normalization, runtime, warning, and resource outcomes. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/diagnostic-catalog Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Look up a code you have just seen, and tell at a glance which phase produced it and whether your rule can catch it. ## How to reason about it - E300–E340 cover unbound names, application, the number of arguments, assignment, pair/range/type/numeric faults, value contexts, letrec, user errors, exception flow, and stale escapes. - E1xx belongs to reader and static normalization, while W2xx and W3xx belong to ordered warnings. - ResourceLimit is deliberately outside catchable E3xx and is reported as its own outcome. ## Stable runtime codes | Code | Condition | Phase / catchability | | --- | --- | --- | | E300 / E303 | unbound read / set! of unbound name | runtime / catchable | | E301 / E302 | non-procedure application / wrong number of arguments | runtime / catchable | | E310 / E311 / E312 | pair-list domain / range-index / primitive type | runtime / catchable | | E313 / E314 | division by zero / non-finite production | runtime / catchable | | E320 / E321 | value-count misuse / uninitialized letrec read | runtime / catchable | | E330 / E331 / E332 | user error / uncaught raise / non-continuable handler return | runtime / signal-specific | | E340 | escape continuation no longer active | runtime / catchable fault after consumption | | W330 | deprecated `%` call, so prefer `modulo` | runtime warning / once per source call site | | W331 | deprecated `list-first` or `list-rest` call, so prefer `first` or `rest` | runtime warning / once per source call site | | ResourceLimit | declared recursion/resource ceiling | resource / not catchable as E3xx | ## A common mistake Codes are stable contracts only where the one authoritative runtime definition pins them. ## Keep going The manual shows how to read a diagnostic in a running program, and the guide shows how a rule recovers from one. [Errors, Warnings, and Diagnostics](/en/docs/manual/diagnostics) · [Handling Errors Deterministically](/en/docs/guides/errors) --- Source: https://www.lispex.com/v1.20/en/docs/reference/procedure-index.md # Procedure Index > The built-in procedures are a closed list of 205 names, grouped into numeric, equality, list, string/character, higher-order, and output families. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/procedure-index Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Reach the family page that owns a signature, and settle whether a name you are about to call is one of the 205 built-ins at all. ## How to reason about it - The R7RS spelling is the preferred name. Documented aliases mean the same thing, and deprecated aliases emit warnings. - Every procedure takes either a fixed number of arguments or a declared variable number, and every type or domain failure is a deterministic E3xx. - The family pages own signatures and edge behavior, and this page is the navigation index. - The built-in denominator is exactly 205 names, and the complete list is printed below. ## Procedure families | Family | Preferred names | Arguments / result | | --- | --- | --- | | Arithmetic | + - * / abs square min max floor ceiling round truncate | declared variable count or one argument, returning a number | | Integer division | modulo quotient remainder floor-quotient floor-remainder truncate-quotient truncate-remainder floor/ truncate/ | 2 integers, returning one or two values | | Equality | eq? eqv? equal? = < > <= >= boolean=? | 2 or more values in the documented domain, returning a boolean | | Predicates | zero? positive? negative? even? odd? null? pair? list? empty? boolean? char? string? symbol? number? integer? procedure? vector? bytevector? | 1 argument, returning a boolean | | Lists / aggregates | cons car cdr list append reverse list-ref vector vector-ref vector-set! bytevector-u8-ref | family-specific, returning a value or zero values | | Higher order | map filter reduce fold-left fold-right all? any? apply for-each vector-map string-map | procedure plus collection(s), returning a collection, an accumulator, or zero values | | Exceptions / output | error raise raise-continuable with-exception-handler display write newline println | contract-specific, producing a signal, one or more values, or zero values | ## The closed list of 205 names ```text != % * + - / < <= = == > >= abs all? any? append apply assoc assq assv boolean=? boolean? bytevector bytevector-length bytevector-u8-ref bytevector? caaaar caaadr caaar caadar caaddr caadr caar cadaar cadadr cadar caddar cadddr caddr cadr call-with-current-continuation call-with-values call/cc car cdaaar cdaadr cdaar cdadar cdaddr cdadr cdar cddaar cddadr cddar cdddar cddddr cdddr cddr cdr ceiling char->integer char-alphabetic? char-ci<=? char-ci=? char-ci>? char-downcase char-foldcase char-lower-case? char-numeric? char-upcase char-upper-case? char-whitespace? char<=? char=? char>? char? complex? cons display dynamic-wind empty? eq? equal? eqv? error error-object-irritants error-object-message error-object? even? exact exact->inexact exact-integer-sqrt exact-integer? exact? expt filter first floor floor-quotient floor-remainder floor/ fold-left fold-right for-each gcd inexact inexact->exact inexact? integer->char integer? lcm length list list->string list->vector list-copy list-first list-ref list-rest list-tail list? make-bytevector make-list make-string make-vector map max member memq memv min modulo negative? newline not nth null? number->string number? odd? pair? positive? println procedure? quotient raise raise-continuable rational? real? reduce remainder rest reverse round square string->list string->number string->symbol string->vector string-append string-ci<=? string-ci=? string-ci>? string-copy string-downcase string-foldcase string-for-each string-length string-map string-ref string-upcase string<=? string=? string>? string? substring symbol->string symbol=? symbol? truncate truncate-quotient truncate-remainder truncate/ values vector vector->list vector->string vector-copy vector-for-each vector-length vector-map vector-ref vector-set! vector? with-exception-handler write zero? ``` ## A common mistake An unlisted host global is not an implicit primitive. ## Keep going The family pages carry the exact signatures, domains, and failure codes behind these names. [Numeric Procedures](/en/docs/reference/numeric-procedures) · [Lists and Aggregates](/en/docs/reference/list-aggregate-procedures) · [Text and Bytes](/en/docs/reference/string-char-bytevector) · [Higher-Order Procedures](/en/docs/reference/higher-order-procedures) --- Source: https://www.lispex.com/v1.20/en/docs/reference/numeric-procedures.md # Numeric Procedures > Numeric procedures cover exact and mixed finite-real arithmetic, exact comparison, integer division, rounding, gcd/lcm, and exact integer square root. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/numeric-procedures Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Check how many arguments a numeric operation takes, whether the result stays exact, and which fault a zero divisor or a non-finite result produces. ## See it run ```lispex (call-with-values (lambda () (exact-integer-sqrt 20)) list) ``` **Observed result** ```text (4 4) ``` ## How to reason about it - `+ - * /` are specified to take any number of arguments. Comparisons require at least two arguments, and integer-domain operations reject non-integers. - `floor/` and `truncate/` return quotient and remainder as two values. - `expt` accepts an exact-integer exponent, and `exact-integer-sqrt` returns root and remainder. ## Numeric signatures | Signature | Result | Fault boundary | | --- | --- | --- | | (+ number ...) / (* number ...) | number, exact unless any operand is inexact | E312 wrong type, E314 non-finite | | (/ number number ...) | exact rational or finite real | E313 zero divisor, E314 non-finite | | (floor/ integer integer) | two values, the quotient and the remainder | E312 non-integer, E313 zero divisor | | (expt number exact-integer) | number preserving base exactness | E313 exact zero to a negative power, E314 unrepresentable | | (exact-integer-sqrt exact-nonnegative-integer) | two exact values, the root and the remainder | E312 wrong domain | ## A common mistake General transcendental functions and non-finite values are absent. ## Keep going The manual explains the exactness and contagion rules behind these signatures, and the index places them among the other families. [Exact and Inexact Numbers](/en/docs/manual/numbers) · [Procedure Index](/en/docs/reference/procedure-index) --- Source: https://www.lispex.com/v1.20/en/docs/reference/list-aggregate-procedures.md # List and Aggregate Procedures > Lists, pairs, vectors, and bytevectors have explicit proper-list, index, identity, and mutation boundaries. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/list-aggregate-procedures Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Check the argument shape of an aggregate operation, whether it returns a fresh value or keeps the original identity, and which of E310, E311, and E312 a bad argument raises. ## See it run ```lispex (list (list-ref (list 10 20 30) 1) (vector-ref #(4 5) 0)) ``` **Observed result** ```text (20 4) ``` ## How to reason about it - List access/search includes the c...r family, `list-ref`, `list-tail`, `member`/`assoc` variants, copy, append, reverse, and constructors. - Vector construction, access, copy, map, and `vector-set!` are available. Bytevectors are read-only in this profile. - Bad pair/list domains are E310, bad indices or ranges are E311, and wrong primitive types are E312. ## Aggregate signatures | Signature | Result / identity | Fault | | --- | --- | --- | | (cons a d) | fresh pair | none | | (car pair) / (cdr pair) | stored component | E310 non-pair | | (list-ref proper-list k) | k-th element | E312 non-integer, E311 range, E310 list that does not end properly | | (vector-ref vector k) / (vector-set! vector k value) | element / zero values, and the vector keeps its identity | E312 type, E311 range | | (bytevector-u8-ref bytevector k) | exact integer 0..255 | E312 type, E311 range | ## A common mistake Pair and bytevector mutators are deferred, and quoted aggregates cannot be mutated. ## Keep going The manual says which aggregates exist and which of them can be mutated, and the index places these names among the other families. [Data and Aggregate Types](/en/docs/manual/data-types) · [Procedure Index](/en/docs/reference/procedure-index) --- Source: https://www.lispex.com/v1.20/en/docs/reference/string-char-bytevector.md # String, Character, and Bytevector Procedures > Strings and characters use Unicode scalar values with a documented ASCII-exact case approximation, and bytevectors contain bytes 0 through 255. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/string-char-bytevector Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Check a text or byte signature, and see where the ASCII-exact case approximation and the read-only bytevector profile stop you. ## See it run ```lispex (list (string-upcase "Lispex") (char-numeric? #\7) (bytevector-u8-ref #u8(65) 0)) ``` **Observed result** ```text ("LISPEX" #t 65) ``` ## How to reason about it - String construction, length, reference, copy, append, comparison, case conversion, mapping, and list/vector conversion are supported. - Character predicates and comparisons are deterministic, and `char-numeric?` recognizes ASCII digits only. - Bytevector length and `bytevector-u8-ref` are available with strict byte/range checks. ## Text and byte signatures | Signature | Result | Current boundary | | --- | --- | --- | | (string-ref string k) | Unicode scalar character | E312 type, E311 range | | (string-append string ...) | fresh immutable string | no string-set! in the current profile | | (char-ci=? char char ...) | boolean under ASCII-exact approximation | documented Unicode folding edges remain | | (string-map proc string) | fresh string, left-to-right callbacks | one string only, and the callback returns exactly one character | | (bytevector-u8-ref bytes k) | exact integer 0..255 | read-only bytevector profile | ## A common mistake Exact Unicode folding, mutable strings, bytevector mutation/copy, and UTF-8 codecs are deferred. ## Keep going The manual places text and byte values among the other aggregates, and the index places these names among the other families. [Data and Aggregate Types](/en/docs/manual/data-types) · [Procedure Index](/en/docs/reference/procedure-index) --- Source: https://www.lispex.com/v1.20/en/docs/reference/higher-order-procedures.md # Higher-Order Procedures > `map`, `filter`, `reduce`, folds, `for-each`, vector/string variants, and `apply` call guest procedures through the interpreter application path. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/higher-order-procedures Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Check the traversal order of a higher-order procedure, how many values its callback may return, and that every one of them takes a single collection. Guest means your own Lispex code, as opposed to the host, the surrounding program Lispex runs inside. ## See it run ```lispex (fold-right cons (list) (list 1 2 3)) ``` **Observed result** ```text (1 2 3) ``` ## How to reason about it - List, string, and vector traversal is left to right. `fold-right` is the deliberate exception, and it calls `(f element accumulator)` from the right. - `reduce` and `fold-left` are the same left fold and call `(f accumulator element)`. - `all?` and `any?` stop as soon as the answer is known. Their predicate must return `#t` or `#f`, while `filter` uses ordinary Lispex truthiness instead. - `for-each` runs for effect, accepts any number of callback values, and returns zero values itself. - Callback errors and one-shot escapes stay inside the program that runs your rule. LIL does not hand the procedure to the host's own `apply` or to a host callback. ## Callback contracts | Signature | Traversal / result | Value context | | --- | --- | --- | | (map proc list) | left-to-right, fresh proper list | callback exactly one value | | (filter predicate list) | left-to-right, retained elements | predicate exactly one value, and only #f rejects | | (all? predicate list), (any? predicate list) | left-to-right and stopping early, strict boolean | predicate exactly one boolean | | (reduce proc init list), (fold-left proc init list) | left accumulator | callback exactly one value | | (fold-right proc init list) | right accumulator | callback exactly one value | | (string-map proc string), (vector-map proc vector) | left-to-right, fresh result | callback exactly one value, and a string result must be a character | | string/vector/list for-each | left-to-right effects, overall zero values | callback results are discarded | | (apply proc arg ... final-list) | shared application dispatcher, tail-safe | every value the procedure returns is preserved | ## A common mistake These procedures accept one collection, not the multi-list variants offered by some Scheme systems. String characters and vector elements are snapshotted before the first callback, so mutating the source vector during traversal does not change which elements are visited. ## Keep going The guide assembles these procedures into one working pipeline, and the index places them among the other families. [Working with map, filter, fold, and apply](/en/docs/guides/higher-order) · [Procedure Index](/en/docs/reference/procedure-index) --- Source: https://www.lispex.com/v1.20/en/docs/guides/ai-assistant.md # Use Lispex with an AI Assistant > Connect the local Native MCP server for exact language lookup, trusted-source evaluation, diagnostics, and fixed runtime comparisons. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/ai-assistant Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Connect one local command to an MCP-capable assistant and use an exact write-run-repair loop for Lispex source. ## Connect the Native server Install Native from [Downloads](/en/downloads), confirm `lispex --version`, and add this local stdio server to the assistant. ```json { "mcpServers": { "lispex": { "command": "lispex", "args": ["mcp", "serve"] } } } ``` The installed Native executable owns `lispex mcp serve`. After reconnecting, the assistant receives four tools. | Tool | Result | | --- | --- | | `lispex_reference` | forms, procedures, reader spellings, resource profiles, and runtime routes | | `lispex_eval` | Rust tree reference observation for reviewed source | | `lispex_diagnostic` | explanation of an exact diagnostic code such as `E302` | | `lispex_compare_routes` | agreement or disagreement for one named runtime comparison | ## First request > Use the Lispex tools. Check that `if` is admitted, write a rule that returns > `approve` when the input is at least 10 and `review` otherwise, run it with > input 12, and repair any diagnostic before answering. The assistant can check the form, evaluate the program, and resolve diagnostics against the installed catalog. Lispex requires an `else` arm on `if`; `#f` is the false value; the reader publishes its exact accepted comment forms. ## Local data flow The Lispex server communicates through local stdio. The guest program receives explicit datum input and the language's pure computation surface. The tool result contains the source hash, observations, and diagnostics, and source storage ends with the request. The surrounding assistant application applies its own data policy to text entered into that application. ## Compare runtime routes The built-in comparison is ready with the base server. ```json { "court": "tree-rust", "source": "(+ input 1)", "input": "41" } ``` It compares the Rust tree reference and Rust VM over one source, input, Core IR, bytecode, and resource request. Add exact Topaz products at server startup for the `rust-topaz` and `all-four` comparisons. ```json { "command": "lispex", "args": [ "mcp", "serve", "--topaz-vm", "/absolute/path/to/topaz-vm", "--topaz-compiler", "/absolute/path/to/topaz-compiler", "--rust-tools", "/absolute/path/to/rust-tools" ] } ``` `rust-topaz` compares the two virtual machines. `all-four` adds the tree run and a product compiled ahead of time for the request. Each comparison retains its selected route set. ## Authoring resource profile | Resource | Value | | --- | ---: | | source per request | 65,536 bytes | | input per request | 16,384 bytes | | evaluation result | 1 MiB | | evaluation wall time | 5 seconds | | comparison result | 4 MiB | | `all-four` wall time | 11 minutes | Timeout, cancellation, malformed input, unavailable product, build, cleanup, and process terminal states are returned explicitly. Use this surface with reviewed authoring source. The [Resource-Controlled Evaluator Contract](/en/docs/reference/bounded-evaluator) is the application runtime for untrusted rules. Optional products are selected from absolute startup paths. Comparison output is an authoring observation. The Vouch workflow adds publisher authentication, request binding, current re-execution, and a local gate. Close the MCP stdio connection when finished. The local process exits and releases request state. [MCP Tool Reference](/en/docs/reference/mcp) · [Learning Path](/en/docs/learn) · [Lispex Vouch](/en/docs/vouch) --- Source: https://www.lispex.com/v1.20/en/docs/reference/runtime-backends.md # Runtime and Backends > Choose among the Rust reference runtime, LIL, LIT, the Rust VM, and installed Topaz products through explicit versioned routes. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/runtime-backends Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you You will understand each runtime family, its current capability count, its artifact lineage, and the product route that executes it. ## Runtime families | Family | Current capability rows | Implementation lineage | Primary role | | --- | ---: | --- | --- | | Rust reference | 205/205 | installed Rust reference interpreter | operational language reference | | LIL | 205/205 | interpreter written in Lispex | self-hosted language route | | LIT | 84/205 | Topaz transcription | Topaz-owned implementation route | All 205 registry rows carry `profile-required`. Each backend reports its implemented rows through the same versioned observation contract. LIT returns an explicit capability status for the remaining 121 rows, which gives Topaz a precise implementation queue. The historical family receipt binds 144 named cases to executed Rust, LIL, and LIT product-runner artifacts, resource profiles, observations, and replay. ## Rust product surfaces | Product | Runtime and tools | | --- | --- | | Native | Rust tree reference, Rust VM, formatting, MCP authoring, Core IR, bytecode, installed Topaz VM and AOT routes on macOS ARM64, receipt generation, and the full Vouch chain | | npm CLI and package | Rust reference through WebAssembly, image support, offline receipt verification and replay, policy tooling, and authenticated Vouch verification | | Public WebAssembly | Rust reference API and image encode, inspect, decode, and run | | Playground | Interactive Rust reference execution and image workflows in the browser | Native, npm, Public WebAssembly, and Playground share the whole-source interactive projection. They read and normalize the complete source, render explicit output and each successful form in order, and report terminal status as `0`, `1`, or `2`. Ordinary runtime faults retain output already committed by earlier forms. Resource termination returns empty output, one resource diagnostic, and status `2`. Browser results expose `output`, `diagnostics`, `ok`, and `exit_status` directly. `lispex fmt`, `fmt --check`, and `fmt --write` use the installed Native binary. The VS Code and Open VSX extension delegates Format Document to that binary. `lispex mcp serve` uses local stdio to provide the current language and primitive registry, authoring evaluation of trusted source under declared byte and time limits, diagnostics, and fixed route comparisons. Native owns this authoring surface. ## Core IR and compiled execution Native lowers the complete current profile to canonical `lispex.core-ir/v1`, strictly validates it, and exposes resolved cells, captures, tail positions, requirements, source anchors, and identities. Strict Core IR compiles to canonical `lispex.bytecode/v1`. The verifier checks the artifact before VM state is created, and `lispex-rust-vm/v1` executes all 205 primitive rows, including the 18 guest-calling rows through iterative VM state machines. Rust tree remains the default engine; `--engine vm` selects the VM explicitly. On Native macOS ARM64, the installed `lispex-topaz-vm/v1` product reads the same bytecode through its own Topaz reader, verifier, and explicit-control VM. The request records exact source, Core IR, bytecode, input, product identity, full-`u64` transition limit, transport caps, and five zero fallback counters. The Topaz AOT route emits a readable static control graph, compiles it with the installed Topaz 5.11 toolchain, and creates a source-free product. Its product, source map, executable, tool identities, input, resource request, and observations remain bound through `aot build`, `inspect`, `validate`, and `run`. `compare-engines`, `compare-vms`, and `compare-routes` publish atomic diagnostic reports for explicitly selected routes. Each report keeps semantic, resource, and lineage observations in separate fields. ## Vouch integration Core IR and bytecode provide canonical meaning and execution artifacts. Native Vouch creates a source-bound `lispex.vouch-compiled-artifact/v1`, authenticates the request, derives Core IR and bytecode again from the recipient-selected source, records current tree and Meaning agreement, compares the verified Rust VM observation, and passes the result to the local gate. Topaz VM, AOT, and route-comparison reports remain engineering routes with their own product identities. The compiled Vouch path uses the Rust VM artifact derived from the exact recipient-selected source. ## Runner admission record | Field | Recorded value | | --- | --- | | backend kind | interpreter family and versioned route | | invocation | deterministic command or framed protocol | | artifact identity | executed binary, WebAssembly, and glue bytes | | provenance | declared source and producer lineage | | resource profile | named limits and reported counters | | observation scope | exact corpus, family, target, and host variant | These fields keep every comparison attached to the product that produced it and give later releases a precise continuation point. [Bytecode and Rust VM](/en/docs/reference/bytecode-vm) · [Backend Observation Matrix](/en/docs/reference/backend-observation-matrix) · [Choosing Where to Run](/en/docs/guides/choosing-runtime) --- Source: https://www.lispex.com/v1.20/en/docs/reference/cli.md # Native and npm CLI > Use Lispex source, SICP, Meaning Graph, Core IR, verified bytecode, installed runtimes, images, receipts, and Vouch through explicit command families. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/cli Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you You will choose the command that owns each artifact or execution route and interpret its output and exit status. ## Product surfaces | Product | Command surface | | --- | --- | | Native | complete source runtime, SICP, formatting, MCP, Meaning Graph, Core IR, bytecode, Rust VM, installed Topaz VM and AOT routes, images, receipts, and the full Vouch chain | | npm CLI | source runtime through WebAssembly, images, structural receipt verification, replay, policy tools, Vouch authentication, and inspection | Run `lispex --help` or `lispex --help` for flags accepted by the installed version. ## Source and authoring | Command | Reads | Produces | | --- | --- | --- | | `lispex [FILE\|-]` | Lispex source | reference-interpreter value, stdout, warnings, and diagnostics | | `lispex sicp run ` | one SICP source up to 1 MiB | SICP stdout and final value | | `lispex fmt [--check\|--write] [FILE\|-]` | UTF-8 Lispex source | formatted source, quiet check status, or atomic in-place replacement | | `lispex mcp serve` | framed local stdio requests | language and registry reference, authoring evaluation, diagnostics, and fixed route comparisons | The MCP authoring evaluator uses declared byte and time limits. Native owns this local authoring surface. The host application owns workspace paths, network access, and external actions. ## Meaning Graph and Core IR | Command | Reads | Produces | | --- | --- | --- | | `lispex lower --graph-version v1 SOURCE` | exact source through validated Core IR | canonical resolved Meaning Graph v1 | | `lispex eval-graph [--steps N] [--trace] GRAPH` | Meaning Graph v0 or v1 and optional input | tag-selected Meaning report with terminal status and optional trace | | `lispex meaning-diff [--input I] SOURCE` | source and optional datum | current Rust tree and Meaning observations in `csk.meaning-differential-report/v1` | | `lispex core-ir build --source S --out O` | exact source | canonical resolved `lispex.core-ir/v1` and summary | | `lispex core-ir inspect --ir IR` | Core IR | resolved cells, captures, requirements, anchors, and identities | | `lispex core-ir validate --ir IR` | Core IR | strict validation and canonical re-encode result | Core IR build, inspect, and validate report `execution: "not-run"` and `authority: "integrity-only"`. Execution begins with the explicit runtime, Meaning, bytecode, or Vouch command selected by the user. ## Bytecode and runtime routes | Command | Reads | Produces | | --- | --- | --- | | `lispex bytecode build --ir IR --out O` | strict Core IR | verified canonical `.lpxbc` and summary | | `lispex bytecode inspect --bytecode BC` | verified bytecode | identities, counts, requirements, opcodes, roots, and source-map coverage | | `lispex bytecode validate --bytecode BC` | bytecode | strict decode, verify, and canonical re-encode result | | `lispex bytecode run --bytecode BC [--input I]` | verified bytecode and optional datum | Rust VM observation | | `lispex bytecode run --engine topaz --topaz-vm ROOT ...` | installed Topaz product, bytecode, and optional datum | Topaz VM observation under the named resource profile | | `lispex run --backend rust --engine tree\|vm FILE` | Lispex source | explicitly selected Rust tree or VM observation | | `lispex compare-engines --receipt R FILE` | Lispex source | atomic same-lineage tree and Rust VM comparison report | | `lispex compare-vms --topaz-vm ROOT --receipt R FILE` | source and installed Topaz VM | atomic Rust and Topaz VM comparison report | The selected route retains its own error, resource, and lineage status. The comparison reports keep semantic, resource, and provenance fields separate. ## Installed Topaz products | Command | Reads | Produces | | --- | --- | --- | | `lispex routes install ...` | exact catalog entry and stored-ZIP archive | closed product directory and `installation.json` | | `lispex routes fetch --route topaz-vm\|aot-compiler ...` | Native embedded official catalog | HTTPS acquisition and the same closed installation | | `lispex routes lock ...` | reviewed installed route | canonical selection lock | | `lispex routes run --selection LOCK ...` | selection lock and source | observation from the locked route | | `lispex aot build --source S ... --out O` | exact source and absolute build tools | source-free Native product with tool identities | | `lispex aot inspect\|validate --product P` | installed AOT product | inventory, identity, and derivation result | | `lispex aot run --product P [--input I] [--json]` | installed product and resource request | direct executable observation | | `lispex compare-routes ... --receipt R SOURCE` | exact source, input, Topaz VM, and AOT product | atomic four-route semantic, resource, and lineage report | ## Images | Command | Produces | | --- | --- | | `lispex image encode --source SOURCE --out IMAGE` | canonical `.lspx.png` or `.lspx-images.zip` | | `lispex image inspect --image IMAGE` | format, profile, page, identity, and commitment summary | | `lispex image decode --image IMAGE --out SOURCE` | exact recovered source | | `lispex run --image IMAGE` | reference-interpreter observation of recovered source | Vouch commands that accept source context allow exactly one of `--source RULE` and `--source-image IMAGE`. Re-execution and gating pair that source with the separately supplied `--input INPUT`. ## Receipts and Vouch | Command | Produces | | --- | --- | | `lispex diff-receipt --input I RULE` | `csk.differential-receipt/v0` | | `lispex verify RECEIPT [--source RULE]` | offline structural consistency verdict | | `lispex replay CORPUS --against BASELINE` | changed-decision report | | `lispex vouch policy create\|check ...` | canonical recipient trust policy and validation report | | `lispex vouch issue ...` | signed payload, DSSE envelope, and issue report | | `lispex vouch verify ...` | authentication report for the exact signed context | | `lispex vouch verify --reexecute ...` | authentication plus current tree and Meaning agreement | | `lispex vouch gate --require-decision ...` | live local grant or denial and gate report | | `lispex vouch compiled build ... --out A` | source-bound `lispex.vouch-compiled-artifact/v1` and summary | | `lispex vouch compiled inspect --artifact A` | container and embedded-bytecode integrity summary | | `lispex vouch compiled validate ...` | exact source→Core IR→bytecode derivation result | | `lispex vouch verify --reexecute --compiled-artifact A` | current tree, Meaning, and verified Rust VM agreement | | `lispex verify-bridge REPORT` | Bridge structure and receiver-selected byte-binding verdict | The compatibility names `receipt`, `issue-native`, `verify-native`, and the flat `verify` retain their published artifact contracts. Namespaced `vouch` commands provide the authenticated workflow. ## Exit status and publication - Exit `0` means the requested operation succeeded. - Exit `10` on authenticated Vouch routes means authentication succeeded and the gate or diagnostic-promotion stage withheld admission. - Exit `1` reports validation, runtime, comparison, or authentication rejection. - Exit `2` reports usage, selected-engine, or resource handling errors. - Exit `3` reports input/output or named-report publication errors. Named artifacts and reports are published atomically to a new path. JSON artifacts keep stdout byte-clean. The host application consumes a local gate result and owns the resulting external action. [Bytecode and Rust VM](/en/docs/reference/bytecode-vm) · [Core IR Contract](/en/docs/reference/core-ir) · [Choosing Where to Run](/en/docs/guides/choosing-runtime) --- Source: https://www.lispex.com/v1.20/en/docs/guides/choosing-runtime.md # Choosing a Runtime > Choose the reference interpreter, verified Rust VM, Topaz VM, Topaz AOT, resource-controlled embed, npm, WebAssembly, Playground, or SICP surface. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/choosing-runtime Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Match your task to a Lispex execution product, inspect its exact identity, and record the route you selected. ## Quick choices | Task | Product | | --- | --- | | run ordinary `.lspx` source | reference interpreter through Native, npm, WebAssembly, or Playground | | execute verified bytecode | Native Rust VM | | compare a separately installed VM | Topaz VM on Native macOS ARM64 | | build a standalone executable | Topaz AOT on Native macOS ARM64 | | run a supplied rule with explicit resource values | `lispex embed` or `lispex embed full` | | create and recover exact source images | Native, npm, WebAssembly, or Playground | | authenticate signed decision evidence and evaluate a local gate | Native Vouch, with npm verification | | study SICP | sicp.io, `lispex sicp run`, Playground SICP profile, or `@lispex/sicp` | | compare implementation families | Native differential, Meaning, and route comparison commands | ## Reference interpreter The reference interpreter runs the complete current Lispex profile and remains the default for `lispex rule.lspx`. It is the direct authoring and application route across Native, npm, WebAssembly, and the Playground. ## Verified virtual machines Native compiles source through canonical Core IR and verified bytecode into the Rust VM with `--engine vm`. On macOS ARM64, Native can also use an exact installed Topaz 5.11 VM and compare both virtual machines over one bytecode artifact. The Rust tree and Rust VM share the Rust implementation lineage. The Topaz VM uses a separately maintained source implementation and records its Topaz Rust Stage 0 producer identity. Comparison receipts publish both lineages, exact artifacts, results, diagnostics, and resources. ## Standalone AOT product The Topaz AOT route emits readable Topaz, a source map, and a standalone executable from verified control flow. The route records source, Core IR, bytecode, generated bundle, compiler, executable, request, result, and resource identities. ## Resource-controlled execution `lispex embed` selects the decision profile. `lispex embed full` selects the complete current profile with all 205 primitive rows. Both use import-free WebAssembly components, fresh instances, separate preparation and evaluation resources, and portable cores. ## Inspect and lock a route ```sh lispex routes inventory --out inventory.json lispex routes doctor --inventory inventory.json lispex routes select --route rust-vm --out route.json lispex routes run --selection route.json rule.lspx ``` External products use their exact absolute installation path. Selection locks record product identity and route choice while keeping local paths outside the lock. ## Measure local execution ```sh lispex routes measure \ --selection route.json \ --samples 3 \ --input input.datum \ --out timing.json \ rule.lspx ``` The measurement records host identity, route identity, sample count, and nanosecond observations for that local run. Comparison receipts separately record language results and resource counters. ## Product availability | Product | Main surfaces | | --- | --- | | Native | every execution route, Core IR, bytecode, embed, images, decision exchange, Vouch, and SICP | | npm | reference evaluation, package APIs, images, decision and Vouch verification, and SICP | | WebAssembly | reference evaluation, image codec, and published embed and SICP components | | Playground | browser-local reference evaluation, Lispex Images, Native handoff, and SICP profile | ## Keep going [Downloads](/en/downloads) · [Run Verified Bytecode](/en/docs/guides/verified-bytecode) · [Build a Topaz AOT Product](/en/docs/guides/topaz-aot) --- Source: https://www.lispex.com/v1.20/en/docs/guides/portable-routes.md # Install an Optional Extra Engine > Fetch an exact official Topaz virtual machine or ahead-of-time compiler companion, install a reviewed local archive, and select the route explicitly. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/portable-routes Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you A route here means another way of running Lispex that you install and select explicitly. You can fetch the exact companion admitted by your Native binary, or install a reviewed local catalog and archive. Installation and route selection remain separate steps. ## Start with the ordinary runtime Lispex starts with its built-in reference interpreter. ```sh lispex rule.lspx ``` This reads your source directly. It is the default and the semantic reference. Install a companion when you choose the exact Topaz virtual machine or the admitted Topaz compiler that builds ahead of time. ## Fetch an official companion Native contains an exact, immutable route catalog. The current catalog has two macOS ARM64 entries. They are the Topaz 5.11 virtual machine and the exact Topaz 5.11 compiler that Lispex uses to build ahead of time. Choose a new absolute destination. ```sh lispex routes fetch \ --route topaz-vm \ --target aarch64-apple-darwin \ --out /absolute/tools/lispex-topaz-vm ``` The command uses the immutable URL, channel, version, registry, and catalog in the Native route catalog. It checks the response length, SHA-256, accepted stored-ZIP shape, every installed file, and the closed Topaz product identity before publishing the destination. Target admission is resolved before the download begins. Fetching publishes the installed product. Route selection happens at [Use the product explicitly](#use-the-product-explicitly), where you pass `/absolute/tools/lispex-topaz-vm/product`. Fetch the compiler companion separately when you intend to build a product compiled ahead of time. ```sh lispex routes fetch \ --route aot-compiler \ --target aarch64-apple-darwin \ --out /absolute/tools/lispex-aot-compiler ``` Its closed product contains the exact compiler and release manifest. `aot build` combines that installed compiler executable with the absolute Rust tool directory selected by the caller. ```sh lispex aot build \ --source rule.lspx \ --topaz-compiler /absolute/tools/lispex-aot-compiler/product/bin/topaz-bin \ --rust-tool-bin /absolute/rust/bin \ --out /absolute/products/rule-aot ``` ## Install a handed-off archive offline Obtain these two immutable local files from the same provider handoff. - a `lispex.route-catalog/v1` file in its one accepted form, together with its exact SHA-256 - the stored-ZIP archive named by the exact route and target entry The catalog is a closed allowlist. It names the provider product, language mode, manifest hash, archive hash and length, and every installed file. The installer reads exactly the catalog and archive paths supplied by the caller. ## Install one exact entry Choose a new absolute destination that does not exist. ```sh lispex routes install \ --route topaz-vm \ --target aarch64-apple-darwin \ --catalog /absolute/handoff/routes.json \ --catalog-sha256 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \ --archive /absolute/handoff/topaz-vm-aarch64-apple-darwin.zip \ --out /absolute/tools/lispex-topaz-vm ``` Replace the sample hash with the hash delivered alongside your exact catalog. The command reads local files only. On success it prints the same receipt that it writes here. ```text /absolute/tools/lispex-topaz-vm/ ├── installation.json └── product/ ``` `installation.json` is a `lispex.route-installation/v1` receipt in its one accepted form. It contains no absolute path or timestamp, so moving the unchanged directory preserves its identity. The `product/` directory remains closed for the existing exact product validator. For an admitted ahead-of-time compiler archive, change `--route`. ```sh lispex routes install \ --route aot-compiler \ --target aarch64-apple-darwin \ --catalog /absolute/handoff/routes.json \ --catalog-sha256 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \ --archive /absolute/handoff/lispex-topaz-aot-compiler-aarch64-apple-darwin.zip \ --out /absolute/tools/lispex-aot-compiler ``` The admitted ahead-of-time compiler product targets macOS ARM64. The caller supplies Rust, the linker, the platform development kit, and system libraries for that exact target. ## Use the product explicitly Installation publishes the product while the reference interpreter remains the default. Select the route by supplying the closed product root. ```sh lispex routes inventory \ --topaz-vm /absolute/tools/lispex-topaz-vm/product ``` You can then create a lock and diagnose it. A lock records the identity of the installed product you chose independently from its filesystem path. ```sh lispex routes lock \ --route topaz-vm \ --topaz-vm /absolute/tools/lispex-topaz-vm/product \ --out topaz-route.json lispex routes doctor \ --selection topaz-route.json \ --topaz-vm /absolute/tools/lispex-topaz-vm/product ``` If you relocate the installation, pass the new absolute `product/` path. Neither the lock nor the installation receipt remembers a filesystem path. ## Run the complete installed journey After building the compiled product, take an inventory of both optional engines and create one lock for each. ```sh lispex routes inventory \ --topaz-vm /absolute/tools/lispex-topaz-vm/product \ --aot-product /absolute/products/rule-aot lispex routes lock --route aot \ --aot-product /absolute/products/rule-aot \ --out aot-route.json ``` Use `routes measure --samples 1` for one four-way comparison under fixed limits, then execute only the chosen lock. ```sh lispex routes run \ --selection aot-route.json \ --aot-product /absolute/products/rule-aot \ --input input.datum \ rule.lspx ``` You can move the virtual machine installation or the finished compiled product. Supply its new absolute root to `routes doctor` and `routes run` while keeping the lock unchanged. Doctor revalidates the bytes at that root, and the lock preserves the selection identity across relocation. The maintained [portable route journey](https://github.com/clavef/lispex/tree/develop/examples/portable-routes) shows fetch, build, inventory, locks, doctor, measurement under fixed limits, locked execution, and relocation together. ## What the archive is allowed to contain Lispex accepts only one uncompressed stored-ZIP shape, fixed down to the byte. It rejects compression, Zip64, descriptors, encryption, timestamps, extras, comments, directories, duplicate or unsorted names, path traversal, absolute paths, backslashes, symbolic links, special files, excess files or bytes, and every hash mismatch. It writes through a private sibling stage and publishes only to a destination that still does not exist. Exit 2 reports command usage, exit 1 reports an identity or byte-form contract, and exit 3 reports local input and output, a resource value, or atomic publication. Every result records the selected entry, target, version, path, and engine. ## Artifact roles A valid catalog and installation receipt establish exact byte integrity for installation. Signed distribution policy identifies the provider, comparison receipts record agreement with Rust, and the host application owns external actions. Vouch derives its evidence from authenticated exact source and a consumer-pinned request. The route receipt records `automatic_fallback:false` to preserve the selected engine. ## Keep going Use the runtime chooser for the simple default and the route doctor before any locked advanced execution. [Choosing Where to Run](/en/docs/guides/choosing-runtime) · [Native CLI](/en/docs/reference/cli) · [Build a Product Compiled Ahead of Time](/en/docs/guides/topaz-aot) --- Source: https://www.lispex.com/v1.20/en/docs/guides/lispex-images.md # Lispex Images > A Lispex Image is a machine-readable picture of exact `.lspx` source bytes, fixed down to the byte. Native, npm, and the browser Playground handle them. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/lispex-images Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you A Lispex Image is a machine-readable picture of exact `.lspx` source bytes whose format is fixed down to the byte. Native and npm provide file commands, while the local browser Playground can create, open, navigate, recover, download, and explicitly run the same images. ## How to reason about it - Create one page with `lispex image encode --source rule.lspx --out rule.lspx.png`. Sources that need several pages require the fixed `.lspx-images.zip` destination. A mismatched suffix fails before output. - Inspect format/profile identifiers, page count, exact-source identity, and every integrity commitment with `lispex image inspect --image rule.lspx.png`. Inspection never prints the source. - Recover byte-for-byte source with `lispex image decode --image rule.lspx.png --out recovered.lspx`. Existing outputs are never overwritten. - Run only after full decoding, integrity checks, parity checks, and a rebuild that matches the stored bytes exactly, with `lispex run --image rule.lspx.png`. - Line endings, comments, spacing, and Unicode bytes survive the round trip exactly. The image represents source bytes, not only parsed forms. - In the Playground, Create image uses the editor bytes, Open image proves a local PNG/ZIP before preview, page controls extract only proved PNG pages, Recover source changes the editor without running it, and Run image remains a separate explicit action. - After the image is fully proved, use it as Vouch source context with `--source-image`. Vouch adds producer authentication, recipient trust policy, request binding, current replay, and the local gate decision. ## Exact image commands ### 1. Encode exact source ```sh lispex image encode --source refund-window.lspx --out refund-window.lspx.png ``` ### 2. Inspect public commitments ```sh lispex image inspect --image refund-window.lspx.png ``` ### 3. Recover the exact bytes ```sh lispex image decode --image refund-window.lspx.png --out recovered.lspx ``` ### 4. Prove and run explicitly ```sh lispex run --image refund-window.lspx.png ``` ## A common mistake Screenshots, resizing, color conversion, metadata injection, recompression, page removal, and page reordering are rejected. This is an exact digital interchange format, not OCR or a camera-readable code. ## Product roles - A Lispex Image is source-equivalent public data with exact-byte integrity. - Native and npm expose the same file commands. The public WebAssembly build exposes the same Rust image operations for embedding, and the Playground wraps them in a local file UI. - Native accepts `--source-image` throughout Vouch identity, policy, issue, inspect, authentication, re-execution, and gate. npm accepts it for identity, policy, and authenticated verification. The recipient supplies the exact input and applies the request-bound authority chain. ## Keep going Once the workflow is comfortable, check the runtime chooser before moving it into a local tool or deployment. [Learning Path](/en/docs/learn) · [Choosing Where to Run](/en/docs/guides/choosing-runtime) --- Source: https://www.lispex.com/v1.20/en/docs/reference/image-format-safety.md # Image Format and Safety > The `csk.lispex-image/v2` format carries up to 1 MiB of Lispex source in one byte-exact PNG or an ordered ZIP page set. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/image-format-safety Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you You will understand the exact image layout, decoder limits, integrity checks, and the role of a Lispex Image in Vouch. ## Byte-exact format The format fixes its image, inspection, profile, and codebook tags; a 1304-pixel width; the Sunlit Amber palette; page geometry; fixed-Huffman PNG encoding; stored-ZIP grammar; page order; and manifest bytes. The decoder accepts up to 1 MiB of source, 16,384 reader nodes, reader depth 256, and 32 pages. It validates lengths and offsets before allocation. Reed–Solomon parity detects changed payload symbols, and regeneration checks the exact supplied PNG or ZIP bytes. ```text decode(encode(source)) = source encode(decode(image)) = image ``` ## Artifact roles | Product | Role | | --- | --- | | Lispex Image | Carries exact source bytes in a canonical PNG or page set | | `image inspect` | Reports format, profile, page count, source identity, and commitments | | `image decode` | Returns source after structure, integrity, parity, and regeneration checks | | Vouch | Connects recovered source identity to authentication, request binding, re-execution, and a local gate | | Host media workflow | Owns visual presentation, resizing, distribution privacy, and access control | [Lispex Images](/en/docs/guides/lispex-images) · [Lispex Vouch overview](/en/docs/vouch) --- Source: https://www.lispex.com/v1.20/en/docs/reference/core-ir.md # Core IR Contract > The canonical `lispex.core-ir/v1` contract records the resolved meaning of the current profile in one validated representation of up to 16 MiB. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/core-ir Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you You can identify a Core IR artifact, understand the resolved facts it records, and connect intact bytes to execution and Vouch through their dedicated commands. Canonical on this page means one fixed form, down to the byte, so the same meaning always produces the same bytes. ## Fixed identities | Axis | Identity | | --- | --- | | artifact schema | `lispex.core-ir/v1` | | semantic profile | `lispex-profile-1.5` | | primitive registry | `lispex.primitive-registry/v1` | | cost model | `lispex.core-ir-cost/v1` | | producer family | `lispex-rust-core-ir/v1` | | artifact hash domain | `lispex/core-ir-hash/v1` | | registry hash domain | `lispex/primitive-registry-hash/v1` | The registry gives each of the 205 executable builtin names one stable numeric ID. A hidden normalizer intrinsic uses its primitive ID directly. A source-visible builtin remains an ordinary mutable global cell initialized with that ID, so shadowing and top-level redefinition keep their current meaning. ## From source to resolved meaning ```text exact source bytes → reader → hygienic normalized Core → binding and closure resolution → canonical Core IR bytes ``` The artifact removes shorthand syntax and records the following. - lexical and global cell identities instead of name lookup - fixed and rest parameters, `let`, `letrec`, internal definitions, and dynamically activated forwarding definition cells - shared mutable closure captures, including transitive captures - ordinary and tail calls without asking a consumer to infer tail position - zero, one, and multiple-value contexts - guard, exception, continuation, and dynamic-wind control boundaries - canonical literal data and one-based source anchors - explicit input requirements - primitive-registry and cost-model identities The audit projection reproduces the exact normalized Canonical Core bytes used before lowering and records preservation inside the Rust lineage. Other backends add their own implementation identities and execution observations. ## One accepted encoding The artifact is canonical UTF-8 JSON with fixed field order, tagged arrays, minimal non-negative decimal integers, exact Unicode strings, and exactly one final line feed. Globals, requirements, captures, bindings, and functions obey deterministic ordering and continuity laws. Strict reading rejects duplicate, missing, unexpected, or reordered fields. It also rejects alternate number or datum spellings, unknown tags and IDs, broken references, captures, or tail positions, invalid source anchors, trailing bytes, and any artifact that does not re-encode byte for byte. Limits are checked before table reads and allocation. | Limit | Maximum | | --- | ---: | | source input | 4 MiB | | Core IR artifact | 16 MiB | | expression nodes | 100,000 | | bindings | 100,000 | | functions | 100,000 | | globals | 100,000 | | structural depth | 1,024 | The `source_sha256` field uses the existing domain-separated identity of the exact source bytes. `core_ir_sha256` uses the domain-separated identity of the complete canonical artifact. Consumers use these contract fields directly for source and artifact identity. ## Native command reports - `core-ir build` emits `lispex.core-ir-build/v1` when writing a named artifact. With `--out -`, it emits artifact bytes only. - `core-ir validate` emits `lispex.core-ir-validation/v1` after a strict read and re-encode. - `core-ir inspect` emits `lispex.core-ir-inspection/v1` with identities, counts, globals, requirements, and readable normalized roots. - Usage errors exit 2, validation or source errors exit 1, and a run that reaches a declared resource limit or fails on input, output, or publication exits 3. Native owns these three artifact commands. npm, public WebAssembly, and the Playground own source execution through the reference runtime. ## Meaning Graph coexistence Core IR owns name resolution, closure captures, tail positions, and the complete normalized profile. Option-free `lower` and `diff-receipt` retain the published name-level v0 contract. `lower --graph-version v1` projects validated Core IR to resolved `csk.meaning-graph/v1`, `eval-graph` dispatches by graph tag, and `meaning-diff` writes the v1 Meaning comparison report. Native owns these v1 commands. Vouch derives Core IR again from authenticated exact source inside its compiled workflow. ## Product role Core IR is `integrity-only` compilation material. Canonical bytes, strict reading, inspection, and domain-separated identity establish the resolved artifact consumed by Meaning Graph, bytecode compilation, VM execution, and the source-bound compiled Vouch workflow. Recipient policy and current re-execution add authentication and decision context. ## Keep going Use the guide for a short command workflow or the runtime page to compare the places Lispex runs. [Building and Inspecting Core IR](/en/docs/guides/core-ir) · [Runtime and Backends](/en/docs/reference/runtime-backends) --- Source: https://www.lispex.com/v1.20/en/docs/guides/core-ir.md # Building and Inspecting Core IR > Use the Native CLI to turn exact Lispex source into resolved Core IR, then validate or inspect the artifact without executing it. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/core-ir Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you You will build one `.lpxir` artifact, check its exact identity, read its resolved meaning, and see how later execution and Vouch workflows consume it. ## Build without running Core IR is the intermediate form a program is translated into before anything runs it. Start with a source file such as `refund-window.lspx`. ```sh lispex core-ir build \ --source refund-window.lspx \ --out refund-window.lpxir ``` The command reads and normalizes the exact source, resolves names to cells, marks tail calls, records closure captures, and writes `lispex.core-ir/v1` bytes in the one accepted form. The JSON report records `execution: "not-run"` and names the source hash, Core IR hash, primitive-registry hash, semantic profile, and counts held under fixed limits. The destination must be new. Lispex will not overwrite an existing artifact. In a pipeline, `-` means standard input or output. ```sh cat refund-window.lspx | lispex core-ir build --source - --out - >refund-window.lpxir ``` When `--out -` is used, stdout contains only artifact bytes in that one accepted form. Diagnostics stay on stderr. ## Validate before storing or comparing ```sh lispex core-ir validate --ir refund-window.lpxir ``` Validation checks the byte limit, JSON shape, fixed schema/profile/registry identities, source anchors, resolved references, captures, tail positions, datum text in its one accepted form, ordering, and exact re-encoding. A harmless-looking whitespace or field-order change is rejected because one meaning artifact has one accepted byte representation. ## Inspect the resolved meaning ```sh lispex core-ir inspect --ir refund-window.lpxir ``` The inspection report includes the following. - `source_sha256` for the exact input source bytes - `core_ir_sha256` for the complete artifact - counts for globals, requirements, roots, nodes, bindings, and functions - resolved global cells and their initial primitive identities - required explicit host inputs - readable normalized-Core roots with source positions The report says `execution: "not-run"` and `authority: "integrity-only"`. Inspection supports review and deterministic comparison. The `.lpxir` artifact continues into bytecode compilation and execution. ## Continue into verified bytecode Core IR itself remains non-executable. When you need Native to run compiled bytecode instead, lower the strictly validated artifact. ```sh lispex bytecode build \ --ir refund-window.lpxir \ --out refund-window.lpxbc lispex bytecode validate --bytecode refund-window.lpxbc ``` The separate `lispex.bytecode/v1` artifact has its own binary identity, checker, resource model, and Rust virtual machine. Its compiler consumes the `.lpxir` artifact while the inspection report remains a readable projection. ## Core IR and Meaning Graph are different Option-free `lispex lower` still emits the older name-level `csk.meaning-graph/v0`, and `diff-receipt` remains the frozen v0 receipt path. The explicit `lower --graph-version v1` path instead projects validated Core IR into resolved `csk.meaning-graph/v1`; `eval-graph` selects v0 or v1 by tag, and `meaning-diff` emits `csk.meaning-differential-report/v1`. Core IR remains the single authority for resolved cells, captures, and tail positions. Projection preserves those identities directly. Native provides the v1 Meaning commands in v1.19, while Vouch continues through its compiled-artifact workflow. ## Choose the right product Core IR and bytecode commands are available in the Native product. npm, WebAssembly, and the Playground provide source evaluation, images, package APIs, and Vouch verification through their documented surfaces. ## Product roles A matching hash and valid artifact establish canonical Core IR integrity. Signed envelopes identify issuers, recipient policy records trust, request binding selects source and input, re-execution observes a current result, and the Vouch gate records the required local decision. ## Keep going Use the contract reference for the exact format and the CLI reference for automation and exit boundaries. [Run Verified Bytecode](/en/docs/guides/verified-bytecode) · [Core IR Contract](/en/docs/reference/core-ir) · [Native CLI](/en/docs/reference/cli) --- Source: https://www.lispex.com/v1.20/en/docs/reference/bytecode-vm.md # Bytecode, Verifier, and Native VMs > The exact lispex.bytecode/v1 binary, strict verifier, built-in Rust VM, installed Topaz VM, resource model, and Vouch integration. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/bytecode-vm Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you You can identify a bytecode artifact, understand what strict verification checks, reason about the Rust VM execution model, and connect compiled execution to the Vouch workflow. A VM is a virtual machine, the program that runs an already compiled list of instructions. Canonical on this page means one fixed form, down to the byte, so the same meaning always produces the same bytes. A route is one way of running a rule, and a resource profile fixes its limits in advance. ## Product pipeline ```text exact source -> reader and hygienic normalizer -> lispex.core-ir/v1 -> deterministic bytecode compiler -> lispex.bytecode/v1 -> strict reader and verifier -> lispex-rust-vm/v1 -> ordinary Lispex outcome, output, warning, and diagnostic ``` This pipeline compiles the existing `lispex-profile-1.5` and preserves its syntax, datum kinds, primitives, and semantics. The tree interpreter remains the reference and default Rust engine. ## Fixed identities | Axis | Identity | | --- | --- | | bytecode schema | `lispex.bytecode/v1` | | bytecode hash domain | `lispex/bytecode-hash/v1` | | producer | `lispex-rust-bytecode/v1` | | instruction set | `lispex.bytecode-instructions/v1` | | source map | `lispex.bytecode-source-map/v1` | | cost model | `lispex.bytecode-cost/v1` | | verifier | `lispex.bytecode-verifier/v1` | | built-in VM engine | `lispex-rust-vm/v1` | | admitted external VM | `lispex-topaz-vm/v1` | | Topaz request/result | `lispex.bytecode-engine-request/v1` / `lispex.bytecode-engine-result/v1` | | semantic profile | `lispex-profile-1.5` | | input Core IR | `lispex.core-ir/v1` | | primitive registry | `lispex.primitive-registry/v1` | The header binds the exact source identity, Core IR hash, primitive-registry tag and hash, profile, instruction/source-map/cost identities, producer, and sorted requirements. Tooling records the product version alongside the stable semantic bytes. The artifact identity is computed like this. ```text SHA-256("lispex/bytecode-hash/v1" || 0x00 || canonical-bytecode-bytes) ``` Producer identity records provenance for the recipient's trust policy. ## Canonical binary envelope The binary has one eight-byte magic/version prefix, one fixed section count, strictly increasing known section tags, a big-endian `u32` length for each payload, and no padding or trailer. The canonical section order is shown below. ```text identity strings constants anchors bindings globals scopes functions guards blocks roots ``` Indexes and counts are big-endian `u32`. Text is exact UTF-8 prefixed by its byte length. Strings, constants, anchors, IDs, and table references have one canonical order and representation. The strict reader bounds before allocation, uses checked arithmetic, validates UTF-8 and every typed table, then re-encodes and requires byte-for-byte equality. ## Instruction families | Family | Instructions | | --- | --- | | values and access | `constant`, `load-lexical`, `load-global`, `load-primitive`, `make-closure`, `require-one`, `discard`, `make-values` | | mutation and scope | `set-lexical`, `set-global`, `define-lexical`, `define-global`, `enter-let`, `enter-recursive-scope`, `initialize-lexical`, `leave-scope` | | control | `jump`, `jump-if-false`, `call`, `tail-call`, `guard`, `return` | Blocks contain linear instructions. Jump operands are decoded instruction indexes, not byte offsets. Source order is preserved. The compiler performs no constant folding, dead-code elimination, reordering, inlining, numeric reassociation, or fresh tail inference. It copies Core IR's resolved contract. ## Verification order Before constants, globals, closures, input, or VM state can exist, the verifier checks the following, in order. 1. magic, sections, lengths, canonical encoding, and all fixed identities 2. sorted unique pools, exact datum rendering, contiguous IDs, table roles, and every reference 3. primitive/global identity, lexical visibility, forwarding overlays, function captures, guard descriptors, and source anchors 4. reachable control flow, legal jump targets, stack and outcome shapes, scope balance, branch joins, terminal tail calls, and complete returns 5. instruction charges and aggregate resource limits An unknown opcode, dangling reference, noncanonical constant, invalid merge, residual stack, unbalanced scope, missing return, or unreachable instruction fails closed. Validation establishes structural admissibility. Signed artifact workflows identify producers, and engine comparison records semantic agreement. ## Fixed bounds and resource model - artifact size, at most 32 MiB - each major pool or table, at most 100,000 entries - each variable-width operand list, at most 100,000 entries - static verification work, which is checked linear work over instructions and edges Every executed instruction, primitive dispatch, and guest-procedure transition has a nonnegative versioned charge. Runtime reports selected limits, transitions used, output bytes, peak explicit-control frames, completed roots, and forbidden fallback count. Output limits cover primitive effects and top-level auto-print in their exact order. Resource exhaustion produces a terminal engine status. Tree recursion depth and VM transitions publish separate resource profiles. ## Source maps and diagnostics Every instruction names one positive line-and-column anchor inherited from Core IR. Paths, host names, timestamps, and platform newline choices belong to the host-application record. Runtime faults use the current instruction anchor, so tree/VM comparison can check diagnostic code, location, message, partial output, and warnings as semantic axes. ## Rust VM execution model The VM uses explicit code activations, lexical scopes, return frames, handlers, guard state, wind state, and one-shot continuations. Tail calls replace the current activation rather than growing a host call stack. Closures retain shared mutable cells, including forwarding overlays for dynamic definitions. All 205 current primitive rows are dispatchable. Ordinary primitive leaves share the installed Rust value, number, aggregate, rendering, diagnostic, and writer code. The 18 primitives that call guest procedures use VM-owned iterative state machines, including mapping, folds, `apply`, `call-with-values`, exception handlers, continuations, and `dynamic-wind`. The tree interpreter uses the reference path for these primitives. The VM and tree interpreter remain part of the same Rust product lineage and form a differential execution route. ## Exact Topaz VM boundary The Topaz route consumes the same canonical bytes through a separate checked reader, verifier, and explicit-control VM written in Topaz. It is available in Native macOS ARM64 with an exact separately installed Topaz 5.11 product root. Before invocation, Lispex checks the fixed provider manifest, Topaz artifact, executable, wrapper, managed files, source/compiler lineage, target, primitive registry, and five zero fallback counters. The closed request binds the exact source, Core IR, bytecode, optional canonical input, full `u64` transition limit, structural limits, and product identities. Private staging is mode 0700. The child receives a cleared environment with a fixed system `PATH` and `C` locale. The provider profile sets process-output, result-JSON, and timeout limits. Lispex accepts the result after validating its request hash, invocation, identities, canonical decimal `u64`, status/exit pair, output accounting, structural counts, target, lineage, and fallback counters. Closed product selection keeps each failure on the selected Topaz route. ## Static Topaz AOT branch Native macOS ARM64 can instead emit the verified control graph as readable Topaz source and build a source-free executable with the exact installed Topaz 5.11 compiler and exact Rust tool proxies. AOT stands for ahead-of-time compilation, which turns the rule into a standalone program before it runs, so nothing compiles it at run time. The installed product binds source, Core IR, bytecode, generated-source bundle, source map, `topaz.artifact.v1`, executable, producer, target, resource request, and five zero fallback counters. Runtime executes the installed executable directly. This is a complete-profile correctness route with an explicit calling convention. Use `lispex aot build|inspect|validate|run`, and see [Build a Product Compiled Ahead of Time](/en/docs/guides/topaz-aot) for the exact installed-product workflow. ## Engine selection and comparison - `lispex run --backend rust` defaults to `--engine tree`. - `--engine vm` performs source → Core IR → bytecode → verify → VM in memory. - A selected VM compile, verification, resource, or runtime failure returns on the selected VM route. - LIL and LIT are selected through their backend families. - `lispex compare-engines --receipt FILE SOURCE` records exact intermediate identities and semantic mismatch axes in `lispex.rust-engine-comparison/v1`. - `lispex bytecode run --engine topaz --topaz-vm ROOT --bytecode FILE` selects the exact installed Topaz product. - `lispex compare-vms --topaz-vm ROOT --receipt FILE SOURCE` derives bytecode once and records Rust/Topaz mismatch axes in `lispex.topaz-vm-comparison/v1`. A report is atomically published diagnostic material for inspection and comparison. ## Product support | Where it runs | Bytecode tools | Rust VM | Topaz VM | Topaz AOT | | --- | --- | --- | --- | --- | | Native macOS ARM64 | yes | built in | exact separate product | exact installed tools | | Other Native platforms | yes | built in | — | — | | npm CLI/package API | — | — | — | — | | Shared public WebAssembly | — | — | — | — | | Playground | — | — | — | — | Each product returns its documented command status and preserves the selected engine. ## How verified bytecode enters Vouch Vouch derives compiled evidence from exact source or a canonical Lispex Image that recovers it. Producer authentication, recipient policy, consumer input, engine agreement, and the decision gate each keep their explicit record in the workflow. Native can explicitly build `lispex.vouch-compiled-artifact/v1` from that exact source. A compiled Vouch invocation authenticates and pins the request, re-derives the artifact's Core IR and bytecode, preserves current tree/Meaning agreement, and only then compares the verified Rust VM transcript. The source and input remain explicit alongside the container. Inspection, validation, re-execution, and gate reports keep their own artifact roles. The Topaz VM route publishes its request, result, hashes, executable identity, output, and comparison receipt as route evidence. The compiled Vouch path uses the Rust VM artifact derived from the consumer-pinned source. ## Keep going Use the guided workflow for commands and recovery, and the Core IR reference for the resolved input contract. [Run Verified Bytecode](/en/docs/guides/verified-bytecode) · [Core IR Contract](/en/docs/reference/core-ir) · [Checked Surfaces](/en/docs/reference/checked-surfaces) --- Source: https://www.lispex.com/v1.20/en/docs/reference/bounded-evaluator.md # Resource-Controlled Evaluator Contract > The exact evaluator profiles, work and allocation models, import-free WebAssembly interface, portable core, lifecycle, and distribution. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/bounded-evaluator Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you The resource-controlled evaluator runs a rule with work, memory, depth, output, and transcript values fixed before execution. This page names the exact bytes, identities, result classes, and lifecycle used by Native and embed consumers. ## Contract set | Contract | Identifier | | --- | --- | | decision profile | `lispex/r7rs-rule-embedded-core/1` | | work and logical-allocation model | `lispex-vm-meter/1` | | full language profile | `lispex/r7rs-rule-current-profile-bounded/1` | | full work model | `lispex-full-vm-meter/1` | | value codec | `lispex.embed-value/v1` | | transcript | `lispex.embed-transcript/v1` | | WebAssembly interface | `lispex.embed-wasm-abi/v1` | | portable core | `lispex.embed-receipt-core/v1` | The bundle manifest identifies the provider by its exact WebAssembly SHA-256. That identity follows the bytes across release archives and consumers. ## Two evaluator components The decision component runs the closed operation set recorded by its bundle. The full component runs all 205 generated primitive rows with zero Deferred rows under component identity `lispex-evaluator/rust-vm-current-profile/1`. It uses the `LPXFAR01` envelope, while decision artifacts use `LPXART01`. Both components preserve the same v1 interface, value codec, transcript, and portable-core contracts. Native selects the full component through explicit `embed full` commands. ## Interface and lifecycle The module has zero imports, one memory with 18 initial and 256 maximum pages, and exports allocation, deallocation, interface-version, prepare, and evaluate functions with standard memory boundary globals. Requests use length-delimited, big-endian fields and the byte values declared by the caller. Every operation creates a fresh Wasmtime Store, Instance, memory, allocator, guest heap, interner, cells, continuations, work counter, transcript, and result buffer. An immutable compiled Module can be shared under the exact WebAssembly identity. ## Resource domains Preparation owns `raw_source_bytes`, `prepare_work`, `prepare_logical_allocation`, and `syntax_depth`. Evaluation owns `canonical_input_bytes`, `eval_work`, `eval_logical_allocation`, `semantic_frames`, `traversal_depth`, `output_bytes`, `diagnostic_bytes`, `transcript_bytes`, `transcript_events`, and `result_bytes`. Work uses a versioned deterministic tariff. Logical allocation uses units defined by the model. Charges occur before effects, use full `u64`, and stop at the first reservation beyond the selected value. Proper tail calls reuse the current semantic continuation. ## Identity and results The portable core binds the exact submitted source, canonical source, semantic rule, canonical input, resource contract, request, evaluator artifact, evaluation, transcript, and result through the `lispex.evaluation-identity/v1` length-delimited SHA-256 construction. | Terminal class | Product record | | --- | --- | | deterministic semantic outcome | result, transcript, and portable core | | deterministic request refusal | refusal, transcript, and portable core | | operational interruption | terminal engine status | | engine fault | terminal engine status and diagnostics | An issuer can sign completed portable-core bytes through the decision-exchange and Vouch workflows. ## Native decision directory The Native workflow is: ```text rule run -> inspect -> verify -> replay ``` `rule run` accepts exact source and strict JSON files plus separate preparation and evaluation values. JSON objects become records, arrays become vectors, strings, booleans, and exact integers keep their value kinds, and `null` becomes the empty list. A completed run creates five files in a new output directory. | Member | Role | | --- | --- | | `prepared.lpxembed` | exact prepared rule artifact | | `canonical-input.lpxvalue` | canonical input | | `result.lpxembed` | deterministic outcome and request binding | | `receipt-core.lpxreceipt` | portable core | | `summary.json` | human-readable projection of the canonical members | `inspect` summarizes the directory, `verify` checks its member set and byte bindings, and `replay` evaluates the recorded request in a fresh instance and matches the result and portable core. ## Distribution and product ownership Native contains the exact provider bytes. Releases also publish the WebAssembly bundle, manifest, vectors, verifier material, software bill of materials, dependency dispositions, safety evidence, and append-only release-DAG records. Retained provider bytes keep historical receipts readable. The host application owns source retention, network access, business policy, freshness, replay prevention, and external actions. Decision exchange owns issuer envelopes and recipient policy. Vouch owns signed evidence and the local decision gate. Topaz components keep their own compiler and admission identities. ## Keep going Use [Embed Lispex](/en/docs/guides/bounded-embedding) for the Native workflow. --- Source: https://www.lispex.com/v1.20/en/docs/guides/verified-bytecode.md # Run Verified Bytecode > Compile Core IR to verified bytecode, run it in the built-in Rust virtual machine or the exact installed Topaz virtual machine, and compare the two. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/verified-bytecode Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you You will turn one decision rule into a `.lpxbc` artifact, verify it before execution, supply one explicit input, and know when to use the built-in Rust virtual machine or the separately installed Topaz virtual machine. ## Prepare a rule and an input Save this as `refund-window.lspx`. ```scheme (define (decide days) (if (<= days 30) 'refund 'review)) (decide input) ``` Save the single input datum as `request.lspx`. ```scheme 14 ``` `input` is not a file or environment lookup. It is an explicit requirement recorded in Core IR and bytecode, then supplied by the command below. ## Build Core IR, then bytecode ```sh lispex core-ir build \ --source refund-window.lspx \ --out refund-window.lpxir lispex bytecode build \ --ir refund-window.lpxir \ --out refund-window.lpxbc ``` The first command resolves names, cells, captures, tail positions, and source anchors without executing the rule. The second command lowers that Core IR to `lispex.bytecode/v1`, verifies the result, and writes a new binary artifact. Neither command overwrites an existing destination. ## Inspect or validate before running ```sh lispex bytecode inspect --bytecode refund-window.lpxbc lispex bytecode validate --bytecode refund-window.lpxbc ``` `inspect` prints identities, table counts held under fixed limits, requirements, opcode counts, root anchors, and source-map coverage. `validate` is the quieter automation boundary. It strictly decodes, verifies, re-encodes, and accepts only the one byte representation the format allows. Both commands establish canonical bytecode integrity. Signed distribution identifies the producer, application policy approves the rule, and Vouch binds the consumer request and current decision. ## Run only after verification ```sh lispex bytecode run \ --bytecode refund-window.lpxbc \ --input request.lspx ``` **Result** ```text refund ``` The Native CLI verifies the complete artifact before it creates any virtual machine state. Malformed bytes fail before input use, output, primitive dispatch, or a single machine step. If the artifact declares `input`, omitting `--input` fails, and supplying input to an artifact that does not declare it also fails. One stdin stream cannot carry both inputs. This call is rejected. ```sh lispex bytecode run --bytecode - --input - ``` Use a named file for either the bytecode or the datum instead. ## Run the same artifact in the Topaz virtual machine Rust is built in and remains the default. On macOS ARM64, you can explicitly select the exact admitted Topaz 5.11 product. ```sh lispex bytecode run \ --engine topaz \ --topaz-vm /absolute/path/to/aarch64-apple-darwin \ --bytecode refund-window.lpxbc \ --input request.lspx ``` The product root must be an absolute path to the separately installed `lispex-topaz-vm/v1` product. Lispex checks its manifest, Topaz artifact, executable, wrapper, managed files, compiler/source lineage, target, resource contract, and zero-fallback declaration. It never searches `PATH`, a sibling checkout, the network, or an older installation. A missing, changed, timed-out, or malformed Topaz product is reported as a failure of that way of running, and Rust is not retried. ## Select the virtual machine for source For a self-contained source file, use the shorter form. ```sh lispex run --backend rust --engine vm rule.lspx ``` `tree` remains the default. ```sh lispex run --backend rust --engine tree rule.lspx ``` An explicit `vm` request never retries through `tree`. `--engine` belongs only to the Rust backend. Combining it with another backend such as LIL or LIT, or with an external backend registry, is a usage error. ## Compare both Rust engines ```sh lispex compare-engines \ --receipt tree-vm.json \ rule.lspx ``` The atomically published report records exact source, Core IR, and bytecode identities, both semantic observations, mismatch axes, virtual machine resource measurements, and the fallback count. The report identifies the shared Rust values and primitive leaves and serves as regression evidence for the named source and request. To compare the two bytecode virtual machines instead, use this command. ```sh lispex compare-vms \ --topaz-vm /absolute/path/to/aarch64-apple-darwin \ --receipt rust-topaz.json \ rule.lspx ``` This derives bytecode once, runs Rust and Topaz explicitly, and compares status, output, values, warnings, diagnostics, resource observations, and completed roots. The report records both the structurally separate Topaz source and the Topaz Rust Stage 0 producer identity as differential route evidence. When you have also built the matching product compiled ahead of time, compare every Native way of running it. ```sh lispex compare-routes \ --topaz-vm /absolute/path/to/aarch64-apple-darwin \ --aot-product /absolute/path/to/refund-window-aot \ --receipt four-routes.json \ --input request.lspx \ refund-window.lspx ``` The command uses one frontend result and one verified bytecode artifact for the tree run, the Rust virtual machine, the Topaz virtual machine, and the product compiled ahead of time. A mismatch in the source, the Core IR, or the bytecode rejects that compiled product before any of them runs. The receipt is published atomically and records semantic and comparable-resource mismatch axes separately and exposes every lineage and fallback counter. Vouch uses the source-bound compiled artifact described below. ## Choose the right product | Product | Runtime role | | --- | --- | | Native CLI on macOS ARM64 | bytecode tools, built-in Rust virtual machine, exact Topaz virtual machine, product compiled ahead of time, and four-way comparison | | Native on other supported platforms | bytecode tools and built-in Rust virtual machine | | npm CLI and package | source tree execution and Exact Image support | | Public WebAssembly build | source tree execution and Exact Image support | | Playground | interactive source tree execution and Exact Image support | Native owns the bytecode reader, checker, and virtual machine. The other products own their source tree and Exact Image workflows. ## Add verified bytecode to Vouch A bytecode hash identifies exact bytes. Verification establishes structural admissibility under configured resource values, and local virtual-machine execution records the Native observation. Vouch adds issuer authentication, recipient policy, source and input binding, current tree and Meaning agreement, and the decision gate through a source-bound container. When a consumer deliberately wants the virtual machine to agree in addition to the existing Vouch checks, Native builds a separate source-bound container. ```sh lispex vouch compiled build \ --source refund-window.lspx \ --out refund-window.lpxvca lispex vouch compiled validate \ --artifact refund-window.lpxvca \ --source refund-window.lspx ``` `vouch verify --reexecute --compiled-artifact refund-window.lpxvca` and `vouch gate --compiled-artifact refund-window.lpxvca` require the consumer's exact external source and input, trust policy, authentication, and current agreement between the tree run and the meaning record. Native re-derives the Core IR and bytecode from that source before running the verified virtual machine. The container, its hashes, inspection and validation output, and the machine result keep their distinct roles in the live Vouch workflow. ## Keep going Use the reference for the exact binary and verifier contract, or return to Core IR to inspect resolved meaning before compilation. [Bytecode and Rust virtual machine reference](/en/docs/reference/bytecode-vm) · [Build a Product Compiled Ahead of Time](/en/docs/guides/topaz-aot) · [Native CLI](/en/docs/reference/cli) --- Source: https://www.lispex.com/v1.20/en/docs/guides/topaz-aot.md # Build a Product Compiled Ahead of Time > Generate readable Topaz, compile it with the exact installed Topaz toolchain, and run a source-free Native Lispex product. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/topaz-aot Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you You will compile one Lispex rule into a standalone macOS ARM64 executable, inspect it without running it, and execute it without the Lispex or Topaz source trees. ## What AOT means here AOT is short for ahead of time. Native compiles the rule before you run it and produces a product with no Lispex source inside it. The Native pipeline is explicit. ```text exact Lispex source -> lispex.core-ir/v1 -> lispex.bytecode/v1 -> readable generated Topaz + source map -> exact installed Topaz 5.11 compiler -> topaz.artifact.v1 -> source-free Native product ``` The generated program executes a static control graph directly. Lispex source, bytecode, the Rust virtual machine, the source tree interpreter, and the separately installed Topaz virtual machine stay on their named build and execution routes. ## Prepare the rule Save `refund-window.lspx`. ```scheme (define (decide days) (if (<= days 30) 'refund 'review)) (decide input) ``` Save the input datum as `request.lspx`. ```scheme 14 ``` ## Select the build tools explicitly Compiling ahead of time is currently a Native macOS ARM64 feature. Use absolute paths to the installed `topaz-lang@5.11.0` compiler and its Rust tool directory. ```sh lispex routes fetch \ --route aot-compiler \ --target aarch64-apple-darwin \ --out /absolute/tools/lispex-aot-compiler TOPAZ_BIN=/absolute/tools/lispex-aot-compiler/product/bin/topaz-bin RUST_TOOL_BIN=/absolute/path/to/rustup/bin ``` Fetch stages the exact closed Topaz package and checks its release manifest. The build selects the compiler through the absolute path you provide and checks the compiler, npm wrapper, installer, and Rust tool proxies there. Its discovery set is exactly those supplied paths. ## Build without overwriting ```sh lispex aot build \ --source refund-window.lspx \ --topaz-compiler "$TOPAZ_BIN" \ --rust-tool-bin "$RUST_TOOL_BIN" \ --out refund-window-aot ``` The destination must not exist. Lispex builds in a private staging area under fixed limits, strictly validates the compiler-emitted Topaz artifact and every managed file, then removes path-sensitive local linker symbols and replaces the linker signature with one fixed ad-hoc Lispex AOT signature. The product manifest records the exact `/usr/bin/strip` and `/usr/bin/codesign` hashes, and the final Topaz artifact is rebound to the finalized executable. Lispex writes its manifest last and atomically publishes the closed product. The installed directory contains only these files. ```text lispex-aot-product.json lispex-source-map.json topaz-artifact.json target/debug/program LICENSE NOTICE GENERATED-OUTPUT-NOTICE.txt ``` Generated Topaz and original Lispex source are not required to run it. ## Inspect and validate without execution ```sh lispex aot inspect --product "$PWD/refund-window-aot" lispex aot validate --product "$PWD/refund-window-aot" ``` Both commands require an absolute product root. They verify the closed file inventory, the source, Core IR, bytecode, and product identities, the source map, the exact compiler and macOS finalizer lineage, Topaz artifact, executable hash, target, and zero fallback counters. Neither command starts the executable. ## Run the installed product ```sh lispex aot run \ --product "$PWD/refund-window-aot" \ --input request.lspx ``` **Result** ```text refund ``` `run` revalidates the installed product and starts its recorded executable. The result stays on that explicit AOT route with zero fallback attempts. For a machine-readable result, add `--json`. ```sh lispex aot run \ --product "$PWD/refund-window-aot" \ --input request.lspx \ --json ``` The result binds the product manifest, source, Core IR, bytecode, generated Topaz bundle, source map, Topaz artifact, executable, input, requested resources, observations, and five zero fallback counters. ## Set resource limits ```sh lispex aot run \ --product "$PWD/refund-window-aot" \ --input request.lspx \ --machine-transitions 1000000 \ --output-bytes 1048576 \ --control-frames 10000 \ --json ``` All three values are unsigned 64-bit decimals in one fixed written form. Leading zeroes, signs, overflow, mismatched accounting, or an impossible success/diagnostic combination fail closed. Different engines can charge different resource models, so compare like-for-like requests. Equal counters record resource agreement, while the four-way receipt records semantic agreement separately. A reached resource limit remains a typed `fault` result with its diagnostic and observed counters. The Native parent preserves that JSON with the compiled process exit status. ## Compare all four ways of running it After building the compiled product, you can run the Rust tree, the built-in Rust virtual machine, the exact installed Topaz virtual machine, and the compiled executable for one source and input. ```sh lispex compare-routes \ --topaz-vm /absolute/path/to/aarch64-apple-darwin \ --aot-product "$PWD/refund-window-aot" \ --receipt four-routes.json \ --input request.lspx \ refund-window.lspx ``` Lispex parses and normalizes the source once, derives one Core IR and bytecode artifact, proves that the prebuilt AOT product binds those exact identities, validates both installed Topaz products, and then runs each of the four explicitly. Each result stays on its selected route. The atomically published receipt keeps semantic mismatch axes separate from comparable resource mismatch axes. The Rust virtual machine, the Topaz virtual machine, and the compiled product share the bytecode cost model and must agree on transition, output, control-frame, and completed-root counts. The tree reports its own depth model and leaves unrelated transition and frame counts absent. Exit 0 means all four completed and every checked axis agreed. Exit 1 means a checked mismatch. Exit 2 means an execution or product failure. Exit 3 means the receipt could not be published. ## Product roles A compiled executable, product manifest, source map, inspection, validation, run report, and four-way receipt provide `execution-material-only` and local diagnostic evidence. Vouch adds publisher authentication, recipient trust policy, exact external source and input, request-bound current replay, and the local gate decision across the tree run, the meaning record, and the Rust virtual machine. The Rust tree run and the Rust virtual machine remain independently selectable recovery paths. Each route keeps its result and route identity. ## Product support | Product | Build | Inspect / validate / run | | --- | --- | --- | | Native macOS ARM64 | exact installed Topaz 5.11 | supported | The path records exact source, Core IR, bytecode, compiler, Rust, macOS finalizer, and host identities in one Native product lineage. Rebuilds made with the same recorded host and tools can be compared byte for byte. Topaz owns execution performance, binary size, cross-compilation, and interface evolution. Vouch owns publisher authentication, trust policy, and the local grant. [Run Verified Bytecode](/en/docs/guides/verified-bytecode) · [Native CLI](/en/docs/reference/cli) · [Runtime and Backends](/en/docs/reference/runtime-backends) --- Source: https://www.lispex.com/v1.20/en/docs/guides/bounded-embedding.md # Run a Rule with a Resource Profile > Choose the decision or full Native evaluator, set preparation and evaluation values, and inspect the core binding rule, input, resources, and result. Canonical page: https://www.lispex.com/v1.20/en/docs/guides/bounded-embedding Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Run a supplied rule through an import-free WebAssembly evaluator with explicit work, memory, depth, output, and transcript values. ## Choose the evaluator `lispex embed` runs the decision profile `lispex/r7rs-rule-embedded-core/1`. `lispex embed full` runs all 205 primitive rows in `lispex/r7rs-rule-current-profile-bounded/1`. Both create a fresh instance for every operation and use separate preparation and evaluation resources. The full workflow uses the same command shape. ```sh lispex embed full prepare --source policy.lspx --limits prepare-limits.json --out policy.lpxfull lispex embed full evaluate --prepared policy.lpxfull --input input.lpxvalue --limits evaluation-limits.json --out result.lpxfull lispex embed full inspect --artifact result.lpxfull lispex embed full verify --artifact result.lpxfull lispex embed full replay --artifact result.lpxfull ``` ## 1. Prepare the rule Create `prepare-limits.json`. ```json { "raw_source_bytes": 4096, "prepare_work": 1000000, "logical_allocation": 1000000, "syntax_depth": 64 } ``` Prepare the source. ```sh lispex embed prepare \ --source policy.lspx \ --limits prepare-limits.json \ --out policy.lpxembed ``` Preparation reads UTF-8, normalizes the program, builds and verifies canonical bytecode, checks the selected profile, and records the source, semantic rule, feature set, bytecode, evaluator, and resource identities. ## 2. Evaluate the prepared rule The input is one canonical `lispex.embed-value/v1` value. Create `evaluation-limits.json`. ```json { "canonical_input_bytes": 4096, "eval_work": 1000000, "logical_allocation": 1000000, "semantic_frames": 1000, "traversal_depth": 256, "output_bytes": 1000000, "diagnostic_bytes": 1000000, "transcript_bytes": 1000000, "transcript_events": 100, "result_bytes": 1000000 } ``` Evaluate the prepared artifact. ```sh lispex embed evaluate \ --prepared policy.lpxembed \ --input input.lpxvalue \ --limits evaluation-limits.json \ --out result.lpxembed ``` The result keeps preparation and evaluation usage separate. Its portable core binds the rule, input, selected resources, evaluator artifact, transcript, and result. ## 3. Inspect, verify, and replay ```sh lispex embed inspect --artifact result.lpxembed lispex embed verify --artifact result.lpxembed lispex embed replay --artifact result.lpxembed ``` `inspect` prints a stable JSON projection. `verify` recomputes the envelope, hashes, category, values, and portable core. `replay` evaluates the recorded request in a fresh instance and matches the result and portable core. ## Product roles The embed artifact records deterministic semantic outcomes, request refusals, and engine status. Decision exchange adds issuer envelopes and recipient policy. Vouch authenticates signed evidence and evaluates the local decision gate. The host application owns network access and business actions. ## Keep going Read the exact identities and terminal classes in the [Resource-Controlled Evaluator Contract](/en/docs/reference/bounded-evaluator). --- Source: https://www.lispex.com/v1.20/en/docs/reference/mcp.md # MCP Tool Reference > The Native MCP server provides exact language reference, trusted-source evaluation, diagnostics, and fixed runtime comparisons over local stdio. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/mcp Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. `lispex mcp serve` starts a local stdio server from the installed Native binary. Every request and response uses a closed versioned frame. ## Tools | Tool | Input | Result | | --- | --- | --- | | `lispex_reference` | `topic` and optional exact `name` | installed forms, procedures, reader grammar, resources, or routes | | `lispex_eval` | source and optional datum | Rust tree observation with value, stdout, warnings, and diagnostics | | `lispex_diagnostic` | one `E3xx` or `W3xx` code | exact catalog explanation and trigger condition | | `lispex_compare_routes` | named court, source, and optional input | route observations, agreement status, resources, and lineage | The reference tool uses topics `forms`, `procedures`, `reader`, `resources`, and `routes`. Unknown names return `known: false`, which lets an assistant correct a request against the installed version. ## Fixed comparisons | Court | Products | | --- | --- | | `tree-rust` | built-in Rust tree and Rust VM | | `rust-topaz` | Rust VM and the exact Topaz VM selected at startup | | `all-four` | Rust tree, Rust VM, selected Topaz VM, and a fresh AOT product | Select optional Topaz products through absolute paths when starting the server. ```sh lispex mcp serve \ --topaz-vm /absolute/path/to/topaz-vm \ --topaz-compiler /absolute/path/to/topaz-compiler \ --rust-tools /absolute/path/to/rust-tools ``` Each comparison retains the named route set and records `agreement`, `partial_comparison`, `answer_selected`, terminal statuses, resource values, and product identities. ## Resource profile | Resource | Value | | --- | ---: | | source per request | 65,536 bytes | | input per request | 16,384 bytes | | evaluation result | 1 MiB | | evaluation wall time | 5 seconds | | comparison result | 4 MiB | | `all-four` wall time | 11 minutes | The server returns timeout, cancellation, input, product, build, cleanup, and process terminal states explicitly. It is an authoring surface for reviewed source. Application rules from external users belong in the [Resource-Controlled Evaluator](/en/docs/reference/bounded-evaluator). ## Data and authority flow Source and optional datum enter over local stdio. The worker holds request data in memory and releases it when the request ends. Tool results contain the source hash, observations, resource values, and diagnostics. Absolute startup paths select optional products for the lifetime of that server. MCP produces authoring observations. Lispex Vouch consumes exact source and input through its own authenticated request, current re-execution, and local gate. The host application consumes the gate result and owns the external action. [AI assistant setup](/en/docs/guides/ai-assistant) · [Runtime and Backends](/en/docs/reference/runtime-backends) · [Lispex Vouch](/en/docs/vouch) --- Source: https://www.lispex.com/v1.20/en/docs/reference/backend-observation-matrix.md # Backend Observation Matrix > The execution families, capability counts, corpora, observations, and receipt identities used to compare Lispex backends. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/backend-observation-matrix Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. Lispex compares backends through named source programs and exact observable results. Each matrix row identifies the implementation, capability registry, execution route, corpus, and receipt format. ## Execution families | Family | Implementation | Current observation | | --- | --- | --- | | Rust reference | reference interpreter in Native and WebAssembly | 205 of 205 tracked primitive rows | | LIL | Lispex interpreter written in Lispex | 205 of 205 tracked primitive rows | | LIT | Lispex interpreter written in Topaz | 84 of 205 tracked primitive rows | | Rust VM | canonical Core IR and verified bytecode executed by the Rust VM | exact source, Core IR, bytecode, result, diagnostics, and resource identities | | Topaz VM | the separately installed Topaz 5.11 VM product | exact provider, request, bytecode, result, diagnostics, and resource identities | | Topaz AOT | Lispex compiled into a standalone Topaz product | source map, generated bundle, executable, request, result, and resource identities | | SICP | the explicit SICP profile in Native and `@lispex/sicp` WebAssembly | typed `sicp-observation/v1` and exact `lispex-trace/v1` execution trace | ## Comparison records | Record | What it compares | | --- | --- | | `csk.differential-receipt/v0` | the historical Rust, LIL, and LIT corpus | | `lispex.rust-engine-comparison/v1` | Rust tree and Rust VM over one derived Core IR and bytecode artifact | | `lispex.topaz-vm-comparison/v1` | Rust VM and the exact installed Topaz VM over one bytecode artifact | | `csk.meaning-differential-report/v1` | Rust reference behavior and Meaning Environment v1 over the selected source | | `sicp-observation/v1` | SICP profile termination, value, stdout, diagnostics, warnings, and artifact identity | Every record carries the corpus or source, executor identities, profile, observable channels, and comparison status. Capability rows use explicit supported and unsupported results, so backend growth is visible one row at a time. ## Reading the numbers Primitive counts describe registry coverage. Corpus counts describe the named programs executed in a receipt. Engine comparisons describe exact routes and artifacts. Together they show implementation progress and the observations available to downstream tools. ## Keep going [Checked Surfaces](/en/docs/reference/checked-surfaces) · [Runtime and Backends](/en/docs/reference/runtime-backends) --- Source: https://www.lispex.com/v1.20/en/docs/reference/checked-surfaces.md # Checked Product Surfaces > The direct product journeys that exercise Lispex Native, npm, WebAssembly, Playground, backends, images, Vouch, and SICP. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/checked-surfaces Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. Lispex checks each public surface through the behavior a user installs or opens. The owning module keeps focused tests during implementation, and release checks exercise the immutable product artifacts and public channels. ## Product journeys | Surface | Direct behavior checked | Current product status | | --- | --- | --- | | Native reference | source evaluation, values, stdout, warnings, diagnostics, files, and exit status | reference interpreter with 205 tracked primitive rows | | Meaning v1 | Core IR projection, shared cells, mutation, tail execution, escape control, dynamic cleanup, and exact observations | Native `lower`, `eval-graph`, and `meaning-diff` | | Rust VM | canonical Core IR and bytecode, verifier refusals, tree agreement, diagnostics, and resources | built into Native | | Topaz VM and AOT | exact provider identity, request binding, results, source map, executable, and route receipts | macOS ARM64 companion products | | npm | clean install, reference evaluation, artifact inspection, Vouch verification, and SICP command routing | `lispex@1.20.0` | | WebAssembly and Playground | browser evaluation, canonical Lispex Images, recovery, explicit image execution, and profile selection | production English, Korean, and Russian sites | | Resource-controlled embed | preparation, evaluation, inspection, verification, replay, terminal classes, and portable core | decision and full components | | Decision exchange and Vouch | key identity, recipient policy, issuer authentication, request binding, re-execution, and decision gate | Native issue and gate, npm verification | | SICP | Native and WebAssembly execution, typed observation, exact trace, chapter examples, and sicp.io course navigation | `@lispex/sicp@1.0.0` and sicp.io | ## Backend observations LIL reports 205 of 205 tracked primitive rows. LIT reports 84 of 205. Rust tree/VM and Rust/Topaz comparisons bind source, intermediate artifacts, executor identity, result, diagnostics, and resources. Each receipt names the corpus and execution family it observed. ## Release observation The release path builds immutable Native and package artifacts once, installs those exact bytes, exercises the Native Meaning v1, npm reference, and SICP journey, publishes the artifacts, and reads the public products back from npm, Blob, and Production. ## Keep going [Backend Observation Matrix](/en/docs/reference/backend-observation-matrix) · [Release History](/en/docs/history) --- Source: https://www.lispex.com/v1.20/en/docs/reference/current-scope.md # Current Product Catalog > The language profiles, execution products, artifacts, evidence workflows, and public surfaces available in Lispex v1.20.0. Canonical page: https://www.lispex.com/v1.20/en/docs/reference/current-scope Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. This catalog names the products available in Lispex v1.20.0 and the role each one owns. ## Language and execution | Product | Available behavior | Public surface | | --- | --- | --- | | Reference interpreter | complete current Lispex profile with 205 tracked primitive rows | Native, npm, WebAssembly, Playground | | Meaning v1 | Core IR projection, explicit semantic evaluation, shared cells, mutation, tail calls, escape control, dynamic cleanup, and exact observations | Native | | Rust VM | canonical Core IR, verified bytecode, explicit-control execution, diagnostics, and resources | Native | | Topaz VM | exact separately installed Topaz 5.11 execution product | Native macOS ARM64 | | Topaz AOT | readable generated Topaz, source map, standalone executable, and exact build identities | Native macOS ARM64 | | Resource-controlled embed | decision profile with configured preparation and evaluation resources | Native and import-free WebAssembly component | | Full embed | complete current profile with all 205 primitive rows and fresh instances | Native and import-free WebAssembly component | | SICP | Scheme-compatible educational profile, typed observations, exact traces, and chapter systems | Native, `@lispex/sicp`, Playground profile, sicp.io | | LIL | Lispex interpreter written in Lispex with 205 tracked primitive rows | Native differential tools | | LIT | Lispex interpreter written in Topaz with 84 tracked primitive rows | Native differential tools | ## Artifacts and workflows | Product | Role | | --- | --- | | Core IR | canonical resolved meaning with binding, global, primitive, tail-position, source-anchor, and requirement identities | | Verified bytecode | canonical instruction artifact for the Rust and Topaz VM routes | | Portable core | binds exact rule, input, resource contract, evaluator artifact, transcript, and result | | Lispex Image | canonical PNG or ZIP representation of exact source bytes | | Decision directory | five-member local record for run, inspect, verify, and replay | | Decision exchange | issuer envelope, recipient policy, request binding, authentication, and replay | | Vouch | signed evidence authentication and the Native local decision gate | | Route catalog | exact companion product acquisition, installation receipt, selection lock, diagnosis, and relocation | ## Platform availability | Surface | Reference | Meaning v1 | Rust VM | Topaz routes | Embed | Vouch | SICP | | --- | --- | --- | --- | --- | --- | --- | --- | | Native macOS ARM64 | yes | yes | yes | VM and AOT | decision and full | issue, verify, replay, gate | yes | | Other Native targets | yes | yes | yes | catalog status | decision and full | issue, verify, replay, gate | yes | | npm | yes | through Native artifacts | artifact inspection | route metadata | package APIs | verification | yes | | WebAssembly | yes | reference surface | reference surface | route metadata | import-free components | shared verification core | yes | | Playground | yes | product guidance | reference surface | downloads guidance | product guidance | Native handoff | SICP profile | ## Product ownership The runtime profile owns language meaning. Core IR and bytecode contracts own canonical compilation artifacts. Embed owns resource-controlled evaluation and portable cores. Decision exchange owns issuer and recipient artifacts. Vouch owns signed evidence and local gate evaluation. The host application owns business policy, network access, freshness, replay prevention, and external actions. Topaz owns its compiler, adapter, admission, and release products. ## Keep going [Runtime and Backends](/en/docs/reference/runtime-backends) · [Checked Product Surfaces](/en/docs/reference/checked-surfaces) --- Source: https://www.lispex.com/v1.20/en/docs/philosophy.md # Philosophy > Lispex gives decision rules one fixed grammar, deterministic semantics, explicit inputs, exact artifacts, and clear product ownership. Canonical page: https://www.lispex.com/v1.20/en/docs/philosophy Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. Lispex treats a decision rule as a program whose meaning, input, runtime, and result can be named exactly. The language stays close to Scheme while making every production-facing choice explicit. ## Five design rules 1. **One language contract.** `LISPEX-RUNTIME.md` defines forms, values, procedures, diagnostics, and execution semantics. 2. **Deterministic requests.** Exact source and explicit input produce a deterministic observation under a named resource profile. 3. **Fixed grammar.** Core and derived forms normalize to one canonical meaning, and the 205 built-in procedure names come from one registry. 4. **Explicit host boundary.** The host application supplies data and consumes the decision. Files, network, clocks, transactions, and external actions stay visible in the application architecture. 5. **Typed artifacts.** Source, Lispex Images, Core IR, bytecode, receipts, authentication reports, re-execution reports, and gate reports each answer a named question and have a named consumer. ## Product choices | Choice | Product value | | --- | --- | | fixed semantic profile | repeatable results and stable diagnostics | | explicit input and host boundary | portable rules and reviewable application integration | | exact source identity | byte-level review, images, policy allowlists, and request binding | | resource profiles | predictable execution and comparable observations | | receipts and Vouch | durable decision records, publisher authentication, current re-execution, and local grants | ## One path from rule to action ```text exact source + explicit input → reference-interpreter observation → optional canonical image, Core IR, or bytecode → receipt or signed Vouch evidence → recipient policy and current re-execution → local gate → host application action ``` Each arrow names the product responsible for the next transformation. This keeps integrity, authentication, current execution, policy, and business action easy to inspect together. ## Evolution New language forms enter the language contract, normalizer, reference runtime, direct behavior checks, and public documentation as one change. New runtime products keep their own identities, resource profiles, and observation scopes. This lets Lispex grow while preserving the exact meaning of published artifacts. [Current Product Catalog](/en/docs/reference/current-scope) · [Runtime and Backends](/en/docs/reference/runtime-backends) · [Lispex Vouch](/en/docs/vouch) --- Source: https://www.lispex.com/v1.20/en/docs/history.md # History > A curated record of Lispex v1 from the first deterministic runtime through Exact Images, verified bytecode, Native Topaz AOT, and the four-route court. Canonical page: https://www.lispex.com/v1.20/en/docs/history Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you Look up when a capability arrived and which release moved a boundary. Lispex grows through minor releases. Each minor marks the product boundary you install. Open a row to see the releases and development checkpoints with that minor version, newest first. For example, v1.19 contains v1.19.x entries. Inside is an engineering record, so internal names appear as they are. ## Abbreviations | Abbreviation | Meaning | | --- | --- | | `ABI` | application binary interface | | `AOT` | ahead-of-time compilation | | `DSSE` | Dead Simple Signing Envelope | | `IR` | intermediate representation | | `LIL` | Lispex-in-Lispex, the Lispex interpreter written in Lispex | | `LIT` | Lispex-in-Topaz, the Lispex interpreter written in Topaz | | `MCP` | Model Context Protocol | | `VM` | virtual machine | | `WASM` | WebAssembly | ## Releases
v1.20. Adds exact five-axis resource usage to Rust and LIL and aligns whole-source output and resource termination across Native, npm, WebAssembly, and Playground. SICP receives refreshed link-preview artwork. The v1.20 public minor assembles the work from five numbered development checkpoints, v1.19.1 through v1.19.5. Their entries are grouped under v1.19. | Version | What changed | | --- | --- | | v1.20.0 | Adds exact five-axis resource usage to Rust and LIL execution, reports recursion safety exhaustion as resource status, and aligns whole-source output across Native, npm, WebAssembly, and Playground. Successful forms render in order, ordinary runtime faults retain committed output, and resource termination returns empty output with status `2`. Browser results expose `output`, `diagnostics`, `ok`, and `exit_status`. The SICP site also receives refreshed link-preview artwork. |
v1.19. Meaning Graph v1 and explicit Meaning Environment v1 define control flow and mutation. Development checkpoints refine source and identifier handling, observation identity, exact resource usage, diagnostics, and whole-source output across Native, npm, WebAssembly, and Playground. All Meaning Graph and Meaning Environment work kept the v1.18.0 development identity until it was assembled as v1.19.0. | Version | What changed | | --- | --- | | v1.19.5 | Adds exact usage for frontend transitions, tokens, normalization steps, machine transitions, and output bytes across Rust and LIL. Normalizes diagnostic families, reports recursion-safety exhaustion as `non-tail-call-depth` resource termination, aligns whole-source output across Native, npm, WebAssembly, and Playground, and refreshes the SICP link-preview artwork. | | v1.19.4 | Publishes formal product-manifest claims, separates observation schema identity from observation contract identity, completes the observation identity envelope, and aligns LIL stdout effects with Rust. Batch execution omits automatic top-level values while the whole-source CLI renders each successful form. Normalizer diagnostics retain their original phase. | | v1.19.3 | Moves unbound-identifier detection to the first demanded lookup. Dormant unbound identifiers remain admissible, while demanded lookups report `E300` at the original identifier span and retain stdout committed before the fault. | | v1.19.2 | Accepts zero-byte, whitespace-only, comment-only, and whitespace-plus-comment sources as empty programs with zero values, empty output, and status `0`. | | v1.19.1 | Recursively splices `begin` forms in top-level and internal-definition contexts in source order while preserving one definition scope. A `define` in an ordinary expression-context `begin` remains a static error. | | v1.19.0 | Adds Meaning Graph v1 and explicit Meaning Environment v1, shared-cell semantics for `letrec`, internal definitions, rest arguments, `set!`, and `define`, actual TCO, one-shot upward escape-only `call/cc`, outward-cleanup-only `dynamic-wind`, exact stdout, value, warning, and error observations, and non-Vouch `meaning-diff`. Resolves 15 named gaps across the selected 61-case corpus at the behavioral level. |
v1.18. Provides the SICP educational runtime through `@lispex/sicp@1.0.0`, `lispex sicp run`, and sicp.io. Native and import-free Wasm support resource limits, typed observations, exact traces, eight chapter systems including a metacircular evaluator and a register machine, deterministic graphics, and schedule exploration. All SICP P0 through P9 work kept the v1.17.0 development identity until it was assembled as v1.18.0. The runtime and course continue in v1.20.0 with the same `@lispex/sicp@1.0.0` package identity. | Version | What changed | | --- | --- | | v1.18.0 | Introduces the separately installable `@lispex/sicp@1.0.0` educational runtime, explicit `lispex sicp run` command, Native and import-free Wasm execution, fixed resource limits, typed observations, and exact execution traces. It passes all 26 representative corpus cases and provides memoized streams, mutable Unicode strings, a deterministic real domain, arbitrary-precision numbers, chapter data and derived-syntax hosts, eight chapter systems consisting of metacircular, analyzing, lazy, and amb evaluators, logic query, register machine, explicit-control evaluator, and compiler, deterministic SVG, and a cooperative schedule explorer. It preserves 104 scoped external measurements against MIT/GNU Scheme, Racket SICP, Chibi, and Gauche. |
v1.17. Provides key preparation and decision authentication under recipient policies through a refund example. Its Image-backed Vouch path binds two refund inputs together with a request ID, actor, action, and expiry for the application handoff. | Version | What changed | | --- | --- | | v1.17.0 | publishes the exact ready-made refund example with local key preparation, recipient policy composition, authenticated decision exchange, Image-backed request-bound Vouch, protocol-confusion refusals, and a six-value application handoff |
v1.16. Publishes a separate import-free evaluator for all 205 procedures and develops the refund workspace and its application handoff. Native adds local key generation and workspace status, while Native and npm add key inspection and direct recipient-policy tools. | Version | What changed | | --- | --- | | v1.16.6 | adds one explicit current-host installed Native and npm practicality court runner, a static quick checker, and a closed mutation-site authority for the final F16 boundary | | v1.16.5 | materializes the final handoff and canonical manifest, builds the exact 26-member archive of the ready-made refund example, adds a separate Native archive reader and independent ZIP court, and documents the full journey in three locales | | v1.16.4 | adds Native-only `workspace status` with an embedded independent contract for the exact 26-file inventory, canonical 25-entry manifest, eight existence-only work slots, and two fixed candidate command names. It also completes the publication-final walkthrough with the decision exchange first and a separate Image-backed Vouch lane | | v1.16.3 | activates direct Native and npm decision-policy creation and checking from one reviewed public key and four explicit serialized constraints, with byte identity to the retained directory-derived F14 policy path. It preserves the append-only A0 pre-admission failure, exact 23-path repair A1 `ece930ea`, and exact five-path direct child B `fb07ae7c`. A preservation-only recovery completed the exact final `lispex.recipient-sample-provenance/v1` after the post-delete court stopped | | v1.16.2 | adds Native-only operating-system-CSPRNG Ed25519 key generation into a caller-named new directory and Native and npm inspection that reports distinct decision-issuer and Vouch identifiers for the same exact public SPKI DER | | v1.16.1 | activates F16 with a closed 26-file final workspace contract, an exact 21-file core, five byte-identical predecessor projections, and three refund facts mapped independently to portable strings and canonical decisions | | v1.16.0 | publishes F15 as a separate exact import-free resource-controlled evaluator for all of `lispex-profile-1.5`, with a generated closed-world 205-row authority, distinct full-profile meter and component identities, explicit fresh-instance Native prepare, evaluate, inspect, verify, and replay, portable provider vectors, redistribution, and retained release-DAG records |
v1.15. Provides authenticated decision exchange and develops a separate full-profile evaluator for all 205 procedures. Per-procedure resource costs, execution permits, and result-value encoding support import-free Wasm running in a fresh instance for each execution and evaluator redistribution. | Version | What changed | | --- | --- | | v1.15.8 | freezes the separate full-profile evaluator provider and adds one machine-checkable, component-only Topaz handoff with distinct retained `LPXART01` and full `LPXFAR01` contracts, vectors, redistribution, retention, release-DAG records, and final court | | v1.15.7 | adds a separate exact import-free full-profile Wasm evaluator and explicit Native prepare, evaluate, inspect, verify, and replay with a fresh instance for every execution | | v1.15.6 | binds all 205 current-profile primitive rows to generated Fixed, Numeric, Text, Collection, Effect, or GuestCalling runtime permits with zero pending execution rows | | v1.15.5 | closes fallible snapshots, callback vectors, conservative output buffers, final list/vector/string construction authority, and work-budget diagnostics for all 18 admitted GuestCalling rows | | v1.15.4 | binds all 18 GuestCalling rows to one generated authority and the explicit VM control machine with exact work boundaries and zero host-recursive rows | | v1.15.3 | closes a separate 205-row full-profile tariff design with zero Deferred rows and implements every portable codec-v1 data tag in a private iterative full-result encoder | | v1.15.2 | makes one generated 205-row registry the only primitive-installation and Core IR identity authority | | v1.15.1 | activates F15 and generates the exact current-profile reader, form, opcode, value, diagnostic, and 205-primitive surface plus contract-reuse decisions | | v1.15.0 | publishes the complete authenticated decision exchange covering one task-first refund path, exact Native authoring handoff, Ed25519 issuer envelope, recipient-owned policy, canonical `.lpxdecision`, full Native lifecycle, and verification-only npm inspection and authentication |
v1.14. Connects JSON rule execution and replay with Sunlit Amber v2 Images, the refund mode in Playground, and separate version identities. Develops authenticated decision exchange with issuer envelopes, recipient policies, canonical bundles, Native replay, and npm authentication. | Version | What changed | | --- | --- | | v1.14.6 | closes F14 with one clean-installed source-free Native/npm decision-exchange court, exact relocation and replay, and a compact nonauthoritative product receipt | | v1.14.5 | adds one seven-member canonical `.lpxdecision` bundle, full Native issue/inspect/authenticate/replay, and verification-only npm inspect/authenticate | | v1.14.4 | adds a distinct Ed25519 decision-issuer envelope over exact portable-core bytes, recipient-owned policy creation and validation, and nonexecuting Native authentication | | v1.14.3 | adds a closed task-first refund mode to the Playground with one-click maintained input changes and three exact source-bearing Native authoring handoffs | | v1.14.2 | separates development, published, documentation, semantic-profile, and immutable-distribution identities, and generates browser, Native, landing, and three-locale refund projections from one authority | | v1.14.1 | advances canonical Lispex Images to the Sunlit Amber v2 image, profile, and codebook contracts across Native, npm, public WASM, Playground, and maintained samples | | v1.14.0 | publishes the complete checkable decision workflow covering strict JSON input, exact limits, atomic `rule run`, nonexecuting inspect and verify, fresh-instance replay, one generated refund example across human and agent docs, and the exact licensed evaluator redistribution archive |
v1.13. Joins an import-free embedded evaluator with a checkable JSON rule workflow. Separate preparation and evaluation limits, atomic decision records, inspection, verification, and fresh-instance replay carry one refund example from input to a reusable record. | Version | What changed | | --- | --- | | v1.13.4 | joins the generated refund fixture, strict JSON adapter, atomic decision directory, nonexecuting inspection and verification, fresh-instance replay, relocation, denial and tamper cases in one installed Native workflow. The landing page and three locales now teach the same exact example | | v1.13.3 | adds `lispex rule inspect`, `verify`, and `replay` for the exact five-member decision directory, with deep prepared-bytecode and result binding checks and one fresh-instance replay | | v1.13.2 | adds atomic Native `lispex rule run` over exact source, strict JSON, separate preparation/evaluation limits, and the built-in evaluator | | v1.13.1 | adds one generated refund-rule fixture and a strict deterministic JSON-to-evaluator-value adapter with duplicate-key and inexact-number refusal | | v1.13.0 | publishes Native `lispex embed prepare/evaluate/inspect/verify`, one exact import-free evaluator component, separate preparation/evaluation limits, the frozen resource-controlled profile, meter, ABI, value-codec, and portable-core contracts, plus a manifest-generated `/llms.txt` and current-only sitemap |
v1.12. Local MCP tools provide reference lookup, evaluation, diagnostics, and route comparison. Development checkpoints define an import-free embedded evaluator with separate preparation and evaluation limits, deterministic resource accounting, a Wasm ABI, and portable result contracts. | Version | What changed | | --- | --- | | v1.12.4 | freezes the exact resource-controlled profile, deterministic work/logical-allocation model, import-free Wasm ABI, and portable-core schema after the final evaluator bytes pass mutation, property, reachability, safety, installed-product, and cross-architecture courts | | v1.12.3 | adds Native `lispex embed prepare`, `evaluate`, `inspect`, and `verify` over one exact embedded import-free Wasm evaluator. Preparation and evaluation use separate exact limits, every operation gets a fresh Store/Instance, and completed evaluations carry canonical result-value bytes | | v1.12.2 | adds a reproducible import-free resource-controlled evaluator Wasm bundle, a closed value-only candidate ABI, canonical prepared-bytecode handoff, exact request ownership, and fresh-instance Rust VM execution for three maintained policy rules | | v1.12.1 | replaces the obsolete generic step/allocation contract with four preparation axes and ten evaluation axes, removes consumed usage from the portable-core candidate, and adds independent Node/Rust vectors plus three maintained policy-fit cases | | v1.12.0 | publishes exact installed reference lookup, size- and time-capped trusted-source Rust-tree authoring evaluation, diagnostic lookup, fixed closed route comparison, the public primer/descriptor, and the maintained installed-product court as one Native stdio authoring surface |
v1.11. Connects installation of pinned Topaz VM and AOT compiler packages with local MCP reference lookup, evaluation, diagnostics, and route comparison. The comparison tools use explicit companion admission and per-request execution state. | Version | What changed | | --- | --- | | v1.11.3 | adds the maintained installed Native MCP product court for the four exact tools, E100/E303/E321 CLI parity, denied capabilities, per-call state isolation, resource-budget termination and recovery, closed-court agreement/disagreement, and a deterministic clean-room authoring journey | | v1.11.2 | adds `lispex_compare_routes` with the fixed `tree-rust`, `rust-topaz`, and `all-four` courts, strict startup-only companion admission, fresh per-request AOT builds, and explicit agreement or disagreement results | | v1.11.1 | adds `lispex mcp serve` with stable MCP 2025-11-25 and exactly three Native tools for the installed language reference, size- and time-capped trusted-source Rust-tree authoring evaluation, and diagnostic lookup | | v1.11.0 | publishes the canonical route catalog and stored-ZIP installer, pinned exact companion fetch, admitted macOS ARM64 Topaz VM/AOT compiler cells, and the maintained fetch-to-relocation journey as one Native product |
v1.10. Connects route inventory, diagnostics, measurement, and locked execution with official catalogs, pinned Topaz VM and AOT compiler downloads, and stored-ZIP installation. Installed Topaz tools build AOT products, and pinned routes keep working after relocation. | Version | What changed | | --- | --- | | v1.10.4 | adds a maintained exact-product court and copyable journey that joins both companion installations with AOT build, four-route inventory and measurement, path-free VM/AOT locks, doctor, locked execution, and unchanged-lock relocation | | v1.10.3 | adds official `routes fetch --route aot-compiler` for the exact eight-file Topaz 5.11 macOS ARM64 compiler companion, validates its immutable release manifest, and uses the relocated installed compiler in deterministic source-free AOT builds | | v1.10.2 | adds Native `routes fetch` with one embedded exact official catalog and a deterministic companion package for the admitted Topaz 5.11 VM on `aarch64-apple-darwin` | | v1.10.1 | adds Native `routes install`, canonical `lispex.route-catalog/v1` and path-free `lispex.route-installation/v1`, and a canonical stored-ZIP profile for exact local Topaz VM or AOT compiler companions | | v1.10.0 | publishes stable Native inventory, doctor, path-free route locks, configured route measurements, and locked tree/Rust VM/Topaz VM/AOT execution as one coherent product |
v1.9. Combines beginner documentation, LIL coverage of all 205 procedures, Core IR, verified bytecode, formatting, compiled Vouch, and Topaz VM/AOT execution. Adds inventory, diagnostics, measurement, route locks, and locked execution for the four routes. | Version | What changed | | --- | --- | | v1.9.3 | adds locked `routes run`, aligns the four routes under one typed result, and closes F7 with tree retained as compatible default/reference/recovery | | v1.9.2 | adds Native `routes measure` samples over tree, Rust VM, exact Topaz VM, and exact AOT beside a separate canonical comparison receipt | | v1.9.1 | adds Native `routes inventory`, canonical no-clobber `routes lock`, and strict `routes doctor` for the tree, Rust VM, exact installed Topaz VM, and exact AOT routes | | v1.9.0 | publishes the beginner learning system, LIL 205/205 convergence, canonical Core IR, verified bytecode and Rust VM, request-bound compiled Vouch, source formatting, and the explicit exact Topaz VM/AOT plus four-route court as one coherent product |
v1.8. Brings Lispex Images together with beginner documentation and LIL support for all 205 procedures. Adds Core IR, verified bytecode and the Rust VM, source formatting, compiled Vouch, and Topaz VM/AOT execution with four-route comparison. | Version | What changed | | --- | --- | | v1.8.20 | adds Native `compare-routes` with one source/input frontend derivation, exact matching AOT admission, explicit tree/Rust VM/Topaz VM/AOT execution, and a no-clobber `lispex.route-comparison/v1` receipt with semantic and comparable-resource mismatch axes. It repairs AOT primitive-call charging and structured resource faults, and deterministically finalizes macOS executables by recording exact strip/sign tool identities and rebinding the Topaz artifact | | v1.8.19 | adds complete-profile Lispex-to-Topaz AOT on Native macOS ARM64 with deterministic readable Topaz and source maps, exact installed Topaz/Rust build-tool admission, and strict source-free product `build`, `inspect`, `validate`, and `run` with canonical full-width `u64` resources, diagnostics, warnings, and five visible zero fallback counters | | v1.8.18 | adds the explicit macOS ARM64 Native `bytecode run --engine topaz --topaz-vm` route for the exact installed Topaz 5.11 `lispex-topaz-vm/v1` product and `compare-vms` receipts over one verified bytecode artifact. Optimized Native builds also retain every Core IR and bytecode compilation operation | | v1.8.17 | adds deterministic Native `lispex fmt`, quiet `--check`, safe `--write`, and VS Code/Open VSX Format Document integration while preserving comments, pragmas, tokens, and original literal spellings | | v1.8.16 | adds canonical `lispex.vouch-compiled-artifact/v1`, Native `vouch compiled build/inspect/validate`, opt-in `vouch verify --reexecute --compiled-artifact`, and a compiled local gate requiring exact source derivation plus matching current tree/Meaning and verified Rust VM transcripts | | v1.8.15 | adds canonical binary `lispex.bytecode/v1`, strict pre-execution `lispex.bytecode-verifier/v1`, complete-profile `lispex-rust-vm/v1`, Native bytecode build/inspect/validate/run, explicit source `--engine vm`, and exact no-clobber tree/VM comparison reports | | v1.8.14 | adds canonical complete-profile `lispex.core-ir/v1` with stable 205-row primitive IDs, resolved lexical/global cells, exact closure captures and tail positions, source anchors, Canonical Core audit projection, and Native `core-ir build`, `validate`, and `inspect` commands | | v1.8.13 | implements `%`, `list-first`, and `list-rest` in LIL with their exact W330/W331 compatibility warnings, raising current capability coverage from 202/205 to 205/205 | | v1.8.12 | implements `display`, `write`, `newline`, and `println` in LIL through a private effect sink with a fixed output budget, raising current support from 198/205 to 202/205 | | v1.8.11 | implements all 12 remaining collection higher-order rows in LIL through explicit guest-machine continuation frames, raising current support from 186/205 to 198/205 and guest-calling coverage from 6/18 to 18/18 | | v1.8.10 | implements nine exact-intermediate division rows and `gcd`/`lcm` folds in LIL, and admits exact-integer `expt` plus two-value `exact-integer-sqrt` through the recorded numeric kernel, raising current support from 173/205 to 186/205 | | v1.8.9 | admits exactness-preserving `floor`, `ceiling`, `round`, `truncate`, exact/inexact conversion, and integer parity through the recorded numeric host kernel, and implements mixed-tower `min`/`max` folds in LIL, raising current support from 161/205 to 173/205 | | v1.8.8 | admits 18 character/string case predicates, conversions, and case-insensitive ordering operations through LIL's explicitly recorded Unicode host kernel, raising current support from 143/205 to 161/205 | | v1.8.7 | implements list copying, lookup and shared-tail navigation, deterministic list/string constructors, and character-indexed string/vector conversion inside LIL, raising current support from 135/205 to 143/205 | | v1.8.6 | implements case-sensitive character and string ordering chains inside LIL using Unicode scalar and lexicographic order, raising current support from 127/205 to 135/205 | | v1.8.5 | implements three finite-real tower predicates, structural `!=`, `memv`, `assoc`, `assq`, and `assv` inside LIL, raising current support from 119/205 to 127/205 | | v1.8.4 | implements `abs`, `square`, three sign/zero predicates, `boolean=?`, and `symbol=?` by composition inside LIL, raising current support from 112/205 to 119/205 | | v1.8.3 | implements all 27 previously missing composed pair accessors from `caar` through `cddddr` inside the Lispex-written LIL kernel, raising current LIL coverage from 85/205 to 112/205 | | v1.8.2 | records all 205 current capabilities as normatively `profile-required`, separately classifies host-only and future-profile decisions, and gives every one of the 179 historical pair divergences one machine-checked primary reason | | v1.8.1 | rebuilds the Modern documentation as a four-step beginner course, Syntax at a Glance, ten globally numbered groups, and 53 production-final English, Korean, and Russian surfaces. Downloads adds exact version verification, command recovery, and official VS Code and Open VSX guidance | | v1.8.0 | publishes exact Lispex Images as one same-Rust product across Native, npm, Node/browser WASM, and the local Playground, then lets a canonical image supply the exact source bytes to the existing Request-Bound Vouch journey |
v1.7. Combines request-bound Vouch with exact Lispex Images. Native, npm, WebAssembly, and Playground gain source-to-image creation and recovery, while canonical images supply source bytes to the identity, policy, and authenticated verification workflow. | Version | What changed | | --- | --- | | v1.7.3 | lets a canonical Lispex Image supply the exact source bytes for Native Vouch identity, policy, issue, inspect, authentication, re-execution, and gate, plus npm identity, policy, and authenticated verify. The maintained refund-window flow now uses image ingress end to end | | v1.7.2 | extends the one Rust image core to the npm CLI, Node/browser WASM, and a fully local Playground workflow with create/open, verified page navigation, exact recovery, download, and separate explicit run. Cross-surface single/multipage bytes match the fixed C1 goldens | | v1.7.1 | introduces canonical Lispex Images in Native with exact source-to-PNG/ZIP encoding, public commitment inspection, byte-for-byte decoding, and explicit execution only after full canonical proof | | v1.7.0 | publishes Request-Bound Vouch as one consumer-owned journey. Derive exact identities, create and check policy, issue a bundle, authenticate it against an optional external source/input request on Native or npm, then re-execute and gate only that live request on Native |
v1.6. Extends portable Vouch bundles and source policies with key, engine, and input identities. Native and npm verification bind separately supplied source and input, Native re-execution and gating use that request, and reproducible npm Wasm builds accompany the multilingual documentation refresh. | Version | What changed | | --- | --- | | v1.6.4 | makes the verification-only npm Vouch WASM regenerate to the same tracked bytes from clean, dirty, or relocated source checkouts and keeps the standalone export-surface audit runnable from a clean checkout | | v1.6.3 | Native bundle re-execution and gate require matching external source/input and pass only live request-bound evidence through re-execution to the grant. The localized documentation refresh adds the `/v1.6` public-minor route namespace, Downloads, numbered current/Classic navigation, aligned document surfaces, concise browser titles, balanced responsive hero copy, a Korean 리스펙스 wordmark, and one readable locale-aware display-label system for landing eyebrows, form/data folios, results, pagers, and menu categories | | v1.6.2 | Native/npm pinned bundle verify authenticates first and then compares separately supplied exact source/input bytes | | v1.6.1 | Native/npm `vouch key-id`, `engine-id`, and `input-id` close public identity derivation beside `source-id` through shared Rust | | v1.6.0 | aggregates portable bundle v0, key-local exact-source policy v1, shared-Rust source-id and policy tooling, and raw/bundle authentication into one consumer-owned Vouch workflow |
v1.5. Pairs capability-tracked LIL and LIT execution with the Vouch workflow. Native adds issuance, re-execution, and gating, while Native and npm share authentication, portable bundles, source identities, and consumer-owned source policies. | Version | What changed | | --- | --- | | v1.5.8 | Native/npm `vouch policy create/check` composes and validates canonical consumer trust policy v1 through shared Rust | | v1.5.7 | Native/npm `vouch source-id --source` derives the exact source identity from bytes under the configured budget through the shared Rust core | | v1.5.6 | trust policy v1 rejects a fully valid signed rule unless its exact source identity is allowed by the selected key | | v1.5.5 | canonical envelope/source/input bundle with Native emission/consumption and npm authentication-only consumption | | v1.5.4 | npm `vouch verify` authenticates signed Native envelopes and exact source/input/profile through a verification-only build of the shared Rust core, matching Native v0 report bytes and C-VN-06 outcomes | | v1.5.3 | Native `vouch gate --require-decision` requires authentication, current complete-transcript agreement, and an exact decision match before returning a local grant | | v1.5.2 | namespaced Vouch workflow, maintained refund-window flow, LIL 85/205 capability boundary, and native `vouch verify --reexecute` with separate authentication and current-execution agreement | | v1.5.1 | native Vouch issuance. Qualifying checked decisions can be constructed and signed as DSSE envelopes, then authenticated against a consumer-supplied trust policy | | v1.5.0 | capability-tracked LIL and LIT execution lines, 84-of-205 capability ledgers, a three-family joint receipt, and coordinated native/npm/WASM/Playground distribution |
v1.4. Aligns Native, npm, WebAssembly, and Playground execution, including `apply` and multiple-value handling in the checked evaluator. Receipt execution budgets and pinned downloads connect runtime behavior to the installed product. | Version | What changed | | --- | --- | | v1.4.0 | runtime and distribution refresh with apply and multiple-value paths in the checked evaluator, configured receipt fuel, native/npm/WASM/Playground alignment, and pinned native downloads |
v1.3. Develops offline decision receipts and replay into the Vouch workflow and Bridge interoperability. Native receipt generation, release-build engine identity, replay corpora, and strict checks cover linked artifacts, nested data, optional context, and external-engine reports. | Version | What changed | | --- | --- | | v1.3.11 | canonical Bridge read-side acceptance, closed-world nested checks, linked artifact and optional context checks | | v1.3.10 | adversarial artifact-class checks and explicit authenticity non-goals | | v1.3.9 | twelve-case welfare-style replay evaluation corpus | | v1.3.8 | Vouch Bridge report shape, offline checker, and external-engine example | | v1.3.1-v1.3.7 | closed the usable Vouch loop with native receipt generation, release-build engine identity, offline verify, versioned replay corpus, and an explicit authenticity boundary | | v1.3.0 | checked-profile decision receipts, offline verify, replay, and release gates |
v1.2. Establishes the deterministic runtime, recoverable error handling, and Native, npm, WebAssembly, and Playground execution. Development checkpoints add canonical Core, Meaning Graph and Meaning Environment, execution receipts, the checked decision profile, and offline verification and replay backed by semantic vectors and Scheme comparisons. | Version | What changed | | --- | --- | | v1.2.15-v1.2.19 | external Scheme-oracle ledger, authored semantic vectors, strict artifact readers, tamper fixtures, and mutation drills | | v1.2.14 | expanded the checked decision profile and gallery with search, rounding, any/all traversal, strict faults, and clearer replay ergonomics | | v1.2.9-v1.2.13 | checked-profile boundary, intrinsic binding, control/arithmetic gallery, closures and traversals, host-input binding, npm offline verify, and replay UX | | v1.2.2-v1.2.8 | versioned canonical Core, execution receipt, conformance manifest, Meaning Graph and lowering, separate Meaning Environment evaluator, and differential receipt contract | | v1.2.0 | first consolidated v1 tag. It added recoverable raise, guard, and with-exception-handler semantics while shipping Native, Node/WASM, Playground, and download paths. The initial v1 implementation line from 2026-06-28 and 2026-06-29 supplied the deterministic reader, hygienic normalizer, trampoline evaluator, exact integer/rational plus finite-real profile, pinned rendering, one-shot upward `call/cc`, `dynamic-wind`, multiple values, proper-tail `apply`, R7RS-shaped procedures, WASM, and Playground |
## Version ownership - Language, package, and artifact-contract versions each advance with their own product change. - The runtime profile owns evaluation behavior. Named CSK and Vouch contracts own their artifact schemas and compatibility identifiers. - Backend records identify their capability rows, host routes, corpora, and receipts. - Release entries state language-semantic changes directly. ## Keep going If Lispex is new to you, the Introduction is the practical entrance. The Roadmap holds what is planned next. [Introduction](/en/docs/introduction) · [Roadmap](/en/docs/roadmap) --- Source: https://www.lispex.com/v1.20/en/docs/roadmap.md # Product Roadmap > The current Lispex product, the systems that already ship, and the next work on language semantics, execution routes, decision workflows, and learning. Canonical page: https://www.lispex.com/v1.20/en/docs/roadmap Version check: this file describes v1.20. Fetch https://www.lispex.com/version.json before treating it as the current manual. ### What this page gives you This page shows the product as it works today and the work that moves Lispex forward. Release History records the exact chronology of shipped versions. ## The product today Lispex is a deterministic decision language. The Rust reference interpreter defines the runtime behavior and supports all 205 tracked primitive rows. The same source and input produce the same observable result under the selected resource profile. Native, npm, WebAssembly, the Playground, and sicp.io provide distinct ways to use the language. Exact source and input identities, canonical artifacts, stable diagnostics, and typed observations connect those surfaces. | System | Product role | | --- | --- | | Reference interpreter | Runs Lispex source directly with the complete current language profile. | | Meaning Graph and Meaning Environment v1 | Project Core IR into an explicit semantic graph and evaluate control flow, shared cells, mutation, tail calls, one-shot escape continuations, dynamic cleanup, stdout, values, warnings, and errors. | | Core IR and verified bytecode | Resolve bindings and tail positions once, compile canonical bytecode, and execute it in the Rust virtual machine. | | Native execution routes | Select and inspect tree, Rust VM, Topaz VM, and Topaz AOT products through exact route identities and path-free selection locks. | | Resource-controlled embed | Runs the decision profile with configured work and memory values and produces a portable core for eligible outcomes. | | Full embed | Runs all 205 primitive rows through a separately identified import-free WebAssembly component and a fresh instance for every operation. | | Lispex Images | Encode exact source bytes into canonical PNG or ZIP artifacts and recover those bytes across Native, npm, WebAssembly, and the Playground. | | Decision exchange | Packages canonical decision artifacts, issuer envelopes, recipient policies, request binding, inspection, authentication, and replay. | | Vouch | Authenticates signed decision evidence and lets Native evaluate a consumer-pinned request through the local decision gate. | | SICP | Provides the `@lispex/sicp@1.0.0` educational runtime, `lispex sicp run`, typed observations, exact execution traces, and the chapter course at sicp.io. | | LIL and LIT | Run Lispex through implementations written in Lispex and Topaz. LIL covers 205 of 205 tracked primitive rows and LIT covers 84 of 205. | ## Current direction ### Complete semantic structure Meaning Graph and Meaning Environment v1 establish an explicit-control foundation for shared lexical cells, mutation, tail execution, escape control, and exact observations. The next semantic work extends this foundation through direct runtime behavior and keeps Core IR as the single resolved authority. ### Grow LIT coverage LIT currently implements 84 of 205 tracked primitive rows. Meaning Graph v1, Core IR, and the conformance corpus provide reusable execution observations for the Topaz implementation. Each added row ships with its direct behavior, diagnostics, and resource accounting. ### Make exact execution easier to use Native continues to unify inventory, installation, route selection, diagnostics, measurement, locked execution, and relocation. npm and WebAssembly carry the same canonical artifacts and typed results into application workflows. ### Strengthen decision workflows Decision exchange and Vouch continue around exact source, exact input, recipient-owned policy, authenticated issuer identity, fresh re-execution, and an explicit application handoff. The receiving application owns the final business action. ### Expand learning paths The six-step Lispex course, reference manuals, Playground, and SICP course grow together. English, Korean, and Russian pages use one terminology system, and each lesson connects source to an exact result or typed observation. ## Release discipline Feature work proves its behavior in the module that owns it. A release candidate then builds immutable Native and package artifacts, exercises one installed product journey, publishes those bytes, and confirms the public channels. Roadmap items receive a version when implementation begins. ## Keep going Use History for the exact chronology and Philosophy for the product principles. [History](/en/docs/history) · [Philosophy](/en/docs/philosophy)