// ZSHRS — THE FIRST COMPILED UNIX SHELL

zshrs v0.12.8 · Anti-fork architecture · 23 coreutils builtins · VM-executed parallel · Bytecode caching · JIT · Full reference · Daemon impl map

// Color scheme

>_ZSHRS REFERENCE

The most powerful shell ever created. No-fork architecture, AOP intercept, worker thread pool, bytecode caching, fusevm compiled execution.

SHELL SCRIPTS AT MACHINE CODE SPEED.

NO FORK. NO INTERPRETER. JUST BYTECODES.

0
forks in hot path
100%
bytecode compiled
18
worker threads
180+
builtins
23
coreutils builtins
100x
warm start speedup
2000x
fork avoidance speedup
1st
compiled Unix shell

For the first time in the history of computing — since the dawn of Unix at Bell Labs in 1970 — a shell compiles to executable bytecodes and runs them on a virtual machine with fused superinstructions. Every interactive command line, every shell script, every function invocation, every source’d file compiles to fusevm bytecodes and executes at near-machine-code speed. No tree-walking interpreter. No fork. No parsing at runtime if bytecodes are cached.

Compiled bytecodes are cached as rkyv zero-copy archives mmap'd directly into memory. Function invocations deserialize cached bytecodes in microseconds — skipping the lexer, parser, and compiler entirely. source’d scripts and interpreted scripts follow the same path: compile once, cache, execute from bytecode forever. This has never been achieved in a Unix shell.

[0x00a] INVENTIONS — THE LIST

This is a legacy, not a battle. Every item below originated in zshrs and is offered as 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. Ports must credit zshrs as the invention source in their docs — see CREATORS.md for the suggested wording. The protected invariants in MAINTAINERS.md guard upstream identity, not the ideas.

Compiled Unix shell

First Unix shell to compile every command (interactive, script, function, sourced file) to bytecode and execute on a purpose-built VM. Every shell since Bell Labs 1970 has been an interpreter.

fusevm bytecode VM

NaN-boxed register VM with fused superinstructions and a Cranelift JIT for hot blocks. Shared substrate with stryke so a shell and a scripting language ride the same value representation.

Zsh grammar introspection to stdout

First shell to emit, in canonical diffable formats, zsh’s lexer token stream, wordcode (Eprog) layout, and a structured parser AST (S-expression) — the zshrs binary (--dump-tokens, --dump-wordcode, --dump-ast) and the matching zshrs_dump loadable module (dumptokens, dumpwordcode). Stock zsh does not ship this trio as a user-facing pipeline.

Fusevm bytecode on argv (--disasm)

The zshrs binary prints the fusevm op listing (name pool, subroutine entries, each opcode, nested sub_chunks) to stdout before every VM run — the IR the shell actually executes, next to the lexer/AST/wordcode dump trio. Stock zsh does not expose its internal wordcode VM stream on argv this way.

Persistent worker thread pool

18 (configurable [2-18]) tokio threads owned by the shell. $(cmd), <(cmd), &, globbing, completion, autoloading all dispatch to the pool instead of fork(2). Zero forks in the hot path.

90/10 daemon / shell split

Singleton zshrs-daemon owns every mutation (canonical state, fsnotify, schedule, jobs, locks, cache, history). Thin shell clients are stateless and forkable. No shared writer, no second process tree, no auto-spawn.

Recorder-owns-rebuild (AOP intercept)

zshrs-recorder AOP-intercepts every state-mutating dispatcher at runtime — alias / function / export / fpath edit / hash -d / zstyle / bindkey / compdef / zmodload / setopt / trap / sched / source / assignment — and ships (kind, name, value, file, line, fn_chain) to the daemon. Replaces the static-walker approach every other shell uses for completion / fpath scanning.

rkyv canonical-state shards

Daemon's in-memory canonical state persists as content-addressed rkyv archives under ~/.zshrs/images/. Cold-start shells mmap the shard and skip every dotfile in /etc + ~. ~10ms cold-start vs >100ms re-source.

Single ~/.zshrs/ directory rule

Every config + log + sqlite + rkyv shard + socket lives under one root. $ZSHRS_HOME overrides for sandboxes / hermetic harnesses. rm -rf ~/.zshrs/ is the one-verb total reset.

Three log files, one per binary

zshrs.log (shell) + zshrs-daemon.log + zshrs-recorder.log — never interleaved. One paths::is_zshrs_log_file matcher feeds rotation, tail, clear, snapshot bundling.

Three TOML configs, all auto-seeded

zshrs.toml + zshrs-daemon.toml + zshrs-recorder.toml with documented defaults. Every binary seeds the dir on first run; idempotent across all four. Auto-migrates legacy daemon.tomlzshrs-daemon.toml.

z* builtin family

One namespace, twenty-three builtins, one daemon route. zcache, zls, zid, zping, ztag, zsend, znotify, zsubscribe, zjob, zsync, zask, zhistory, zsource, zcomplete, zsuggest, zlog, zwhere, zd, zlock, zpublish.

Cross-shell pub/sub + named locks

zsubscribe / zpublish / zlock as builtins routed through the singleton daemon. Replaces flock + socat + named pipes glued by hand. Locks are token-issued; release requires the original token (lost shell can’t accidentally release someone else’s lock).

Session-persistent supervised jobs

zjob submit spawns under the daemon — survives shell exit, output captured to disk, status persisted in catalog.db, history survives daemon restarts. Replaces nohup + screen + pueue + disown.

Bidirectional ptmx zjob attach

--pty submit allocates a pseudo-terminal pair; child runs with slave on 0/1/2. zjob attach switches client termios to raw mode, pumps stdin via job_input (base64), drains daemon broadcast back to user’s tty, propagates SIGWINCH via job_resize. Ctrl-] detaches; job keeps running. Solves bg-jobs-blocked-on-stdin.

Auto-derived OpenAPI 3.1

GET /openapi serves a spec-compliant OpenAPI doc generated on every request from the daemon’s op registry (OP_NAMES). 108 paths today (4 meta + 101 ops + 3 stream routes). bearerAuth declared only when [http.tokens] is populated. Loopback bind requires no token; non-loopback bind refuses without one.

Daemon HTTP listener default-on (loopback)

Seeded zshrs-daemon.toml ships [http] listen = "127.0.0.1:7733" so zd health works out of the box. Same trust model as the Unix socket on a single-user box; flips to required-auth the moment the bind goes non-loopback.

zd — HTTP bin AND in-process builtin

Same arg surface, two transports. zd the binary uses ureq against the HTTP listener (works from bash / fish / CI / curl). zd the builtin inside zshrs uses the local Unix socket via the daemon Client — 5.5× faster (0.48ms vs 2.64ms, no fork).

zd doctor

One-command health sweep: cache-root perms, file-perms drift, pidlock liveness, socket presence, catalog integrity (sqlite PRAGMA integrity_check), shards-present count, fsnotify-alive, supervised-job count, legacy-litter scan (~/.zcompdump*, ~/*.zwc). Pretty ASCII table; non-zero exit on any FAIL.

Flat history + sibling FTS5 sqlite

~/.zshrs/zshrs_history (flat zsh-extended-history text, cat-able and grep-able) + ~/.zshrs/zshrs_history.db (FTS5 index for fast search / dedup / frequency). The writer keeps both in lockstep; on open, the text mirror is rehydrated from the index if stale. Auto-migrates the legacy ~/Library/Application Support/zshrs/history.db.

Recorder sources the full 8-file login chain

zshrs-recorder by default mirrors a real zsh -l -i: /etc/zshenv, ${ZDOTDIR:-$HOME}/.zshenv, /etc/zprofile, ~/.zprofile, /etc/zshrc, ~/.zshrc, /etc/zlogin, ~/.zlogin. Missing files skipped silently. $ZDOTDIR re-resolved per file.

zsync up --all

Single command snapshots every overlay table (alias / galias / salias / setopt / params / env / path / manpath / fpath / named_dir / compdef / zstyle) and pushes into the daemon’s canonical state. Shell-side overlay_snapshot::enumerate_all_overlays registered via fn-pointer trampoline so the daemon crate stays decoupled from ShellExecutor.

23 anti-fork coreutils builtins

cat, head, tail, wc, sort, find, uniq, cut, tr, seq, rev, tee, sleep, date, mktemp, hostname, uname, whoami, id, basename, dirname, touch, realpath. All in-process; one cat in a pipeline doesn’t fork.

Parallel-as-syntactic-primitive

fish-style parallel iterators (par_for, par_map, par_filter, par_reduce) ship as VM opcodes, not library calls. Glob walks parallelize at depth ≥ 32 by default. Worker pool is the substrate.

The --no-fork philosophy as a measurement

Every accepted commit is graded by “does this remove a fork?” not “does this add a feature?” Optimization layers (zinit turbo, p10k instant prompt, zwc, zcompile, BG_NICE, lazy autoload) are evidence that zsh can’t solve the problem in userspace; zshrs accepts the architecture cost to solve it for real.

First shell with native LSP server + DAP debug adapter

World’s first shell to ship Language Server Protocol and Debug Adapter Protocol as first-class subsystems of the shell binary itself. zshrs --lsp starts an LSP server on stdio (completion, hover, documentSymbol, foldingRange, semanticTokens, formatting, rename, diagnostics) consumed by any editor — JetBrains, VS Code, Helix, Neovim. zshrs --dap HOST:PORT speaks the full Debug Adapter Protocol over TCP (breakpoints, stepping, frames, scopes, variables, evaluate) so any DAP client can debug zsh scripts. No other shell (bash, zsh, fish, nu, elvish, oil, xonsh, murex) ships either — bash-language-server is a Node-based third-party project, not part of bash; no zsh equivalent exists at all. The JetBrains plugin at editors/intellij/ drives both, and additionally surfaces every sourced zsh plugin (zinit / oh-my-zsh / prezto / antidote / antigen / zplug / zsh-more-completions / zpwr / loose) under the IDE’s External Libraries node via zshrs --dump-plugins — cmd-clickable, find-usages-able, rename-across-plugin-boundary, indexed once per project. No other shell exposes its plugin-manager state as IDE library roots; the closest precedents (bash-language-server, fish-shell.vscode) ignore plugin managers entirely. Hand-rolled JSON-RPC framing, zero new dependencies.

First POSIX-compatible shell with a builtin unit-test framework

World’s first POSIX-compatible shell to ship a unit-test framework + worker-pool runner in the binary, zero external install. zassert_eq / zassert_ne / zassert_ok / zassert_gt / zassert_lt / zassert_match / zassert_contains / zassert_near / zassert_dies — 14 assertion verbs — plus ztest_skip and ztest_run (alias run_tests) are shell builtins, callable from any .zsh / .sh script with no npm i, gem install, or cargo install step. zshrs --ztest [paths…] runs a worker-pool: N persistent --ztest-worker subprocesses (one per CPU) fork-on-receive per test, JSON-over-pipe wire protocol, per-test fd 2 capture so concurrent workers never tear each other’s output — the same architecture cargo-nextest brought to Rust testing, now in a shell binary. Every other POSIX-family shell (bash, zsh, ksh, dash, fish) relies on third-party packages installed separately: bats-core, shunit2, Bach, ShellSpec, zunit, korn-spec. PowerShell’s Pester (preinstalled on Windows 10+) is the closest precedent, but PowerShell is not POSIX. Nushell ships std assert builtins but is its own non-POSIX language and has no integrated runner. Lives in src/extensions/ztest.rs; port of strykelang’s stryke test runner.

Full enumeration + suggested attribution wording in CREATORS.md. Op-by-op detail in daemon-report.html. Port-coverage report in report.html.

[0x00] THE COMPILATION PIPELINE

Every path through zshrs ends at the same place: fusevm bytecode execution.

┌─────────────────────────────────────────────────────────────────┐ │ THREE EXECUTION PATHS │ │ │ │ ┌─────────────┐ Interactive command line │ │ │ REPL Input │──► Parser ──► ShellCompiler ──► fusevm::Op │ │ └─────────────┘ │ │ │ ▼ │ │ ┌─────────────┐ Shell script / source file VM::run() │ │ │ Script File │──► Parser ──► ShellCompiler ──► │ │ │ └─────────────┘ │ │ │ │ └──► rkyv image ──────────┘ │ │ (cached on first compile) │ │ │ │ ┌─────────────┐ Autoload function (compinit) │ │ │ rkyv image │──► mmap zero-copy archive ──► fusevm::Chunk ──►│ │ │ shard │ (no lexer, no parser, VM::run() │ │ └─────────────┘ no compiler — microseconds) │ └─────────────────────────────────────────────────────────────────┘
PathLexParseCompileExecuteCache
Interactive commandYesYesYesfusevmNo (ephemeral)
Script file (first run)YesYesYesfusevmYes → rkyv
Script file (cached)NoNoNofusevmHit → deserialize
Autoload function (cached)NoNoNofusevmHit → deserialize
Plugin source (cached)NoNoNofusevmDelta replay → µs

[0x01] ARCHITECTURE

zshrs Architecture ┌─────────────────────────────────────────────────────┐ │ REPL / ZLE │ │ reedline + syntax highlighting + autosuggestions │ └──────────────────────┬──────────────────────────────┘ │ ┌──────────────────────▼──────────────────────────────┐ │ ShellExecutor (18K lines) │ │ parser ─► compiler ─► fusevm bytecode dispatch │ │ 180+ builtins │ AOP intercept │ trap/signal │ └──────┬─────────┬─────────┬─────────┬────────────────┘ │ │ │ │ ┌──────▼───┐ ┌───▼────┐ ┌─▼──────┐ ┌▼──────────────┐ │ Worker │ │ rkyv │ │ fusevm │ │ compsys │ │ Pool │ │ images │ │ VM │ │ completion │ │ [2-18] │ │ + │ │ │ │ engine │ │ threads │ │catalog │ │ Op enum│ │ │ │ │ │ .db │ │ fused │ │ MenuState │ │ glob │ │(query) │ │ super- │ │ MenuKeymap │ │ rehash │ │bytecode│ │ instr │ │ rkyv shards │ │ compinit │ │mmap'd │ │ JIT ► │ │ │ │ history │ │ shards │ │Cranelft│ │ │ └──────────┘ └────────┘ └────────┘ └───────────────┘

Source-tree layout: ported / extensions / recorder split

The runtime crate is physically split so port code and original code can never be confused. Bots, contributors, and humans all read docs/PORT.md before writing a single line of code; tests/port_purity.rs mechanically enforces the rules in CI.

  • src/ported/ — 106 files, FROZEN. Strict 1:1 port. Every .rs mirrors a real src/zsh/Src/<x>.c file (same stem, same relative subpath). Every top-level fn carries a /// Port of <cname>() from Src/<file>.c:NNNN doc-comment. New file creation is banned; new fn names that don't exist in upstream zsh C source are banned. The freeze closes both drift vectors: bots invent helper names ("shell_quote", "find_in_path") and bots create fresh files to drop helpers in. Both blocked.
  • src/extensions/ — 42 files. The non-port directory. Features zsh C demonstrably does not have: AOT (aot.rs, compile_zsh.rs), autoload/plugin/script caches, fish-style autosuggest/abbrev/highlight, persistent worker pool, arith JIT, AST s-exp dump, ZWC byte-code helpers, recorder hooks, daemon presence, structured logging, ZLE keymaps/widgets, ext builtins, regex module, config, overlay snapshot + canonical apply, subscript/fds/hist extensions. port_purity exempts this directory from the 1:1 file-existence rule on the basis that no C ancestor exists.
  • src/recorder/ — 1 file, feature-gated. Every symbol #[cfg(feature = "recorder")]; deleted by rustc when the feature is off. Compiled into the separate zshrs-recorder binary, never the default zshrs build.
  • src/zsh/ — vendored upstream. Read-only reference. The C spec; never modified.

Lexer + parser ports live in src/ported/lex.rs and src/ported/parse.rs (no separate parse/ crate). Workspace sibling: daemon/ (41 files, zshrs-daemon); compsys was folded into the main zshrs crate (no longer a standalone sibling). Vendored: vendor/fish/ (157 files, fish-style reader/highlighter/abbreviations), bins/ (4 entry points: zshrs, zshrs-recorder with required-features = ["recorder"], zd with required-features = ["zd"], bench-autoload). 628 .rs files total · 700,413 Rust LOC (git ls-files '*.rs' | xargs wc -l, 2026-06-21). Test count: 16,369 #[test] markers across the tree.

[0x01] ANTI-FORK ARCHITECTURE

Every fork is a full process copy. On macOS, fork() costs 2-5ms including exec + ld.so + libc init. zsh forks for every $(...), <(...), cat, grep, subshell, and completion. zshrs forks for none of them.

OperationzshzshrsSpeedup
cat filefork + exec /bin/catBuiltin — zero fork2000-5000x
head/tail/wcfork + execBuiltin — zero fork2000-5000x
sort/find/uniqfork + execBuiltin — zero fork2000-5000x
date/hostname/unamefork + execDirect syscall3000-8000x
sleep/mktemp/touchfork + execBuiltin — zero fork2000-5000x
xattr operationsfork + exec xattrDirect syscall2000-5000x
pmap/pgrep/peachfork N times to sh -cVM execution — zero forkNx
$(cmd)fork + pipe + execIn-process stdout capture via dup2
<(cmd) / >(cmd)fork + FIFOWorker pool thread + FIFO
Glob **/*.rsSingle-threaded opendirParallel walkdir per-subdir on pool
rehashSerial readdir per PATH dirParallel scan across pool
Autoload functionRead file + parse every timeZero-copy mmap of rkyv-archived bytecode (µs)100x

Coreutils Builtins (23 commands, zero fork)

cat head tail wc sort find uniq cut tr seq rev tee basename dirname touch realpath sleep whoami id hostname uname date mktemp

Every invocation of these commands is 2000-5000x faster than forking to the external binary.

[0x02] WORKER THREAD POOL

Persistent pool of warm threads. Bounded crossbeam channel with backpressure. Panic recovery keeps workers alive. Task cancellation on Ctrl-C. Instant shutdown on exit.

# ~/.zshrs/zshrs.toml (seeded on first run; idempotent) [log] level = "info" # env $ZSHRS_LOG overrides; "trace" prints startup diagnostics [shell] skip_configs = "auto" # when daemon up + canonical shard recorded, skip /etc/zsh{env,rc} + ~/.{zshenv,zprofile,zshrc,zlogin} [worker_pool] size = 8 # 0 = auto (num_cpus clamped [2, 18]) [completion] bytecode_cache = true # compile autoload functions to fusevm bytecodes [history] async_writes = true # daemon-side writes via IPC; prompt never blocks [glob] parallel_threshold = 32 # min files before parallel metadata prefetch recursive_parallel = true # fan out **/ across worker pool

Tasks shipped to the pool:

compinit

Background fpath scan + bytecode compilation of 16K+ functions

Process Sub

<(cmd) and >(cmd) on pool threads instead of fork

Parallel Glob

**/ recursive walk split per-subdir across pool

Metadata Prefetch

Glob qualifiers: one parallel stat batch, zero syscalls after

PATH Rehash

Parallel readdir across every PATH directory

History Writes

Daemon-side writes via IPC — prompt never waits, zero client SQLite handle

[0x03] AOP INTERCEPT

The first shell ever with aspect-oriented programming. Hook before, after, or around any command or function — at machine code speed, no fork. One primitive that replaces defer, profile, memo, retry, and timeout.

# Before — log every git command intercept before git { echo "[$(date)] git $INTERCEPT_ARGS" >> ~/git.log } # After — show timing for completion functions intercept after '_*' { echo "$INTERCEPT_NAME took ${INTERCEPT_MS}ms" } # Around — memoize expensive function intercept around expensive_func { local cache=/tmp/cache_${INTERCEPT_ARGS// /_} if [[ -f $cache ]]; then cat $cache else intercept_proceed | tee $cache; fi } # Around — retry with backoff intercept around flaky_api { repeat 3; do intercept_proceed; [[ $? == 0 ]] && break; sleep 1; done } # Fat binary — stryke code at machine code speed intercept after 'make *' { @pmaps { notify "done: $_" } @(slack email) }

Variables available in advice:

VariableAvailableDescription
$INTERCEPT_NAMEallCommand name
$INTERCEPT_ARGSallArguments as space-separated string
$INTERCEPT_CMDallFull command string
$INTERCEPT_MSafterExecution time in milliseconds (nanosecond source)
$INTERCEPT_USafterExecution time in microseconds
$?afterExit status

[0x04] RKYV ZERO-COPY CACHE LAYER

Cached bytecode lives in rkyv archives mmap'd by clients — zero-copy deserialization, no allocator pressure on hot paths. The daemon owns all writes; clients only mmap. The single queryable mirror is catalog.db (SQLite) for dbview introspection — never touched on the hot path.

images/{hash}-{slug}.rkyv

Per-source-root rkyv shards. Compiled bytecode for autoloads, plugins, sourced scripts. Daemon writes; clients mmap zero-copy. Validates with rkyv's bytecheck on first access; format-versioned for migration safety.

index.rkyv

Top-level shard index: source-root path → shard hash + mtime. Daemon rewrites on changes; clients mmap to resolve which shard to load.

catalog.db (SQLite mirror)

Daemon-hydrated FTS5-indexed mirror of all rkyv contents. Used ONLY by dbview and zcache introspection — never read on the hot path. Clients have ZERO SQLite handles. The daemon's own FTS5 history (history.db) sits next to it; the shell's user-facing history is zshrs_history (flat zsh-extended-history-format text) plus a sibling FTS5 index zshrs_history.db, both in $ZSHRS_HOME.

Versioned & migration-safe. Every shard opens through a fixed header — magic (ZRSC for scripts, ZRAL for autoloads), format_version, the building zshrs_version, pointer_width, and built_at_secs — validated by rkyv::check_archived_root on mmap. Any mismatch (schema bump, a different build, or a 32-vs-64-bit pointer width) fails the header check and the shard is silently recompiled from source — never a hard error, never a broken load. Writes take an exclusive flock on <shard>.lock, serialize with rkyv::to_bytes, fsync a temp file, and atomic-rename over the live shard, so concurrent shells never observe a half-written cache. The SQLite mirrors carry their own schema migrations applied on open.

Browse caches without SQL:

dbview # list all tables + row counts (hits catalog.db) dbview autoloads # dump autoloads: name, body size, ast size dbview autoloads _git # single row: source, body, ast status, preview dbview comps git # search comps for "git" dbview executables rustc # search PATH cache dbview history docker # search history zcache rebuild # force daemon to recompile every shard zcache verify # bytecheck every rkyv archive

[0x04b] FILE LAYOUT & BINARIES

One directory holds every zshrs file: $ZSHRS_HOME (defaults to ~/.zshrs/). All four binaries — zshrs, zshrs-daemon, zshrs-recorder, zd — seed the directory and three default configs on first run via CachePaths::ensure_default_configs. Idempotent — never overwrites user edits. Auto-migrates legacy daemon.tomlzshrs-daemon.toml and the legacy macOS history at ~/Library/Application Support/zshrs/history.db~/.zshrs/zshrs_history.db.

~/.zshrs/ ├── zshrs.toml # shell config [log] [daemon] [shell.skip_configs] ├── zshrs-daemon.toml # daemon config [log] [http] [http.tokens] ├── zshrs-recorder.toml # recorder config [log] ├── zshrs.log # shell tracing ├── zshrs-daemon.log # daemon tracing ├── zshrs-recorder.log # recorder tracing ├── zshrs_history # flat zsh-extended-history-format text ├── zshrs_history.db # FTS5 index sibling ├── catalog.db # daemon canonical-state mirror (FTS5) ├── history.db # daemon's own FTS5 history ├── cache.db # daemon KV cache ├── plugins.db ├── images/ # rkyv canonical shards (per source root) ├── replay/ # non-deterministic .zshrc fragments ├── artifacts/ # content-addressed artifact cache ├── snapshots/ # tag-based canonical-state snapshots ├── jobs/ # supervisor stdout/stderr captures ├── daemon.sock # Unix domain socket ├── daemon.pid # singleton flock └── index.rkyv # shard registry

Three log files (one per binary)

FileOwnerLevel source
zshrs.logshell[log] level in zshrs.toml (env $ZSHRS_LOG wins)
zshrs-daemon.logdaemon[log] level in zshrs-daemon.toml
zshrs-recorder.logrecorder[log] level in zshrs-recorder.toml

Helper paths::is_zshrs_log_file matches all three for rotation, tail, and clear. Default daemon startup emits 7 INFO lines; with level = "trace" an additional ~5 startup diagnostics print (resolved env, pidlock, db sizes, ticker spawn, schedule spawn, http listener address).

[shell] skip_configs = "auto"

When the daemon is up AND has a recorded zshrs canonical shard, the shell SKIPS sourcing /etc/zshenv + ~/.{zshenv,zprofile,zshrc,zlogin} entirely and rebuilds executor state from the rkyv shard. canonical_apply wires alias/galias/salias/env/params/setopt/path/fpath/named_dirs/autoload_functions/zstyle/bindkey/compdef/zle widgets. Inline functions are deferred until the recorder ships bytecode in the shard.

[0x04c] RECORDER (zshrs-recorder)

Separate binary — not a flag on zshrs. Sources the full zsh login chain in order, skipping any missing file silently:

1. /etc/zshenv 2. ${ZDOTDIR:-$HOME}/.zshenv 3. /etc/zprofile 4. ${ZDOTDIR:-$HOME}/.zprofile 5. /etc/zshrc 6. ${ZDOTDIR:-$HOME}/.zshrc 7. /etc/zlogin 8. ${ZDOTDIR:-$HOME}/.zlogin

-f PATH overrides the chain to source one file. End-of-run ships a recorder_ingest IPC bundle to the daemon, which folds it into the canonical shard for the matching source root.

[0x04d] zd — TWO SURFACES

SurfaceTransportLatencyUse case
zd binaryHTTP via ureq to [http].listen2.64 ms (fork+exec)bash, fish, CI, anything outside zshrs
zd builtin (in-process)local Unix socket via Client0.48 ms (5.5× faster)inside zshrs — same arg surface

Default HTTP listener: 127.0.0.1:7733, seeded into zshrs-daemon.toml on first run so zd health works out of the box. Default token comes from $DAEMON_TOKEN. Loopback bind requires no token; non-loopback bind refuses to start until [http.tokens] is populated. GET /openapi (alias /openapi.json) returns an OpenAPI 3.1 document auto-derived from OP_NAMES — 108 paths today (4 meta + 101 ops + 3 streams), with ErrPayload in components and bearerAuth declared only when tokens are configured.

zd subcommands

zd health # liveness probe zd ops # enumerate every op zd metrics # Prometheus exposition zd ping [echo...] zd info zd call OP [JSON_BODY] # raw op invocation zd doctor [--json] # pretty health table: perms, db integrity, shards, # fsnotify, pidlock, jobs, legacy litter; exit 1 on any fail zd config get KEY # runtime knob plumbing zd config set KEY VALUE zd config list zd snapshot save TAG [--notes N] # canonical-state freeze zd snapshot list zd snapshot load TAG zd snapshot diff A B zd cache <put|get|del|list|stats> zd job <submit|list|status|output|kill|cancel|wait> zd lock <try|acquire|release|list> zd publish TOPIC [DATA] [--json '...'] zd events / zd watch / zd defs zd artifact <put|get|list|gc> zd schedule <add|add-once|list|remove> zd export TARGET FORMAT [--json] # raw export — NO json envelope by default zd view TARGET [FORMAT]

zd export aliases pdf > out.pdf produces a real PDF — payload is streamed direct for sh / csv / json / yaml / text / pdf. --json opt-in restores the JSON envelope.

[0x04e] NEW z* BUILTINS

BuiltinDescription
zlock try NAMECross-process named lock — non-blocking try
zlock acquire NAME [--timeout S]Poll-wait acquire with optional timeout
zlock release NAME TOKENRelease by token
zlock listList all held locks
zpublish TOPIC / TOPIC DATA / TOPIC --json '{...}'Producer side of the pub/sub bus (consumer is zsubscribe)
zwhere SUBSYS NAMEQuery daemon canonical state for "where did this alias / function / zstyle come from" with file:line attribution

Full builtin family: zcache, zls, zid, zping, ztag, zuntag, zsend, znotify, zsubscribe, zunsubscribe, zjob, zsync, zask, zhistory, zsource, zcomplete, zsuggest, zcmd-result, zlog, zwhere, zd, zlock, zpublish.

zjob — bidirectional ptmx attach

zjob submit [--pty] [--cwd DIR] [--tag T...] [--env K=V...] -- CMD ARGS... zjob list [--state running|exited|killed|failed] [--tag T] [--limit N] zjob status <id> zjob output <id> [--follow] [--stderr] [--lines N] zjob attach <id> # read-only file-tail for non-pty; # bidirectional raw-mode pump for --pty zjob kill <id> [--signal NAME] zjob cancel <id> [--grace SECS] zjob wait <id> [--timeout SECS]

With --pty the daemon calls nix::pty::openpty() and the child runs with the slave on 0/1/2 via pre_exec dup2; the master fd lives in JobMeta. Two new IPC ops drive it:

  • job_input {id, bytes_b64} — base64-decode, write to master
  • job_resize {id, rows, cols}TIOCSWINSZ for SIGWINCH propagation

On zjob attach against a pty job: termios cfmakeraw on stdin, a stdin reader thread batches keystrokes and fires job_input, output is broadcast as job:N.stdout events with bytes_b64 payload (decoded back to the user's tty), and SIGWINCH is forwarded as job_resize. Ctrl-] is the detach key. Termios is restored on exit via a Drop guard. Use case: background jobs that block on stdin (deploy scripts asking y/n, REPLs in background) — submit with --pty, attach later, type, detach, attach again.

zsync up --all

Now wired (was a stub). The shell-side enumerator (src/extensions/overlay_snapshot.rs) snapshots every overlay table and ships push_canonical per subsystem. Covers alias/galias/salias, setopt, params (vars+arrays+assoc unioned), env, path, manpath, fpath, named_dir, compdef, zstyle. Skipped: function (needs source-text round-trip), bindkey (lives in ZleManager), zmodload (no canonical "currently loaded" list).

zsync up --all # promote every overlay subsystem zsync up <subsystem> KEY VALUE zsync up <subsystem> --json '<obj>' zsync pull <subsystem> zsync diff <subsystem> --overlay '<obj>' zsync watch <subsystem>...

[0x05] BYTECODE CACHING

Every autoload function in fpath gets compiled to fusevm bytecodes during compinit. Compiled chunks are serialized via rkyv into per-source-root shards and written by the daemon. Subsequent loads mmap the archive zero-copy, validate via bytecheck, and dispatch directly — no lex, no parse, no compile, no allocator hit.

First call to _git (daemon path): fpath/_git (source text) │ ▼ ShellParser::parse_script() ~1ms │ ▼ ShellCompiler::compile() ~0.5ms │ ▼ fusevm::Chunk (bytecodes) │ ├──► VM::run() native dispatch │ └──► rkyv::to_bytes() ~0.1ms (zero-copy archive) │ ▼ images/{hash}-fpath.rkyv (daemon writes) Every subsequent call (client path, ZERO daemon RTT): images/{hash}-fpath.rkyv mmap (kernel page cache) │ ▼ rkyv::access::<ArchivedChunk> ~0 µs (zero-copy access) │ ▼ fusevm::Chunk (no lexer, no parser, no compiler, no alloc) │ ▼ VM::run() native bytecode dispatch

[0x06] FUSEVM BYTECODE TARGET

100% lowered. Every shell construct compiles to fusevm bytecodes — a language-agnostic VM with fused superinstructions and Cranelift JIT. The same VM that powers stryke (which beats LuaJIT on benchmarks). No tree-walking interpreter remains. Hot bytecodes compile to native x86-64 machine code.

stryke source ───► stryke compiler ──┐ ├──► fusevm::Op ──► VM::run() ──► JIT ──► native zshrs source ───► shell compiler ──┘ │ ├── Linear JIT: straight-line code ├── Block JIT: loops, conditionals └── Cranelift codegen → x86-64

Shell constructs already lowered to fusevm bytecodes:

Arithmetic

$(( )) — full precedence, ternary, assignment, hex/octal, bitwise

Loops

for, for(()), while, until, repeat

Conditionals

if/elif/else, case, [[ ]] with all file tests and comparisons

Commands

Exec, ExecBg, pipelines, redirects, here-docs, here-strings

Functions

Definition, Call/Return, PushFrame/PopFrame

Fused Ops

AccumSumLoop, SlotIncLtIntJumpBack, PreIncSlotVoid — single-dispatch loop execution

[0x07] EXCLUSIVE BUILTINS

Parallel Primitives (VM-executed, zero fork)

BuiltinDescription
async / awaitShip work to pool, collect result
pmapParallel map with ordered output — compiles to bytecode, runs on VM, zero forks
pgrepParallel filter — compiles to bytecode, runs on VM, zero forks
peachParallel for-each, unordered — compiles to bytecode, runs on VM, zero forks
barrierRun all commands in parallel, wait for all

AOP / Debugging

BuiltinDescription
interceptAOP before/after/around advice on any command. Glob pattern matching. Nanosecond timing.
intercept_proceedCall original command from around advice.
doctorFull diagnostic: worker pool metrics, cache stats, bytecode coverage, startup health.
dbviewBrowse the daemon's catalog.db mirror without SQL. Tables: autoloads, comps, executables, history, plugins. Hot path uses rkyv mmap directly.
profileIn-process command profiling. Nanosecond accuracy. No fork overhead in measurement.

Unit Test Framework

Port of the strykelang test framework (stryke testzshrs --ztest). Worker-pool runner — one persistent --ztest-worker subprocess per CPU, fork-on-receive per test file, JSON-over-pipe wire protocol, per-test fd 2 capture so concurrent workers can’t tear each other’s lines. Test discovery: test_* / t_* prefix × .zsh/.sh/.zshrs suffix under t/ or tests/.

BuiltinDescription
zassert_eq / zassert_neString equality / inequality
zassert_ok / zassert_err / zassert_true / zassert_falseTruthiness (non-empty AND not "0" → truthy)
zassert_gt / zassert_lt / zassert_ge / zassert_leNumeric ordering
zassert_matchRegex match (Rust regex syntax)
zassert_containsSubstring containment
zassert_nearFloat approximate equality (epsilon)
zassert_diesPasses when given shell command exits non-zero
ztest_skipMark current assertion skipped (yellow ↓)
ztest_run / run_testsPrint summary, roll counters into totals
zshrs --ztest [-j N] [-q] [paths…]Worker-pool runner (default workers = num_cpus)
zshrs --ztest-workerPersistent worker subprocess (JSON over stdin/stdout)

Coreutils (Anti-Fork)

BuiltinDescriptionSpeedup vs fork
catConcatenate files — no fork2000-5000x
head / tailFirst/last N lines — no fork2000-5000x
wcLine/word/char count — no fork2000-5000x
sort / uniqSort and dedupe — no fork2000-5000x
findWalk directories — no fork2000-5000x
cut / tr / revText manipulation — no fork2000-5000x
seq / teeNumber sequences, copy stdin — no fork2000-5000x
dateCurrent date/time — direct strftime3000-8000x
sleepDelay — std::thread::sleep2000-5000x
mktempCreate temp file/dir — no fork2000-5000x
hostname / unameSystem info — direct syscall3000-8000x
id / whoamiUser info — direct syscall3000-8000x
touch / realpathFile ops — no fork2000-5000x
basename / dirnamePath manipulation — no fork2000-5000x
zgetattr / zsetattrxattr ops — direct syscall2000-5000x

[0x07b] SHELL LANGUAGE FEATURES

Every shell construct compiles to fusevm bytecode — no tree-walker dispatch lives in zshrs. The categories below are summaries; the full reference documents each entry with a runnable code example.

Control Flow

if, while, until, for, for ((;;)), case, select, coproc, break, continue, return, ;/&&/||/&.

Indexed Arrays

arr=(a b c), arr+=(d), ${arr[1]} (1-based), ${arr[-1]}, ${arr[@]} (argv splice), ${#arr[@]}.

Associative Arrays

typeset -A m, m[key]=val, ${m[key]}, ${(k)m} (keys), ${(v)m} (values).

Parameter Expansion

${var:-x}, ${var:=x}, ${var:?msg}, ${var:+x}, ${#var}, ${var:o:l}, ${var#pat}, ${var/pat/repl}, ${var:u}/:l.

Zsh Flags

(L)/(U) case, (j: :) join, (s. .) split, (f) newline-split, (o)/(O) sort, (P) indirect, (@) force-array, (k)/(v), (#). Stack: (jL), (s:,:U).

Redirects & Pipelines

> >> < <<EOF <<< 2>&1 &> &>> | |& ! <(cmd) >(cmd).

Background & Async

cmd & (fork + setsid), $!, wait, jobs/fg/bg; async/await (worker pool, no fork).

Coprocesses

coproc { body } creates two pipes, forks, registers $COPROC=[read_fd, write_fd]. Read from /dev/fd/${COPROC[1]}, write to /dev/fd/${COPROC[2]}.

Eval & Indirect Dispatch

eval 'echo $x' defers expansion correctly (single-quoted specials honored). cmd=ls; $cmd routes through host intercepts.

Arithmetic

$((expr)), (( cond )), let; full integer expression grammar compiled inline (no runtime parser).

Glob & Brace

*.rs, **/*.rs (parallel walk), {a,b,c}, {1..10}, glob qualifiers *(.x) *(N).

Tilde & Cmd-Sub

~, ~user, ~+/~-; $(cmd) (in-process pipe-capture), backticks.

For the complete catalog — every supported builtin, keyword, parameter-expansion form, ZshFlag, AOP primitive, parallel primitive, and anti-fork coreutils replacement with a code example for each — see the FULL REFERENCE.

[0x08] INSTALL

# Via Homebrew tap (auto-bumped by each release) brew tap MenkeTechnologies/menketech brew install zshrs # core: zshrs + zd # OR the umbrella: zshrs + zd + zshrs-recorder + zshrs-daemon brew install zshrs-all # From crates.io cargo install zshrs # From source — lean build, pure shell, no stryke dependency git clone https://github.com/MenkeTechnologies/zshrs cd zshrs && cargo build --release # target/release/zshrs
# Set as login shell sudo sh -c 'echo "$(which zshrs)" >> /etc/shells' chsh -s "$(which zshrs)" # Tab completion for zshrs itself cp completions/_zshrs /usr/local/share/zsh/site-functions/

[0x09] DIAGNOSTICS

# Full health check zshrs --doctor # In-session diagnostics doctor # Browse cache dbview dbview autoloads _git # Profile a command profile 'compinit' profile -s 'for i in {1..1000}; do echo $i > /dev/null; done' # Show intercepts intercept list

[0x09c] GRAMMAR & SYNTAX — CANONICAL TABLES

Every reserved keyword, builtin, setopt option, special variable, parameter flag, glob qualifier, operator, history expansion, and word modifier recognized by zshrs. Sourced directly from upstream zsh C tables (Src/hashtable.c::reswds[], Src/builtin.c::builtins[], Src/Modules/*.c, Src/options.c::optns[], Src/params.c::special_params[]) plus the zshrs extension builtins in daemon/builtins.rs + src/extensions/. Single source of truth lives at data/grammar/canonical.json; regenerate this section via python3 scripts/gen_grammar_docs.py.

50
Keywords
157
Builtins
196
Options
88
Special vars
38
Param flags
44
Glob quals
55
Operators
10
History exp.
16
Modifiers

Generated 2026-05-31 from data/grammar/canonical.json.

Reserved keywords (50)

Source: src/zsh/Src/hashtable.c::reswds[] + zshrs lexer extensions.

Control flow (20)

[[ ]] always case do done elif else end esac fi for foreach if in repeat select then until while

Declaration (10)

declare export float integer let local readonly set shift typeset

Function (1)

function

Grouping (2)

{ }

I/O / source (5)

. eval exec source trap

Loop control (5)

break continue exit logout return

Modifier (precommand) (6)

builtin command coproc nocorrect noglob time

Operator-like (1)

!

Builtins (157)

Every command implemented inside the shell — no fork/exec required.

POSIX / zsh core (74)

Source: src/zsh/Src/builtin.c::builtins[].

. : [ alias autoload bg break bye cd chdir continue declare dirs disable disown echo emulate enable eval exit export false fc fg float functions getln getopts hash hashinfo history integer jobs kill let local logout mem patdebug popd print printf pushd pushln pwd r read readonly rehash return set setopt shift source suspend test times trap true ttyctl type typeset umask unalias unfunction unhash unset unsetopt wait whence where which zcompile zmodload

zsh modules (59)

Source: src/zsh/Src/Modules/*.c (curses, datetime, pcre, files, stat, terminfo, zftp, zselect, zsystem, zutil, …).

cap chgrp chmod chown clone echotc echoti example getcap ln local log mkdir mv nameref pcre_compile pcre_match pcre_study private rm rmdir setcap stat strftime sync syserror sysopen sysread sysseek syswrite zcurses zdelattr zf_chgrp zf_chmod zf_chown zf_ln zf_mkdir zf_mv zf_rm zf_rmdir zf_sync zformat zftp zgdbmpath zgetattr zlistattr zparseopts zprof zpty zregexparse zselect zsetattr zsocket zstat zstyle zsystem ztcp ztie zuntie

zshrs extensions (24)

Source: daemon/builtins.rs + src/extensions/ext_builtins.rs.

zask zcache zcompdump zcomplete zd zhistory zid zjob zlock zlog zls znotify zping zpublish zsend zsource zsubscribe zsuggest zsync ztag zunsubscribe zuntag zwc zwhere

setopt options (196)

Source: src/zsh/Src/options.c::optns[]. All upstream zsh options recognized by name; use setopt / unsetopt to toggle, or NO_ prefix (e.g. NO_GLOB).

ALIASES ALIASFUNCDEF ALLEXPORT ALWAYSLASTPROMPT ALWAYSTOEND APPENDCREATE APPENDHISTORY AUTOCD AUTOCONTINUE AUTOLIST AUTOMENU AUTONAMEDIRS AUTOPARAMKEYS AUTOPARAMSLASH AUTOPUSHD AUTOREMOVESLASH AUTORESUME BADPATTERN BANGHIST BAREGLOBQUAL BASHAUTOLIST BASHREMATCH BEEP BGNICE BRACECCL BRACEEXPAND BSDECHO CASEGLOB CASEMATCH CASEPATHS CBASES CDABLEVARS CDSILENT CHASEDOTS CHASELINKS CHECKJOBS CHECKRUNNINGJOBS CLOBBER CLOBBEREMPTY COMBININGCHARS COMPLETEALIASES COMPLETEINWORD CONTINUEONERROR CORRECT CORRECTALL CPRECEDENCES CSHJUNKIEHISTORY CSHJUNKIELOOPS CSHJUNKIEQUOTES CSHNULLCMD CSHNULLGLOB DEBUGBEFORECMD DOTGLOB DVORAK EMACS EQUALS ERREXIT ERRRETURN EVALLINENO EXEC EXTENDEDGLOB EXTENDEDHISTORY FLOWCONTROL FORCEFLOAT FUNCTIONARGZERO GLOB GLOBALEXPORT GLOBALRCS GLOBASSIGN GLOBCOMPLETE GLOBDOTS GLOBSTARSHORT GLOBSUBST HASHALL HASHCMDS HASHDIRS HASHEXECUTABLESONLY HASHLISTALL HISTALLOWCLOBBER HISTAPPEND HISTBEEP HISTEXPAND HISTEXPIREDUPSFIRST HISTFCNTLLOCK HISTFINDNODUPS HISTIGNOREALLDUPS HISTIGNOREDUPS HISTIGNORESPACE HISTLEXWORDS HISTNOFUNCTIONS HISTNOSTORE HISTREDUCEBLANKS HISTSAVEBYCOPY HISTSAVENODUPS HISTSUBSTPATTERN HISTVERIFY HUP IGNOREBRACES IGNORECLOSEBRACES IGNOREEOF INCAPPENDHISTORY INCAPPENDHISTORYTIME INTERACTIVE INTERACTIVECOMMENTS KSHARRAYS KSHAUTOLOAD KSHGLOB KSHOPTIONPRINT KSHTYPESET KSHZEROSUBSCRIPT LISTAMBIGUOUS LISTBEEP LISTPACKED LISTROWSFIRST LISTTYPES LOCALLOOPS LOCALOPTIONS LOCALPATTERNS LOCALTRAPS LOG LOGIN LONGLISTJOBS MAGICEQUALSUBST MAILWARN MAILWARNING MARKDIRS MENUCOMPLETE MONITOR MULTIBYTE MULTIFUNCDEF MULTIOS NOMATCH NOTIFY NULLGLOB NUMERICGLOBSORT OCTALZEROES ONECMD OVERSTRIKE PATHDIRS PATHSCRIPT PHYSICAL PIPEFAIL POSIXALIASES POSIXARGZERO POSIXBUILTINS POSIXCD POSIXIDENTIFIERS POSIXJOBS POSIXSTRINGS POSIXTRAPS PRINTEIGHTBIT PRINTEXITVALUE PRIVILEGED PROMPTBANG PROMPTCR PROMPTPERCENT PROMPTSP PROMPTSUBST PROMPTVARS PUSHDIGNOREDUPS PUSHDMINUS PUSHDSILENT PUSHDTOHOME RCEXPANDPARAM RCQUOTES RCS RECEXACT REMATCHPCRE RMSTARSILENT RMSTARWAIT SHAREHISTORY SHFILEEXPANSION SHGLOB SHINSTDIN SHNULLCMD SHOPTIONLETTERS SHORTLOOPS SHORTREPEAT SHWORDSPLIT SINGLECOMMAND SINGLELINEZLE SOURCETRACE STDIN SUNKEYBOARDHACK TRACKALL TRANSIENTRPROMPT TRAPSASYNC TYPESETSILENT TYPESETTOUNSET UNSET VERBOSE VI WARNCREATEGLOBAL WARNNESTEDVAR XTRACE ZLE

Special variables (88)

Source: src/zsh/Src/params.c::special_params[]. Includes scalar ($?, $RANDOM) and array forms ($path, $pipestatus); upper-case and lower-case names are linked pairs where applicable.

$! $# $$ $* $- $0 $? $@ $ARGC $CDPATH $COLUMNS $EGID $ERRNO $EUID $FIGNORE $FPATH $FUNCNEST $GID $HISTCHARS $HISTCMD $HISTSIZE $HOME $IFS $KEYBOARD_HACK $LANG $LC_ALL $LC_COLLATE $LC_CTYPE $LC_MESSAGES $LC_NUMERIC $LC_TIME $LINENO $LINES $MAILPATH $MANPATH $MODULE_PATH $NULLCMD $OPTARG $OPTIND $PATH $POSTEDIT $PPID $PROMPT $PROMPT2 $PROMPT3 $PROMPT4 $PS1 $PS2 $PS3 $PS4 $PSVAR $RANDOM $READNULLCMD $RPROMPT $RPROMPT2 $RPS1 $RPS2 $SAVEHIST $SECONDS $SHLVL $SPROMPT $TERM $TERMINFO $TERMINFO_DIRS $TRY_BLOCK_ERROR $TRY_BLOCK_INTERRUPT $TTYIDLE $UID $USERNAME $WORDCHARS $ZLE_RPROMPT_INDENT $ZSH_EVAL_CONTEXT $ZSH_SUBSHELL $_ $argv $cdpath $fignore $fpath $histchars $mailpath $manpath $module_path $path $pipestatus $prompt $psvar $status $zsh_eval_context

Parameter expansion flags (38)

Single-letter modifiers inside ${(X)var}. Composable: ${(jL)arr} = join lowercase.

FlagMeaning
${(@)var}array-context retain $@ semantics; quoting-preserving even in scalar context
${(A)var}create as an array
${(a)var}sort by array index
${(c)var}count words in a parameter (e.g., scalar split count)
${(C)var}capitalize words
${(D)var}treat as DIRECTORY name (apply directory substitution like ~/...)
${(e)var}perform parameter expansion / arithmetic / etc. on the result
${(f)var}split result at newlines
${(F)var}join array elements with newlines
${(g)var}process escape sequences like print does (g:o: process octals, g:c: process \c)
${(i)var}case-insensitive sort
${(j)var}join array with separator: ${(j:sep:)arr}
${(k)var}for assoc arrays: keys ${(k)hash}
${(K)var}subscript flags: use keys
${(L)var}lowercase
${(M)var}match: use longest match (also for case-insensitivity in sort)
${(n)var}numeric sort
${(o)var}sort ascending
${(O)var}sort descending
${(p)var}interpret embedded escape sequences in j/s separator
${(P)var}treat value as parameter name → indirect (P)
${(q)var}quote the result (q-/q+/qq/qqq variants for shell-quote levels)
${(Q)var}remove quoting
${(r)var}right-justify within field width: ${(r:N::pad:)var}
${(l)var}left-justify within field width: ${(l:N::pad:)var}
${(s)var}split at separator: ${(s:sep:)var}
${(S)var}subscript: search subscript ranges
${(t)var}test parameter type
${(u)var}unique (dedupe array)
${(U)var}uppercase
${(v)var}for assoc arrays: values ${(v)hash}
${(V)var}make invisible / control chars visible
${(w)var}split into words
${(W)var}split into words (alternate)
${(z)var}split as the shell would (z-tokens)
${(#)var}expand result as arithmetic; numeric value
${(%)var}expand prompt percent escapes in result
${(~)var}treat values as patterns (e.g., for /pat/repl)

Glob qualifiers (44)

Modifiers inside *(X). Composable; use ^ to negate the group, , to OR-combine groups.

QualMeaning
*(/)directories only
*(.)regular files only
*(@)symbolic links only
*(=)sockets only
*(p)named pipes (FIFOs) only
*(*)executable plain files only
*(%)device special files only
*(%b)block special files
*(%c)character special files
*(r)owner-readable
*(w)owner-writable
*(x)owner-executable
*(A)group-readable
*(I)group-writable
*(E)group-executable
*(R)world-readable
*(W)world-writable
*(X)world-executable
*(s)setuid (S_ISUID)
*(S)setgid (S_ISGID)
*(t)sticky bit
*(d N)device number N
*(l[+-=]N)exactly / less-than / greater-than N hard links
*(U)owned by EUID
*(G)owned by EGID
*(u N)owned by uid N
*(g N)group gid N
*(f spec)permission mask: f:o+w: e.g.
*(L [+-=] N)size: blocks / k / m / p suffix (Lk / Lm / Lp)
*(a [Mwhms] [+-=] N)access time
*(m [Mwhms] [+-=] N)modify time
*(c [Mwhms] [+-=] N)ctime
*(o [name|size|links|mtime|atime|ctime])sort ascending
*(O [name|size|links|mtime|atime|ctime])sort descending
*([N,M])select range of matches
*(e:str:)external test: each match passed to expression
*(+func)external test: each match passed to function
*(N)nullglob: silently drop unmatched pattern
*(D)include dotfiles
*(Y N)limit to N results
*(M)include directory names as if trailing slash
*(:mod)apply history modifier (e.g., :t :h :r :e)
*(^)negate the qualifier list
*(,)OR-combine qualifier groups

Operators / redirections / substitution forms (55)

Lexer-recognized tokens. Grouped by kind: pipeline / list / case / redirect / procsub / subst / arith / cond / assign / compare / glob / tilde / brace / expansion / string / extension.

SymbolKindMeaning
|pipelinePipeline. stdout of LHS → stdin of RHS.
|&pipelinePipeline with stderr merged (= |2>&1).
&&listLogical AND: run RHS only if LHS exit==0.
||listLogical OR: run RHS only if LHS exit!=0.
;listSequence: run RHS after LHS regardless of status.
&listBackground: run LHS async; sets $!.
;;caseEnd case arm.
;;&caseFall through and test next case pattern.
;|caseFall through without test.
!negNegate exit status (reserved word).
>redirectStdout redirect (overwrite).
>>redirectStdout append.
<redirectStdin redirect.
<<redirectHeredoc; body terminated by marker.
<<-redirectHeredoc, strip leading tabs from body.
<<<redirectHere-string; literal text as stdin.
>|redirectStdout force-overwrite (bypass NO_CLOBBER).
>!redirectSame as >|; force-overwrite.
&>redirectRedirect both stdout and stderr (bash-compat).
&>>redirectAppend both stdout and stderr.
2>&1redirectDuplicate fd2 to fd1 (stderr → stdout).
>&-redirectClose fd.
<>redirectOpen for read+write.
<(procsubProcess substitution: <(cmd) is a path readable from cmd's stdout.
>(procsubProcess substitution: >(cmd) is a path writable into cmd's stdin.
=(procsubZsh-only =(cmd): tempfile capture.
$(substCommand substitution: $(cmd) captures cmd's stdout.
${substParameter expansion: ${var}.
$((substArithmetic expansion: $((expr)).
((arithArithmetic command. ((expr)) exits 0 iff expr != 0.
))arithClose arithmetic command.
[[condOpen conditional command: [[ expr ]].
]]condClose conditional command.
=assignAssignment. Also: equality in [[ ]].
+=assignAppend assignment (scalar concat / array push).
-=assignNumeric subtract-assign (in (( ))).
:=assign${var:=default}: assign default if unset/empty.
?=assign(arith) ternary.
==compareEquality in (( )) / [[ ]].
!=compareInequality.
=~compareRegex match in [[ ]] (POSIX ERE / PCRE depending on opts).
*globGlob: match any sequence (including empty).
**globRecursive glob (matches dir/subdir/.../ levels).
?globGlob: match one character.
~tildeTilde expansion: ~ → $HOME, ~user, ~+ / ~- / ~N for dirstack.
{a,b,c}braceBrace expansion: comma-separated list.
{1..10}braceBrace expansion: numeric range.
{a..z}braceBrace expansion: character range.
${~var}expansionTreat result of var as pattern.
${^var}expansionArray element rcexpansion.
${=var}expansionWord-split on IFS.
$'…'stringANSI-C quoted string: \n \t \xNN etc.
$"…"stringLocale-translated string.
`…`substBacktick command substitution (legacy form of $()).
@{}extensionZshrs @-prefix: dispatch to stryke embedded scripting.

History expansions (10)

Recall previous commands / words. Lexer-stage expansion before parsing.

FormMeaning
!!previous command
!Ncommand N in history
!-Ncommand N back
!?strmost recent containing str
!strmost recent starting with str
!$last word of previous command
!^first arg of previous command
!*all args of previous command
!:NNth word of previous command
^old^newquick substitute in previous command

Word modifiers (16)

Trailing :X modifiers applied to history words, filename expansions, and parameter results.

ModifierMeaning
:hhead: dirname of path
:ttail: basename of path
:rroot: strip extension
:eextension: keep only extension
:llowercase
:uuppercase
:qquote for shell re-input
:Qremove quoting
:s/old/new/substitute first match
:gs/old/new/global substitute
:aabsolutize (resolve relative path)
:Aabsolutize and resolve symlinks
:Pphysical resolved path
:xsplit into words on whitespace
:wselect words
:Ffollow symlinks (in conjunction with above)

[0xFF] THE PHILOSOPHY

Shells haven't fundamentally improved since the 1990s. bash is a GNU rewrite of the Bourne shell from 1979. zsh added features but kept the fork-based C architecture. fish focused on UX and abandoned POSIX. nushell reinvented the data model but lost compatibility.

zshrs takes a different approach: keep everything that makes zsh powerful — glob qualifiers, parameter expansion flags, the completion system, ZLE, zstyle, modules — and replace the runtime with modern systems engineering. Rust instead of C. Thread pool instead of fork. rkyv mmap'd zero-copy archives instead of flat files. Bytecode VM instead of tree-walker. AOP instead of monkey-patching.

The result is the first shell that gets faster as you add more plugins, because the plugin cache means each plugin is only parsed once. The first shell where **/*.rs scales with your CPU count. The first shell where you can intercept any command with nanosecond-accurate timing and zero overhead.

The result is the first shell where every command — interactive or scripted — compiles to bytecodes and executes on a VM with fused superinstructions. The first shell where autoload functions load from pre-compiled bytecodes in microseconds. The first shell where source ~/.zshrc can skip the lexer, parser, and compiler entirely because the bytecodes are mmap'd zero-copy from rkyv archives the daemon already validated.

Since the Bourne shell at Bell Labs in 1970, through csh, ksh, bash, zsh, and fish — every Unix shell has been an interpreter. zshrs is the first to be a compiler. Shell scripts at machine code speed. Achieved in alpha.

THE FIRST COMPILED UNIX SHELL. THE MOST POWERFUL SHELL EVER CREATED.