Awesome-omni-skill clack-guidelines
Comprehensive guide for building beautiful interactive command-line interfaces using Clack. Use when creating CLI tools with text input, selections, autocomplete, progress tracking, and streaming output.
git clone https://github.com/diegosouzapw/awesome-omni-skill
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/tools/clack-guidelines" ~/.claude/skills/diegosouzapw-awesome-omni-skill-clack-guidelines && rm -rf "$T"
skills/tools/clack-guidelines/SKILL.mdClack Guidelines
Overview
This skill provides guidance for building beautiful interactive command-line interfaces using Clack. It covers common patterns for text input, selections, autocomplete, progress tracking, streaming output, and creating complete interactive CLI applications.
Quick Start
Installation
npm install @clack/prompts
Basic Program
import { text, isCancel, cancel } from "@clack/prompts"; const projectPath = await text({ message: "Where should we create your project?", placeholder: "./my-awesome-project", initialValue: "./sparkling-solid", validate: (value) => { if (!value) return "Please enter a path."; if (value[0] !== ".") return "Please enter a relative path."; }, }); if (isCancel(projectPath)) { cancel("Operation cancelled."); process.exit(0); } console.log(`Creating project at: ${projectPath}`);
Complete Interactive CLI
import * as p from "@clack/prompts"; import color from "picocolors"; async function createApp() { console.clear(); p.intro(color.bgCyan(color.black(" create-myapp "))); const config = await p.group( { name: () => p.text({ message: "What is your project name?", placeholder: "my-awesome-app", validate: (value) => { if (!value) return "Project name is required"; }, }), framework: () => p.select({ message: "Choose your framework", options: [ { value: "react", label: "React", hint: "Popular" }, { value: "vue", label: "Vue" }, { value: "svelte", label: "Svelte" }, ], }), typescript: () => p.confirm({ message: "Use TypeScript?", initialValue: true, }), }, { onCancel: () => { p.cancel("Setup cancelled"); process.exit(0); }, }, ); console.log(config); } createApp().catch(console.error);
Common Patterns
Text Input
Single-line text input with validation and placeholders.
import { text } from "@clack/prompts"; const name = await text({ message: "Enter your name", placeholder: "John Doe", validate: (value) => { if (!value) return "Name is required"; }, });
Password Input
Secure password input with masking.
import { password } from "@clack/prompts"; const userPassword = await password({ message: "Provide a password", mask: "•", validate: (value) => { if (!value) return "Please enter a password."; if (value.length < 8) return "Password should have at least 8 characters."; }, });
Autocomplete Single Selection
Type-ahead search with real-time filtering.
import { autocomplete } from "@clack/prompts"; const country = await autocomplete({ message: "Select a country", options: [ { value: "us", label: "United States", hint: "NA" }, { value: "ca", label: "Canada", hint: "NA" }, { value: "uk", label: "United Kingdom", hint: "EU" }, ], placeholder: "Type to search countries...", maxItems: 8, initialValue: "us", });
Autocomplete Multi-Select
Type-ahead search with multi-selection.
import { autocompleteMultiselect } from "@clack/prompts"; const frameworks = await autocompleteMultiselect({ message: "Select frameworks (type to filter)", options: [ { value: "react", label: "React", hint: "Frontend/UI" }, { value: "vue", label: "Vue.js", hint: "Frontend/UI" }, { value: "nextjs", label: "Next.js", hint: "React Framework" }, ], placeholder: "Type to filter...", maxItems: 8, initialValues: ["react", "nextjs"], required: true, });
Single Selection Menu
Choose one option from a scrollable list.
import { select } from "@clack/prompts"; const projectType = await select({ message: "Pick a project type", initialValue: "ts", maxItems: 5, options: [ { value: "ts", label: "TypeScript" }, { value: "js", label: "JavaScript" }, { value: "rust", label: "Rust" }, { value: "go", label: "Go" }, ], });
Multi-Select Menu
Select multiple options from a list.
import { multiselect } from "@clack/prompts"; const tools = await multiselect({ message: "Select additional tools", initialValues: ["prettier", "eslint"], required: true, options: [ { value: "prettier", label: "Prettier", hint: "recommended" }, { value: "eslint", label: "ESLint", hint: "recommended" }, { value: "stylelint", label: "Stylelint" }, ], });
Confirmation Dialog
Binary yes/no choice.
import { confirm } from "@clack/prompts"; const shouldInstallDeps = await confirm({ message: "Install dependencies?", active: "Yes, please", inactive: "No, skip", initialValue: false, });
Progress Bar
Visual progress indicator for long-running operations.
import { progress } from "@clack/prompts"; import { setTimeout } from "node:timers/promises"; const downloadProgress = progress({ style: "block", max: 100, size: 40, }); downloadProgress.start("Downloading packages"); for (let i = 0; i < 100; i += 10) { await setTimeout(500); downloadProgress.advance(10); downloadProgress.message(`Downloaded ${i + 10}%`); } downloadProgress.stop("Download complete!");
Spinner Loading Indicator
Display progress for long-running operations.
import { spinner } from "@clack/prompts"; import { setTimeout } from "node:timers/promises"; const s = spinner(); s.start("Installing packages via pnpm"); await setTimeout(2000); s.message("Downloading dependencies"); await setTimeout(1500); s.stop("Installation complete!");
Task Log with Live Output
Display streaming output that clears on success and persists on error.
import { taskLog } from "@clack/prompts"; import { spawn } from "node:child_process"; const log = taskLog({ title: "Running npm install", limit: 10, retainLog: true, spacing: 1, }); const npmInstall = spawn("npm", ["install"]); npmInstall.stdout.on("data", (data) => { log.message(data.toString(), { raw: true }); }); npmInstall.on("close", (code) => { if (code === 0) { log.success("Installation complete!"); } else { log.error("Installation failed!", { showLog: true }); } });
Streaming Output for LLMs
Stream dynamic content from async iterables.
import { stream } from "@clack/prompts"; import { setTimeout } from "node:timers/promises"; await stream.step( (async function* () { const words = "Building your application with modern tools".split(" "); for (const word of words) { yield word; yield " "; await setTimeout(100); } })(), );
Grouped Prompts with Sequential Execution
Execute multiple prompts in sequence with shared state.
import * as p from "@clack/prompts"; import color from "picocolors"; p.intro(color.bgCyan(color.black(" create-app "))); const project = await p.group( { path: () => p.text({ message: "Where should we create your project?", placeholder: "./sparkling-solid", validate: (value) => { if (!value) return "Please enter a path."; if (value[0] !== ".") return "Please enter a relative path."; }, }), type: ({ results }) => p.select({ message: `Pick a project type within "${results.path}"`, initialValue: "ts", options: [ { value: "ts", label: "TypeScript" }, { value: "js", label: "JavaScript" }, { value: "rust", label: "Rust" }, ], }), tools: () => p.multiselect({ message: "Select additional tools", options: [ { value: "prettier", label: "Prettier", hint: "recommended" }, { value: "eslint", label: "ESLint", hint: "recommended" }, ], }), install: () => p.confirm({ message: "Install dependencies?", initialValue: true, }), }, { onCancel: () => { p.cancel("Operation cancelled."); process.exit(0); }, }, ); console.log(project.path, project.type, project.tools, project.install);
Task Execution with Spinners
Run multiple tasks with automatic spinner management.
import * as p from "@clack/prompts"; import { setTimeout } from "node:timers/promises"; await p.tasks([ { title: "Installing dependencies", task: async (message) => { message("Downloading packages"); await setTimeout(1000); message("Building native modules"); await setTimeout(500); return "Installed 127 packages"; }, }, { title: "Running linter", task: async () => { // Run linter return "No issues found"; }, }, ]);
Logging Messages
Display formatted status messages with different severity levels.
import { log } from "@clack/prompts"; import color from "picocolors"; log.info("Starting build process..."); log.step("Compiling TypeScript"); log.success("Build completed successfully!"); log.warn("Some dependencies are outdated"); log.error("Failed to connect to database"); // Custom symbol log.message("Custom message", { symbol: color.cyan("→"), });
Intro, Outro, and Notes
Frame your CLI sessions with beautiful headers.
import { intro, outro, note } from "@clack/prompts"; import color from "picocolors"; intro(color.bgCyan(color.black(" my-cli-tool v2.0.0 "))); // ... prompts and operations ... note("cd my-project\nnpm install\nnpm run dev", "Next steps"); outro( `Problems? ${color.underline(color.cyan("https://github.com/myorg/myproject/issues"))}`, );
Custom Key Bindings
Configure alternative key mappings for navigation.
import { updateSettings } from "@clack/prompts"; // Enable WASD navigation updateSettings({ aliases: { w: "up", s: "down", a: "left", d: "right", }, });
Non-Interactive Mode Detection
Handle CI environments where prompts aren't supported.
import { text, block } from "@clack/prompts"; // In CI environments, prompts automatically use defaults const name = await text({ message: "Project name?", defaultValue: "default-project", }); // block() utility prevents input in non-TTY environments const unblock = block(); // Perform operations unblock();
Cancellation and Error Handling
Robust error handling for user cancellations and validation errors.
import * as p from "@clack/prompts"; async function setupProject() { try { const responses = await p.group({ name: () => p.text({ message: "Project name?", validate: (v) => { if (!v) return "Required"; }, }), confirm: ({ results }) => p.confirm({ message: `Create "${results.name}"?`, }), }); // Check if any step was cancelled if (p.isCancel(responses.name) || p.isCancel(responses.confirm)) { p.cancel("Setup cancelled"); return; } if (!responses.confirm) { p.outro("Setup aborted"); return; } // Proceed with setup p.outro("Project created!"); } catch (error) { p.log.error(`Setup failed: ${error.message}`); process.exit(1); } } setupProject();
Advanced Features
Custom Render Function with @clack/core
Build custom prompts with full control over rendering.
import { TextPrompt } from "@clack/core"; import color from "picocolors"; const customPrompt = new TextPrompt({ validate: (value) => (value.length < 3 ? "Too short!" : undefined), render() { const title = `>>> ${color.bold("Enter your name")}:`; const input = this.valueWithCursor || color.dim("(empty)"); switch (this.state) { case "error": return `${title}\n${color.red(input)}\n${color.red(this.error)}`; case "submit": return `${title} ${color.green(this.value)}`; case "cancel": return `${title} ${color.strikethrough(this.value)}`; default: return `${title}\n${color.cyan(input)}`; } }, }); const result = await customPrompt.prompt(); console.log(`Result: ${result}`);
Event-Driven Custom Prompt
Subscribe to prompt events for advanced interactions.
import { TextPrompt } from "@clack/core"; const prompt = new TextPrompt({ render() { return `Input: ${this.valueWithCursor}`; }, }); // Listen to events prompt.on("value", (value) => { console.log(`Current value: ${value}`); }); prompt.on("submit", () => { console.log("User submitted the form"); }); prompt.on("cancel", () => { console.log("User cancelled"); }); const result = await prompt.prompt();
Complete CLI Application Example
Full-featured setup wizard combining multiple prompt types.
import { setTimeout } from "node:timers/promises"; import * as p from "@clack/prompts"; import color from "picocolors"; async function createApp() { console.clear(); p.intro(color.bgCyan(color.black(" create-myapp "))); const config = await p.group( { name: () => p.text({ message: "What is your project name?", placeholder: "my-awesome-app", validate: (value) => { if (!value) return "Project name is required"; if (!/^[a-z0-9-]+$/.test(value)) { return "Use only lowercase letters, numbers, and hyphens"; } }, }), framework: () => p.select({ message: "Choose your framework", options: [ { value: "react", label: "React", hint: "Popular" }, { value: "vue", label: "Vue" }, { value: "svelte", label: "Svelte" }, { value: "solid", label: "Solid" }, ], }), features: () => p.multiselect({ message: "Select features", required: false, options: [ { value: "router", label: "Router" }, { value: "state", label: "State Management" }, { value: "testing", label: "Testing Setup" }, { value: "ci", label: "CI/CD Pipeline" }, ], }), typescript: () => p.confirm({ message: "Use TypeScript?", initialValue: true, }), install: () => p.confirm({ message: "Install dependencies now?", initialValue: true, }), }, { onCancel: () => { p.cancel("Setup cancelled"); process.exit(0); }, }, ); // Execute setup tasks await p.tasks([ { title: "Creating project structure", task: async () => { // Create project files return `Created ${config.name}`; }, }, { title: "Installing dependencies", task: async (message) => { message("Resolving packages..."); await setTimeout(1000); message("Downloading..."); await setTimeout(2000); return "Installed 42 packages"; }, enabled: config.install, }, ]); // Display next steps const nextSteps = [ `cd ${config.name}`, config.install ? "" : "npm install", "npm run dev", ] .filter(Boolean) .join("\n"); p.note(nextSteps, "Next steps"); p.outro( `All set! ${color.underline(color.cyan("https://docs.example.com"))}`, ); } async function createProjectFiles(config) { // Implementation... } createApp().catch(console.error);
Detailed API Reference
For comprehensive API documentation including all prompt types, configuration options, and advanced features, see the detailed API reference:
This reference includes:
- Complete prompt type documentation
- Configuration options for each prompt
- Validation and error handling patterns
- Streaming and async patterns
- Custom key bindings and settings
- Integration with @clack/core
- TypeScript support
- And more
Resources
references/
This skill includes detailed API documentation:
- clack-api.md - Comprehensive API reference for Clack prompts, organized by prompt type with code examples for each feature.