# pardes A text environment in the acme tradition: columns of panes, each pane a tag line plus a body, where the body is a live terminal, a file, an image, or a PDF. The mouse carries meaning — left selects, middle executes, right looks — and everything on screen is text that is equally alive, whether a shell printed it or you typed it. One core, five frontends. The core owns editing, layout, rendering, and the filesystem namespace. Frontends translate native input into `pardes.Event`, present `pardes.Surface`, and perform host effects such as spawning processes. Fifteen [native Pardes themes](docs/themes.md) coordinate the editor, search, diagnostics and embedded terminal: `orchard` (the near-black default), `dusk`, `ink`, `paper`, `daybreak`, and the Acme-inspired `atelier`. `ink` and `daybreak` provide high contrast dark and light choices. Six classic-inspired adaptations add `forge`, `lagoon`, `solarium`, `spectrum`, `harvest`, and `clay`. `forge_black` and `orchard_black` offer pure-black variations; `forge_soft` offers a deliberately softer contrast. Execute `ThemeSel` to choose native themes first, followed by the existing legacy/imported collection. `FocusTint` toggles the active pane and column tag tints (on by default), and `SyntaxBold` toggles bold syntax keywords (off by default), in both GUI and TTY. SDL also supports `Font :` and optional pixel companions in the unused workspace tag: `Pet cat`, `Pet frog`, or `Pet off`. `Mini path` opens a braille minimap with syntax colors: two text columns by four lines per cell. It reads through the normal filesystem namespace; run it again to refresh. Mini snapshots survive Dump/Restore without rereading the source. On Linux, `Tty9p` (`SPC n 9`) opens a terminal with the session's 9P tree mounted through kernel v9fs. It asks sudo in that pane, then starts your shell as your normal user. Access the tree through `$PARDES_MOUNT`. See [mounted terminals](docs/v9fs.md). Beyond acme's per-window files the tree serves the layout: `/layout` lists the columns, their places and panes, and `/tag` and `/col//tag` are the workspace and column tags, editable like a window's ([the tree](docs/fs.md#the-served-tree)). ## Requirements Zig **0.16.0** (`build.zig.zon` pins `minimum_zig_version`). Dependencies are fetched and pinned by the manifest; no system package is required for the terminal build. The SDL shell builds SDL3 and FreeType from source. Native PDF support builds MuPDF and is on by default (`-Dmupdf=false` to drop it). Optional 9P-over-QUIC support (`-Dquic=true`) uses system OpenSSL 3.6+ and pkg-config. The default Unix socket and optional TCP transport do not need it. ## Build ``` zig build ``` That is the whole of it, and it is an *install*: it builds both native shells and puts them in `~/.local/bin`. ``` ~/.local/bin/pardes the terminal shell (libvaxis) ~/.local/bin/pardes-gui the SDL3 window ``` Override with `--prefix `. Test, benchmark and run steps build what they need without installing development binaries. ``` pardes --version e.g. pardes 0.0.1 (e61bbb2e86bd) pardes --help every flag ``` The version comes from `build.zig.zon`'s `.version`; the commit is read from `git` at configure time and is simply absent when there is no repository to ask. ## The five platforms | build | what it is | |---|---| | `zig build` | the terminal shell and the SDL window, together | | `zig build -Dplatform=tty` | the terminal shell alone | | `zig build -Dplatform=gui` | the SDL3 window alone | | `zig build web -Dplatform=web -Dtarget=wasm32-freestanding -Ddump=` | a freestanding wasm core plus vanilla JavaScript, rendered as HTML/CSS | | `zig build -Dplatform=macos` | an AppKit and CoreText app over a static `libpardes.a` | | `zig build -Dplatform=esp32p4` | a freestanding riscv32 editor object for ESP32-P4, using a 384 KiB heap | Firmware images are built in the sibling `../05-zig-p4` toolchain, which needs ESP-IDF register headers. After building the editor object here, `zig build -Dpardes` there links `src/esp32p4/app.zig`. The separate GPIO 9P image uses `zig build -Dapp=../02-pardes-code/src/esp32p4_9p.zig` there; it does not link the editor. Its fixed GPIO namespace is in `src/esp32p4_gpio.zig`. ## Detached sessions A shell need not be in the same process as the core. ``` pardes --detach=work a core with no terminal of its own pardes --attach=work become a frontend of it pardes-gui --attach=work ...the SDL window can attach too ``` Several frontends may be attached at once and all see the same screen. The detached core performs every effect that needs a disk or a process table, so its pane shells outlive every frontend; a frontend keeps only what needs the human's own display. From inside the editor, `Attach` and `Detach` do the same thing as words. See `docs/detached.md`. ## Tests ``` zig build unit-test module and shell unit tests zig build test-build compile the unit-test programs without running them zig build unit-profile test request time and process memory as JSONL zig build unit-profile-test profiler timing, failure and timeout checks zig build core-test core tests without native shell tests zig build pane-test pane and namespace integration tests zig build syntax-test tree-sitter tests without building the editor zig build syntax deterministic per-byte highlighting snapshots zig build syntax-bench highlighting latency and allocation counts zig build perf-test benchmark validation without compiling the editor zig build lspbench-check require every configured language probe to be correct zig build lspbench-test language benchmark omission and expectation gates zig build history-test historical measurement and comparison tests zig build fs-test real sessions and mounts over 9P zig build agent-session-test interactive session driver checks over 9P zig build fs-bench-test filesystem benchmark option checks without the editor zig build 9p-test freestanding protocol tests zig build quic-test -Dquic=true optional QUIC transport tests zig build snap scripted input traces against frozen golden grids zig build snap-driver-test retry evidence, strict failures and fixture isolation zig build monkey random snapshot scripts hunting panics (not a gate) zig build monkey-test the monkey's generator and panic detector zig build hxdiff differential suite against helix's own behaviour zig build hxdiff-test comparator, allocation and CLI regression checks zig build hxdiff-live compare against a freshly run hx-harness zig build hxdiff-update update reference results only after comparison passes zig build hxparity file-pane vs pty-pane editing parity zig build hxgolf every helix-golf example, step by step, against helix zig build mupdf-check compile, link, render and search docs/design.pdf zig build web-snap browser highlighting and touch interactions zig build web-driver-test browser driver timeouts and cleanup zig build web-e2e Chrome-driven DOM end-to-end suite ``` `snap -- --record=/tmp/captures` writes independent snapshots for comparing binaries without changing goldens. `snap -- --update` replaces goldens; `snap -- --no-retry` makes the first failure decisive. Retried runs retain each attempt's report and mismatching grid in a fresh printed directory. For custom differential cases, use `zig build hxdiff -- --strict cases.jsonl reference.jsonl [waivers.jsonl]`. Without a reference, the driver only emits results; exit zero does not mean a comparison passed. Custom arguments must include `--strict` to check coverage. The benchmark steps — `perf`, `pdf-bench`, `pdf-scroll-bench`, `pdf-sections-bench`, `lspbench`, `fs-bench` — all accept `-- --json`. Snapshot scripts can use `snap9p` to capture core cells and styles through the default socket alongside the terminal emulator's independent captures. `zig build monkey -Dplatform=tty -- [steps] [--from=N] [--out=DIR] [--keep]` writes one random script per seed (keys, leader bursts, typing, clicks, drags, wheel, tiny resizes, prompts and long prompt text over bad-UTF-8 and wide-glyph files), runs it through pardes-snap and looks for a panic's `.zig:N:N: 0x` frame in the report and in the captured grid. A hit keeps the script, its captures and its log in DIR (default `/tmp/pardes-monkey`); a seed always makes the same script, so `--from=N` with one seed replays it. A trace longer than the grid scrolls away: replay the kept script at a larger `start` size. Each crash found gets a fix and a regression script in `test/snapshots/`. The tty's tagline is the body's pitch, so what a narrower tagline does is fuzzed by a unit test instead (`a monkey over notices…` in `src/draw.zig`, longer with `PARDES_FUZZ_SEED`/`PARDES_FUZZ_STEPS`). `-Dtest-filter=` applies to every unit-test binary. Use `-Doptimize=ReleaseFast` for performance measurements. To record output and first/warm command runtimes across revisions, run: ``` jj status zig build history -- run 'ancestors(@, 2)' /tmp/pardes-history -- zig build unit-test zig build history -- compare /tmp/pardes-history/.json /tmp/pardes-history/.json 1.20 ``` The history runner uses `jj run` serially, with recordings outside its isolated checkouts without integrating history changes. Run `jj status` before measuring `@`: the runner deliberately does not snapshot pending edits. `history record` measures current files directly. Add `run --allow-immutable` to measure immutable revisions. Each command runs four times; the first run is reported separately from the warm median. Standard output and errors are preserved for every run. Commands must exist in the selected revisions. The optional comparison ratio fails the command when runtime regresses beyond that limit. Add `--snapshots` to require stable, identical stdout and stderr, or `--benchmarks` to compare individual `syntax-bench` cases, including allocation counts; the ratio limit also applies to each case's cold and median time, using medians across the last three processes. First-process cold times are reported separately, not gated. All four captures must contain the same cases and input sizes. Old revisions need the same harness and uncached test execution for meaningful comparisons. The recorded Zig version identifies the recorder's compiler; record the child toolchain separately when comparing different compilers. Recordings are exclusive: use a fresh output directory to repeat a measurement. Existing results and partial runs are never overwritten. `perf -- --base old.json` requires matching build metadata, harness, viewport, repetition count, fixtures, and `--only` selection. Reports identify the compiler, resolved target/CPU, driver/core/dependency optimization modes, and feature flags. Missing or different metadata is rejected; old reports must be regenerated. JSON reports omit unmeasured cells. Gesture checks run outside the timed interval, and each process owns and removes its fixture directory. Hardware, machine load and runtime library versions must be matched separately. `zig build perf -Dplatform=tty -Doptimize=ReleaseFast -Dtree-sitter=zig -- --mini --json` measures braille generation, full highlighting plus generation, and cached Mini redraws separately, checking output hashes and allocation balance. `zig build perf -Doptimize=ReleaseFast -- --terminal-mib 64 --json` streams colored, wrapped agent-like output past the terminal history limit. It checks the newest text, colors and input, and measures raw redraws, modal movement, edit-overlay redraws and memory. Linux RSS comes from the current process image's `VmHWM`; allocator counts exclude the terminal library's private mappings. `python3 -B test/agent_session.py zig-out/bin/pardes --ready 'ready text' --min-rows 20000 -- command args` runs a caller-selected interactive command in a private POSIX shell and checks its history and an unsubmitted input probe through 9P. Use an owned copy of any saved conversation. Reports contain counts, hashes and 9P observation times, not conversation text or physical keyboard latency. GUI builds need `--gui-grid`. `test-build -Dtest-rebuild` forces fresh Zig test compilation while retaining cached C dependencies. Use a disposable local cache for repeated cold-build experiments. Ordinary `unit-test` always runs its tests, even with cached builds. `unit-profile` measures the request-to-result interval, including test-runner communication, and reports whole-process time and memory separately. Filtered test steps fail if no named test matches, even when import guards pass. The default differential suites require exact case coverage and reject stale waivers. Each waiver pins both the reference and editor result. Live Helix steps use `-Dhelix-harness=`, `HX_HARNESS`, or `hx-harness` on PATH. ## Documentation Start with `src/panes.zig` (and the pane kinds it names, `src/File.zig`, `src/Terminal.zig`, ...), `src/layout.zig`, and `src/fs.zig` for ownership and operations, and `src/pardes.zig` for input, with one file per thing beside it (`edit.zig`, `normal.zig`, `look.zig`, `exec.zig`, `mouse.zig`, ...). `docs/design.typ` is the architecture sketch; `docs/design.pdf` is a retained rendering/search fixture and may lag it. | file | subject | |---|---| | `docs/design.typ` | architecture: the seams, the data model, the build graph | | `docs/detached.md` | one core, many frontends, over a unix socket | | `docs/config.md` | build options and runtime configuration | | `docs/tags.md` | editable workspace, column and pane tags; filename drafts | | `docs/selections.md` | the normal-mode selection model and how it differs from helix's | | `docs/fs.md` | default 9P service, Look resolution, and named mounts | | `docs/lsp.md` | in-process ZLS and external language servers | | `docs/lsp-evaluation.md` | why that backend, measured against the alternatives | | `docs/helix-keys.md` | the helix-compatible key model and its differential suite | | `docs/macos.md` | the native macOS shell, its bundle and its signing | | `docs/web.md` | the browser shell | | `docs/ghostty-macos-notes.md` | notes on the ghostty dependency | | `docs/ideas.typ` | scratch notes; nothing compiles it, and it says so | `next-steps.txt` is a wishlist with a status header saying which items have shipped; `transactions.txt` records one open structural gap against helix, and says which waiver proves it is still open. ## Layout ``` src/ core events (pardes.zig), panes, edit, look, exec, layout, fs, syntax src/detached/ the wire, the detached core, the frontend client src/lsp/ ZLS and external language-server backends test/ harnesses, snapshot goldens, helix cases build/ build-time helpers (the snapshot suite) docs/ see above ```