# 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-ci>=? char-ci>? char-downcase
char-foldcase char-lower-case? char-numeric? char-upcase
char-upper-case? char-whitespace? char<=? char 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-ci>=? string-ci>? string-copy string-downcase string-foldcase
string-for-each string-length string-map string-ref string-upcase
string<=? string 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)