CAC
SkillProductivityGuides your agent to build and fix command-line tools using the CAC JavaScript library.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the CAC skill
About this capability
Build and maintain command-line interfaces with CAC. Use when a task involves the `cac` package, authoring or reviewing CLI apps, defining commands/options/arguments, generating help or version output, handling parse errors, or explaining CAC-specific behavior such as default commands, boolean negat
What this skill tells your AI
The instructions your AI receives, as published by cacjs/cac in skills/cac/SKILL.md and read by ahel’s review.
Use CAC to build small, expressive CLIs with a compact command grammar:
import { cac } from 'cac'
const cli = cac('my-cli')
cli
.command('build <entry> [...files]', 'Build project files')
.option('--minify', 'Minify output')
.action((entry, files, options) => {
console.info({ entry, files, options })
})
cli.help()
cli.version('1.0.0')
cli.parse()
Install with pnpm add cac.
Build CLIs This Way
- Choose the command shape first.
- Use global parsing only for tiny CLIs.
- Use
cli.command(...)for verb-based CLIs. - Use a default command when the main behavior should run without an explicit verb.
- Model positional arguments before options.
<arg>is required.[arg]is optional....is variadic and may only appear on the final positional argument.
- Attach options at the narrowest useful scope.
- Use
cli.option(...)for flags shared by multiple commands. - Use
command.option(...)for command-specific flags.
- Use
- Add
help()andversion()for user-facing tools. - Use plain
cli.parse()for simple flows; usecli.parse(argv, { run: false })plusawait cli.runMatchedCommand()when you need centralized or async error handling.
Syntax and Parsing
| Need | CAC form | Result |
|---|---|---|
| Required arg | build <entry> | action receives entry |
| Optional arg | build [entry] | action receives undefined when omitted |
| Variadic arg | build <entry> [...rest] | final action arg is an array |
| Boolean flag | --open | accepts both --open and --no-open automatically |
| Optional option value | --scale [level] | value or true |
| Required option value | --out <dir> | missing value throws |
| Global option | cli.option('--cwd <dir>', ...) | available to all commands |
| Command option | command.option('--watch', ...) | scoped to one command |
| Repeated option | --include a --include b | becomes ['a', 'b'] |
| Dot-nested option | --env.API_SECRET xxx | becomes options.env.API_SECRET |
| Passthrough args | -- pnpm test | stored in options['--'] |
Kebab-case option names are read in camelCase:
cli.option('--clear-screen', 'Clear screen')
// read options.clearScreen
Only the first segment is camel-cased, so --env.API_SECRET becomes options.env.API_SECRET.
Bare booleans already accept negation:
cli.option('--open', 'Open browser')
// --open -> { open: true }
// --no-open -> { open: false }
Declare an explicit negated option only when the negated form should appear in help, should default to true, or must pair with a required-value option:
cli
.option('--no-config', 'Disable config file')
.option('--config <path>', 'Use a custom config file')
For array-valued options, prefer repeated flags:
--include a --include b --include c
CAC parses that as:
{ include: ['a', 'b', 'c'] }
Do not model array input as --include a,b,c and split the string manually unless the CLI intentionally documents comma-separated syntax. If consumers should always receive an array, use type: [] so even one --include a becomes ['a'].
Scenario References
Use the reference that matches the user's task:
| Scenario | Reference |
|---|---|
| Parse args plus global options | basic-usage |
| Parse explicit argv outside normal Node flow | browser |
| Add examples to command help | command-examples |
| Add command-scoped options | command-options |
| Define an empty-name default command | default-command |
| Make a named command also act as default | default-command-inverted |
| Use CAC from Deno | deno |
| Parse nested option keys | dot-nested-options |
| Combine help, version, global options, and a default command | help |
| Show defaults in help without filling parsed output | ignore-default-value |
| Declare an explicit negated option | negated-option |
| Combine multiple subcommands in one CLI | sub-command |
| Accept trailing positional lists | variadic-arguments |
Centralized Error Handling
try {
cli.parse(process.argv, { run: false })
await cli.runMatchedCommand()
} catch (error) {
console.error(error)
process.exit(1)
}
Important Behaviors
- When a matched command has an action, CAC validates unknown options, missing option values, missing required args, and unused extra args.
- Use
allowUnknownOptions()only when forwarding another tool's flags. - Use
ignoreOptionDefaultValue()when help should show defaults but parsed output should stay sparse. - Variadic positional args arrive as arrays.
options['--']is reserved for everything after a double dash.command.alias(name)accepts plain aliases; usealias('!')to mark a named command as the default command.- Listen to
command:<name>,command:!, andcommand:*when you need matched/default/unknown-command hooks.
API Surface
CLI
cac(name?)
cli.command(name, description?, config?)
cli.option(name, description, config?)
cli.help(callback?)
cli.version(version, customFlags?)
cli.usage(text)
cli.example(example)
cli.parse(argv?, { run }?)
cli.runMatchedCommand()
cli.outputHelp()
cli.outputVersion()
cli.parse() returns { args, options } and also sets:
cli.rawArgs
cli.args
cli.options
cli.matchedCommand
cli.matchedCommandName
Command
command.option(name, description, config?)
command.action(callback)
command.alias(name)
command.allowUnknownOptions()
command.ignoreOptionDefaultValue()
command.example(example)
command.usage(text)
Option config supports:
{
default?: any
type?: any[]
}
Use type: [] to force array output and type: [String] to transform each value.
Signals
- GitHub stars
- 3k
- Forks
- 119
- Last commit
- Aug 2026
Advanced
- Catalog kind
- skill
- Gateway key
cac- Source
- github.com/cacjs/cac