Skip to content

REPL Mode

Padrone includes a built-in REPL (Read-Eval-Print Loop) that lets users interactively run commands in a persistent session. The REPL supports command history, tab completion, scoped sessions, and customizable output formatting.

Call .repl() on your program to start an interactive session. It returns an AsyncIterable that yields a result for each executed command:

import { createPadrone } from 'padrone';
import * as z from 'zod/v4';
const program = createPadrone('myapp')
.configure({ version: '1.0.0' })
.command('greet', (c) =>
c
.arguments(z.object({ name: z.string() }), { positional: ['name'] })
.action((args) => `Hello, ${args.name}!`)
)
.command('add', (c) =>
c
.arguments(z.object({ a: z.number(), b: z.number() }))
.action((args) => args.a + args.b)
);
for await (const result of program.repl()) {
// Each successfully executed command yields a result
console.log(result.command.name, result.result);
}

Errors during execution are caught and printed to the terminal without crashing the session.

Users can enter the REPL from the command line using the --repl flag:

Terminal window
# Start REPL
myapp --repl
# Start REPL scoped to a subcommand
myapp --repl db

All REPL built-in commands use a dot prefix to avoid collisions with user-defined commands:

CommandDescription
.helpShow REPL commands and keybindings
.exitExit the REPL
.quitExit the REPL (alias)
.clearClear the screen
.historyShow command history for the session
.scope <cmd>Scope the session to a subcommand subtree
.scope .. or ..Go up one scope level
.Execute the current scoped command

Scoped REPLs let you focus on a subcommand tree. When scoped, commands are interpreted relative to the scope and the prompt updates to reflect it:

const program = createPadrone('myapp')
.command('db', (c) =>
c
.command('migrate', (c) =>
c
.command('up', (c) => c.action(() => 'migrated up'))
.command('down', (c) => c.action(() => 'migrated down'))
)
.command('seed', (c) => c.action(() => 'seeded'))
);
// Start scoped to 'db'
for await (const result of program.repl({ scope: 'db' })) {
// User types 'migrate up' instead of 'db migrate up'
}

The prompt reflects the current scope:

myapp> .scope db
myapp/db> migrate up
# Runs: db migrate up
myapp/db> .scope migrate
myapp/db/migrate> up
# Runs: db migrate up
myapp/db/migrate> ..
myapp/db> .
# Runs: db (executes the scoped command itself)

The scope option is strongly typed to valid command paths in your program.

The REPL provides tab completion for:

  • Command names and subcommands
  • Option names (e.g., --port, --host)
  • Aliases

Tab completion is enabled by default. Disable it with completion: false.

The REPL supports up/down arrow key navigation through command history. You can provide initial history entries and view the session history with .history:

for await (const result of program.repl({
history: ['greet World', 'add --a 1 --b 2'],
})) {
// Up arrow cycles through history
}
program.repl({
prompt: 'app> ',
// Or dynamic:
prompt: () => `${getCurrentBranch()}> `,
});

The default prompt is the program name with a bold > in ANSI-capable terminals.

program.repl({
greeting: 'Welcome! Type a command to get started.',
hint: 'Press Tab for completions, Ctrl+C twice to exit.',
});

Set greeting: false or hint: false to suppress them. The default greeting shows the program name and version. The default hint shows .help and .exit instructions.

Control separators before and after command output:

program.repl({
// Blank line before and after each command output
spacing: '',
// Repeated character
spacing: '-', // Prints a line of dashes
// Independent before/after
spacing: {
before: '',
after: '-',
},
});

Prefix each line of command output:

program.repl({
outputPrefix: '| ',
});

This adds | before each line of output, creating a visual distinction.

  • Type .exit or .quit to exit gracefully
  • Press Ctrl+C once to see an exit hint
  • Press Ctrl+C twice to force exit
OptionTypeDefaultDescription
promptstring | (() => string)"<name>> "REPL prompt
greetingstring | falseProgram name + versionWelcome message
hintstring | falseHelp/exit instructionsHint shown below greeting
historystring[][]Initial history entries
completionbooleantrueEnable tab completion
spacingPadroneReplSpacing | { before?, after? }noneOutput separators
outputPrefixstringnonePrefix for output lines
scopestringnoneStart scoped to a command path