#interactive-cli #prompt #yaml #interactive #cliclack

cliclack_yaml

A YAML-based configuration layer for cliclack interactive CLI prompts

2 releases

Uses new Rust 2024

0.1.1 Mar 4, 2026
0.1.0 Mar 4, 2026

#243 in Command-line interface

MIT license

57KB
991 lines

cliclack-yaml

A Rust crate that lets you configure cliclack interactive CLI prompts using YAML files instead of code.

Features

  • Define CLI prompts entirely in YAML — no Rust code needed per prompt
  • 11 step types: intro, outro, input, password, confirm, select, multiselect, spinner, print, progress, clearscreen
  • Variable interpolation with {variable_name} syntax
  • Conditional step execution based on previous step results
  • Text styling (colors, backgrounds) for intro/outro steps
  • Input validation (not-empty, regex, min-length)

Installation

Add to your Cargo.toml:

[dependencies]
cliclack_yaml = "0.1.1"

Quick Start

1. Set up a prompts folder

Create a folder in your project to hold YAML prompt files, for example:

src/
  prompts/
    auth/
      login.yaml
    init/
      setup.yaml
    greeting.yaml

2. Configure cliclack_yaml in main.rs

use std::env;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Set the application root (typically the current working directory)
    cliclack_yaml::set_app_root(env::current_dir()?)?;

    // Set the prompt folder relative to app root
    cliclack_yaml::set_prompt_folder("src/prompts")?;

    // Run a prompt defined in src/prompts/greeting.yaml
    let results = cliclack_yaml::render_prompt_interaction("greeting")?;
    println!("User said: {:?}", results);

    Ok(())
}

3. Write YAML prompt files

Simple greeting (src/prompts/greeting.yaml):

- type: intro
  text: " Welcome to My CLI "
  style:
    color: black
    background: cyan

- type: input
  prompt: "What is your name?"
  output: "name"

- type: outro
  text: " Hello, {name}! "
  style:
    color: black
    background: green

Login flow with password (src/prompts/auth/login.yaml):

- type: intro
  text: " 🔐 Login "
  style:
    color: black
    background: cyan

- type: input
  prompt: "Email address"
  output: "email"

- type: password
  prompt: "Password"
  output: "password"

- type: outro
  text: " Authenticating... "
  style:
    color: black
    background: blue

Run nested prompts using the folder path:

let results = cliclack_yaml::render_prompt_interaction("auth/login")?;
let email = results.get("email").unwrap();

Passing Variables

You can pass variables into prompts and reference them with {variable_name}:

let results = cliclack_yaml::render_prompt_interaction_with_vars(
    "init/setup",
    vec![("config_path", "/home/user/.config/myapp")],
)?;
- type: print
  text: "Config will be created at: {config_path}"

YAML Step Reference

clearscreen

Clears the terminal screen.

- type: clearscreen

intro

Displays a styled introduction banner.

- type: intro
  text: " My Application "
  style:
    color: black        # black, white, red, green, blue
    background: cyan    # cyan, green, red, yellow

input

Prompts for text input with optional validation.

- type: input
  prompt: "Project name"
  placeholder: "my-project"
  output: "project_name"
  validate:
    - type: not-empty
      message: "Project name is required"
    - type: must-start-with-letter
      message: "Must start with a letter"
    - type: regex
      pattern: "^[a-z][a-z0-9-]*$"
      message: "Only lowercase letters, numbers, and hyphens"

password

Prompts for password input with masking.

- type: password
  prompt: "Enter password"
  output: "password"
  mask: '*'
  confirm_password: true
  confirm_prompt: "Confirm password"
  validate:
    - type: not-empty
      message: "Password is required"
    - type: min-length
      length: 8
      message: "Must be at least 8 characters"

confirm

Prompts for yes/no confirmation. Returns true/false in the output.

- type: confirm
  prompt: "Continue?"
  output: "confirmed"
  default: true

select

Prompts the user to select one option from a list.

- type: select
  prompt: "Choose a framework"
  output: "framework"
  items:
    - label: "React"
      value: "react"
    - label: "Vue"
      value: "vue"
      hint: "Recommended"
    - label: "Angular"
      value: "angular"

multiselect

Prompts the user to select multiple options.

- type: multiselect
  prompt: "Select features"
  output: "features"
  required: true
  items:
    - label: "Authentication"
      value: "auth"
    - label: "Database"
      value: "db"
      is_selected: true
    - label: "API"
      value: "api"

spinner

Displays a spinner while executing a named function.

- type: spinner
  start_text: "Installing dependencies..."
  stop_text: "Dependencies installed!"
  run_fn: "install_deps"
  output: "install_result"

Note: The run_fn value must match a function name registered in your execute_function_by_name handler.

print

Prints a message within the CLI frame. The loglevel field controls the visual style:

loglevel Symbol Description
(omitted) Bar continuation — blends into the frame
none Remark — connect-left, no marker icon
info Info marker (blue)
warning/warn Warning marker (yellow)
error Error marker (red)

Plain text (no loglevel) — blends into the frame:

- type: print
  text: "This text appears as part of the frame"

With log level marker:

- type: print
  loglevel: info
  text: "Config path: {config_path}"
  input: config_path  # optional: variable to read

Remark style (connect-left, no icon):

- type: print
  loglevel: none
  text: "A remark without a marker icon"

Tip: Use no loglevel for content like tables or formatted output that should blend seamlessly into the cliclack frame. Use loglevel: none when you want a visual separator () without an icon. Use info/warning/error for messages that need attention markers.

progress

Displays a progress bar or spinner for long-running tasks.

- type: progress
  progress_type: Bar
  start_message: "Downloading..."
  stop_message: "Download complete!"
  items:
    - name: "file1.zip"
      duration_ms: 2000
    - name: "file2.zip"
      duration_ms: 1500

multi-progress

Displays multiple progress bars simultaneously.

- type: multi-progress
  title: "Installing components"
  progress_bars:
    - label: "Core"
      progress_type: Bar
      duration_ms: 3000
    - label: "Plugins"
      progress_type: Spinner
      duration_ms: 2000

outro

Displays a styled closing message.

- type: outro
  text: " All done! "
  input: result_var   # optional: variable to display
  style:
    color: black
    background: green

Conditional Steps

Steps can be conditionally executed based on previous step results:

- type: confirm
  prompt: "Enable advanced mode?"
  output: "advanced"
  step_name: "advanced_check"

- type: input
  prompt: "Enter API key"
  output: "api_key"
  condition:
    parent: "advanced_check"
    value: true

The input step only runs if the user confirmed "advanced_check".

Advanced: Embedded Prompts with Fallback

For distributing your CLI as a single binary, you can embed YAML files at compile time using include_dir and fall back to them when no external prompt folder is found:

use std::collections::HashMap;
use anyhow::Result;
use include_dir::{include_dir, Dir};

// Embed all YAML files from src/prompts/ into the binary
static EMBEDDED_PROMPTS: Dir = include_dir!("src/prompts");

fn get_embedded_yaml(prompt_name: &str) -> Result<String> {
    let file_path = format!("{}.yaml", prompt_name);
    EMBEDDED_PROMPTS
        .get_file(&file_path)
        .and_then(|f| f.contents_utf8())
        .map(|s| s.to_string())
        .ok_or_else(|| anyhow::anyhow!("Prompt '{}' not found", prompt_name))
}

/// Try external folder first, fall back to embedded prompts
pub fn run_prompt(
    prompt_name: &str,
    vars: Option<HashMap<String, String>>,
) -> Result<HashMap<String, String>> {
    let yaml_str = match cliclack_yaml::get_yaml_content(prompt_name) {
        Ok(content) => content,
        Err(_) => get_embedded_yaml(prompt_name)?,
    };

    let steps: Vec<cliclack_yaml::PromptStep> = serde_yml::from_str(&yaml_str)?;
    cliclack_yaml::create_prompt_with_vars_custom(steps, vars)
}

This pattern lets users override prompts by placing YAML files in the configured prompt folder, while keeping defaults baked into the binary.

License

MIT

Examples

See the examples/config/ folder for a complete set of white-label YAML configurations covering auth flows, initialization, config management, CRUD operations, installation progress, system checks, and showcases for every feature (conditionals, variables, validation, styling).

For a full working CLI application that integrates cliclack_yaml with clap, see the cliclack-yaml-cli-example repository. It demonstrates embedded prompts, configuration management, and how to structure a white-label CLI project using this crate.

Dependencies

~11–16MB
~348K SLoC