| name | pikku-cli |
| description | Use when building CLI commands with Pikku. Covers wireCLI, pikkuCLICommand, subcommands, options, parameters, custom renderers, and nested command groups. TRIGGER when: code uses wireCLI/pikkuCLICommand, user asks about CLI commands, terminal tools, command-line interface, or adding subcommands. DO NOT TRIGGER when: user asks about the pikku CLI tool itself (use pikku-info) or HTTP endpoints (use pikku-http). |
| installGroups | ["core"] |
Pikku CLI Wiring
Agent Operating Procedure
Use this skill as an execution checklist, not reference material.
- Discover before editing. Prefer OpenCode tools such as
pikku-meta when available; otherwise run the relevant pikku meta ... --json command and inspect only the focused output you need.
- Identify the source files that own the behavior. Do not start by reading generated output,
.pikku, node_modules, vendored packages, or broad build artifacts.
- Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
- Validate with the narrowest relevant command first, then run
pikku-verify or pikku all when functions, wirings, schemas, or generated clients may have changed.
- If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
Wire Pikku functions as CLI commands with parameters, options, subcommands, and custom terminal renderers.
Before You Start
pikku info functions --verbose
pikku info tags --verbose
See pikku-concepts for the core mental model.
API Reference
wireCLI(config)
import { wireCLI } from '@pikku/core/cli'
wireCLI({
program: string,
options?: {
[key: string]: {
description: string,
short?: string,
default?: any,
}
},
render?: PikkuCLIRender,
commands: {
[name: string]: PikkuCLICommand | {
description: string,
subcommands: { [name: string]: PikkuCLICommand }
}
},
})
pikkuCLICommand(config)
import { pikkuCLICommand } from '#pikku'
pikkuCLICommand({
parameters?: string,
func: PikkuFunc,
description?: string,
render?: PikkuCLIRender,
options?: {
[key: string]: {
description: string,
short?: string,
default?: any,
choices?: string[],
}
},
})
pikkuCLIRender(fn)
import { pikkuCLIRender } from '@pikku/core/cli'
const renderer = pikkuCLIRender<OutputType>((services, data) => {
console.log(data)
})
Usage Patterns
Basic Commands
wireCLI({
program: 'todos',
commands: {
add: pikkuCLICommand({
parameters: '<text>',
func: createTodo,
description: 'Add a new todo',
render: todoRenderer,
options: {
priority: {
description: 'Set priority',
short: 'p',
default: 'normal',
choices: ['low', 'normal', 'high'],
},
},
}),
list: pikkuCLICommand({
func: listTodos,
description: 'List all todos',
render: todosRenderer,
options: {
completed: {
description: 'Show completed only',
short: 'c',
default: false,
},
},
}),
},
})
Nested Subcommands
wireCLI({
program: 'app',
options: {
verbose: { description: 'Verbose output', short: 'v', default: false },
},
commands: {
greet: pikkuCLICommand({
parameters: '<name>',
func: greetUser,
render: greetRenderer,
}),
user: {
description: 'User management',
subcommands: {
create: pikkuCLICommand({
parameters: '<username> <email>',
func: createUser,
render: userRenderer,
options: {
admin: { description: 'Admin role', short: 'a', default: false },
},
}),
list: pikkuCLICommand({
func: listUsers,
render: usersRenderer,
options: {
limit: { description: 'Max results', short: 'l' },
},
}),
},
},
},
})
Custom Renderers
A renderer receives (services, data) where data is the func's output. Set render on wireCLI as the program-wide default; set render on a pikkuCLICommand to override it for that command.
const todoRenderer = pikkuCLIRender<{ todo: Todo }>((_services, { todo }) => {
console.log(`✓ Created: ${todo.text} (priority: ${todo.priority})`)
})
wireCLI({
program: 'todos',
render: jsonRenderer,
commands: {
add: pikkuCLICommand({ func: createTodo, render: todoRenderer }),
},
})
The func's input is the positional parameters plus options, merged (e.g. parameters: '<username> <email>' + an admin option → func input { username, email, admin }).
Complete Example
For a full functions + renderers + nested-subcommand wiring walkthrough, see references/complete-example.md.