my-cli pr list or docker container ls.
When to Use Sub-Commands
Use sub-commands when you need:- Logical grouping - Group related operations (e.g., all PR commands under
pr) - Namespace separation - Keep command names short without conflicts
- Modular organization - Split large CLIs into separate modules
- Deep hierarchies - Create multi-level command trees
git remote add, docker container stop, gh pr create
Creating Command Groups
1
Create the root CLI
2
Start with a router CLI:
3
import { Cli, z } from 'incur'
const cli = Cli.create('my-cli', {
description: 'My CLI',
})
4
Create a separate group CLI
5
Create another
Cli instance for the group:6
const pr = Cli.create('pr', {
description: 'Pull request commands',
})
7
Add commands to the group
8
pr.command('list', {
description: 'List pull requests',
options: z.object({
state: z.enum(['open', 'closed', 'all']).default('open'),
}),
run(c) {
return { prs: [], state: c.options.state }
},
})
9
Mount the group
10
Mount the group on the root CLI:
11
cli
.command(pr) // Mount the entire pr group
.serve()
Complete Example from README
Here’s the complete PR group example from the incur README:Usage
Help Text
Multiple Commands in a Group
Add multiple commands to create a rich command group:Multiple Groups
Mount multiple command groups on the root CLI:Nested Command Hierarchies
You can nest groups multiple levels deep:Output Policy Inheritance
Groups can set output policies that inherit to all child commands:my-cli internal sync in a terminal, they won’t see the output data (but agents will receive it via --json or --format).
Override per Command
Middleware Inheritance
Groups can register middleware that runs for all child commands:Middleware runs in order: root CLI → groups (in traversal order) → per-command. Each level’s middleware wraps the next.

