Prompts
Define prompts once, infer types automatically, and read values from cli.storage.
oscli prompt builders are the center of the framework. You define the input
shape once, resolve prompts with cli.prompt.<name>(), then read typed values
from cli.storage.
Canonical chain order
Use the same chain order for every prompt builder so definitions stay easy to scan.
b.<type>()
.label()
.describe()
.placeholder()
.default()
.optional()
.validate()
.transform()
.color()Shared methods
These methods exist on every prompt builder.
Prop
Type
Prompt builders
These are the available prompt factories.
Prop
Type
Text
Use b.text() for plain string input.
export const cli = createCLI((b) => ({
description: "text prompt",
prompts: {
project: b
.text()
.label("Project")
.placeholder("my-app")
.default("my-app")
.validate((value) =>
value.length >= 2 ? true : "Use at least 2 characters.",
)
.transform((value) => value.trim()),
},
}));While prompting:
┌
│ Project
│ › my-app_
└After submit:
┌
│ ✓ Project: my-app
└Password
Use b.password() when the user types sensitive text.
export const cli = createCLI((b) => ({
description: "password prompt",
prompts: {
token: b.password().label("API token"),
},
}));While prompting:
┌
│ API token
│ › ********_
└After submit:
┌
│ ✓ API token: ********
└Number
Use b.number() when the stored value must be a number.
export const cli = createCLI((b) => ({
description: "number prompt",
prompts: {
retries: b.number().label("Retries").min(0).max(5),
budget: b.number().label("Budget").prefix("$").min(0),
},
}));While prompting:
┌
│ Budget
│ $ › 500_
└After submit:
┌
│ ✓ Budget: 500
└Select
Use b.select() for one choice from a fixed list.
export const cli = createCLI((b) => ({
description: "select prompt",
prompts: {
mode: b
.select({ choices: ["personal", "team"] as const })
.label("Mode")
.rule("personal", "single-user setup")
.rule("team", "shared project"),
},
}));While prompting:
┌
│ Mode
│ › ● personal single-user setup
│ ○ team shared project
│ ↑↓ navigate enter select
└After submit:
┌
│ ✓ Mode: personal
└Multiselect
Use b.multiselect() when the user can choose multiple values.
export const cli = createCLI((b) => ({
description: "multiselect prompt",
prompts: {
features: b
.multiselect({ choices: ["api", "ui", "docs", "tests"] as const })
.label("Features")
.min(1)
.max(3),
},
}));While prompting:
┌
│ Features (1–3)
│ › ◉ api
│ ○ ui
│ ◉ docs
│ ○ tests
│ ↑↓ navigate space toggle enter confirm
└After submit:
┌
│ ✓ Features: api, docs
└Confirm
Use b.confirm() for boolean input. Toggle is the default. Simple keeps the
older typed y/n flow.
approved: b.confirm().label("Continue?").default(true)approved: b.confirm("simple").label("Continue?").default(false)Toggle: inlineYes / Noselector, arrow keys ory/n, then EnterSimple: typedy/ninput
Toggle while prompting:
┌
│ Continue?
│ ● Yes / ○ No
└Toggle after submit:
┌
│ ✓ Continue?: yes
└Simple while prompting:
┌
│ Continue?
│ › (y/N) _
└Simple after submit:
┌
│ ✓ Continue?: no
└Search
Use b.search() when the choice list is fixed, but the user needs to filter it
while typing.
export const cli = createCLI((b) => ({
description: "search prompt",
prompts: {
framework: b
.search({ choices: ["react", "vue", "svelte", "solid"] as const })
.label("Framework")
.rule("react", "large ecosystem")
.rule("svelte", "minimal runtime"),
},
}));While prompting:
┌
│ Framework
│ › sv_
│ › ● svelte minimal runtime
│ ○ solid
│ ↑↓ navigate enter select
└After submit:
┌
│ ✓ Framework: svelte
└List
Use b.list() for repeated free-form input. The prompt ends on an empty Enter.
export const cli = createCLI((b) => ({
description: "list prompt",
prompts: {
tags: b.list().label("Tags").min(1).max(5),
},
}));While prompting:
┌
│ Tags 1 / 5
│ › api_
└Accepted items:
┌
│ ✓ Tags: api
│ ✓ Tags: docs
│ ✓ Tags: tests
└After submit:
┌
│ ✓ Tags: api, docs, tests
└Date
Use b.date() for validated date input stored as Date.
export const cli = createCLI((b) => ({
description: "date prompt",
prompts: {
deadline: b.date().label("Deadline").format("YYYY-MM-DD"),
},
}));While prompting:
┌
│ Deadline
│ › 2026-03-31_
└After submit:
┌
│ ✓ Deadline: 2026-03-31
└┌
│ Deadline
│ › tomorrow_
│ ✗ Use a valid date in YYYY-MM-DD format.
└If you do not set a placeholder for b.date(), oscli uses the configured
format as the placeholder.
Resolution behavior
Prompt builders share the same runtime rules once a value is submitted.