███████╗███████╗██╗ ██╗██████╗ ███████╗
╚══███╔╝██╔════╝██║ ██║██╔══██╗██╔════╝
███╔╝ ███████╗███████║██████╔╝███████╗
███╔╝ ╚════██║██╔══██║██╔══██╗╚════█��║
███████╗███████║██║ ██║██║ ██║███████║
╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝
[THE FIRST COMPILED UNIX SHELL]
"No fork, no problems."
[PATENT PENDING]
The first Unix shell to compile to bytecodes and execute on a purpose-built virtual machine with fused superinstructions. Since the Bourne shell at Bell Labs in 1970, every Unix shell has been an interpreter. zshrs is the first to be a compiler. A drop-in zsh replacement written in Rust — 318k+ lines, 386 source files across a 4-crate workspace (zshrs runtime, compsys, zshrs-daemon), with the runtime split into a strict 1:1 port directory (src/ported/ — 89 files, every fn maps to a real Src/<x>.c zsh function, enforced by tests/port_purity.rs), a non-port extensions directory (src/extensions/ — 31 files, features zsh C does not have: AOT, daemon coordination, plugin/script/autoload caches, fish-style autosuggest/abbrev/highlight, persistent worker pools, ZWC byte-code helpers), and a feature-gated recorder (src/recorder/). 100% ZLE widget coverage (193/193 entries from zsh's Src/Zle/iwidgets.list — history navigation, vi find/repeat/marks, undo/redo, isearch, yank-pop, shell-aware word motion, region/visual mode, text objects, completion menu, $zle_highlight parsing), 48 fish-ported builtins, persistent worker pool, AOP intercept, rkyv-backed bytecode images (mmap hot path; the only shell bytecode cache), read-only SQLite mirrors beside them for dbview / SQL inspection only (no cache semantics), and full zsh compatibility.
Docs · Reference · Coverage Report · strykelang · fusevm · compsys
Table of Contents
- [0x00] Overview
- [0x01] Install
- [0x02] No-Fork Architecture
- [0x03] Bytecode Compilation
- [0x04] Concurrent Primitives
- [0x05] AOP Intercept
- [0x06] Worker Thread Pool
- [0x07] RKYV cache layout
- [0x08] Exclusive Builtins
- [0x09] Shell Language Features
- [0x0A] Compatibility
- [0x0B] Architecture
- [0xFF] License
[0x00] OVERVIEW
zshrs replaces fork + exec with a persistent worker thread pool, compiles every command to fusevm bytecodes, and persists compiled chunks only in rkyv shards under ~/.zshrs/images/ (single-directory rule — every zshrs file lives under $ZSHRS_HOME / ~/.zshrs/; see docs/DAEMON.md). Beside that tree, catalog.db and related SQL views are read-only mirrors for inspection (dbview, ad-hoc SQL): daemon-hydrated, never authoritative for cache hit/miss or execution. They are not a second shell cache. history.db holds history only — it is unrelated to bytecode caching. The result: shell startup, command dispatch, globbing, completion, and autoloading are all faster by orders of magnitude.
[0x01] INSTALL
# From crates.io
# From source — lean build, pure shell, no stryke dependency
&&
# binary: target/release/zshrs
# Set as login shell
[0x02] NO-FORK ARCHITECTURE
Every operation that zsh forks for runs in-process. Zero forks for builtins.
| Operation | zsh | zshrs |
|---|---|---|
$(cmd) |
fork + pipe | In-process stdout capture via dup2 |
<(cmd) / >(cmd) |
fork + FIFO | Worker pool thread + FIFO |
cat file |
fork + exec /bin/cat | Builtin — zero fork |
head/tail/wc |
fork + exec | Builtin — zero fork |
sort/find/uniq |
fork + exec | Builtin — zero fork |
date/hostname/uname |
fork + exec | Builtin — direct syscall |
sleep/mktemp/touch |
fork + exec | Builtin — zero fork |
xattr operations |
fork + exec xattr | Direct syscall — zero fork |
pmap/pgrep/peach |
fork N times | VM execution — zero fork |
**/*.rs |
Single-threaded opendir |
Parallel walkdir per-subdir on pool |
*(.x) qualifiers |
N serial stat calls |
One parallel metadata prefetch |
rehash |
Serial readdir per PATH dir |
Parallel scan across pool |
compinit |
Synchronous fpath scan | Background scan + bytecode compilation |
| History write | Synchronous fsync |
Fire-and-forget to pool |
| Autoload | Read file + parse every time | Bytecode mmap + zero-copy load from rkyv |
| Plugin source | Parse + execute every startup | Delta replay from rkyv image |
Coreutils Builtins (Anti-Fork)
23 coreutils commands run in-process with zero fork overhead:
cat head tail wc sort find uniq cut tr seq rev tee
basename dirname touch realpath sleep whoami id hostname
uname date mktemp
Speedup: 2000-5000x per invocation (2-5ms fork overhead → 0.001ms builtin call).
[0x03] BYTECODE COMPILATION
Every command compiles to fusevm bytecodes via a faithful port of zsh's lexer + parser:
Interactive command ──► lex::zshlex ──► parse::parse ──► ZshCompiler ──► fusevm::Op ──► VM::run()
(port of (port of (original;
Src/lex.c) Src/parse.c) ~1.4k LOC)
Script file (first) ──► lex::zshlex ──► parse::parse ──► ZshCompiler ──► VM::run() ──► persist rkyv shard
Script file (cached) ──► index.rkyv + mmap shard ──► deserialize Chunk ──► VM::run()
(no lex, no parse, no compile)
Autoload function ──► rkyv shard ──► deserialize Chunk ──► VM::run()
(microseconds)
The lexer and parser are direct ports from zsh's C source (Src/lex.c, Src/parse.c); only the bytecode compiler is original Rust. The 4-tier ZshProgram → ZshList → ZshSublist → ZshPipe → ZshCommand AST is preserved verbatim from zsh, ensuring per-construct behavior parity. The bytecode compiler targets the same Op enum that strykelang uses. Both frontends share fused superinstructions, extension dispatch, and the Cranelift JIT path.
Execution Pipeline
┌─────────────────────────────────────────────────────────────────────────┐
│ Script file │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ rkyv bytecode cache (images/*.rkyv + index.rkyv) │ │
│ │ lookup(path, mtime) → mmap'd fusevm::Chunk │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ├─── HIT (100x faster) ────────────────────────┐ │
│ │ │ │
│ ▼ MISS ▼ │
│ lex+parse → ZshCompiler ────────► fusevm::Chunk │
│ │ │ │
│ ▼ │ │
│ persist_shard() │ │
│ │ │
│ ┌───────────────────────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ fusevm::VM::run() │ │
│ │ │ │
│ │ ┌───────────────────────────────────────────────────────────┐ │ │
│ │ │ JIT eligibility check │ │ │
│ │ └───────────────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ├─── Block JIT (loops, branches) ──► Cranelift ──► x86-64│ │
│ │ │ │ │
│ │ ├─── Linear JIT (straight-line) ──► Cranelift ──► x86-64 │ │
│ │ │ │ │
│ │ ▼ Fallback │ │
│ │ ┌───────────────────────────────────────────────────────────┐ │ │
│ │ │ Interpreter: jump table dispatch + fused superinstructions│ │ │
│ │ └───────────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
| Tier | What | When |
|---|---|---|
| rkyv image hit | Skip lex/parse/compile | Warm script runs |
| Block JIT | Native x86-64 via Cranelift | Loops, conditionals |
| Linear JIT | Native x86-64 via Cranelift | Straight-line arithmetic |
| Interpreter | Jump table + superinstructions | Builtins, I/O, strings |
Benchmark: 100x warm start speedup
Cold (cache miss): 717ms — lex + parse + compile + cache write + execute
Warm (cache hit): 7ms — deserialize + execute
[0x04] CONCURRENT PRIMITIVES
Full parallelism in the lean binary. No stryke dependency needed.
# Async/await
id=
result=
# Parallel map — ordered output
# Parallel filter
# Parallel for-each — unordered, fire as completed
# Barrier — run all, wait for all
[0x05] AOP INTERCEPT
First shell with aspect-oriented programming:
# Before — log every git command
# After — timing
# Around — memoize
[0x06] WORKER THREAD POOL
Persistent pool of [2-18] threads. Configurable:
# ~/.zshrs/zshrs.toml (single-directory rule; configurable via $ZSHRS_HOME)
[]
= 8
[]
= true
[]
= true
[]
= 32
= true
[0x07] RKYV CACHE LAYOUT
Compiled bytecode and plugin/autoload payloads live in rkyv under ~/.zshrs/images/:
| Path | Purpose |
|---|---|
index.rkyv |
Top-level index: fq_name → shard id, generation, byte offset |
images/{hash8}-*.rkyv |
Mmap-ready shards (system, completions, plugins, scripts, .zshrc, …) |
SQLite (read-only mirrors) — same directory, different job: daemon-maintained copies you can query with SQL or dbview. They are not the bytecode cache and are not read when deciding cache hit/miss or when running compiled code.
| Store | Purpose |
|---|---|
catalog.db |
Joinable mirror of catalog metadata (human / tooling reads only) |
history.db |
Command history persistence (orthogonal to bytecode caching — not a cache layer for compiled chunks) |
| Mirror / FTS views | Optional SQL-side views of names and paths for dbview — read-only; see docs/DAEMON.md |
Browse mirrors without SQL:
[0x08] EXCLUSIVE BUILTINS
Parallel Primitives (VM-executed, zero fork)
| Builtin | Description |
|---|---|
async / await |
Ship work to pool, collect result |
pmap |
Parallel map with ordered output — runs on VM, not fork |
pgrep |
Parallel filter — runs on VM, not fork |
peach |
Parallel for-each, unordered — runs on VM, not fork |
barrier |
Run all commands in parallel, wait for all |
AOP / Debugging
| Builtin | Description |
|---|---|
intercept |
AOP before/after/around advice on any command |
intercept_proceed |
Call original from around advice |
doctor |
Full diagnostic: pool metrics, cache stats, bytecode coverage |
dbview |
Read-only browse of SQLite mirrors (not the rkyv cache) |
profile |
In-process command profiling with nanosecond accuracy |
Coreutils (Anti-Fork)
| Builtin | Description |
|---|---|
cat |
Concatenate files — no fork |
head / tail |
First/last N lines — no fork |
wc |
Line/word/char count — no fork |
sort / uniq |
Sort and dedupe — no fork |
find |
Walk directories — no fork |
cut / tr / rev |
Text manipulation — no fork |
seq |
Number sequences — no fork |
tee |
Copy stdin to files — no fork |
date |
Current date/time — direct syscall |
sleep |
Delay — no fork |
mktemp |
Create temp file/dir — no fork |
hostname / uname / id / whoami |
System info — direct syscall |
touch / realpath / basename / dirname |
File ops — no fork |
zgetattr / zsetattr / zdelattr / zlistattr |
xattr ops — direct syscall |
[0x09] SHELL LANGUAGE FEATURES
Every shell construct compiles to fusevm bytecode — no tree-walker dispatch lives in zshrs. The full reference documents each entry with a runnable example.
Control flow
# Standard POSIX/zsh control structures — all compile to fusevm bytecode
if ; then ; elif ; then ; else ; fi
while ; do ; done
until ; do ; done
for; do ; done
for; do ; done
; do coproc { while ; do ; done} # bidirectional pipe
Indexed arrays
arr=(alpha beta gamma) # literal
arr+=(delta epsilon) # append
for; do ; done # iterate (flattens via BUILTIN_ARRAY_FLATTEN)
Associative arrays
# declare
m[name]=Jacob; m[role]=eng # set
for; do ; done # keys
for; do ; done # values
Parameter expansion flags (zsh-style)
Parameter expansion forms
Background, async, coprocesses
& # fork + setsid; parent gets Status(0)
; ; | coproc { } # bidirectional pipe; $COPROC=[rd_fd, wr_fd]
Eval, dynamic dispatch, AOP
cmd=ls;
[0x0A] COMPATIBILITY
- Full zsh script compatibility — runs existing
.zshrc - Full bash compatibility via emulation
- Fish-style syntax highlighting, autosuggestions, abbreviations
- 180+ builtins (150 zsh + 23 coreutils + parallel primitives) — see the Reference for the full catalog
- ZWC precompiled function support
- Glob qualifiers, parameter expansion flags, completion system
- zstyle, ZLE widgets, hooks, modules
--posixmode for strict POSIX compliance
Test corpus parity
| Suite | Tests | Coverage |
|---|---|---|
zsh_construct_corpus |
392 | Every sh/zsh construct outside modules |
zsh_corpus_via_new_pipeline |
123 | Native lex+parse+ZshCompiler path |
no_tree_walker_dispatch |
158 | Behavioral pins for the no-tree-walker invariant |
compile_zsh_smoke |
28 | Per-construct bytecode-level smoke |
tree_walker_absent |
8 | Source-level absence checks (anti-regression) |
zsh_parser_probe |
91 | AST-shape probes for every construct |
ztst_runner |
70 | Real .ztst files from upstream zsh |
| Total | 876 | All green on the new (default) pipeline |
[0x0B] ARCHITECTURE
The codebase is structurally divided into ported code vs extensions, with the boundary mechanically enforced by tests/port_purity.rs. Bots, contributors, and humans all read docs/PORT.md before writing a single line.
┌────────────────────────────────────────────────────────────────┐
│ zshrs workspace │
│ 4 crates · 386 .rs files · 318k+ lines │
├──────────────────────────────────────────┬─────────────────────┤
│ src/ (124 .rs — runtime crate) │ fish/ (157 .rs) │
│ ┌────────────────────────────────────┐ │ reader / line edit │
│ │ src/ported/ (89 — STRICT PORT) │ │ syntax highlight │
│ │ every .rs ↔ a real Src/<x>.c file │ │ autosuggest │
│ │ every fn carries `/// Port of …` │ │ abbreviations │
│ │ enforced by tests/port_purity.rs │ │ env dispatch │
│ │ builtins/ · zle/ · modules/ · │ │ history backend │
│ │ hist · jobs · params · pattern · │ │ process control │
│ │ signals · glob · subst · math · │ │ event system │
│ │ prompt · utils · init · … │ ├─────────────────────┤
│ └────────────────────────────────────┘ │ parse/ (4 .rs) │
│ ┌────────────────────────────────────┐ │ port of lex.c + │
│ │ src/extensions/ (31 — NON-PORT) │ │ parse.c — shared │
│ │ features zsh C does NOT have: │ │ by zshrs runtime │
│ │ AOT · plugin/script/autoload │ │ and the daemon │
│ │ cache · fish_features · worker │ ├─────────────────────┤
│ │ pool · zwc · arith_compiler · │ │ daemon/ (41 .rs) │
│ │ hooks · keymaps · widgets · │ │ zshrs-daemon — IPC │
│ │ daemon_presence · log · … │ │ · HTTP · OpenAPI · │
│ └────────────────────────────────────┘ │ fsnotify · cache · │
│ ┌────────────────────────────────────┐ │ zsource/zhistory/ │
│ │ src/recorder/ (1 — feature gate) │ │ zjob builtins │
│ │ AOP intercept; #[cfg(recorder)] │ ├─────────────────────┤
│ │ → zero bytes in default binary │ │ compsys/ (27 .rs) │
│ └────────────────────────────────────┘ │ rkyv mmap · zstyle │
├──────────────────────────────────────────┴─────────────────────┤
│ bins/ (3 — entry points) │
│ zshrs zshrs-recorder zd │
│ (default) (--features recorder) (--features zd) │
├────────────────────────────────────────────────────────────────┤
│ fusevm (bytecode VM) │
│ 129 opcodes · fused superinstructions · JIT │
└────────────────────────────────────────────────────────────────┘
Directory rule (PORT.md)
| Directory | Rule | Enforcement |
|---|---|---|
src/ported/ |
Strict 1:1 port. Every .rs mirrors a real src/zsh/Src/<x>.c; every top-level fn carries /// Port of <cname>() from Src/<file>.c:NNNN; no invented helpers; directory and file set FROZEN (89 files, no new files allowed). |
tests/port_purity.rs |
src/extensions/ |
Non-port only. Features zsh C demonstrably does not have. Must not duplicate or shadow any port. | port_purity exempts the 1:1 file rule for this directory only |
src/recorder/ |
Feature-gated. Every symbol #[cfg(feature = "recorder")]; deleted by rustc when off. |
Cargo.toml required-features = ["recorder"] on the zshrs-recorder bin |
src/zsh/ |
Read-only reference. Vendored upstream zsh C source. The spec; never modified. | n/a |
[0xFF] LICENSE
MIT — Copyright (c) 2026 MenkeTechnologies
Original-authorship record + portability stance: CREATORS.md. Maintainer governance + protected invariants: MAINTAINERS.md.
This is a legacy, not a battle. The synthesis
(compiled-shell architecture, 90/10 daemon split,
recorder-owns-rebuild AOP intercept, single ~/.zshrs/ rule,
session-persistent supervised jobs with bidirectional ptmx
attach, cross-shell pub/sub + named-lock builtins, auto-derived
OpenAPI surface, flat-text history + sibling FTS5 index) is
prior art for the shell-design commons under the MIT grant.
Future shells — bash, fish, nushell, elvish, oil, xonsh, murex,
projects that don't exist yet — should inherit any of it. The
protected invariants in MAINTAINERS.md guard upstream
identity, not the ideas.
Ports must credit zshrs as the invention source in their docs — a one-line attribution in your README / design doc / release notes. Suggested wording:
Inspired by / ported from zshrs by Jacob Menke (MenkeTechnologies).
Ideas can't be copyrighted so this is an ask, not an MIT-enforced clause; honoring it keeps the legacy traceable. See CREATORS.md § Legacy + § Attribution expectation for the full list + suggested forms.