State & Persistence
Turn agents are designed to run indefinitely. The runtime provides native, file-backed state persistence without requiring databases, ORMs, or complex state machines.
The Persistence Vector (persist let)
The persist keyword modifies a standard let binding to serialize the variable directly to the .turn_store directory immediately upon assignment.
persist let x = y;When the VM boots, before it executes the first line of your script, it scans the .turn_store directory for persisted variables and pre-loads them into the global environment.
// First run: run_count is 0, then becomes 1
// Second run: run_count pre-loads as 1, then becomes 2
persist let run_count = 0;
persist let run_count = run_count + 1;
call("echo", "This loop has run " + run_count + " times.");How it works
- The compiler emits an
Instr::StorePersist(name)bytecode instruction exactly after the standardInstr::Store. - The VM writes the serialized JSON value to
.turn_store/persist_<name>.json. - If the script halts, crashes, or is shut down, the value remains on disk.
- On the next execution, the initial
persist let run_count = 0;acts as a fallback default only. The loaded value from disk shadows the right-hand-side expression.
NOTE
You can persist any valid Turn type: strings, numbers, lists, maps, and even structured JSON objects.
Orthogonal Persistence (suspend)
For workflows that require waiting for external events or human-in-the-loop approval, you can suspend the entire VM execution state:
let msg = suspend for Any "Waiting for input";When the VM hits the suspend primitive, it halts execution cleanly. The full state of the process — the instruction pointer, the stack, and the lexical environment — is preserved. The process can be resumed later from exactly where it left off.
call("echo", "Waiting for payment confirmation...");
// Process yields here until the external world wakes it up
let payment = suspend for Any "Awaiting callback data";
call("echo", "Payment received, continuing execution.");
let receipt = infer Receipt { "Generate receipt for payment: " + payment; };This allows Turn programs to represent business logic naturally, without inverting control flow into complex event-driven callbacks.
State vs. Semantic Memory
Persistence (persist let) and Semantic Memory (remember) serve different purposes:
| Feature | Best For | Storage Mechanism | Retrieval |
|---|---|---|---|
persist let | Exact state, counters, config flags | .turn_store/persist_x.json | Exact variable name |
remember | Unstructured text, facts, learnings | HNSW Vector Graph (items.hnsw) | Semantic similarity (recall) |
Use persist let for exact application state that the script needs to run correctly (e.g., an incrementing sequence ID, or a configuration JSON map). Use remember for knowledge the agent should use to answer questions or make decisions later.
Time-Travel Replay
Every infer call, tool invocation, and state mutation is written to a versioned Write-Ahead Log inside .turn_store/<agent-id>/. If an agent crashes, you do not need to re-run it to understand what happened.
turn replay my-agentThis opens an interactive session:
Frame 0: infer Report { "Summarize quarterly results" }
[n] next [p] prev [q] quit
> n
Frame 1: tool called fs_write { path: "report.txt", content: "..." }You can step forward and backward through every operation the agent performed. This replaces the need for log scraping, debug print statements, or re-running long LLM workflows just to see what went wrong.
Next Steps
- The infer Primitive Cognitive Type Safety and typed LLM inference.
- Probabilistic Routing Confidence thresholds and deterministic fallbacks.