Skip to main content
Single-command CLIs are perfect for utilities that perform one specific task. Instead of registering subcommands, you pass the run handler directly to Cli.create().

When to Use Single-Command Pattern

Use this pattern when your CLI:
  • Performs a single, focused task
  • Doesn’t need subcommands or command groups
  • Has a simple input/output flow
Examples: greet, convert, validate, ping

Basic Single-Command CLI

1
Import incur
2
Start by importing Cli and z from incur:
3
import { Cli, z } from 'incur'
4
Define the CLI with run
5
Pass the run handler directly to Cli.create():
6
Cli.create('greet', {
  description: 'A greeting CLI',
  args: z.object({
    name: z.string().describe('Name to greet'),
  }),
  run(c) {
    return { message: `hello ${c.args.name}` }
  },
}).serve()
7
Run the CLI
8
greet world
# → message: hello world

Adding Arguments

Define positional arguments using a Zod schema. Arguments are parsed in the order they appear in the schema:
Arguments are always required unless marked with .optional(). Use z.coerce.number() or z.coerce.boolean() to parse string input from the command line.

Adding Options

Options are named flags that users pass with --flag syntax:

Option Aliases

Create short aliases for options:

Output Handling

The return value from run is automatically formatted and displayed to the user.

Default Output (TOON)

By default, incur uses TOON format - a compact, token-efficient format:

Async Handlers

Handlers can be async:

Error Handling

Use c.error() for structured errors:
Or throw an IncurError:

Context Properties

The run handler receives a context object with:
  • c.args - Parsed positional arguments
  • c.options - Parsed option flags
  • c.name - The CLI name (useful for help messages)
  • c.agent - true if called by an agent (stdout is not a TTY)
  • c.env - Parsed environment variables (if env schema is defined)
  • c.var - Variables set by middleware
  • c.ok(data, meta?) - Return success with optional CTAs
  • c.error(options) - Return an error

Built-in Help

Help is generated automatically from your schemas:

Complete Example

Here’s a complete single-command CLI with all features:
If you need subcommands, use the multi-command pattern instead. Don’t pass both run and .command() calls - they have different purposes.