Scripts#

Scripts live in Documents/Ohm (override with OHM_SCRIPTS_DIR). They are plain files in a folder you own — visible in your file manager, trackable in git, and readable by other scripts.

Three kinds run, and the Run button appears for all three:

.ohm Ohm — Lua 5.4 with LaTeX maths. Compiles to Lua and runs.
.volt Volt — parsed into a graph, which is then evaluated. No model involved in getting there.
.bolt Bolt — English, translated by a local model into a program that must compile before it runs.

On first start the folder is seeded with working examples:

ai/agent.ohm  ai/compose.ohm  ai/parallel.ohm  ai/research.ohm
models/list-models.ohm  models/download-gguf.ohm
models/download-web-model.ohm  models/compare-profiles.ohm
browse.ohm  math.ohm  memory.ohm  welcome.ohm  README.md
volt/01-lists.volt … volt/07-sketch.volt
bolt/research.bolt  bolt/compare.bolt  bolt/cheapest.bolt  bolt/README.md

A folder of examples you have never had is added when Ohm starts, so a new set arrives on upgrade. A group you already have is left alone entirely — an example you deleted stays deleted, and one you edited is never overwritten.

README.md there is the language reference. Settings → Scripts can restore the examples without touching your own files.

The Scripts panel#

Ctrl+Shift+E. Create files and folders with + and ⊞, rename with F2 or a double-click, and run a script by hovering it and pressing ▶.

Deleting moves to .ohm/trash rather than unlinking, so a misclick is recoverable. The .ohm folder also holds script memory and screenshots and is hidden from the tree.

The editor#

  • Ohm syntax highlighting, and completion after \ and after browser. / tab.
  • Live syntax errors from the real compiler
  • A Code / Math / Lua switch (see below)
  • F5 save and run, Ctrl+S save, Shift+F5 stop

Completion, hover and signature help#

Typing \ offers commands and every operator with its family and signature; typing a dot after a host object (browser., tab., ai., lib., remote.…) offers that object's members; and lib. offers the library entries that actually exist. Hovering explains whatever is under the pointer, and inside a call the argument list stays visible with the current argument highlighted — for \CoT_{\Psi}(q; C) as much as for tab.waitFor(sel, ms).

Typing \Su: the matching operators, with the selected one's arguments, return value and example beside it

The documentation beside the list is the same text as the operator reference — both are generated from the operator registry, so the editor and the docs cannot drift apart.

Each of those is a switch in Settings → Editor:

Settings → Editor: the completion switches and the error delay

Setting Effect
Suggest while typing the master switch — off means no completion at all
Operators and commands \CoT, \Search, \frac… after a backslash
Host API members suggestions after browser., tab., ai., lib., remote.…
Library entries your saved prompts and functions
Insert placeholders arguments as tab stops rather than bare names
Hover documentation explain the operator or function under the pointer
Signature help the argument list while the cursor is inside a call
Syntax errors appear after the idle delay in milliseconds before the compiler runs

Reading the math#

The toolbar switches between three views of the same file:

View Shows
Code the source, editable
Math the LaTeX typeset — $\frac{22}{7}$ becomes a real fraction
Lua the compiled output

The Math view: the Lua stays code and only the math regions are typeset

In the Math view the Lua stays as code and only the math regions are typeset, so the file still reads as a program: a \sum_{i=1}^{n} i^{2} becomes a ∑ with its limits above and below, \CoT_{\Psi}(q; C) becomes CoT with a Ψ subscript, and \mathcal{M}["last"] becomes ℳ["last"].

Click any formula to flip that one back to its LaTeX, and click again to typeset it — so you can check the source of a single expression without leaving the view.

Two things worth knowing:

  • The typesetting comes from the compiler's own parser, so it understands Ohm's operators (\CoT_{\Psi}, \Retrieve_{\Gamma}) which a general LaTeX renderer would reject.
  • It is therefore honest: a region the compiler would refuse is shown as its source with the error, not as pretty output.

The same switch appears when a .ohm file is opened from a project's Files section, where annotating happens in the Code view.

Because compilation preserves line numbers, an error at .ohm line 12 is reported at line 12 and clicking it in the console jumps there.

Running#

Runs stream their output live to the console on five streams: out (print), info, warn, err, and result (bare expressions and the return value).

Shift+F5 stops a run. Stopping terminates the worker thread, so it works even on a script stuck in a tight loop with no host calls — at the cost of discarding that session's state.

One run at a time per session; the run history is pruned automatically.

Arguments and context#

Every script gets ctx:

print(ctx.script)        -- this script's path
print(ctx.project)       -- the project it belongs to, or nil
print(ctx.args)          -- arguments passed to the run

A script under projects/<id>/ is automatically bound to that project, whichever project is active. A loose script uses the active project and tells you clearly when there is none.

Memory#

\mathcal{M} (mem in Lua) persists between runs of the same script:

$$
  \mathcal{M}["runs"] := (\mathcal{M}["runs"] or 0) + 1
$$
print("run number", mem.runs)

It is re-read after every run, including one that failed, and written back only when it changed.

Files#

fs is confined to the scripts folder:

fs.write("notes/today.md", "# Notes\n")
print(fs.read("notes/today.md"))
for _, name in ipairs(fs.list("notes")) do print(name) end

Anything that resolves outside the folder — or into .ohm — is refused.

Import and export#

Settings → Scripts, or the ⇩ and ⇧ buttons in the panel, import a folder and export the selection or everything. Nothing is ever overwritten: a clashing name gets a numbered suffix.

For a whole project — items, documents, annotations and all — use a bundle instead.