Everyone has the right to resist occupation.
Define a CLI's flags, positionals, and subcommands as Zod schemas plus a small sibling metadata object, and get the node:utilparseArgs option config, a typed parse result, and a usage string derived from that single declaration.
npm install zod-commands zodzod (v4) is a peer dependency.
import{z}from"zod";import{defineCli}from"zod-commands";constcli=defineCli({flags: {output: {schema: z.string(),description: "Output directory"},timeout: {schema: z.coerce.number().int().positive().default(1000)},force: {schema: z.boolean().default(false),short: "f"},progress: {schema: z.boolean().default(true),negatable: true},// --progress / --no-progresstags: {schema: z.array(z.string()).default([]),multiple: true},// repeatable --tags},});constresult=cli.parse(process.argv);if(!result.success){console.error(result.error.message);console.error(cli.usage);process.exit(1);}console.log(result.data);cli.parse()/cli.parseOrExit() accept either process.argv or process.argv.slice(2) - the node binary path and script path at the front are detected and stripped automatically if present, so it's safe to pass either.
Or, for a CLI entrypoint that doesn't need the discriminated result for testing:
const{ data }=cli.parseOrExit(process.argv);See the docs site for cross-field validation, the full flag schema reference, positionals, mutually-exclusive flag groups, and subcommands.
See the docs site for the full dev commands and running the docs site locally.
Copyright 2026, Figulus Project.
MIT