CLI framework · Zig 0.16+

Your folder structure is your CLI.

Files become commands. Folders become subcommand groups. Structs become type-checked flags. Help text, completions, "did you mean?", prompts, progress bars, and docs — wired up at compile time for zero-cost dispatch.

$ curl -fsSL zcli.sh/install.sh | sh
0 runtime reflection 8 built-in plugins 8 prompt types 215 KB hello-world
myapp — zsh
$ myapp deploy api --env staging
Deploying api to staging

$ myapp dploy api
Error: unknown command 'dploy'
  Did you mean deploy? (run with --help)

$ myapp users create --help
USAGE  myapp users create <name> [options]
  -a, --admin     Grant admin role
      --output   json · table · plain
 generated from your command metadata
How it actually works

No routing table. No registration calls.

Hover a file to see the command it becomes. Dispatch is generated Zig code — there's no runtime filesystem scan, no reflection, nothing to register by hand.

src/commands/
├── deploy.zig
├── init.zig
└── users/
    ├── index.zig
    ├── create.zig
    └── list.zig
resulting CLI
$ myapp deploy api --env staging
Deploying api to staging
No routing table. No registration calls. Dispatch is generated Zig code.
See it run

A real recording, not a mockup.

Every file in the showcase task tracker on the left is a command — the recording on the right is that exact CLI running, with interactive prompts, a colored table, live search, and a spinner, captured from a real terminal with VHS. The highlighted files are the ones you see run.

tasks/src/commands/tree
src/commands/
├── add.zig
├── config.zig
├── done.zig
├── edit.zig
├── import.zig
├── init.zig
├── list.zig
├── remove.zig
├── search.zig
├── show.zig
├── sync.zig
└── sprint/
    ├── index.zig
    ├── close.zig
    ├── create.zig
    └── list.zig
tasks — recorded with vhs
Recording of the tasks showcase CLI: interactive prompts, a colored task table, live search filtering, and a spinner
Every frame is a real capture — the showcase lives in examples/showcase.
Type safety, demonstrated

Wrong types never compile.

Args and Options are plain Zig structs. Typo a field or reach for one that doesn't exist, and the build fails — naming the exact command file, not a runtime stack trace.

src/commands/deploy.zigzig
pub const Options = struct {
    env: []const u8 = "production",
};

pub fn execute(args: Args, options: Options, context: *Context) !void {
    try context.stdout().print(
        "target: {s}\n", .{ options.envv });
}
zig builderror
commands/deploy.zig:6:52: error: no field named 'envv' in struct 'commands.deploy.Options'
    try context.stdout().print("target: {s}\n", .{options.envv});
                                                           ^~~~
commands/deploy.zig:2:16: note: struct declared here
note: did you mean 'env'?
Numbers, not adjectives

What "batteries-included" costs you.

215 KB
ReleaseSmall hello-world
✓ v0.19.0
195 KB
static musl binary
✓ v0.19.0
libSystem
only macOS runtime dep
✓ v0.19.0
0
ANSI escapes with NO_COLOR set
✓ v0.19.0
3 OSes
CI, every commit
✓ v0.19.0
The meta-CLI

The tool that scaffolds your CLI is itself a zcli app.

zcli init, zcli add command, and zcli dev restructure your project without hand-editing struct fields or meta blocks. The same scaffolder writes an AGENTS.md for you — a version-matched reference at zcli guide that keeps AI coding agents from hallucinating stale APIs.

AI agents & AGENTS.md →
myapp — zsh
$ zcli init myapp
 Project 'myapp' created successfully!

$ zcli add command users/create
 Created src/commands/users/create.zig

$ zcli dev
watching src/ — rebuild on change…
Why not zig-clap, or zli?

Three tools, three different jobs.

zig-clap

An argument parser, and the lightest of the three. If flag parsing is all you need, it's a great choice.

zli

A batteries-included framework built around a runtime builder — commands assembled with Command.init() as the program starts.

zcli

The directory tree is the command tree, discovered at build time. Batteries extend past parsing into the whole terminal experience.

Full comparison →
Built with zcli

Dogfooded, not just demoed.

zcli — the meta-CLI

init, add, mv, rm, tree, dev, guide, and release are files in its own commands/ directory, running on the framework's own plugins.

tasks — showcase app

A fully functional task tracker: 14 commands, nested groups, every prompt type, themed output, config files, and doc generation.

Your project here — open a PR
Ready in two minutes

Stop wiring up arg parsers.

Add zcli to build.zig.zon, drop a file in commands/, and run zig build. That's the whole onboarding.