https://github.com/kurtgokhan/padrone
Create type-safe, interactive CLI apps with Zod schemas
https://github.com/kurtgokhan/padrone
ai argument-parser cli command-line command-line-tool esm nodejs shell standard-schema terminal type-safe typescript validation zod
Last synced: 3 months ago
JSON representation
Create type-safe, interactive CLI apps with Zod schemas
- Host: GitHub
- URL: https://github.com/kurtgokhan/padrone
- Owner: KurtGokhan
- License: mit
- Created: 2025-12-02T09:03:04.000Z (7 months ago)
- Default Branch: main
- Last Pushed: 2026-04-01T00:45:53.000Z (3 months ago)
- Last Synced: 2026-04-01T02:42:41.583Z (3 months ago)
- Topics: ai, argument-parser, cli, command-line, command-line-tool, esm, nodejs, shell, standard-schema, terminal, type-safe, typescript, validation, zod
- Language: TypeScript
- Homepage: http://gkurt.com/padrone/
- Size: 1.47 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
Type-safe CLI framework powered by Zod schemas
---
Define your CLI with Zod schemas. Get type safety, validation, help generation, interactive prompts, shell completions, AI tool integration, and more — all from a single source of truth.
Built on [Standard Schema](https://github.com/standard-schema/standard-schema), so it also works with Valibot, ArkType, and others.
## Install
```bash
npm install padrone zod
```
## Scaffold a New Project
The fastest way to get started is with `padrone init`:
```bash
npx padrone init my-cli
cd my-cli && bun i && bun dev
```
## Quick Start
```typescript
import { createPadrone } from 'padrone';
import * as z from 'zod/v4';
const program = createPadrone('myapp')
.command('greet', (c) =>
c
.arguments(
z.object({
names: z.array(z.string()).describe('Names to greet'),
prefix: z.string().optional().describe('Prefix').meta({ flags: 'p' }),
}),
{ positional: ['...names'] },
)
.action((args) => {
for (const name of args.names) {
console.log(`Hello, ${args.prefix ?? ''} ${name}!`);
}
}),
);
program.cli();
```
```bash
myapp greet John Jane -p Mr.
# Hello, Mr. John!
# Hello, Mr. Jane!
```
## What It Does
```typescript
// Multiple ways to run commands
program.cli(); // from process.argv
program.eval('greet John --prefix Mr.'); // from a string
program.run('greet', { names: ['John'], prefix: 'Mr.' }); // typed args
program.api().greet({ names: ['John'], prefix: 'Mr.' }); // as a function
// Parse without executing
const { args } = program.parse('greet John --prefix Mr.');
// Interactive REPL
for await (const result of program.repl()) { /* ... */ }
// AI tool for Vercel AI SDK
const tool = program.tool();
// MCP server for AI assistants (Claude, Cursor, etc.) [experimental]
await program.mcp(); // or: myapp mcp
// REST server with OpenAPI docs [experimental]
await program.serve(); // or: myapp serve
// Shell completions
const script = program.completion('zsh');
// Help in multiple formats
program.help('greet'); // text
program.help('greet', { format: 'json' }); // json, markdown, html, ansi
```
## Features at a Glance
**Arguments** — positional args, variadic args, short flags (`-v`), long aliases (`--dry-run`), auto kebab-case aliases, negatable booleans (`--no-verbose`), custom negation keywords (`--remote` → sets `local` to `false`).
**Env & Config** — load from environment variables with `.extend(padroneEnv(schema))` and config files with `.extend(padroneConfig({ files, schema }))`. Precedence: CLI > stdin > env > config > defaults.
**Interactive prompts** — auto-prompt for missing fields. Booleans become confirm, enums become select, arrays become multi-select.
**Progress indicators** — auto-managed spinners and progress bars with elapsed time and ETA. `.extend(padroneProgress({ message: 'Deploying...', bar: true, time: true, eta: true }))`.
**Extension-first architecture** — most built-in features (help, version, REPL, color, signal handling, auto-output, stdin, config, interactive, suggestions) are implemented as extensions composed via `.extend()`. Any built-in can be disabled or replaced.
**Interceptors** — middleware hooks for 6 phases (start, parse, validate, execute, error, shutdown). Onion model with `next()`. Extensions register interceptors under the hood. Create your own with `defineInterceptor()`.
**Composition** — mount programs as subcommands with `.mount()`, override commands with merge semantics.
**Wrapping** *(experimental)* — wrap external CLI tools with `.wrap({ command: 'git', args: ['commit'] })`.
## API
### Builder (define commands)
| Method | What it does |
|--------|-------------|
| `.arguments(schema, meta?)` | Define args with Zod schema, positional config, field metadata |
| `.action(handler)` | Set handler `(args, ctx, base?) => result` |
| `.command(name, builder)` | Add subcommand (name or `[name, ...aliases]`) |
| `.context(transform?)` | Define typed context or transform inherited context |
| `.mount(name, program, options?)` | Mount another program as subcommand tree |
| `.configure(config)` | Set title, description, version, etc. |
| `.extend(padroneEnv(schema))` | Map env vars to args (composable extension) |
| `.extend(padroneConfig({ files, schema }))` | Load args from config files (composable extension) |
| `.wrap(config)` | Wrap an external CLI tool *(experimental)* |
| `.extend(padroneProgress(config?))` | Auto-managed progress indicator (extension) |
| `.intercept(interceptor)` | Register middleware interceptor (use `defineInterceptor()`) |
| `.extend(extension)` | Apply a build-time extension (bundle of config, commands, interceptors) |
| `.runtime(runtime)` | Custom I/O (for non-terminal use) |
| `.updateCheck(config?)` | Background version check |
| `.async()` | Mark as async validation |
### Program (run commands)
| Method | What it does |
|--------|-------------|
| `.cli(prefs?)` | Entry point — parses `process.argv`, throws on errors. Pass `context` in prefs. |
| `.eval(input, prefs?)` | Parse + validate + execute string, returns errors softly. Pass `context` in prefs. |
| `.run(command, args, prefs?)` | Run by name with typed args (no validation). Pass `context` in prefs. |
| `.parse(input?)` | Parse without executing |
| `.api()` | Generate typed function API |
| `.repl(options?)` | Interactive REPL session |
| `.help(command?, prefs?)` | Generate help (text, ansi, markdown, html, json) |
| `.tool()` | Vercel AI SDK tool definition |
| `.mcp(prefs?)` | Start MCP server (HTTP or stdio) *(experimental)* |
| `.serve(prefs?)` | Start REST server with OpenAPI docs *(experimental)* |
| `.completion(shell?)` | Shell completion script |
| `.find(command)` | Look up command by path |
| `.stringify(command?, args?)` | Convert back to CLI string |
### Zod `.meta()` fields
| Field | Example | Purpose |
|-------|---------|---------|
| `flags` | `'v'` | Single-char short flag (`-v`) |
| `alias` | `'dry-run'` | Multi-char long alias (`--dry-run`) |
| `negative` | `'remote'` | Custom negation keyword for booleans (disables `--no-`) |
| `examples` | `['8080']` | Example values in help |
| `deprecated` | `'Use --debug'` | Deprecation warning |
| `hidden` | `true` | Hide from help |
| `group` | `'Advanced'` | Group in help output |
### Arguments meta (second param of `.arguments()`)
```typescript
.arguments(schema, {
positional: ['source', '...files', 'dest'],
interactive: ['name', 'template'],
optionalInteractive: ['typescript'],
fields: { verbose: { flags: 'v' } },
stdin: 'data',
autoAlias: true, // default
})
```
## Agent Skill
Give your AI coding agent knowledge of the Padrone API:
```bash
npx skills add KurtGokhan/padrone
```
## Requirements
- Node.js 18+ or Bun
- TypeScript 5.0+ (recommended)
- Zod (or any Standard Schema-compatible library)
## License
[MIT](LICENSE)