Skip to content

Introduction

Padrone is a TypeScript library for building type-safe, interactive CLI applications with Zod schema validation. It provides a fluent API for defining commands and arguments while maintaining full type safety throughout your application.

Building CLI applications in TypeScript often involves:

  • Manual argument parsing with type assertions
  • Repetitive validation code
  • Separate documentation that gets out of sync
  • Boilerplate for help generation

Padrone solves these problems by using Zod schemas as the single source of truth for your CLI’s arguments. Your schema defines:

  • The types of your arguments (automatically inferred)
  • Validation rules (enforced at runtime)
  • Documentation (generated from .describe() calls)
  • Default values

Every argument you define is fully typed from schema definition to action handler:

.arguments(
z.object({
port: z.number().default(3000),
host: z.string().default('localhost'),
})
)
.action((args) => {
// args is typed as { port: number; host: string }
console.log(`Server at ${args.host}:${args.port}`);
})

Padrone uses a chainable builder pattern that reads naturally:

createPadrone('myapp')
.configure({ version: '1.0.0' })
.command('serve', (c) => c.arguments(schema).action(handler))
.command('build', (c) => c.arguments(schema).action(handler))
.cli();

Padrone’s core is minimal — most features are implemented as extensions composed via .extend(). When you call createPadrone(), built-in extensions are automatically applied: help, version, REPL, color, suggestions, signal handling, auto-output, stdin, and interactive prompting.

This means:

  • Built-in features use the same APIs you use for custom code
  • Any built-in can be disabled or replaced
  • You can compose reusable bundles of commands, configuration, and interceptors
// Extensions are functions that transform the builder
const withMetrics = (builder) =>
builder.intercept(defineInterceptor({ name: 'metrics' }, () => ({
execute: (ctx, next) => {
const start = Date.now();
const result = next();
console.log(`${ctx.command.name}: ${Date.now() - start}ms`);
return result;
},
})));
createPadrone('myapp')
.extend(withMetrics)
.extend(padroneEnv(envSchema))
.extend(padroneConfig({ files: 'config.json' }));

Under the hood, extensions register interceptors — middleware that wraps the command lifecycle with an onion model. Six phases (start, parse, validate, execute, error, shutdown) give you full control:

program.intercept(defineInterceptor({ name: 'auth' }, () => ({
execute: (ctx, next) => {
if (!isAuthenticated()) throw new Error('Not authenticated');
return next();
},
})));

Expose your CLI to AI assistants via Model Context Protocol or Vercel AI SDK:

// MCP server for Claude, Cursor, Windsurf, etc. [experimental]
await program.mcp(); // or: myapp mcp
// REST server with OpenAPI docs [experimental]
await program.serve(); // or: myapp serve
// Vercel AI SDK tool
const tool = program.tool();

Automatically prompt users for missing arguments with type-aware prompts. Booleans become confirm prompts, enums become select menus, and arrays of enums become multi-selects — all detected from your Zod schema:

.arguments(
z.object({
name: z.string().describe('Project name'),
template: z.enum(['react', 'vue']).describe('Template'),
}),
{ interactive: ['name', 'template'] }
)

Start an interactive session with command history, tab completion, and scoped navigation:

for await (const result of program.repl()) {
// Each command yields a result
}

Auto-managed spinners and progress bars for long-running commands, implemented as a context-providing extension:

.extend(padroneProgress({
message: {
progress: 'Deploying...',
success: (result) => `Deployed v${result.version}`,
},
bar: true,
time: true,
}))

Mount independent programs as subcommands and override existing commands:

const app = createPadrone('app')
.mount('admin', adminProgram)
.mount('db', dbProgram);
  • CLI mode: Parse process.argv with cli()
  • Eval mode: Parse and execute strings with soft error handling via eval()
  • Programmatic mode: Call commands with typed arguments via run()
  • API mode: Generate a typed function interface via api()
  • REPL mode: Interactive session with repl()
  • MCP mode: Expose commands as AI tools via mcp() (experimental)
  • Serve mode: REST API with OpenAPI docs via serve() (experimental)
  • Node.js 18+ or Bun
  • TypeScript 5.0+ (recommended)
  • Zod 3.25+ or 4.x

Ready to start? Head to the Quick Start guide to build your first Padrone CLI.