CLI
notatio on the command line: a Wolfram-style REPL for compute-engine with the enumeratio symbols declared. The same evaluation core runs three places: an interactive terminal, a plain command line, and — thanks to a browser-safe core — a real terminal emulator in the browser.
Try it live
The live REPL is a real terminal running this exact CLI logic in your browser — pick an example from the dropdown or type your own. The live command line does the same for scriptable notatio invocations.
The prompt is numbered In[n]:= / Out[n]=, like a notebook transcript. Results stay exact — 1/2 + 1/3 is 5 / 6, not 0.833….
Input syntaxes
The default is Epsil — compute-engine's own surface syntax, rendered back as InputForm (re-typeable Epsil): ( for function calls, ^ / / for powers and fractions, capitalized heads (Binomial, Sqrt, Sin). LaTeX lives in $…$ islands. A syntax pragma forces a syntax for one line, and :in <syntax> changes the default.
| Syntax | Example | Notes |
|---|---|---|
| Epsil (default) | Binomial(10, 3) | rendered back as InputForm |
| LaTeX island | $\binom{10}{3}$ | LaTeX inside an Epsil line |
| LaTeX (pragma) | :latex \binom{10}{3} | a whole LaTeX line |
| Wolfram full form | :wolfram Binomial[10, 3] | Head[args] |
| MathJSON | :mathjson ["Binomial", 10, 3] | the interchange form |
All evaluate to the same thing — the combinatorial heads (Binomial, Inversions, Descents, MajorIndex, …) come from @enumeratio/combinatorics/collections. Bare LaTeX (a line starting with \) is not accepted in Epsil — use a $…$ island or :latex.
Output forms
:form <name> switches how results print; :forms lists them with the current one marked. A command line such as :form does not consume an In[n] number. The same expression renders as InputForm, TeX, Wolfram, or compilable source:
In[1]:= x^2 + 1
Out[1]= x ^ 2 + 1
In[2]:= :form wolfram
In[2]:= x^2 + 1
Out[2]= Plus[Power[x, 2], 1]
In[3]:= :form numpy
In[3]:= x^2 + 1
Out[3]= x ** 2 + 1
In[4]:= :form js
In[4]:= x^2 + 1
Out[4]= (_.x * _.x) + 1Forms: inputform (the default), tex, mathjson, wolfram, epsil, outputform, asciimath, mathml, numpy, glsl, wgsl, js. Aliases: standardform is inputform, text is outputform, wl/fullform are wolfram, texform/latex are tex, py/python are numpy.
inputform and epsil both print Epsil, but inputform is what you would retype: it prints PascalCase heads and option names, and normalises the tree (x - 2 for x + -2). epsil is the raw serialisation of the tree, with compute-engine's camelCase library names.
The code forms (numpy/glsl/wgsl/js) are real compute-engine compilation targets — they only apply to numeric/function expressions.
History and variables
Each line is numbered, and a committed line can be referenced from a later one, the way a Wolfram notebook does:
Out(n)is the result of linen, already evaluated. A negative index counts back:Out(-1)is the last result,Out(-2)the one before. (Wolfram's%/%%/%nwork in Wolfram syntax only — in Epsil%isMod.)In(n)is the input of linen, re-evaluated where you ask for it. Wolfram givesIn[n]a delayed value, soIn[1]of a random draw draws again; ours re-evaluates the parsed input the same way.InString(n)is that line as you typed it, as a string.
Bracket spelling is Wolfram's; in Epsil […] builds a list, so the calls are written Out(2), or :wolfram Out[2] for one line in Wolfram syntax.
In[1]:= Binomial(10, 3)
Out[1]= 120
In[2]:= Out(1) + 1
Out[2]= 121
In[3]:= InString(1)
Out[3]= "Binomial(10, 3)"
In[4]:= In(1) / 2
Out[4]= 60A line with controls in it is committed the same way: Enter ends the strip and what you left on screen becomes Out[n], so a later line reading Out[n] gets the state you stopped at — the session is Wolfram-style, one committed cell at a time, not a sheet that keeps re-running (that is a worksheet).
let name = <expr>binds a variable the engine remembers; later lines resolve it, and:varslists the bindings.
In[1]:= let n = 5
Out[1]= n = 5
In[2]:= Binomial(n, 2)
Out[2]= 10
In[3]:= Out(-1) * 3
Out[3]= 30Graphics
:plot <expr> samples a one-variable expression over x ∈ [-5, 5]. :glyph <kind> <list> draws a combinatorial object (permutation, partition, composition, subset, dyck). In the browser terminal the figure appears beside it; the Node CLI writes an SVG to a temp file (and shows it inline on iTerm2 / kitty). Try :glyph partition [5,3,3,1] or :plot Sin(x) in the live REPL.
Figures in the terminal
A value that draws as a figure (a Permutation as strands, a PlaneTree, a DyckPath, an IntegerPartition or StandardTableau as cells) is drawn on character cells: braille for curves and ● for points, box-drawing for rectangles. Typing the value at the prompt draws it under its Out line; notatio show <expr> draws it from the command line, and prints any other result as eval does. Marks keep their rules' colors where the terminal has color.
$ notatio show 'StandardTableau([[1, 2, 4], [3]])'
┌───┬───┬───┐
│ 1 │ 2 │ 4 │
├───┼───┴───┘
│ 3 │
└───┘Layouts draw the same way. Row, Column, Grid, Panel and Labeled are boxes laid out on cells: a Grid is aligned (ruled with Frame -> True or Dividers -> All), a Panel framed, a fraction stacked and a script raised, and an entry that is a figure sits in the layout as it would in a page.
$ notatio show 'Labeled(Permutation([3, 1, 2]), "σ")'
$ notatio show 'Grid([[1, 2], [3, 4]], Frame -> True, Dividers -> All)'
┌───┬───┐
│ 1 │ 2 │
├───┼───┤
│ 3 │ 4 │
└───┴───┘
$ notatio show 'Panel(Row([x, y]))'
┌─────┐
│ x y │
└─────┘
$ notatio show 'Row([1/2, x, "and", x^2])'
1
─── x and x²
2Environments
A result can carry controls — a Slider, a Toggler, a whole Manipulate. What happens to them depends on where the result is going, and the CLI knows two answers.
At a TTY the controls are real: the REPL draws a strip of text sliders under the input. Click or drag a slider with the mouse (the wheel steps it); with the keyboard, ←/→ move the focused one, Shift for the coarse gear, Tab changes focus, Space plays. Enter commits the line — what you left on screen becomes Out[n], referenceable from later lines. A Plot under the strip is drawn on braille cells (or inline as an image on iTerm2 / kitty), so it redraws as you scrub; the y-axis gutter is a fixed width, so the curve never shifts sideways as a label changes.
Anywhere else — a pipe, a file, a page — there is nothing to move a slider with, so the expression is reduced: the controls pin to their starting values and their declarations become a caption, or, for print, the first one is sampled into a grid of small multiples.
notatio "Manipulate(a^2 + b, (a, 0, 1), ((b, 2), 0, 3))"
# Labeled(2, "a = 0 (0 ≤ a ≤ 1); b = 2 (0 ≤ b ≤ 3)", Bottom)
notatio --env print "Manipulate(a * x, (a, 1, 3, 1))"
# Grid([[Labeled(x, "a = 1", Bottom), Labeled(2x, "a = 2", Bottom), …]])--env names one explicitly (web, print, tty, pipe, compact); --json skips the reduction and hands back the expression whole. In the REPL, :env <name> does the same for every result until :env auto. The expression can ask for a reading itself with a trailing rule — Static -> "Pin", Static -> "Sample", or Static -> 3 for a sample count. The same rewrite runs on the site, where printing a page turns its sliders into grids: see the Environments playground and https://github.com/enumeratio/enumeratio/wiki/Rendering-Environments.
Command line
Outside the browser, notatio is also a plain command: give it an expression and it prints the result and exits — ideal for scripts and pipes. Try it in the live command line.
notatio "Binomial(10, 3)" # 120
notatio -f wolfram "x^2 + 1" # Plus[Power[x, 2], 1]
notatio -f numpy "Sin(x) + 1" # np.sin(x) + 1
echo "2 + 40" | notatio # 42
notatio -i wolfram "Inversions[List[3,1,2]]" # 2A bad expression exits non-zero with the error on stderr. With no expression on a TTY, notatio starts the interactive REPL instead.
Subcommands
eval is the default and rarely needs writing. convert re-renders an expression in another form without evaluating it — the way to see x^2 + 1 as WL rather than what it computes to. forms and formats list the output forms and the format registry. completion <shell> prints a completion script to eval, and serve --port N stands up the compute host below.
Command reference
Generated from the CLI's own USAGE, completion tables and form registry, so it cannot drift from the binary. Form and syntax names resolve on any unambiguous prefix, so -f wolf, -f math and -i w all work — and Wolfram spellings (TeXForm, InputForm, FullForm) resolve too.
notatio — evaluate compute-engine expressions
Usage:
notatio [options] <expr> evaluate <expr> and print the result
notatio eval [options] <expr> same, explicit
notatio convert [options] <expr>
re-render <expr> in another form without evaluating
notatio show [options] <expr> draw <expr> as a figure on character cells (a Permutation as
its strands, a DyckPath as its path); other results print as eval
echo <expr> | notatio read the expression from stdin (or pass "-")
notatio (a TTY, no expr) start the interactive REPL
notatio forms | formats list the output forms | the format registry
notatio completion <shell> print a completion script: bash, zsh, fish
notatio serve [--port N] run the local HTTP compute host
Options:
-f, --form <name> output form: inputform, tex, mathjson, wolfram, epsil, outputform, asciimath, mathml, numpy, glsl, wgsl, js
(repeatable; Wolfram names like TeXForm, InputForm, FullForm work too)
-i, --in <syntax> input syntax: latex, mathjson, wolfram, epsil, asciimath, mathml (default epsil)
-c <expr> the expression to evaluate
-N, --numeric numeric approximation of the result
-p, --precision <n> working precision in significant digits
--env <name> reduce the result for an environment: web, print, tty, pipe, compact
(text output defaults to pipe: controls pin, with a caption)
--json print a structured result: { ok, input, syntax, form, result, forms }
-h, --help show this help
-V, --version show the version
Defaults for --form, --in, and --precision can live in a config file
($NOTATIO_CONFIG, ~/.config/notatio/config.json, or ~/.notatiorc).Subcommands
| Subcommand | What it does |
|---|---|
eval | same, explicit |
convert | re-render <expr> in another form without evaluating |
show | draw <expr> as a figure on character cells (a Permutation as its strands, a DyckPath as its path); other results print as eval |
forms | list the output forms |
formats | the format registry |
serve | run the local HTTP compute host |
completion | print a completion script: bash, zsh, fish |
Options
| Flag | What it does |
|---|---|
-f, --form <name> | output form: inputform, tex, mathjson, wolfram, epsil, outputform, asciimath, mathml, numpy, glsl, wgsl, js (repeatable; Wolfram names like TeXForm, InputForm, FullForm work too) |
-i, --in <syntax> | input syntax: latex, mathjson, wolfram, epsil, asciimath, mathml (default epsil) |
-c <expr> | the expression to evaluate |
-N, --numeric | numeric approximation of the result |
-p, --precision <n> | working precision in significant digits |
--env <name> | reduce the result for an environment: web, print, tty, pipe, compact (text output defaults to pipe: controls pin, with a caption) |
--json | print a structured result: { ok, input, syntax, form, result, forms } |
-h, --help | show this help |
-V, --version | show the version |
Output forms
inputform— InputFormtex— TeXFormmathjson— MathJSONwolfram— WolframFullFormepsil— Epsiloutputform— OutputFormasciimath— AsciiMathmathml— MathMLnumpy— NumPy / Pythonglsl— GLSLwgsl— WGSLjs— JavaScript
Input syntaxes
latexmathjsonwolframepsilasciimathmathml
Completion shells
bashzshfish
Running it
The CLI is part of the enumeratio monorepo. In a checkout:
# interactive REPL
pnpm --filter @enumeratio/cli exec tsx src/main.ts
# evaluate one expression
pnpm --filter @enumeratio/cli exec tsx src/main.ts "Binomial(10, 3)"
# or build the bin and run it directly
pnpm --filter @enumeratio/cli build
node packages/cli/bin/notatio.mjs "2 + 2"Formats, import & export
Every output form is a registered format (:formats lists them, with the MIME type and whether it imports, exports, or both). :mime <type> is Wolfram's MIMETypeToFormatList — :mime image/png → PNG.
In the Node CLI, :export <path> writes the last result (or the last graphic, for .svg/.png) with the format inferred from the extension, and :import <path> reads a file back — WL / MathJSON / TeX become the next result, and the format is content-sniffed when the extension is unknown.
In[1]:= x^2 + 1
In[2]:= :export /tmp/expr.wl # wrote /tmp/expr.wl (WL) -> Plus[Power[x, 2], 1]
In[3]:= :import /tmp/expr.wl # Out[3]= x ^ 2 + 1Compute host
notatio serve stands up a small HTTP endpoint over the same eval core — a local compute host for scripts, other tools, or a browser talking to your machine.
notatio serve # http://127.0.0.1:7373
notatio serve --port 8080curl -s localhost:7373/eval -H 'content-type: application/json' \
-d '{"input":"x^2 + 1","form":"wolfram"}'
# {"ok":true,"result":"Plus[Power[x, 2], 1]","forms":{"inputform":"x ^ 2 + 1", …}}Endpoints: POST /eval { input, syntax?, form? } (each request evaluates in a fresh session and returns inputform / tex / mathjson / wolfram forms), GET /formats, and GET /mime?type=…. It binds localhost with no auth — a single-user dev tool; exposing it on a network would need auth and sandboxing first.
REPL command reference
Everything the interactive session accepts; :help prints the same list.
| Command | Does |
|---|---|
<expr> | evaluate (Epsil by default) |
:wolfram / :mathjson / :latex / :epsil <expr> | force an input syntax for one line |
let <name> = <expr> | bind a variable |
% · %% · %n (Wolfram syntax only) | last / 2nd-last / n-th result |
Out(n) · In(n) · InString(n) | n-th result · n-th input, re-evaluated · n-th line as typed |
:form [name] | show or set the display form |
:env [name] | reduce results for an environment |
:forms | list the display forms |
:in <syntax> | set the default input syntax |
:plot <expr> | plot a one-variable expression |
:glyph <kind> <list> | draw a combinatorial glyph |
:export <path> · :import <path> | write / read a file (Node) |
:formats · :mime <type> | the format registry · MIME → formats |
:vars · :clear · :help · :quit | variables · clear · help · exit |
- Source:
packages/cli - Depends on:
analytic,boxes,braid,combinatorics,diagram,evaluation,formats,frontend,groupalgebra,hecke,hopf,hypercomplex,incidence,manifest,modular,number-theory,numerals,quiver,raster,residues,statistics,structures - In development, also:
config