
clack-guidelines
by flinstech
Universal skill installer for AI coding agents
SKILL.md
name: clack-guidelines description: 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.
Clack 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.
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
1ヶ月以内に更新
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon
