REPL and Live Development#
The Kvist REPL evaluates ordinary Kvist in a persistent native session. Definitions, values, imports, macros, package state, and the three most recent results remain available between submissions. Static types, ownership rules, and Odin interoperability are the same as in a compiled program.
Start a Session#
Build Kvist, then give the REPL a source file from the project you want to work with:
odin build src/cli/kvist
./kvist repl examples/language/hello.kvist
The file establishes the package, imports, and symbols available to the
session. Larger applications commonly use a small dev/user.kvist file that
imports the code under development and defines development helpers.
The session does not start with an empty package. Declarations from the saved
context file and its package graph are available immediately, so there is no
need to evaluate the whole buffer before trying forms in a (comment ...)
block. Evaluate a definition or the buffer when you want the live session to
use a current, possibly unsaved declaration as a session-local definition;
unsaved declaration edits are not installed merely by starting the session.
Kvist native REPL
Enter one expression per line; use :reset or :quit.
kvist=> (+ 1 1)
2
kvist=> (defn square [x: int] -> int (* x x))
kvist=> (square 11)
121
The terminal accepts one complete expression per line. Editor clients can send balanced multi-line forms or a group of forms together.
Work with a Session#
Successful definitions are immediately available to later submissions. Compatible redefinitions affect later calls:
kvist=> (defn scale [x: int] -> int (* x 2))
kvist=> (scale 21)
42
kvist=> (defn scale [x: int] -> int (* x 3))
kvist=> (scale 21)
63
An interactively submitted def or defvar becomes typed storage retained
across native generations, so runtime values need explicit types. Compile-time
type aliases and overload sets do not require a retained value type.
Value-producing forms rotate through *1, *2, and *3. Runtime forms run
once; previous submissions are not replayed to rebuild session state.
A failed compilation leaves earlier session state intact. A crash in submitted
native code restarts the worker and clears runtime state. Use :reset to clear
the session deliberately and :quit to stop it.
Some submissions take longer than others, particularly the first use of a large imported project. Kvist accelerates common interactive work where it can do so without changing language behavior and otherwise uses its normal native compiler path. This choice should normally be invisible apart from latency.
For isolated evaluation that must not observe session history, use:
kvist eval file.kvist '(form)'
Work with Odin#
The REPL can provide a typed, persistent development surface over ordinary Odin code. A Kvist definition may contain an Odin body and still be redefined and called like any other session function:
(defn odin-step [value: int] -> int
(odin "return value * 2 + 1"))
(odin-step 5)
;; => 11
For larger implementations, keep the code in normal .odin files, import the
package directory, and define only the interactive helpers you need in Kvist:
(import native "./native")
(defn native-double [value: int] -> int
(native.double value))
A project may therefore remain mostly Odin while using a small dev/user.kvist
as its live development entry point. An isolated (odin "...") at the prompt
is useful for an experiment, but its local declarations do not persist into
later submissions. Put reusable Odin inside a typed Kvist definition or an
.odin package.
The runnable REPL/Odin example shows embedded control flow, Odin calling Kvist, an imported Odin-only package, and compatible redefinition. See Odin interoperability for the broader package model.
Editors#
The Emacs client provides source-buffer evaluation, completion, documentation, retained-value inspection, stepping, traces, conditions, restarts, and project-scoped sessions.
Kvist also provides an experimental nREPL adapter for Calva and CIDER:
./kvist nrepl examples/language/hello.kvist
Use a real application entry file or development context so the server knows which package graph and source files belong to the session. See the nREPL editor guide for setup and current limitations.
Other editor clients can use the JSONL protocol:
./kvist repl examples/language/hello.kvist --protocol jsonl
Experimental: Attach to a Reload-Enabled Application#
The normal REPL runs code in its own worker, so it does not share the live
state of an already-running application. Applications built around
kvist:reload can instead expose a private local endpoint and service REPL
requests at explicit safe points:
KVIST_REPL_ENDPOINT=.kvist/repl kvist run app.kvist --reload
kvist repl app.kvist --attach .kvist/repl --protocol jsonl
The application must reach reload.checkpoint! regularly. At a checkpoint, an
attached editor can evaluate code inside the application process, inspect live
values, invoke capabilities registered by the application, or request a
reload. Olive uses this mechanism for integrated live development, but it is
not part of the ordinary standalone REPL workflow.
See the reload step example for the application structure. Because attached evaluations run inside the host, a panic or crash in submitted code can terminate the application.
Expectations and Boundaries#
- A clean
check,test, orrunremains the reproducible truth. REPL history is development state, not an implicit part of the program. - Compatible redefinitions affect later session calls. Code already running continues with the definitions it started with.
- Pointer and opaque resource results are retained only when Kvist has a safe lifecycle for them.
- Loaded code and session allocations are reclaimed by
:resetor when the session exits.
If a result differs from a clean run, or a submission appears unexpectedly
slow, --execution native is available as a diagnostic comparison. It is not
needed for normal REPL use.