Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Creates a new CLI command following the Commander.js pattern in src/commands/. Handles command registration in src/cli.ts, telemetry tracking via tracked() wrapper, and option parsing. Use when user says add command, new CLI command, create subcommand, or adds files to src/commands/. Do NOT use for modifying existing commands or fixing bugs in existing commands.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 78% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 74% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 57% | 0% |
| case-04 | ✗→✓ | ▲ Improved | -4% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 47% | 0% |
export async function myCommand(options?: OptionType). Never use default exports..command() chain in src/cli.ts, wrapped with tracked() for telemetry.throw new Error('__exit__') to exit gracefully without printing the error message. Use chalk for user-facing messages.src/commands/{commandName}.ts with named async export.export async function {commandName}Command(options?: { optionName?: optionType }) { ... }console.error(chalk.red('message')); throw new Error('__exit__');throw new Error('Detailed error message'); — this will print and exit with code 1..fail() before throwing.import { {commandName}Command } from './commands/{commandName}.js';sources)..command('{kebab-name}').description('...').option(...).action(tracked('{kebab-name}', {commandName}Command))sources add): sources.command('add').description(...).action(tracked('sources:add', sourcesAddCommand))tracked('{command-name}', handler) for automatic telemetry..option() chains before .action(): .option('--flag', 'Description') or .option('--opt <value>', 'Description').option('--opt <value>', 'Description', parseFunction).action(tracked('name', (opts) => command(opts)))new Error('__exit__') for user errors.User says: "Add a command to show config status"
Actions taken:
Result: caliber status displays config status; caliber status --json outputs JSON.
Code example:
typescriptimport chalk from 'chalk'; import { loadConfig } from '../llm/config.js'; export async function statusCommand(options?: { json?: boolean }) { const config = loadConfig(); if (options?.json) { console.log(JSON.stringify({ configured: !!config }, null, 2)); return; } console.log(chalk.bold('Status')); console.log(` LLM: ${chalk.green(config?.provider || 'Not configured')}`); }
Registration in src/cli.ts:
typescriptimport { statusCommand } from './commands/status.js'; program .command('status') .description('Show config status') .option('--json', 'Output as JSON') .action(tracked('status', statusCommand));
User says: "Add a sources add subcommand"
Actions taken:
Result: caliber sources add ../lib adds a source.
Code example:
typescriptexport async function sourcesAddCommand(sourcePath: string) { if (!fs.existsSync(sourcePath)) { console.log(chalk.red(`Path not found: ${sourcePath}`)); throw new Error('__exit__'); } const existing = loadSourcesConfig(process.cwd()); existing.push({ type: 'repo', path: sourcePath }); writeSourcesConfig(process.cwd(), existing); console.log(chalk.green(`Added ${sourcePath}`)); }
Registration:
typescriptconst sources = program.command('sources'); sources .command('add') .argument('<path>', 'Path to add') .action(tracked('sources:add', sourcesAddCommand));
User says: "Add init with --agent flag supporting comma-separated values"
Actions taken:
Result: caliber init --agent claude,cursor passes parsed array to handler.
Parser code:
typescriptfunction parseAgentOption(value: string) { const agents = value.split(',').map(s => s.trim().toLowerCase()); if (agents.length === 0) { console.error('Invalid agent'); process.exit(1); } return agents; } program.command('init') .option('--agent <type>', 'Agents (comma-separated)', parseAgentOption) .action(tracked('init', initCommand));
Issue: "SyntaxError: The requested module does not provide an export named 'myCommand'"
export async function myCommand(...) (not export default).Issue: Command appears in help but crashes when run
tracked() or function import mismatch.tracked('command-name', handler).Issue: "Error: __exit__" appears in output for user errors
console.error(chalk.red('message')); throw new Error('__exit__'); for user-facing errors.Issue: --dry-run flag not recognized
.option() or wrong camelCase in interface..option('--dry-run', 'Description') and ensure options interface has dryRun?: boolean.Issue: Subcommand crashes but parent command works
program.command() instead of groupVar.command() for subcommands.const sources = program.command('sources'); sources.command('add')...Issue: Telemetry not appearing
tracked() or wrong command name..action(tracked('{kebab-case}', handler)) wraps handler. Use colon for subcommands like 'sources:add'.Issue: "Cannot find module" with relative imports
.ts extension in imports..js extension: import { x } from '../lib/file.js' (required for ESM).Other measured skills in the registry, with their headline benchmark lift.