zmax
September 5, 2026 · View on GitHub
███████╗███╗ ███╗ █████╗ ██╗ ██╗
╚══███╔╝████╗ ████║██╔══██╗╚██╗██╔╝
███╔╝ ██╔████╔██║███████║ ╚███╔╝
███╔╝ ██║╚██╔╝██║██╔══██║ ██╔██╗
███████╗██║ ╚═╝ ██║██║ ██║██╔╝ ██╗
╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
[POWERFUL CLI IDE // VIM · EMACS · SPACEMACS SUPERSET]
zmax
A modal IDE in Rust
Design goal: a maximally powerful CLI IDE with zero user configuration.
Install the binary, open a project, and get the full power of a graphical IDE
in the terminal — LSP, a debugger, tree-sitter, fuzzy file picker, project
tree, a real PTY terminal, magit-style git, run configs, and twelve embedded
scripting languages — all in one static binary, working on first launch with no
init.el, no plugin manager, and no setup ritual. The reference workflows are
Spacemacs and JetBrains: the same keys you already press should do the
same thing here. See docs/vision.md for the full design goal
and an honest, source-derived account of how far it's met.
zmax targets vim/emacs semantics. The keymap presets — spacemacs (default), hybrid,
vim, helix, kakoune, micro, nano, emacs and cua — are
selectable with keymap = "..." in config.toml or
:keymap <name> at runtime (the list is keymap::PRESETS; the book's
configuration page describes what
each one starts in and where its leader lives). The default spacemacs keymap is vim keys (the keys
you press are the keys vim binds, including operator-pending edits dd, dw,
cw, yy emulated on the Zmax engine) plus the SPC leader and the Emacs
C-x prefix — both open a which-key popup. The pure vim preset drops the
spacemacs layer (no SPC leader, no which-key, C-x is decrement). emacs and
JetBrains functionality is layered on top throughout.
Port report
Coverage is tracked by a port report measuring zmax against the
exhaustive, cited feature surface of the other terminal editors — Vim/Neovim,
Emacs and Spacemacs, plus kakoune, vis, sam, ed, nvi, vile, mg, nano, micro,
mcedit, ne, dte, the Neovim distributions (LazyVim, AstroNvim, LunarVim),
fzf.vim, JetBrains and Cursor. Every inventory item is parsed from that tool's
own primary source: the Neovim runtime docs, the GNU Emacs manual indexes,
kakoune's doc/pages, vile's cmdtbl, nano's src/global.c, mc's shipped
keymap, ne's texinfo manual, and so on — never hand-written.
Live numbers (denominator, ported, partial, per-source breakdown, and item
detail) are in the generated report — never hardcoded here, so they cannot go
stale: docs/port_report.md (styled HTML:
docs/port_report.html).
For the keybinding surface specifically (vim/neovim normal/visual/insert
keys, the Emacs Key Index, and the Spacemacs SPC tree — excluding
ex-commands, options, functions and M-x), see the focused
docs/keybinding_report.md (styled HTML:
docs/keybinding_report.html).
The numerator is re-derived from zmax source on every run; the only curated
artifact is port/mapping.json, and every mapping must point at a real zmax
command — a mapping to non-existent code is flagged as broken, not counted. See
port/README.md for the methodology and the honesty
contract.
Regenerate:
python3 scripts/gen_port_report.py
Install
brew install MenkeTechnologies/menketech/zmax
Tagged releases (git tag vX.Y.Z && git push --tags) build per-target tarballs
(macOS arm64/x86_64, Linux arm64/x86_64) bundling the zmax binary with its
tree-sitter runtime (queries, themes, tutor), publish them to the GitHub
release, and bump the
homebrew-menketech
formula — see .github/workflows/release.yml. The tap update needs a
HOMEBREW_TAP_TOKEN repo secret (a PAT with write access to the tap).
Release builds do not clone or compile tree-sitter grammars: each grammar comes from its own upstream forge, so one forge being down aborted every target. Fetch and compile them once after install:
zmax -g fetch && zmax -g build
Embedded scripting
A world first: the only IDE to embed 12 scripting languages with zero external dependencies and no FFI between them — every interpreter is a pure-Rust crate compiled into the binary, sharing one host API rather than bridging through a C ABI.
zmax embeds twelve scripting interpreters in the binary, evaluated against the
live buffer: elisp (:elisp), vimscript (:vim), awk (:awk), plus
zsh (:zsh), stryke (:stryke), ruby (:ruby), php (:php),
python (:python), node (:node), arb (:arb), tcl (:tcl)
and R (:rlang) on unix.
SPC a r (or :repl) opens a REPL fronting all of them; ~/.zmax/init.el and
init.vim are sourced at startup. See
book/src/scripting.md.
Embedding earns its keep beyond scripting: the fzf.vim commands (:Files,
:Rg, …) are driven by arb's --fzf mode called as a library, so zmax's
fuzzy picker is a function call rather than a fork/exec of somebody else's
binary — while still honoring every $FZF_* variable and the user's existing
fzf configuration.
Polyglot pipelines
:xpipe filters a selection through a chain of those languages inside this
process — no fork, no execve, no pipe file descriptors:
:xpipe awk '{print \$2}' |> php 'echo strtoupper($stdin);' |> ruby 'stdin.reverse'
Stages are separated by a whitespace-delimited |> (a bare | is live syntax
in most of the twelve), each stage receives the previous one's output bound to
stdin in that language's own syntax, and the whole chain lands as one undo
step. Where :pipe spawns a shell per selection, an N-stage :xpipe chain is N
function calls into interpreters already linked into the binary.
Native plugins
Beyond the embedded interpreters, zmax hosts native (compiled Rust) plugins:
an ordinary cdylib loaded at runtime with :zmax-native load <path> — no editor
recompile, no script glue. A plugin registers typable :-commands over a frozen,
versioned C ABI (the zmax-native SDK crate) and can read/edit the
buffer, run command lines, and post status messages through the host API. Manage
loaded plugins with :zmax-native load|unload|list. See
zmax-native/README.md and the buildable examples in
zmax-native/examples (hello, insert-date, buffer-stats,
trim-trailing, banner).
Package manager
zmax has a built-in package manager for those native plugins — Helix, which zmax forks, ships none. Install a compiled plugin straight from a repo:
:zmax-native add owner/repo # clone, cargo build, install, load
:zmax-native add owner/repo@v1.2.0 # pin a tag/branch/commit
:zmax-native add path:./my-plugin # a local checkout (no network)
Installs land in a content-addressed global store at ~/.zmax/pkg/, SHA-256
pinned in ~/.zmax/pkg/installed.toml (the source of truth). Loading is by
mmap: :zmax-native load / add dlopens the store's cdylib, so the OS pages
the library in — it is never copied into a buffer. Put one line per plugin in
your config to self-install on first launch and load with zero network after:
:zmax-native get owner/repo # install if absent, else load from the store
:zmax-native sync # load every installed plugin
Full command surface: add (install, i), get (ensure), sync,
remove (rm, uninstall), registry (installed), info, update
(upgrade, up), gc [--dry-run], clean. A plugin repo may ship an optional
zmax-native.toml ([plugin]/[native]) to declare its name, version, and
build recipe; without one the kind is auto-detected from the tree. See
docs/PACKAGES.md.
Installable example plugins:
zmax-native-wc (:wc),
zmax-native-uuid (:uuid),
zmax-native-toc (:toc),
zmax-native-lorem (:lorem) —
each a standalone cdylib crate built against the zmax-native SDK.
Built-in TUIs
zmax ships a set of interactive terminal panels for tasks that usually mean leaving the editor:
- Snippet library (
:snippets) — a CRUD editor over reusable snippets stored insnippets.toml. Type a snippet's trigger word and pressTabto expand its body with live tab stops (${1:…}/$0); triggers are scoped per language. - Hex editor (
:hex) — a byte-faithful xxd-style viewer/editor; binary files open here automatically instead of being rejected, andCtrl-swrites the raw bytes back. - Merge & diff —
:diffshows the buffer against its gitHEAD, and:mergeopens a JetBrains-style 3-pane (ours/result/theirs) conflict resolver with a diff3 base pane;]n/[njump between conflict markers. - Magit-style git — interactive rebase, per-hunk staging, and branch/stash menus.
- GitHub browser (
:github) — the whole forge in nine tabs: CI runs with their jobs, steps and foldable logs (rerun, rerun-failed, cancel, dispatch, 8-second auto-refresh while a pipeline is live), workflows, pull requests with checks and diffs, issues, releases, branches, commits and your notification inbox. Authenticates through theghCLI when it is installed, else through$GITHUB_TOKEN. - Org-mode — outline folding,
TODOstate cycling, capture, and a date-aware agenda. - Transform library — 200+ selection-transform
:commands: JSON/CSV/TOML reshaping, number/stats ops, identifier-case conversion, encoders (Base32/Caesar/Morse/CRC32/rot47), extraction (URLs/emails/numbers), Markdown/typography, line ops (:align/:reflow/:dedup/:sort-by-field), and generators (:uuid/:lorem/:date/:seq) — each running on the selection (or whole buffer). When a transform needs real logic, drop to the embedded languages. - fzf.vim commands, with no fzf (
:Files,:Rg,:GFiles,:Buffers,:BLines,:Maps,:Colors, … underSPC F) — the picker isarb --fzfrunning in this process: nofork, noexec, nofzfbinary to install. It is a drop-in, so it reads$FZF_DEFAULT_OPTS_FILE,$FZF_DEFAULT_OPTS,$FZF_DEFAULT_COMMANDand the$FZF_CTRL_T_*pair, paints fzf's own palette, and exports theFZF_*variables (FZF_QUERY,FZF_PREVIEW_LINES,FZF_MATCH_COUNT, …) that preview commands read. A source command such asgit ls-filesis of course still a process; the picker is not. - IDE workbench (
:ide/F2) — a project file-tree, a tree-sitter structure outline, problems/run panels, and an error-stripe minimap; the whole layout persists to appdata. - Integrated terminal (
:terminal) — a PTY shell in a pane, with aC-\window leader for split/focus and click-to-focus across panes. - Comint shell (
comint_shellfrom the command palette, emacsM-x shell) — a line-oriented subprocess buffer: type a command,Enterruns it, output streams into the scrollback;M-p/M-nwalk the input history,C-cinterrupts,F12detaches. The dumb-terminal REPL model behind inferior-lisp /gud. - Help browser (
:help,SPC h h) — searchable across every command, key, and topic;SPC hdescribe-* routes symbol lookups through LSP hover. - Start screen — a startify-style recent-files page (frecency + MRU) shown on launch.
- Wildfire — press
<ret>in normal mode to select the closest text object and again to grow to the next enclosing one;<backspace>shrinks.
Embedded development (Arduino / PlatformIO)
zmax ports the Arduino IDE and PlatformIO IDE workflows by driving the same
command-line backends the official IDEs use — arduino-cli and pio — so no
GUI is needed. Per-project board settings (FQBN, serial port, baud, sketch dir,
PlatformIO environment, monitor filters) persist to
<project-dir>/embedded.toml; the leader menu is SPC a v.
- PlatformIO environment —
:pio-envselects the[env:…]fromplatformio.ini(no arg fuzzy-picks;-clears). Every project-scopedpioaction (build, upload, clean, test, check, debug, monitor, run targets) then targets that one environment via-e. - Build / flash —
:arduino-compile(Verify),:arduino-upload(compile + flash),:arduino-compile-export(Export Compiled Binary),:arduino-burn-bootloader;:pio-build,:pio-upload,:pio-clean,:pio-cleanall,:pio-test,:pio-check,:pio-size,:pio-list-targets. Compiler diagnostics land in the*compilation*list so:next-errorwalks avr-gcc/arm-gcc errors; uploads run live in a PTY panel. - Arduino compile options —
:arduino-compile-verbose(-v),:arduino-compile-quiet(-q),:arduino-compile-clean(--clean),:arduino-compile-jobs <n>(-j),:arduino-compiledb(--only-compilation-database, for the C/C++ LSP),:arduino-compile-warnings <none|default|more|all>,:arduino-compile-profile <name>(build against a sketch profile),:arduino-compile-debug-opt(--optimize-for-debug),:arduino-compile-board-options <opts>(custom board menu options),:arduino-compile-build-property <key=value>(override a build property, e.g.build.extra_flags=-DDEBUG),:arduino-compile-output-dir <dir>(save the compiled artifacts to a directory). Inspect the build without flashing::arduino-compile-properties(--show-properties),:arduino-compile-preprocess(--preprocess),:arduino-compile-dump-profile(--dump-profile). Upload options::arduino-upload-verbose(-v),:arduino-upload-verify(--verify),:arduino-upload-programmer <id>,:arduino-upload-dir <dir>/:arduino-upload-file <file>(flash a pre-built binary without recompiling). - PlatformIO build options —
:pio-build-verbose(-v),:pio-build-silent(-s),:pio-run-jobs <n>(parallel jobs),:pio-build-no-auto-clean,:pio-target <name>(anypio run -t), and:pio-upload-to <port>(flash to a specific port).:pio-exec [args…]builds and runs the native program (pio run -t exec), forwarding each argument as a--program-arg.:pio-upload-monitor [port]builds, flashes, then opens the serial monitor in one shot (pio run -t upload -t monitor) — PlatformIO IDE's "Upload and Monitor". - Test / analysis —
:pio-list-tests,:pio-test-filter <pattern>(run one suite),:pio-check-severity <low|medium|high>. Test options::pio-test-verbose,:pio-test-ignore <pattern>,:pio-test-without-building/-without-uploading/-without-testing,:pio-test-no-reset. Analysis options::pio-check-verbose,:pio-check-json,:pio-check-flags <flags>,:pio-check-fail-on <low|medium|high>,:pio-check-skip-packages,:pio-check-src-filters <pattern>,:pio-check-silent(-s).:pio-test-jsonand:pio-check-jsondump the test / analysis results as JSON to a scratch buffer;:pio-test-junit <path>/:pio-test-json-path <path>write CI reports.:pio-test-port <port>runs tests over a specific serial port,:pio-test-upload-port <port>flashes the test firmware to one, and:pio-test-monitor-dtr <0|1>/:pio-test-monitor-rts <0|1>set the post-test monitor line states. - PlatformIO build targets — the full
pio run -tsurface::pio-compiledb(generatecompile_commands.jsonfor the C/C++ LSP),:pio-buildfs/:pio-uploadfs(SPIFFS/LittleFS filesystem image),:pio-uploadeep,:pio-bootloader,:pio-fuses(AVR),:pio-nobuild(flash without rebuilding),:pio-envdump. - Serial —
:arduino-monitor/:pio-monitor(live PTY serial monitor) and:arduino-plotter/:pio-plotter, which graph the numbers streaming from the board (Arduino IDE Serial Plotter).:embedded-baud <rate>sets the rate.:arduino-monitor-raw(no output transformations) and:arduino-monitor-timestamp(timestamp each line),:arduino-monitor-quiet(suppress non-error diagnostics), and:arduino-monitor-describe(list the port's supported settings) tune the arduino-cli monitor;:pio-monitor-filter <name>(e.g.time,log2file,hexlify,send_on_enter),:pio-monitor-filters-clear,:pio-monitor-eol <CR|LF|CRLF>and:pio-monitor-parity <N|E|O|S|M>tune the PlatformIO monitor, as do:pio-monitor-rts <0|1>,:pio-monitor-dtr <0|1>,:pio-monitor-echo,:pio-monitor-raw,:pio-monitor-encoding <enc>,:pio-monitor-flow <none|rtscts|xonxoff>,:pio-monitor-reconnect <on|off>,:pio-monitor-quiet,:pio-monitor-exit-char <n>and:pio-monitor-menu-char <n>(all persisted per project and threaded into every monitor invocation). - Boards & ports —
:arduino-boards(pick FQBN),:arduino-ports/:pio-devices(pick serial port),:arduino-board-info,:pio-boards(Board Explorer),:pio-boards-installed(installed platforms only),:pio-boards-json(Board Explorer as JSON).:arduino-board-details-fulldumps the complete board detail for the selected FQBN.:pio-device-logicallists logical (disk) devices,:pio-device-mdnslists multicast-DNS / network (OTA) devices, and:pio-device-seriallists serial ports only.:arduino-board-list-watchwatches for boards connecting/disconnecting, and:arduino-board-programmerslists the programmers the selected board supports;:arduino-boards-hiddenlists every known board including platform-hidden variants. - Boards Manager —
:arduino-core-search,:arduino-board-search,:arduino-core-install,:arduino-core-download(fetch without installing),:arduino-core-list(:arduino-core-list-updatablefor upgradable ones,:arduino-core-list-allfor every installed platform),:arduino-core-uninstall,:arduino-core-update-index,:arduino-core-upgrade. - Library Manager —
:arduino-lib-search(search + install),:arduino-lib-search-names <query>(names-only), or:arduino-lib-install <name>(install by name),:arduino-lib-list(:arduino-lib-list-updatablefor upgradable ones,:arduino-lib-list-allincl. built-in),:arduino-lib-download,:arduino-lib-uninstall,:arduino-lib-upgrade,:arduino-lib-update-index,:arduino-lib-examples,:arduino-lib-deps,:arduino-lib-install-git <url>/:arduino-lib-install-zip <path>(install from a repo or archive),:arduino-lib-install-no-deps <name>(skip dependencies); PlatformIO packages via:pio-lib-search,:pio-lib-install,:pio-lib-list,:pio-lib-show,:pio-lib-uninstall,:pio-lib-update,:pio-lib-outdated.:pio-pkg-list-libraries/:pio-pkg-list-platforms/:pio-pkg-list-toolsscope the installed-package list to one kind. - arduino-cli config & cache —
:arduino-config(dump),:arduino-config-get/-set/-add/-remove/-delete/-init,:arduino-cache-clean,:arduino-completion <shell>. Build profiles::arduino-board-attach,:arduino-profile-create,:arduino-profile-set-default,:arduino-profile-lib-add <lib>/:arduino-profile-lib-remove <lib>.:arduino-daemonruns arduino-cli as a gRPC daemon and:arduino-versionreports the CLI version (--format json). - Debug —
:arduino-debug/:pio-debuglaunch the respective debuggers in a terminal panel;:arduino-debug-infoprints the debug config without starting a session and:arduino-debug-programmer <id>debugs through a programmer;:pio-debug-verbose,:pio-debug-interface <name>and:pio-debug-load-mode <always|modified|manual>tune the PlatformIO session. - Maintenance —
:arduino-update/:arduino-upgrade/:arduino-outdatedrefresh and upgrade cores + libraries together (:arduino-update-outdatedrefreshes then reports upgradable items in one step);:arduino-configdumps the active configuration;:pio-upgradeupgrades PlatformIO Core itself (:pio-upgrade-devtracks the development branch,:pio-upgrade-deps-onlyupgrades only its dependencies);:pio-system-info(:pio-system-info-jsonfor the JSON form),:pio-system-prune(drop unused caches/packages) with scoped variants:pio-prune-cache/:pio-prune-core/:pio-prune-platformand:pio-prune-dry-run(report without deleting),:pio-system-completion <shell>,:pio-settings-get/:pio-settings-set/:pio-settings-reset,:pio-ci <src> -b <board>(standalone CI build);:pio-homelaunches the PlatformIO Home GUI (--port,--host,--no-openpassed through). - Platforms & packages —
:pio-platform-install <spec>installs a development platform globally,:pio-tool-install <spec>a tool package (compilers, uploaders, debuggers);:pio-pkg-exec <argv>runs a tool from an installed package (e.g.esptool.py,openocd), the-c/--callform via:pio-pkg-exec-call <argv>, or a specific package via:pio-pkg-exec-pkg <pkg> <argv>(-p);:pio-pkg-show-type <pkg> <library|platform|tool>scopes registry details to a package type. Registry authoring via:pio-pkg-pack(-o <path>for the output),:pio-pkg-publish(extra args forward--owner/--type/--private/--no-notify),:pio-pkg-unpublish(:pio-pkg-unpublish-undo <pkg>restores it). Install options::pio-pkg-install-force <spec>(-f),:pio-pkg-install-global <spec>(-g),:pio-pkg-install-skip-deps <spec>(--skip-dependencies),:pio-lib-install-nosave <name>(--no-save);:pio-pkg-search-sort <query> <relevance|popularity|trending|added|updated>sorts registry search and:pio-pkg-search-page <query> <n>pages through it. Global package management::pio-pkg-list-global/:pio-pkg-update-global. - PlatformIO Remote — drive a remote agent:
:pio-remote-agent-start(forwards--name/--share/--working-dir) /:pio-remote-agent-list,:pio-remote-devices,:pio-remote-monitor(forwards-p/-b/-f/--eol/--socketc.),:pio-remote-run/:pio-remote-run-force(-r),:pio-remote-test,:pio-remote-update(--dry-run).:pio-remote-runand:pio-remote-testforward any extra flags (-t <target>,--upload-port,--test-port,-f/-i,--without-building/-uploading). - PlatformIO account & org —
:pio-account-login/-logout/-show(forwards--offline/--json-output) /-token(forwards--regenerate/--json-output) /-register/-password/-update/-forgot/-destroy; organizations:pio-org-list/-create/-add/-remove/-update/-destroy; teams:pio-team-list/-create/-add/-remove/-update/-destroy; registry access:pio-access-list/-grant/-revoke/-public/-private. - Sketches / projects —
:arduino-new-sketch,:arduino-sketch-archive(:arduino-sketch-archive-fullincludes the build output),:pio-init <board>,:pio-init-sample <board>(with example code),:pio-init-no-deps <board>(skip installing declared dependencies),:pio-init-env-prefix <prefix>(prefix generated env names),:pio-init-ide <ide>(generate IDE integration files),:pio-init-option <name=value>(seed aplatformio.inioption),:pio-build-conf <path>/:pio-test-conf/:pio-check-conf/:pio-debug-confrun those actions against an alternateplatformio.ini(-c, for CI/debug config variants).:pio-project-config(computed config),:pio-project-config-lint(validateplatformio.ini),:pio-project-metadata(IDE/LSP metadata dump);:pio-project-config-json/:pio-project-metadata-jsonemit the JSON form, and:pio-project-metadata-path <path>writes the metadata JSON to a file for external tooling. - Raw passthrough —
:pio <args…>and:arduino-cli <args…>(alias:acli) run any backend command in a terminal panel, so every subcommand, flag, and future capability of both CLIs is reachable even when it has no named command.
zwire colorscheme sync
With sync-zwire-theme = true under [editor], zmax bidirectionally syncs
its colorscheme with the zwire terminal
host, so the editor, the browser, and the HUD share one scheme. A native file
watcher on ~/.zwire/global.toml re-applies the matching zgui-<scheme> /
zgui-<scheme>-light theme the instant zwire's scheme changes — no keypress,
no focus event — and committing a zgui-* theme in zmax (:theme, the
picker, :theme-toggle) writes the scheme back into global.toml (touching
only scheme / ui.light), which zwire fans out to the browser and HUD. Only
the eight app-shell schemes round-trip; any other theme you pick stays local.
Defaults to off. See book/src/themes.md.
Build
cargo build --bin zmax
./target/debug/zmax
The toolchain floats to stable (see rust-toolchain.toml).
The embedded scripting languages live behind the scripting Cargo feature (on by
default). To build a leaner binary without them — dropping every interpreter
crate from the dependency graph — disable default features and keep git:
cargo build --bin zmax --no-default-features --features git
License
Zmax-derived source is licensed under the Mozilla Public License 2.0; see
LICENSE. Provenance and licensing details are in ATTRIBUTION.md.