The zcli CLI

The meta-CLI you install with curl | sh scaffolds projects, restructures commands, watches builds, and cuts releases. It is itself a zcli app — every command below is a file in its own commands/ directory, running on the framework’s own help, completions, “did you mean?”, and self-upgrade plugins. It’s a build-time tool: your finished CLI never depends on it.

zcli
├── init         scaffold a new project
├── add          command · group · arg · option · plugin
├── rm           command · arg · option
├── mv           move/rename a command
├── tree         show the command tree (no build needed)
├── dev          watch, rebuild, optionally re-run
├── guide        version-matched reference, by topic
├── release      version-bump, tag, and push a release
├── gh           add workflow ci · release — GitHub Actions scaffolds
└── upgrade      self-update from GitHub releases

zcli init

zcli init myapp --description "My awesome CLI"
zcli init .    # initialize the current directory

Scaffolds a complete project — build.zig.zon, a build.zig wired with zcli.generate, src/main.zig, a README, an example command — then verifies its own output: it fetches dependencies and runs zig build, so the first command you type runs your CLI, not the compiler. It also initializes a git repository with a Zig .gitignore and an initial commit (skipped when git is absent or you’re already inside a work tree).

On a TTY, init is a short wizard — every step has a sensible default:

  1. Description — one line that anchors every --help render.
  2. CLI shapemulti (subcommands, git style — the default) or single (the app itself is the command, rg style; see single-command CLIs). Asked up front because restructuring between shapes later is annoying.
  3. Plugins — multi-select of the built-ins (help, version, and not-found are preselected). Selecting github_upgrade gets a follow-up prompt for the OWNER/REPO it pulls releases from — defaulted from your git remote when running zcli init . in an existing repo — no TODO: placeholders in generated code.
  4. GitHub Actions — optionally scaffold the ci and/or release workflows (release is preselected when github_upgrade was chosen — it completes the self-update loop).
  5. Summary + confirm — one block showing every decision before anything touches disk.

Every prompt has a flag, so agents and scripts get the identical surface:

zcli init <name|.>
  --description <text>        --app-version <semver>
  --template <multi|single>   --plugins <list|none>
  --upgrade-repo <owner/repo> (github_upgrade config)
  --no-git                    --github <ci,release|none>
  --no-build                  --yes / --defaults
  --dry-run                   (print the plan, write nothing)

Any flag answers its prompt; --defaults answers every remaining prompt with its default (implied when stdin isn’t a TTY); --yes additionally skips the confirm; --dry-run prints the summary and file list and exits without writing.

Every scaffold also includes an AGENTS.md with a marker-delimited zcli section pointing coding agents at zcli guide — re-running init refreshes just that section, never clobbering the rest of the file. See AI agents.

zcli add / rm / mv

Structure changes are mechanical edits — these commands splice command files via an AST engine that keeps struct fields, meta entries, and argument ordering in sync, and preserves your hand-written execute body.

zcli add command users/create -d "Create a user"   # wizard when run bare on a TTY
zcli add group users -d "Manage users"             # a directory + index.zig
zcli add arg users/create name --type []const u8   # positional, spliced into Args
zcli add option users/create admin --type bool --default false --short a
zcli add plugin timing                             # skeleton in src/plugins/

zcli rm option users/create admin                  # one or more names, atomic
zcli rm arg users/create name
zcli rm command users/create                       # removes file, tidies empty dirs

zcli mv users/create people/new                    # move/rename, creates/tidies groups

Details worth knowing:

  • add arg--multiple makes a variadic (last position only), --nullable an optional, --before/--after control placement; ordering rules (required → optional → variadic) are validated on every edit.
  • add option — omit --default on a non-nullable scalar to create a required option; --multiple builds an array option; --short claims a one-letter flag.
  • rm arg/rm option — take several names and apply all-or-nothing; a typo rejects the whole batch rather than half-editing a file.

zcli tree

zcli tree                  # the discovered hierarchy, with descriptions
zcli tree --show-options   # plus each command's args & options signature

Reads command structure straight from source (std.zig.Ast) — no build required — using the same discovery rules as the framework itself. The output is ANSI-free on purpose: it’s the read-back format agents and scripts consume.

zcli dev

zcli dev                          # watch src/, rebuild on change
zcli dev -- ./zig-out/bin/myapp serve   # …and (re)run this after each build

Native file watching (FSEvents/kqueue/inotify) with an ~80 ms debounce to coalesce editor bursts. With -- <cmd>, the spawned process is killed and restarted after each successful rebuild; status lines go to stderr so redirecting stdout stays clean.

zcli guide

zcli guide            # list topics
zcli guide structure  # a worked example for one topic

A version-matched reference: the content ships inside the binary and matches the zcli you’re compiling against, so it can’t drift the way training data or old blog posts do. Topics: structure, sharing, storage, arena, output, prompts, ui, http, secrets, plugins, testing.

zcli release & zcli gh

The release workflow lives in the meta-CLI too — versioning, tagging, CI scaffolding:

zcli gh add workflow ci        # once: build + test on every push/PR
zcli gh add workflow release   # once: scaffold .github/workflows/release.yml
zcli release patch             # bump, test, tag, push — CI builds & publishes

(zcli init can scaffold both workflows up front — the extras step, or --github ci,release.)

Full walkthrough, including binary signing and self-upgrade for your users: Ship & distribute.

zcli upgrade

The meta-CLI updates itself from GitHub releases — zcli upgrade (or --check), with minisign-verified artifacts. Your own CLI can offer the same command by enabling the github_upgrade plugin.