Back to list
flinstech

clack-guidelines

by flinstech

Universal skill installer for AI coding agents

21🍴 5📅 Jan 23, 2026

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:

references/clack-api.md

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

65/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon