CLI Overview
CLI wiring turns your Pikku functions into command-line programs with nested commands, positional parameters, options, and formatted output.
Your domain functions don't need to know they're being called from the command line. They receive typed data, do their work, and return results. Pikku handles argument parsing, help text generation, and output formatting.
Two Ways to Run CLI Commands
Pikku supports two modes of CLI execution:
Local CLI
Run commands directly on your local machine. The CLI invokes functions in-process - no network requests, instant execution.
Use local CLI when:
- Building developer tools and scripts
- Running database migrations
- Executing admin tasks locally
- Working in development/testing environments
Remote CLI
Run commands that invoke functions on a remote server via RPC. The CLI acts as a thin client that sends requests over the network.
Use remote CLI when:
- Managing production systems from your terminal
- Executing admin commands on remote servers
- Building distributed admin tools
- Providing CLI access to cloud-hosted backends
Your First CLI Command
Here are CLI wiring and renderers from the templates, showing a full todo CLI with list, add, show, complete, and delete commands:
loading...
loading...
Now you can use your CLI:
todo-cli list
# Found 3 todo(s):
# [ ] [HIGH] abc123: Buy groceries (due: 2024-12-31)
todo-cli add "Write tests" --priority high
# Success: Write tests
todo-cli complete <id>
# Success
Pikku automatically:
- Parses command-line arguments
- Maps positionals to your function's input type
- Validates required vs optional parameters
- Generates help text
- Formats errors appropriately
Core Features
Positional Parameters
Use <required> and [optional] syntax to declare positionals:
pikkuCLICommand({
parameters: '<package> [version]',
func: installPackage,
description: 'Install a package'
})
Options and Flags
Options are CLI flags with optional short forms:
options: {
environment: {
description: 'Target environment',
short: 'e',
default: 'dev'
},
dryRun: {
description: 'Simulate without applying changes',
short: 'd',
default: false
}
}
Nested Commands
Build hierarchical CLI structures with subcommands:
wireCLI({
program: 'my-tool',
commands: {
user: {
description: 'User management',
subcommands: {
create: pikkuCLICommand({ /* ... */ }),
list: pikkuCLICommand({ /* ... */ }),
delete: pikkuCLICommand({ /* ... */ })
}
}
}
})
Custom Renderers
Renderers control how function output appears in the console:
const userListRenderer = pikkuCLIRender<{ users: Array<User> }>(
(services, data) => {
console.table(data.users)
}
)
Streaming Progress
For long-running operations, stream progress updates using channel.send():
export const buildApp = pikkuSessionlessFunc({
func: async ({ channel }, data) => {
if (channel) {
await channel.send({ type: 'progress', step: 'Installing', percent: 0 })
}
// ... work ...
if (channel) {
await channel.send({ type: 'progress', step: 'Compiling', percent: 50 })
}
// ... more work ...
}
})
Configuration Reference
Add CLI entrypoints to pikku.config.json:
{
"cli": {
"entrypoints": {
"my-cli": [
{
"type": "local",
"path": ".pikku/cli-local.gen.ts"
},
{
"type": "channel",
"name": "cli",
"route": "/cli",
"wirePath": ".pikku/cli-channel.ts",
"path": ".pikku/cli-remote.gen.ts"
}
]
}
}
}
Run npx pikku to generate the CLI executables. Each entrypoint can have both local and remote modes — they share the same wireCLI definition.
wireCLI Options
| Property | Type | Description |
|---|---|---|
program | string | The CLI program name (shown in help text) |
description | string | Program description |
commands | Record<string, Command> | Top-level commands |
pikkuCLICommand Options
| Property | Type | Description |
|---|---|---|
func | PikkuFunc | The Pikku function to invoke |
parameters | string | Positional params: <required> [optional] |
description | string | Command description for help text |
options | Record<string, Option> | Named flags and options |
render | CLIRender | Output renderer function |
Option Properties
| Property | Type | Description |
|---|---|---|
description | string | Help text for the option |
short | string | Single-letter alias (e.g., 'v' for --verbose / -v) |
default | any | Default value (also determines the type: false → boolean flag) |
Next Steps
- Local CLI - Run commands directly in-process
- Remote CLI - Invoke remote functions via RPC
- Core Functions - Understanding Pikku functions
- Middleware - Adding middleware to CLI commands