Documentation Index
Fetch the complete documentation index at: https://mintlify.com/wevm/incur/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Incur uses Zod schemas to validate inputs and outputs. Schemas enable:
- Automatic validation — inputs are parsed before
run() executes
- Type inference — TypeScript infers types from schemas with zero manual annotations
- Error reporting — validation errors include field-level details
- Schema composition — reuse schemas across commands
Importing Zod
Incur re-exports Zod, so you can import z directly from incur:
import { Cli, z } from 'incur'
Arguments Schema
The args schema defines positional arguments. Keys define the order arguments are parsed from the command line.
cli.command('copy', {
args: z.object({
source: z.string().describe('Source file'),
dest: z.string().describe('Destination file'),
}),
run(c) {
// c.args.source and c.args.dest are typed as string
return { copied: `${c.args.source} → ${c.args.dest}` }
},
})
$ my-cli copy file.txt backup.txt
copied: file.txt → backup.txt
Optional Arguments
Use .optional() to make an argument optional:
args: z.object({
package: z.string().optional().describe('Package name'),
})
Default Values
Use .default() to provide a fallback value:
args: z.object({
env: z.enum(['staging', 'production']).default('staging'),
})
Options Schema
The options schema defines named flags. Options are parsed from --name value or --name (for booleans).
cli.command('deploy', {
args: z.object({
env: z.enum(['staging', 'production']),
}),
options: z.object({
force: z.boolean().optional().describe('Overwrite existing deployment'),
dryRun: z.boolean().default(false).describe('Preview changes without deploying'),
}),
run(c) {
// c.options.force: boolean | undefined
// c.options.dryRun: boolean
return { deployed: !c.options.dryRun }
},
})
$ my-cli deploy staging --force
deployed: true
$ my-cli deploy production --dry-run
deployed: false
Boolean Options
Boolean options are flags that don’t require a value:
options: z.object({
verbose: z.boolean().default(false),
})
Use --no- prefix to negate:
$ my-cli run --no-verbose
String Options
String options require a value:
options: z.object({
output: z.string().describe('Output file path'),
})
$ my-cli build --output dist/bundle.js
Number Options
Number options are automatically coerced:
options: z.object({
port: z.number().default(3000).describe('Server port'),
})
$ my-cli serve --port 8080
Enum Options
Use z.enum() for a fixed set of values:
options: z.object({
format: z.enum(['json', 'yaml', 'toml']).default('json'),
})
$ my-cli export --format yaml
Array Options
Use z.array() to collect multiple values:
options: z.object({
include: z.array(z.string()).describe('Files to include'),
})
$ my-cli build --include src/a.ts --include src/b.ts
Kebab-Case to camelCase
Incur automatically maps kebab-case flags to camelCase schema keys:
options: z.object({
saveDev: z.boolean().optional(),
})
$ my-cli install --save-dev
# Parsed as c.options.saveDev = true
Environment Variables Schema
The env schema validates environment variables. Keys are the variable names (e.g. NPM_TOKEN).
cli.command('deploy', {
args: z.object({
env: z.enum(['staging', 'production']),
}),
env: z.object({
DEPLOY_TOKEN: z.string(),
API_BASE: z.string().default('https://api.example.com'),
}),
run(c) {
// c.env.DEPLOY_TOKEN: string
// c.env.API_BASE: string
return { url: c.env.API_BASE, token: c.env.DEPLOY_TOKEN }
},
})
If DEPLOY_TOKEN is not set, incur raises a validation error before run() executes.
Output Schema
The output schema validates the return value from run(). This ensures the command always returns data in the expected shape.
cli.command('deploy', {
args: z.object({
env: z.enum(['staging', 'production']),
}),
output: z.object({
url: z.string(),
duration: z.number(),
}),
run(c) {
// Return value must match output schema
return {
url: `https://${c.args.env}.example.com`,
duration: 3.2,
}
},
})
If the return value doesn’t match, incur raises a validation error.
Type Inference
Incur infers types from schemas automatically. No manual type annotations are required.
cli.command('greet', {
args: z.object({
name: z.string(),
}),
options: z.object({
loud: z.boolean().default(false),
}),
output: z.object({
message: z.string(),
}),
run(c) {
c.args.name // inferred as: string
c.options.loud // inferred as: boolean
return {
message: `hello ${c.args.name}`, // inferred as: string
}
},
})
Type errors are caught at compile time:
run(c) {
return { message: 123 } // ❌ Type error: expected string
}
Schema Composition
Reuse schemas across commands:
import { Cli, z } from 'incur'
// Shared schemas
const envArg = z.object({
env: z.enum(['staging', 'production']).describe('Target environment'),
})
const deployEnv = z.object({
DEPLOY_TOKEN: z.string(),
})
const cli = Cli.create('my-cli', { description: 'My CLI' })
cli
.command('deploy', {
args: envArg,
env: deployEnv,
run(c) {
return { deployed: c.args.env }
},
})
.command('rollback', {
args: envArg,
env: deployEnv,
run(c) {
return { rolledBack: c.args.env }
},
})
.serve()
Schema Extensions
Extend schemas with .merge() or .extend():
const baseOptions = z.object({
verbose: z.boolean().default(false),
})
const deployOptions = baseOptions.extend({
force: z.boolean().optional(),
})
cli.command('deploy', {
options: deployOptions,
run(c) {
// c.options.verbose: boolean
// c.options.force: boolean | undefined
return { deployed: true }
},
})
Validation Errors
When validation fails, incur provides detailed field-level errors:
$ my-cli deploy
Error: missing required argument <env>
See below for usage.
my-cli deploy — Deploy to an environment
Usage: my-cli deploy <env>
Arguments:
env Target environment
In non-TTY mode (agents), errors include machine-readable field details:
{
"ok": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Required",
"fieldErrors": [
{
"path": "env",
"expected": "string",
"received": "undefined",
"message": "Required"
}
]
}
}
Descriptions
Use .describe() to add human-readable descriptions shown in help output:
args: z.object({
name: z.string().describe('Name to greet'),
}),
options: z.object({
loud: z.boolean().default(false).describe('Use uppercase'),
})
$ my-cli greet --help
Usage: my-cli greet <name>
Arguments:
name Name to greet
Options:
--loud Use uppercase
Deprecated Options
Mark options as deprecated with .meta({ deprecated: true }):
options: z.object({
zone: z.string().optional().describe('Availability zone').meta({ deprecated: true }),
region: z.string().optional().describe('Target region'),
})
Deprecated flags show [deprecated] in --help and emit a warning when used:
$ my-cli deploy --zone us-east-1
Warning: --zone is deprecated
Next Steps
Output
Learn about output formats and CTAs
Zod Documentation
Explore Zod’s full schema API