ZY
A Unix shell built entirely from scratch in C: lexer, parser, executor, line editor, prompt renderer, job control, signal handling, tab completion, history, audit logging, policy enforcement, and a structured data pipeline. No readline, no libedit, no yacc. Every subsystem is hand-written.
What began as a tamper-evident command logger grew into a full interactive shell with 356+ builtins, Nushell-style typed data pipelines, 18 truecolor themes, a built-in test framework, terminal data visualization, cheatsheet engine, script debugger, and a security stack with SHA-256 hash-chain audit logging and a policy engine. It runs as a daily-driver shell.

Get Started
sudo dpkg -i zy_1.0.9_amd64.debDownload zy_1.0.9_amd64.deb
Prebuilt Debian/Ubuntu package. dpkg -i to install, dpkg -r zy to remove
Full Documentation & Command Reference
Browse all 356+ commands with syntax, flags, and examples
After Installation
Set zy as your default shell:
chsh -s /usr/bin/zyLog out and back in, or start a new terminal. Every new session will launch zy.
Or try it without committing:
zyThis drops you into an interactive zy session inside your current shell. Type exit to return.
On first launch, zy runs a one-time setup: detects your terminal font (offers to install a Nerd Font if none is found), creates ~/.zyrc with sensible defaults, and opens the customize wizard for theme, prompt style, and feature toggles.
At a Glance
Architecture
SQLite is the only external dependency, powering three subsystems: audit ledger, frecency history, and directory jump rankings. Everything else is standard libc and POSIX.
- src/
- core/
- main.c— REPL loop, signal bootstrap, subsystem init
- executor.c— AST walker, pipeline/fork/exec, builtin dispatch
- input.c— raw-mode line editor, syntax highlighting, autosuggestions
- variables.c— hash table, parameter expansion, arrays, environ sync
- jobs.c— process groups, fg/bg, wait, SIGCHLD handling
- signals.c— deferred signal model, 29 signals, trap dispatch
- parser/
- lexer.c— tokenizer, 47 token types, quoting rules
- parser.c— recursive descent, 22 AST node types, 16 sub-parsers
- glob.c— wildcards, globstar, qualifiers, modifiers, brace expansion
- builtins/
- core_builtins.c— set, setopt, trap, type, echo, printf, read
- data_builtins.c— where, select, sort-by, group-by, each, reduce
- filter_builtins.c— first, last, nth, all, any, shuffle, sort
- string_builtins.c— str length/trim/replace/split/distance/stats
- math_builtins.c— calc, math abs/ceil/floor/sqrt/sin/cos/tan/sum/avg
- type_conv_builtins.c— conv (units), into int/float/string/bool
- format_builtins.c— from/to json/csv/toml/yaml/tsv/xml/md/html
- assert_builtins.c— assert-eq/ne/true/false/error/type, test-run
- viz_builtins.c— sparkline, chart, progress bar
- cheat.c— inline cheatsheets for 50+ commands, Ctrl+H popup
- debugger.c— interactive script debugger with breakpoints
- env_snapshot.c— env-save/restore/snapshots
- fs_watch.c— inotify file watcher with glob/debounce
- task_runner.c— .zytasks runner with dependency resolution
- pipeline_record.c— session record/replay to JSON
- … 15+ more builtin source files
- modules/
- audit.c— SQLite ledger, SHA-256 chain, risk classification
- policy.c— deny/warn/restrict/rate_limit rules
- completion.c— context-aware tab completion, fuzzy scoring
- zyhistory.c— frecency scoring, per-directory context, SQLite
- zyjump.c— z/zi directory jumping, frecency database
- pipeline_data.c— ZyValue type system, zero-copy transport
- ui/
- prompt.c— 5 prompt styles, segment rendering
- theme.c— 18 truecolor themes, RGB interpolation
- table.c— Unicode box-drawing table renderer
- core/
- include/— 73 header files
- tests/— 50 test suites, 1250+ assertions
▶Under the Hood: Lexer State Machine
▶Under the Hood: Variable Expansion
▶Under the Hood: Signal Handling
Data Pipeline
Nushell-style structured data operations inside a POSIX-compatible shell. Values flow through pipes as typed data, no text parsing between stages.
ls | where size > 20kb | sort-by modified | first 5The ZyValue tagged union supports: null, bool, int, float, string, list, record, table, filesize, and duration. Builtin-to-builtin chains never serialize to text; data flows as pointers through a global side-channel. When an external command enters the pipeline, zy auto-serializes (tables become TSV for awk/cut compatibility).
▶220+ pipeline commands across 15 categories
where, select, sort-by, group-by, each, reduce, first, last, nth, skip, take, all, any, flatten, shuffle, reverse, uniq, wrap, unwrap, compact, zip, enumerate, merge, append, prepend, slice, window, chunks, reject, rename, move, insert, update, upsert, transpose, collect, tee, describe, length, is-empty, is-not-empty, default, range, par-each, sort, values, columns, get, input list
str length, str trim, str replace, str contains, str starts-with, str ends-with, str substring, str index-of, str reverse, str upcase, str downcase, str capitalize, str camel-case, str kebab-case, str snake-case, str pascal-case, str title-case, str screaming-snake-case, str split, str join, str distance, str stats, str pad, str repeat, str encode, str decode
math abs, math ceil, math floor, math round, math sqrt, math sin, math cos, math tan, math log, math ln, math exp, math sum, math avg, math min, math max, math median, math mode, math stddev, math variance, math product, calc (40+ scientific functions), conv (18 unit categories, ~200 units)
from json, from csv, from toml, from yaml, from tsv, from xml, to json, to csv, to toml, to yaml, to tsv, to xml, to md, to html
bits and/or/xor/not/shl/shr/rol/ror, bytes length/at/collect/replace/reverse/build, path parse/join/dirname/basename/expand/exists, hash md5/sha256, date now/format/to-record/humanize, random int/float/chars/bool/uuid/dice, seq, seq date, cal, generate, into int/float/string/bool/binary/filesize/duration/record, env list, load-env, with-env, debug, inspect, metadata, timeit, http get/post
Prompt & Themes
Five prompt styles, 18 truecolor themes, and 13 configurable segments, all live-previewable through the customize wizard.
Aura
Powerline pills with rounded separators and full segment rendering
Edge
Angular separators with a sharp, modern aesthetic
Flux
Gradient-blended pills with smooth color transitions
Bare
Minimal text-only prompt, no special fonts required
Classic
Traditional bash-style prompt for familiarity
▶18 color themes
| Theme | Style |
|---|---|
ether | Cool blue-gray (default) |
neon | Hot pink / cyan cyberpunk |
forest | Deep green / moss / bark |
ocean | Navy / teal / seafoam |
sunset | Orange / coral / warm earth |
nord | Arctic blue / muted pastels |
dracula | Purple / pink / green |
monokai | Yellow / magenta / terminal |
solarized | Warm tan / blue / orange |
gruvbox | Retro warm / orange / aqua |
catppuccin | Pastel pink / mauve / teal |
rose-pine | Rose / gold / muted purple |
tokyo | Neon purple / cyan / deep bg |
kanagawa | Wave blue / sakura pink |
everforest | Soft green / warm gray |
moonlight | Ethereal blue / purple haze |
vaporwave | Retro pink / cyan / purple |
cyberdream | Electric blue / neon green |
Available themes
▶13 prompt segments
| Segment | What it shows |
|---|---|
| Directory | Current path (short/full/tail modes) |
| Git branch | Branch name + dirty/staged/ahead/behind status |
| Git commit hash | Short SHA of HEAD (toggleable) |
| User@Host | Auto-shows on SSH or root sessions |
| Python venv | Detected from $VIRTUAL_ENV |
| Language/project | 24 languages via marker files, extensions, versions |
| Docker context | Active Docker context |
| Command duration | Shows elapsed time above a configurable threshold |
| Exit status | Red indicator on non-zero exit |
| Right prompt | Clock (toggleable) |
| OS icon | Linux/macOS/WSL detection |
| Jobs count | Background job count |
| Battery level | Battery percentage (toggleable) |

Security
Policy Engine
Sits between the parser and the executor. Every parsed command is checked against a rule list before execution.
policy add deny "rm -rf /*" "blocked: recursive root delete"
policy add warn "sudo *" "elevated privilege - are you sure?"
policy add rate_limit "curl *" --rate 10 "max 10 requests per minute"
policy restrict # lock down all capabilities
Audit Logging
Every command goes into a local SQLite database with: command text, working directory, username, exit code, duration, timestamp, risk level, session ID, and device fingerprint. Each entry carries a SHA-256 hash computed over its full record plus the previous entry's hash, creating a tamper-evident chain.
audit verify # check the hash chain end to end
audit log # recent entries
audit export out # dump as JSON
audit search sudo # search for specific commands
audit risk # show high-risk commands▶Risk classification
| Level | Triggers |
|---|---|
| privileged | sudo, su, doas, pkexec |
| destructive | rm, rmdir, shred, mkfs, dd, fork bombs |
| modify | mv, cp, chmod, chown, sed -i, git push, redirections |
| inspect | ls, cat, grep, find, git status, ps, top |
| unknown | Everything else |
Benchmarks
49 tests timed with hyperfine (--runs 10 --warmup 3 --shell none). Every test is a standalone POSIX #!/bin/sh script. Every shell runs the exact same file. Correctness is verified first: all three shells must produce identical output before any timing begins.
zy is 2.88× faster than bash and 3.07× faster than zsh on average (geometric mean across 45 comparable tests ≥ 2 ms). zy wins 42 of 45 benchmarks.
Two tests where zy is slower: config parsing (1.83× slower than bash) and path
manipulation (1.65× slower than zsh). Both stem from read-builtin overhead in tight loops,
tracked for improvement. These tests are included in every run and in the aggregate scores above.
| Category | Tests | zy wins | zy vs bash | zy vs zsh |
|---|---|---|---|---|
| Loops & Arithmetic | 6 | 6 | 3.2× | 2.8× |
| String & Variable Ops | 8 | 7 | 4.4× | 3.1× |
| Control Flow & Functions | 6 | 6 | 4.3× | 5.8× |
| I/O & Output | 3 | 3 | 2.3× | 2.1× |
| Process & Pipeline | 7 | 7 | 1.3× | 1.3× |
| File System & Environment | 2 | 2 | 2.8× | 2.7× |
| Array & Data Structures | 3 | 3 | 4.7× | 5.6× |
| Real-World Patterns | 10 | 8 | 2.5× | 3.8× |
| Overall (geometric mean) | 45 | 42 | 2.88× | 3.07× |
Category overview (geometric mean speedup, tests ≥ 2 ms)
▶Full 49-test scorecard
Values below 1.0× mean zy is faster. Tests marked ⚠ are known weaknesses.
| Test | bash | zsh | zy | zy/bash | zy/zsh |
|---|---|---|---|---|---|
| Startup (true) | 1.0 ms | 1.4 ms | 1.0 ms | 1.02× | 0.70× |
| Startup + echo | 1.1 ms | 1.5 ms | 1.1 ms | 1.03× | 0.75× |
Startup
| Test | bash | zsh | zy | zy/bash | zy/zsh |
|---|---|---|---|---|---|
| While loop 50K | 123 ms | 114 ms | 39 ms | 0.31× | 0.34× |
| C-style for 50K | 65 ms | 64 ms | 32 ms | 0.49× | 0.50× |
| Nested 200×200 | 98 ms | 89 ms | 26 ms | 0.26× | 0.29× |
| Arithmetic 100K | 259 ms | 221 ms | 63 ms | 0.24× | 0.29× |
| Complex arith 50K | 202 ms | 148 ms | 70 ms | 0.35× | 0.47× |
| Break/continue 50K | 264 ms | 237 ms | 70 ms | 0.26× | 0.29× |
Loops & Arithmetic
| Test | bash | zsh | zy | zy/bash | zy/zsh |
|---|---|---|---|---|---|
| Variable expansion 20K | 81 ms | 54 ms | 22 ms | 0.27× | 0.41× |
| String length 10K | 34 ms | 28 ms | 8.8 ms | 0.26× | 0.32× |
| String substitution 10K | 48 ms | 34 ms | 9.7 ms | 0.20× | 0.29× |
| Prefix/suffix strip 10K | 62 ms | 47 ms | 51 ms | 0.82× | 1.08× |
| String concat 5K | 211 ms | 32 ms | 6.6 ms | 0.03× | 0.21× |
| Default expansion 20K | 76 ms | 54 ms | 19 ms | 0.26× | 0.36× |
| Multi-var assign 20K | 91 ms | 56 ms | 19 ms | 0.21× | 0.35× |
| Export/unset cycle 5K | 42 ms | 134 ms | 14 ms | 0.34× | 0.11× |
String & Variable Ops
| Test | bash | zsh | zy | zy/bash | zy/zsh |
|---|---|---|---|---|---|
| If/elif branch 20K | 124 ms | 133 ms | 30 ms | 0.24× | 0.22× |
| Case statement 20K | 70 ms | 63 ms | 20 ms | 0.29× | 0.32× |
| Function call 20K | 89 ms | 252 ms | 19 ms | 0.21× | 0.07× |
| Function + locals 10K | 88 ms | 166 ms | 19 ms | 0.22× | 0.12× |
| Recursive depth=300 ×50 | 222 ms | 201 ms | 1.1 ms | 0.01× | 0.01× |
| AND/OR chain 20K | 88 ms | 103 ms | 21 ms | 0.23× | 0.20× |
| Test operators 20K | 137 ms | 138 ms | 29 ms | 0.21× | 0.21× |
Control Flow & Functions
| Test | bash | zsh | zy | zy/bash | zy/zsh |
|---|---|---|---|---|---|
| Echo 20K → /dev/null | 94 ms | 83 ms | 27 ms | 0.29× | 0.33× |
| Printf 20K → /dev/null | 103 ms | 91 ms | 31 ms | 0.30× | 0.34× |
| Redirect to file 5K | 318 ms | 306 ms | 306 ms | 0.96× | 1.00× |
I/O & Output
| Test | bash | zsh | zy | zy/bash | zy/zsh |
|---|---|---|---|---|---|
| Subshell fork 300 | 93 ms | 97 ms | 68 ms | 0.74× | 0.70× |
| Pipeline echo|cat 300 | 285 ms | 308 ms | 274 ms | 0.96× | 0.89× |
| 3-stage pipe 150 | 202 ms | 207 ms | 180 ms | 0.89× | 0.87× |
| Cmd substitution 300 | 105 ms | 101 ms | 80 ms | 0.76× | 0.79× |
| External /bin/true 300 | 185 ms | 215 ms | 181 ms | 0.98× | 0.84× |
| Background wait 200 | 85 ms | 65 ms | 40 ms | 0.47× | 0.61× |
| 5-stage pipe 50 | 71 ms | 85 ms | 65 ms | 0.91× | 0.76× |
Process & Pipeline
| Test | bash | zsh | zy | zy/bash | zy/zsh |
|---|---|---|---|---|---|
| File test ops 20K | 204 ms | 211 ms | 102 ms | 0.50× | 0.48× |
| Trap setup/teardown 20K | 138 ms | 127 ms | 35 ms | 0.25× | 0.28× |
| Glob 100 files ×500 | 159 ms | 157 ms | 2.0 ms | 0.01× | 0.01× |
File System & Environment
| Test | bash | zsh | zy | zy/bash | zy/zsh |
|---|---|---|---|---|---|
| Array append 5K | 20 ms | 26 ms | 5.2 ms | 0.26× | 0.20× |
| Array access 5K | 40 ms | 48 ms | 9.0 ms | 0.23× | 0.19× |
| Array iterate 500-elem ×100 | 57 ms | 61 ms | 9.3 ms | 0.16× | 0.15× |
Array & Data Structures
| Test | bash | zsh | zy | zy/bash | zy/zsh |
|---|---|---|---|---|---|
| Config parser 500-line ×20 ⚠ | 63 ms | 138 ms | 115 ms | 1.83× | 0.84× |
| Path manipulation 10K ⚠ | 101 ms | 77 ms | 127 ms | 1.26× | 1.65× |
| Read 2000 lines | 10 ms | 80 ms | 2.3 ms | 0.23× | 0.03× |
| Word split IFS 10K | 269 ms | 838 ms | 90 ms | 0.33× | 0.11× |
| Parse+exec 2000-line ×5 | 18 ms | 18 ms | 6.8 ms | 0.37× | 0.37× |
| Mixed workload 10K | 98 ms | 167 ms | 21 ms | 0.22× | 0.13× |
| Sequential chain 20K | 99 ms | 119 ms | 24 ms | 0.24× | 0.20× |
| Deep nesting 3-if 20K | 174 ms | 212 ms | 46 ms | 0.27× | 0.22× |
| Conditional file proc 5K | 39 ms | 36 ms | 16 ms | 0.40× | 0.44× |
| Counter + printf 10K | 61 ms | 49 ms | 18 ms | 0.29× | 0.36× |
Real-World Patterns
AMD Ryzen 7 6800H, 16 GB, Linux 6.8. hyperfine 1.18 with
--runs 10 --warmup 3 --shell none. Each test is a standalone #!/bin/sh script; shells are
invoked as bash test.sh, zsh test.sh, zy test.sh. Correctness verified identically before
timing. Geometric mean for aggregate ratios. Build: -O3 -flto -march=native.
Run It Yourself
Install zy via the .deb package, then benchmark on your own machine. Copy-paste this self-contained 12-test script:
▶zy-quickbench.sh (copy-paste, runs in ~2 min)
#!/usr/bin/env bash
# zy-quickbench.sh — 12-test benchmark: bash vs zsh vs zy
# Requires: hyperfine (sudo apt install hyperfine), bash, zsh, zy
set -euo pipefail
DIR=$(mktemp -d); trap 'rm -rf "$DIR"' EXIT
for sh in bash zsh zy; do
command -v "$sh" &>/dev/null || { echo "Missing: $sh"; exit 1; }
done
command -v hyperfine &>/dev/null || { echo "Install: sudo apt install hyperfine"; exit 1; }
mk() { local f="$DIR/$1.sh"; cat > "$f"; chmod +x "$f"; echo "$f"; }
T01=$(mk while50k <<'S'
#!/bin/sh
i=0; while [ $i -lt 50000 ]; do i=$((i+1)); done; echo $i
S
)
T02=$(mk arith100k <<'S'
#!/bin/sh
i=0; while [ $i -lt 100000 ]; do i=$((i+1)); done; echo $i
S
)
T03=$(mk strconcat <<'S'
#!/bin/sh
s=""; i=0; while [ $i -lt 5000 ]; do s="${s}x"; i=$((i+1)); done; echo ${#s}
S
)
T04=$(mk funcall <<'S'
#!/bin/sh
f() { :; }; i=0; while [ $i -lt 20000 ]; do f; i=$((i+1)); done; echo $i
S
)
T05=$(mk arrayiter <<'S'
#!/bin/sh
a=""; i=0; while [ $i -lt 500 ]; do a="$a $i"; i=$((i+1)); done
j=0; while [ $j -lt 100 ]; do for x in $a; do :; done; j=$((j+1)); done; echo done
S
)
T06=$(mk ifsplit <<'S'
#!/bin/sh
line="one:two:three:four:five:six:seven:eight"
i=0; while [ $i -lt 10000 ]; do
old="$IFS"; IFS=":"; set -- $line; IFS="$old"; i=$((i+1))
done; echo $i
S
)
T07=$(mk pipeline <<'S'
#!/bin/sh
i=0; while [ $i -lt 300 ]; do echo hello | cat >/dev/null; i=$((i+1)); done; echo $i
S
)
T08=$(mk subshell <<'S'
#!/bin/sh
i=0; while [ $i -lt 300 ]; do (echo hello) >/dev/null; i=$((i+1)); done; echo $i
S
)
T09=$(mk filetest <<'S'
#!/bin/sh
i=0; while [ $i -lt 20000 ]; do [ -f /etc/hostname ]; i=$((i+1)); done; echo $i
S
)
T10=$(mk echo20k <<'S'
#!/bin/sh
i=0; while [ $i -lt 20000 ]; do echo "hello" >/dev/null; i=$((i+1)); done; echo $i
S
)
T11=$(mk deepnest <<'S'
#!/bin/sh
i=0; while [ $i -lt 20000 ]; do
if [ $((i%3)) -eq 0 ]; then if [ $((i%5)) -eq 0 ]; then if [ $((i%7)) -eq 0 ]; then
:; fi; fi; fi; i=$((i+1))
done; echo $i
S
)
T12=$(mk mixed <<'S'
#!/bin/sh
c=0; t=0; i=0
while [ $i -lt 10000 ]; do
x=$((i*3+7)); s="item_${i}_${x}"
if [ $((i%2)) -eq 0 ]; then c=$((c+1)); fi
t=$((t+x)); i=$((i+1))
done; echo "$c $t"
S
)
run() {
echo "--- $1 ---"
hyperfine --warmup 3 --runs 10 --shell none \
-n bash "bash $2" -n zsh "zsh $2" -n zy "zy $2"
echo
}
echo "=== zy Quick Benchmark (12 tests) ==="
echo "bash $(bash --version | head -1 | grep -oP '\d+\.\d+\.\d+'), \
zsh $(zsh --version | awk '{print $2}'), \
zy $(zy --version 2>&1 | grep -oP '\d+\.\d+\.\d+' || echo '?')"
echo
run "While loop 50K" "$T01"
run "Arithmetic 100K" "$T02"
run "String concat 5K" "$T03"
run "Function call 20K" "$T04"
run "Array iterate 500x100" "$T05"
run "Word split IFS 10K" "$T06"
run "Pipeline 300x" "$T07"
run "Subshell 300x" "$T08"
run "File test 20K" "$T09"
run "Echo 20K" "$T10"
run "Deep nesting 20K" "$T11"
run "Mixed workload 10K" "$T12"Resource Footprint
The Line Editor
Custom terminal line editor: no readline, no libedit. Raw termios, custom cursor management, bracketed paste support.
- Syntax highlighting as you type: green for valid commands, red for missing, cyan for flags, magenta for variables, yellow for strings
- Autosuggestions: ghost text from history + Nushell-style dropdown menu
- Auto-pairing: brackets and quotes auto-close, backspace deletes both
- Magic space:
!!+ space expands to the last command inline - Undo: Ctrl+_ with a 64-state deep stack
▶Key bindings
| Shortcut | Action |
|---|---|
| Tab | Context-aware completion |
| Ctrl+R | Fuzzy reverse history search |
| ↑ / ↓ | Navigate suggestion menu / history |
| → / End | Accept full autosuggestion |
| Alt+→ | Accept one word |
| Ctrl+A / Ctrl+E | Start / end of line |
| Ctrl+U / Ctrl+K | Kill to start / end |
| Ctrl+W | Kill word backward |
| Escape | Dismiss suggestion menu |
Fully remappable with bindkey. 14 built-in widgets.

Tab Completion
Context-aware with fuzzy scoring. Two-pass: strict prefix first, then fuzzy fallback with a 9-factor weighted algorithm.


Built-in completion data for 15+ tools: git, docker, apt, ssh, systemctl, rg, fd, tmux, gh, jq, fzf, stow, make, npm, kubectl, compiled directly into the binary, no subprocess calls needed.
History & Navigation
Smart History
SQLite-backed with frecency scoring (frequency × recency), per-directory context, and duration tracking.
history # show with timestamps
Ctrl+R # fuzzy reverse search (9-factor scoring)
fc -l # list entries
fc -e vim # edit and re-executeFull ! expansion: !!, !$, !^, !*, !n, !-n, !str, !?str?, ^old^new. With histverify, expansions are loaded into the editor for review before executing.
Navigation
cd /path # standard
/some/path # auto-cd: just type a directory name
... # expands to ../..
z proj # frecency jump to most-visited match
zi # interactive fuzzy directory picker
Scripting
Full POSIX sh compatible control structures plus zsh and Nushell extensions.
if [[ -f config.yaml ]]; then source config.yaml; fi
for f in *.c; do gcc -c "$f"; done
for (( i=0; i<10; i++ )); do echo "$i"; done
while [[ $retry -gt 0 ]]; do try_connect && break; (( retry-- )); done
select opt in "Build" "Test" "Deploy" "Quit"; do
case $opt in Build) make ;; Quit) break ;; esac
done# zy-native named parameters
def greet(name, greeting) { echo "$greeting, $name!" }
def --env setup(dir) { cd "$dir"; export ROOT="$PWD" }
# POSIX / bash / zsh syntax all work
greet() { echo "Hello, $1!"; }
() { local tmp="scoped"; echo "$tmp"; } # anonymous function# Nushell-inspired match
match $status {
200 => { echo "OK" }
404 => { echo "Not found" }
_ => { echo "Status: $status" }
}
# case with 3 fall-through modes: ;; / ;& / ;;&
case $input in *.tar.gz) tar xzf "$input" ;; esactry {
mount /dev/sda1 /mnt
do_risky_operation
} catch {
echo "Error: $error"
} finally {
umount /mnt
}27 parameter expansion forms matching zsh: ${#var}, ${var:-default}, ${var//pat/repl}, ${var:offset:length}, ${var^^}, ${(s:d:)var}, and more.
Globbing
Standard globs plus extended patterns and zsh-style qualifiers:
*.c # wildcard
**/*.h # recursive globstar
{a,b,c} # brace expansion
^pattern # negation
*.c~test* # exclusion
*(.) # regular files only (qualifier)
*(/) # directories only
*.c(:r) # remove extension (modifier)Built-in .gitignore support via setopt globfilter gitignore.
Files & Directories
zy follows XDG conventions and keeps a clean separation between configuration, data, and system-wide policy. Here is everything it touches on disk.
Configuration Files
| Path | Format | Purpose |
|---|---|---|
~/.zyrc | Shell script | Main config — auto-loaded on every interactive startup. Stores config set commands, aliases, theme, prompt style. Respects $ZDOTDIR/.zyrc if set. Editable via config edit. |
~/.zy/features.conf | Key=value | Persists feature toggle state (audit, policy, smart-history, stats, syntax-hl, autosuggestions, git-prompt, plugins, skills) |
~/.zy/keybindings | Plain text | Custom key bindings saved by bindkey --save, restored by bindkey --load |
~/.zy/disabled_plugins | Plain text list | Tracks which plugins have been disabled |
~/.inputrc | Readline-compatible | Read-only — zy imports compatible bindings for familiarity |
User & system config
SQLite Databases
SQLite is the only external dependency. Four databases live under ~/.local/share/zy/, all using WAL mode for crash safety.
| Path | Purpose | Key Columns / Notes |
|---|---|---|
~/.local/share/zy/history.sqlite | Smart command history | command, cwd, timestamp, exit code, duration, session ID. Powers frecency ranking, per-directory context, and Ctrl+R fuzzy search. |
~/.local/share/zy/audit.sqlite | Tamper-evident audit ledger | command, cwd, user, exit code, duration, timestamp, risk level, session ID, device fingerprint, SHA-256 hash chain. Verified end-to-end with audit verify. |
~/.local/share/zy/zyjump.db | Directory jump rankings | path, frecency score, last access. Powers z and zi directory jumping. |
~/.local/share/zy/bookmarks.db | Pinned directory bookmarks | name, path. Managed via j @name, j --bookmark. |
SQLite database files
Plain Text History
| Path | Format | Purpose |
|---|---|---|
~/.zy_history | One command per line | zsh-compatible flat history file. Exists alongside the SQLite history for backwards compatibility and tools that expect a text file. |
Flat history file
Directories
| Path | Purpose |
|---|---|
~/.zy/ | Top-level user config directory |
~/.zy/plugins/ | Plugin autoload — each plugin is a subdirectory with init.zy + manifest.zy (or a single *.zy file) |
~/.zy/skills/ | Skill recipes — each skill is ~/.zy/skills/<name>/ with run.zy + manifest.zy |
~/.zy/completions/ | Custom completion scripts, sourced by compinit |
~/.local/share/zy/ | XDG data directory — houses all four SQLite databases and the font-check marker |
~/.local/share/fonts/ | Nerd Font TTF files installed by the first-run font setup |
Runtime directories
System-Wide Files
| Path | Format | Purpose |
|---|---|---|
/etc/zy/policy.conf | Policy rules | System-wide deny/warn/audit/rate_limit/restrict rules. Loaded automatically; can also be specified with --policy. |
/etc/zyprofile | Shell script | System-wide login profile, sourced on login shell startup (like /etc/profile) |
/etc/shells | Text list | System shell registry — the .deb package adds /usr/bin/zy here so chsh recognizes it |
System paths
Login Shell Profiles
| Path | Notes |
|---|---|
/etc/profile | Standard POSIX login profile |
/etc/zyprofile | zy-specific system profile |
~/.profile | Standard user profile |
~/.zy_profile | zy-specific user login profile |
~/.zyrc | Always loaded last (interactive sessions) |
Login profiles (sourced on login shell startup, in order)
Installed Binaries
| Path | Description |
|---|---|
/usr/bin/zy | Primary binary |
/usr/bin/zyvrixsh | Symlink to /usr/bin/zy |
/usr/local/bin/zy | Symlink to /usr/bin/zy (for editors and scripts that search /usr/local/bin) |
/usr/local/bin/zyvrixsh | Symlink to /usr/bin/zy |
/usr/share/zy/setup-font.sh | Bundled Nerd Font installer |
Installed executables and scripts
Marker Files
| Path | Purpose |
|---|---|
~/.local/share/zy/.font-checked | Empty file — created after first-run font detection to prevent re-prompting on every startup |
State markers
▶Full directory tree
- ~/ (home)
- .zyrc — main config (shell script, auto-loaded)
- .zy_history — flat text history (zsh-compatible)
- .zy_profile — login profile (optional)
- .zy/
- features.conf — feature toggles (key=value)
- keybindings — custom key bindings
- disabled_plugins — disabled plugin list
- plugins/
- <name>/
- init.zy — entry point
- manifest.zy — metadata
- <name>/
- skills/
- <name>/
- run.zy — skill script
- manifest.zy — metadata
- <name>/
- completions/ — custom completion scripts
- .local/share/zy/
- history.sqlite — frecency command history (SQLite)
- audit.sqlite — SHA-256 hash-chain audit log (SQLite)
- zyjump.db — directory jump rankings (SQLite)
- bookmarks.db — pinned directory bookmarks (SQLite)
- .font-checked — font detection marker (empty)
- .local/share/fonts/ — Nerd Fonts installed by first-run setup
- /etc/
- zy/
- policy.conf — system-wide policy rules
- zyprofile — system-wide login profile
- shells — shell registry (chsh reads this)
- zy/
- /usr/bin/
- zy — shell binary
- zyvrixsh — symlink → zy
- /usr/local/bin/
- zy — symlink → /usr/bin/zy
- zyvrixsh — symlink → /usr/bin/zy
- /usr/share/zy/
- setup-font.sh — Nerd Font installer
Configuration
customize # interactive 4-step wizard with live preview
config set theme neon
config set prompt_style edge
config list # show all 50+ settings
▶Key configuration options
| Key | Default | Description |
|---|---|---|
prompt_style | aura | Prompt layout (aura/edge/flux/bare/classic) |
theme | ether | Color theme name |
show_git | true | Git status pill |
show_lang | true | Language/project detection |
show_commit_hash | true | Git commit hash in prompt |
show_exec_time | true | Command duration |
suggest_auto_show | true | Auto-show suggestion dropdown |
syntax_highlighting | true | Real-time command coloring |
transient_prompt | false | Collapse previous prompts |
Per-pill customization: pill_dir_bg, pill_git_fg, pill_user_shape, etc. 7 shapes, 4 fonts, opacity 20–100%.
Help System
390+ help entries covering all 356+ builtins, organized into 30 categories. Built into the binary, no man pages, no external files.

help # overview
help --all # everything
help <command> # detailed usage
help --search <word> # full-text searchTesting & Developer Tools
Eight subsystems built into the shell — no plugins, no external dependencies. Every feature ships in the same 5 MB binary.
Built-in Test Framework
Write assertions inline or in .zytest files and run them with test-run:
assert-eq (1 + 1) 2 # pass — values match
assert-true (echo hello | str contains "hello")
assert-type "42" "int" # type checking
assert-error { bad-command } # expects failure
test-run tests/math.zytest # run a test file, report pass/fail/skipTerminal Visualization
Render data directly in the terminal — no external plotting tools needed:
[3, 7, 2, 9, 5, 1, 8] | sparkline # ▃▇▂█▅▁▇
seq 1 5 | wrap value | chart bar # vertical bar chart
curl -s api/progress | progress --total 100 # ████████░░░░ 67%Script Debugger
dbg script.zy launches an interactive debugger with gdb-style commands:
| Command | Action |
|---|---|
b 5 | Set breakpoint at line 5 |
n / s | Step over / step into |
c | Continue |
p $var | Print variable |
bt | Stack trace |
q | Quit debugger |
Cheatsheet Engine
50+ built-in cheatsheets, searchable with cheat <topic> or the Ctrl+H popup:
cheat git # common git recipes
cheat tar # tar flags you always forget
cheat zy-pipe # zy pipeline operatorsFile Watcher, Task Runner, Session Recording
fs-watch src/ --glob "*.c" --exec "make" # rebuild on file change
task build # run task from .zytasks
record --output demo.json # start recording
replay demo.json # replay session
env-save work && env-restore work # snapshot/restore envAlso Included
- Aliases: regular, global (
-g, expands anywhere), suffix (-s, maps file extensions to handlers) - Job control: full POSIX:
fg,bg,wait,disown, process groups,Ctrl+Z - Plugin system: auto-loads
.sofrom~/.zy/plugins/, plugins register builtins - Shell options:
errexit,nounset,xtrace,pipefail,noclobber,correct, 59 total - I/O: all POSIX redirections +
&>,<<<,<(),>() - zsh compat:
emulate,zmodload,strftime,zstat,compinit,autoload, and more - "Did you mean?": Damerau-Levenshtein suggestions on command-not-found
- Nerd Font detection: auto-detects installed Nerd Fonts, falls back to Bare style if missing
- Built-in test framework:
assert-eq,assert-ne,assert-true,assert-false,assert-error,assert-type, andtest-runfor running.zytestfiles - Terminal visualization:
sparkline,chart(bar/horizontal),progressbar — all in-shell, no external tools - Cheatsheet engine:
cheatcommand with 50+ built-in cheatsheets,Ctrl+Hpopup in the line editor - Script debugger:
dbglaunches an interactive debugger with breakpoints, step, continue, variable inspection, and stack traces - File watcher:
fs-watchuses inotify to watch files/directories with glob patterns, debounce, and callback commands - Task runner:
taskreads.zytasksfiles with dependency resolution — a built-in Make alternative for shell workflows - Session recording:
record/replaycaptures full pipeline I/O to JSON for auditing, demos, or debugging - Environment snapshots:
env-save/env-restore/env-snapshots— snapshot and restore environment state across sessions
Design Decisions
▶Why C?
Direct access to fork, pipe, dup2, tcsetpgrp, and sigaction without abstraction layers. Keeps the binary small (5 MB) and startup fast (2 ms).
▶Why a custom parser?
Deterministic error recovery, precise control over error messages, zero build-time dependencies. Recursive descent maps naturally to shell grammar.
▶Why SQLite?
Crash-safe (WAL mode), atomic writes, structured queries. One dependency powers three subsystems: audit ledger, frecency history, and directory jump rankings.
▶Why a structured data pipeline?
Nushell proved typed pipelines are better than parsing text with awk. But Nushell breaks POSIX compatibility. zy gives the same structured pipeline experience inside a shell that still runs existing bash scripts.
This project was developed with an AI coding assistant throughout: architecture decisions, code generation, debugging, test writing, and documentation.
Download
Download zy from Google Drive
Latest .deb and .tar.gz packages, v1.0.9