how it works
An Elm-style update loop. Pure model, pure update, one effect interpreter that folds its results back into the loop as messages.
The Model is pure data. Editor.update is a pure function that takes
a Msg and returns a new model plus a list of effects. runEffect is
the only impure code path — it does file I/O and folds its result back into the loop as another
Msg. Layout.render projects the model to a Screen,
and
Renderer.render writes that grid as ANSI escapes.
+----------------------+
| Model |
| workspace . tree |
| buffers + cursors |
| focus, theme, |
| panels, terminal |
+-----+----------+-----+
| |
read by | | read by
+---------------------+ +---------------------+
| |
v v
+-----------------+ +-------------------+
| Editor.update | | Layout.render |
| (pure) | | (pure) |
+--------+--------+ +---------+---------+
| |
(model', effects) Screen
| |
v v
+-----------------+ +-------------------+
| runEffect | | Renderer.render |
| (impure) | | ANSI escapes |
| ScanWorkspace | +---------+---------+
| LoadFile | |
| SaveBuffer | v
+--------+--------+ terminal output
|
v
Msg ----------> dispatch <---------- KeyPressed / Resize
^ (main loop)
|
feeds back buffer storage
Text buffers use a piece table. The original file contents stay in one string, inserted text is appended to another string, and the visible document is represented as a list of pieces. Inserts and deletes stay local to the piece list while preserving enough state for undo and redo snapshots.
files and encoding
Files are read as UTF-8. The line ending of the loaded file (LF or CRLF) is detected and reused on save; the buffer always works in \n form internally.
Saving writes UTF-8 without a byte-order mark.
concurrency
The workspace scan, file open, file save, clipboard, and config writes all run on the
thread pool via Task.Run. The main loop drains a ConcurrentQueue<Msg> of completed effects each tick, so input never blocks behind I/O. ScanWorkspace and LoadFile each carry a single CancellationTokenSource so a second
invocation drops the previous result.
further reading
The full architecture overview, including module dependency order and the Msg
/ Effect taxonomy, lives in CLAUDE.md in the repo. Phase notes for shipped work are in
CHANGELOG.md.