pikku-cli

$npx mdskill add pikkujs/pikku/pikku-cli

Build powerful CLI tools with Pikku commands and subcommands.

  • Creates executable terminal interfaces with custom options and renderers.
  • Integrates wireCLI and pikkuCLICommand APIs for command definition.
  • Decides scope by detecting CLI-related queries while excluding tool info.
  • Delivers results through structured command execution and output rendering.

SKILL.md

.github/skills/pikku-cliView on GitHub ↗
---
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).'
---

# Pikku CLI Wiring

Wire Pikku functions as CLI commands with parameters, options, subcommands, and custom terminal renderers.

## Before You Start

```bash
pikku info functions --verbose   # See existing functions and their types
pikku info tags --verbose        # Understand project organization
```

See `pikku-concepts` for the core mental model.

## API Reference

### `wireCLI(config)`

```typescript
import { wireCLI } from '@pikku/core/cli'

wireCLI({
  program: string,              // Program name (e.g. 'todos')
  options?: {                   // Global options
    [key: string]: {
      description: string,
      short?: string,           // Single char alias (e.g. 'v')
      default?: any,
    }
  },
  render?: PikkuCLIRender,      // Default renderer for all commands
  commands: {
    [name: string]: PikkuCLICommand | {
      description: string,
      subcommands: { [name: string]: PikkuCLICommand }
    }
  },
})
```

### `pikkuCLICommand(config)`

```typescript
import { pikkuCLICommand } from '#pikku'

pikkuCLICommand({
  parameters?: string,          // Positional args (e.g. '<text>', '<username> <email>')
  func: PikkuFunc,              // Business logic function
  description?: string,
  render?: PikkuCLIRender,      // Custom output renderer
  options?: {
    [key: string]: {
      description: string,
      short?: string,
      default?: any,
      choices?: string[],       // Restrict to values
    }
  },
})
```

### `pikkuCLIRender(fn)`

```typescript
import { pikkuCLIRender } from '@pikku/core/cli'

const renderer = pikkuCLIRender<OutputType>((services, data) => {
  // Format and print output to terminal
  console.log(data)
})
```

## Usage Patterns

### Basic Commands

```typescript
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,
        },
      },
    }),
  },
})
// Usage: todos add "Buy milk" -p high
// Usage: todos list -c
```

### Nested Subcommands

```typescript
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' },
          },
        }),
      },
    },
  },
})
// Usage: app greet Alice
// Usage: app user create bob bob@example.com -a
// Usage: app user list -l 10
// Usage: app -v user list
```

### Custom Renderers

```typescript
const todoRenderer = pikkuCLIRender<{ todo: Todo }>((_services, { todo }) => {
  console.log(`✓ Created: ${todo.text} (priority: ${todo.priority})`)
})

const todosRenderer = pikkuCLIRender<{ todos: Todo[] }>(
  (_services, { todos }) => {
    todos.forEach((t, i) => {
      const check = t.completed ? '✓' : ' '
      console.log(`  ${i + 1}. ${t.text}  ${check}`)
    })
  }
)

// Default renderer for program, override per-command
wireCLI({
  program: 'todos',
  render: jsonRenderer,
  commands: {
    add: pikkuCLICommand({
      func: createTodo,
      render: todoRenderer, // Overrides jsonRenderer
    }),
  },
})
```

## Complete Example

```typescript
// functions/admin.functions.ts
export const createUser = pikkuFunc({
  title: 'Create User',
  func: async ({ db }, { username, email, admin }) => {
    const user = await db.createUser({
      username,
      email,
      role: admin ? 'admin' : 'user',
    })
    return { user }
  },
})

export const listUsers = pikkuSessionlessFunc({
  title: 'List Users',
  func: async ({ db }, { limit }) => {
    return { users: await db.listUsers(limit || 50) }
  },
})

export const deleteUser = pikkuFunc({
  title: 'Delete User',
  func: async ({ db }, { username }) => {
    await db.deleteUser(username)
    return { deleted: username }
  },
})

// wirings/cli.wiring.ts
const userRenderer = pikkuCLIRender<{ user: User }>((_services, { user }) => {
  console.log(`Created user: ${user.username} (${user.email}) [${user.role}]`)
})

const usersRenderer = pikkuCLIRender<{ users: User[] }>(
  (_services, { users }) => {
    console.log(`Users (${users.length}):`)
    users.forEach((u) =>
      console.log(`  ${u.username} <${u.email}> [${u.role}]`)
    )
  }
)

wireCLI({
  program: 'admin',
  commands: {
    user: {
      description: 'User management',
      subcommands: {
        create: pikkuCLICommand({
          parameters: '<username> <email>',
          func: createUser,
          render: userRenderer,
          options: {
            admin: {
              description: 'Create as admin',
              short: 'a',
              default: false,
            },
          },
        }),
        list: pikkuCLICommand({
          func: listUsers,
          render: usersRenderer,
          options: {
            limit: { description: 'Max results', short: 'l' },
          },
        }),
        delete: pikkuCLICommand({
          parameters: '<username>',
          func: deleteUser,
          description: 'Delete a user',
        }),
      },
    },
  },
})
```

More from pikkujs/pikku

SkillDescription
pikku-addon'Use when creating or consuming reusable function packages (addons) in Pikku. Covers wireAddon, addon(), pikkuAddonServices, pikkuAddonWireServices, addon package structure, and cross-project function sharing.
pikku-ai-agent'Use when building AI agents, chatbots, or LLM-powered assistants with Pikku. Covers pikkuAIAgent, tool registration, memory, streaming, and agent invocation.
pikku-ai-vercel'Use when setting up AI agent execution with the Vercel AI SDK in a Pikku app. Covers VercelAIAgentRunner for streaming and non-streaming AI agent steps.
pikku-ai-voice'Use when adding voice input (speech-to-text) or voice output (text-to-speech) to AI agents in a Pikku app. Covers voiceInput/voiceOutput middleware hooks and STT/TTS service interfaces.
pikku-auth-js'Use when integrating Auth.js (NextAuth) with a Pikku app. Covers createAuthHandler, createAuthRoutes, and Auth.js configuration.
pikku-aws'Use when setting up AWS services (S3, SQS, Secrets Manager) in a Pikku app. Covers S3Content for file storage, SQSQueueService for queues, and AWSSecrets for secret management.
pikku-backblaze'Use when setting up Backblaze B2 file storage in a Pikku app. Covers B2Content for file uploads, downloads, and signed URLs.
pikku-concepts'Foundational guide to Pikku framework concepts. Use this skill when working with any Pikku codebase, starting a new Pikku project, or migrating a backend to Pikku. Covers the core mental model, function types, project structure, code generation, testing, and how Pikku maps to traditional backend patterns.
pikku-config'Use when managing secrets, environment variables, config, or OAuth2 credentials in a Pikku app. Covers wireSecret, wireVariable, wireOAuth2Credential, and typed config access.
pikku-cron'Use when adding scheduled tasks, recurring jobs, or cron-based automation to a Pikku app. Covers wireScheduler, cron expressions, scheduled task wire object, and scheduler middleware.