oscli

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.

Prompt chain order
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.

src/cli.ts
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.

src/cli.ts
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.

src/cli.ts
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.

src/cli.ts
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.

src/cli.ts
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.

src/cli.ts
approved: b.confirm().label("Continue?").default(true)
src/cli.ts
approved: b.confirm("simple").label("Continue?").default(false)
  • Toggle: inline Yes / No selector, arrow keys or y/n, then Enter
  • Simple: typed y/n input

Toggle while prompting:


  Continue?
 Yes  /  No

Toggle after submit:


 Continue?:   yes

Simple while prompting:


  Continue?
 (y/N) _

Simple after submit:


 Continue?:   no

Use b.search() when the choice list is fixed, but the user needs to filter it while typing.

src/cli.ts
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.

src/cli.ts
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.

src/cli.ts
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
Validation error

  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.

On this page