Persistent OcaltQL
Two independent mechanisms let state survive beyond a single script execution: PERSISTENT stores values that survive across requests; START PERSIST opens a standing execution timeline with no time limit.
PERSISTENT — Cross-Request Values
SET PERSISTENT stores a value that survives across separate script executions, with no expiry. It persists until it is overwritten. This is fully independent of START PERSIST — it works with no standing timeline open at all.
SET PERSISTENT ?var is nothing more than ordinary variable setting with a persistent capture target. Everything you already know from Variables SET | UNSET applies unchanged — the only difference is the word PERSISTENT sitting in front of the captured ?var. Both capture forms carry straight over: the generic SET PERSISTENT ?var AS value and the typed STRING "x" SET PERSISTENT ?var (or NUMBER, CALCULATE, and every other value-producing verb) are two spellings of the same thing, and both land the same value in persistent storage under that name.
SET PERSISTENT ?pvar AS "some value"
STRING "this" SET PERSISTENT ?var
NUMBER 1000 SET PERSISTENT ?numbervar
CALCULATE 10 + 5 SET PERSISTENT ?total
STRING "hello" SET PERSISTENT ?var
AFTER STRING "world" SET PERSISTENT ?var
(* The persisted value is now "world" — the same overwrite behaviour as an ordinary SET *)
STRING "hello" SET ?source
AFTER SET PERSISTENT ?copy AS ?source
(* ?copy is persisted, carrying ?source's value — the generic AS form doing var-to-var *)
STRING "hello" SET PERSISTENT ?var
AFTER IF ?var IS SET
OPEN
EMIT "still here"
CLOSE
OR
OPEN
EMIT "expired or cleared"
CLOSE
PERSISTENT sits in front of the variable everywhere it appears — on the way in with SET PERSISTENT ?pvar, and on the way out with EMIT PERSISTENT ?pvar. A bare ?pvar is an ordinary script-local variable and has nothing to do with the persisted one, even under the same name. Nothing is guessed from context; the word is what makes it persistent.STRING "Hello World!" SET PERSISTENT ?pvar
AFTER EMIT PERSISTENT ?pvar
STRING "persisted" SET PERSISTENT ?var
AFTER STRING "local" SET ?var
AFTER EMIT ?var
AFTER EMIT PERSISTENT ?var
(* Output: local, then persisted — two separate variables *)
UNSET has no persistent counterpart — there is no UNSET PERSISTENT. Everything else from Variables SET | UNSET — declaring, overwriting, the SET ... AS and typed forms, the IS SET check — mirrors directly by placing PERSISTENT on the variable.EMIT PERSISTENT ?pvar
Persistent Operations
An operation persists the same way a value does. NEW PERSISTENT OPERATION registers it once, across executions; RUN PERSISTENT calls it from any later script without redefining it. Everything from Operations & Return carries over unchanged — parameters, typed parameters, RETURN, the isolated frame — the only difference is the word PERSISTENT.
NEW PERSISTENT OPERATION calculate_total WITH ?price AS NUMBER REQUIRED
OPEN
CALCULATE ?price * 1.15 SET ?total
AFTER RETURN ?total
CLOSE
RUN PERSISTENT calculate_total WITH 100 SET ?result
AFTER EMIT ?result
(* The definition is not in this script at all — it was registered earlier *)
PERSISTENT is written on both halves — NEW PERSISTENT OPERATION to register, RUN PERSISTENT to call. A plain RUN opname only ever finds an operation defined in the current script, so a persistent operation and a script-local one of the same name never collide.START PERSIST / KILL PERSIST — A Standing Execution Timeline
START PERSIST is a separate, distinct mechanism from SET PERSISTENT. Where SET PERSISTENT stores individual values, START PERSIST opens a standing execution timeline with no time limit at all — think of it as turning OcaltQL into a live terminal session. Once started, every later script execution in the same session continues within that same open timeline, carrying its state forward, until KILL PERSIST explicitly closes it.
START PERSIST
KILL PERSIST
PROMISE/WAIT FOR handles asynchronous resolution within a single script’s own live execution. PERSISTENT only carries an already-settled value across separate, later script executions — it has no in-flight, live async-resolution behavior of its own.A Terminal, Built From PERSIST and !QUERY
A standing timeline plus !QUERY is enough to build a real terminal. Inside an open PERSIST timeline an ordinary ?var already carries forward from one submission to the next — nothing has to be marked persistent, because the timeline itself is what is holding the state. !QUERY hands each submission its own source text, so the session can record what was typed.
START PERSIST
AFTER NEW ARRAY SET ?history
AFTER EMIT "session open"
APPEND !QUERY TO ?history
AFTER CALCULATE 40 + 2 SET ?answer
AFTER EMIT ?answer
(* ?history is still the same array from the first submission — the timeline kept it *)
COUNT ?history SET ?n
AFTER EMIT ?n & " commands this session"
AFTER FOREACH ?history SET ?i AS ?cmd
OPEN
EMIT ?i & ": " & ?cmd
CLOSE
EMIT "closing, " & [COUNT ?history] & " commands run"
AFTER KILL PERSIST
(* ?history goes with the timeline *)
PERSISTENT appears anywhere in this example, and that is the point. PERSIST holds the whole execution state open; PERSISTENT stores one named value independently of any timeline. A terminal needs the first, not the second.Sessionless Persistence
CONSISTENT is the session-blind counterpart to PERSISTENT. PERSISTENT is scoped to the session — a value stored during one of your users’ sessions is only ever visible to that same session. CONSISTENT stores one value for the whole namespace: every script in your namespace reads and writes the same value, whichever of your users happens to be running it.
CONSISTENT value lives inside your namespace exactly as your files and databases do — no other namespace can see it, read it, or write to it. The isolation guarantee that applies to everything else applies here unchanged.STRING "Hello World!" SET CONSISTENT "key"
CONSISTENT "key" SET ?var
AFTER EMIT ?var
AFTER EMIT [CONSISTENT "key"]
(* Both forms read the same global value — direct SET capture, or inline reference *)
(* Any script in the namespace, any visitor, any session — all increment the same counter *)
CONSISTENT "page_views" SET ?views
AFTER IF ?views IS NULL OPEN NUMBER 0 SET ?views CLOSE
AFTER ADD 1 TO ?views SET ?views
AFTER STRING ?views SET CONSISTENT "page_views"
AFTER EMIT "This page has been viewed " & ?views & " times"