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.
Why Padrone?
Section titled “Why Padrone?”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
Key Features
Section titled “Key Features”Type Safety
Section titled “Type Safety”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}`);})Fluent Builder API
Section titled “Fluent Builder API”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();Extension-First Architecture
Section titled “Extension-First Architecture”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 builderconst 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' }));Interceptor System
Section titled “Interceptor System”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(); },})));AI Integration
Section titled “AI Integration”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 toolconst tool = program.tool();Interactive Prompting
Section titled “Interactive Prompting”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'] })REPL Mode
Section titled “REPL Mode”Start an interactive session with command history, tab completion, and scoped navigation:
for await (const result of program.repl()) { // Each command yields a result}Progress Indicators
Section titled “Progress Indicators”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,}))Program Composition
Section titled “Program Composition”Mount independent programs as subcommands and override existing commands:
const app = createPadrone('app') .mount('admin', adminProgram) .mount('db', dbProgram);Multiple Execution Modes
Section titled “Multiple Execution Modes”- CLI mode: Parse
process.argvwithcli() - 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)
Requirements
Section titled “Requirements”- Node.js 18+ or Bun
- TypeScript 5.0+ (recommended)
- Zod 3.25+ or 4.x
Next Steps
Section titled “Next Steps”Ready to start? Head to the Quick Start guide to build your first Padrone CLI.