Best for
- Creating multi-step CLI installation or setup wizards
- Building reactive, session-driven terminal interfaces
- Adding real-time progress, spinners, or status displays to CLI tools
PostHog/wizard/.claude/skills/ink-tui/SKILL.md
Build terminal user interfaces (TUIs) using Ink (React for CLIs) and @inkjs/ui with a reactive, session-driven wizard pattern. Use when creating interactive CLI installation wizards, setup flows, or multi-step terminal applications in Node.js/TypeScript. Covers reactive screen resolution, declarative flow pipelines, overlay interrupts, session state management, Ink components, Flexbox terminal layout, and graceful degradation across terminal environments.
Decision brief
Build beautiful, interactive terminal wizard interfaces using Ink (React for CLIs).
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Declared | Source record | Install path and trigger |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/PostHog/wizard --skill ".claude/skills/ink-tui"Inspect the Agent Skill "ink-tui-wizard" from https://github.com/PostHog/wizard/blob/0b87fc8f97fa76ab9f9de39b9c9f848fc0e39b84/.claude/skills/ink-tui/SKILL.md at commit 0b87fc8f97fa76ab9f9de39b9c9f848fc0e39b84. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
Creating multi-step CLI installation or setup wizards
This skill follows a reactive session-driven pattern: the rendered screen is a pure function of session state. Business logic sets state through store setters. The router derives which screen should be active. Nobody imperatively pushes screens around.
WizardSession (src/lib/wizard-session.ts) — single source of truth for all wizard decisions
1. Create the component in src/ui/tui/screens/ 2. Add to Screen enum in router.ts 3. Add a FlowEntry to the flow array with an isComplete predicate 4. Register in screen-registry.tsx
Two patterns depending on the data:
Permission review
The documentation asks the agent to read local files, directories, or repositories.
Read each primitive's source file for its current props interface.Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 91/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 190 | Source | Repository attention, not individual Skill quality |
| Compatibility | 1 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Build beautiful, interactive terminal wizard interfaces using Ink (React for CLIs).
Ink is the dominant Node.js TUI framework — used by Claude Code (Anthropic), Gemini CLI (Google), GitHub Copilot CLI, Cloudflare Wrangler, Shopify CLI, Prisma, and many others.
This skill follows a reactive session-driven pattern: the rendered screen is a pure function of session state. Business logic sets state through store setters. The router derives which screen should be active. Nobody imperatively pushes screens around.
See references/ARCHITECTURE.md for the full reactive architecture: session, router, store, screen resolution, overlays, and data flow.
src/lib/wizard-session.ts) — single source of truth for all wizard decisionssrc/ui/tui/router.ts) — declarative flow pipelines with isComplete predicates per screensrc/ui/tui/store.ts) — nanostores-backed reactive store with explicit setters that trigger React re-renders via useSyncExternalStoresrc/ui/wizard-ui.ts) — interface bridging business logic to store; implemented by InkUI (TUI) and LoggingUI (CI)src/ui/tui/screen-registry.tsx) — factory function mapping screen names to components (App.tsx never changes)src/ui/tui/services/) — injected into screens via props (no dynamic imports in React components)src/ui/tui/screens/Screen enum in router.tsFlowEntry to the flow array with an isComplete predicatescreen-registry.tsxNo other files change.
Two patterns depending on the data:
WizardSession, add setter to WizardStore that calls emitChange(), add method to WizardUI interface + both implementationsWizardStore, add getter + setter, add method to WizardUI interface + both implementationsRead store.ts for examples of both patterns.
The project has reusable layout primitives in src/ui/tui/primitives/.
Always use these instead of building from scratch.
All primitives are barrel-exported from src/ui/tui/primitives/index.ts.
See references/PRIMITIVES.md for the catalog.
Read each primitive's source file for its current props interface.
Shared style constants (Colors, Icons, HAlign, VAlign) live in
src/ui/tui/styles.ts.
Playground: Run pnpm try --playground to see all primitives in action. When you add a new primitive, also add a demo for it under src/ui/tui/playground/demos/ and register it in PlaygroundApp.tsx. The playground is the single place a contributor (or future agent) can see every primitive rendered with realistic props — a primitive that's not in the playground is invisible to anyone who didn't write it, and the next person solving the same UI problem will build a parallel component instead of reusing yours.
All state comparisons use TypeScript enums — no string literals. See the source files for current values:
Screen, Overlay, Flow — in router.tsRunPhase, OutroKind — in wizard-session.tsTaskStatus — in wizard-ui.tsink # Core: React renderer for terminals (uses Yoga for Flexbox)
react # Peer dependency
@inkjs/ui # Official component library: Select, TextInput, Spinner,
# ProgressBar, ConfirmInput, MultiSelect, Badge,
# StatusMessage, Alert, OrderedList, UnorderedList
figures # Unicode/ASCII symbol fallbacks (cross-platform)
Do NOT use the older standalone packages (ink-text-input, ink-select-input,
ink-spinner). The @inkjs/ui package supersedes them.
src/ui/tui/
├── App.tsx # Thin shell — calls screen registry factory
├── store.ts # WizardStore: nanostores + session setters
├── router.ts # WizardRouter: flow pipelines + overlay stack
├── ink-ui.ts # InkUI: bridges getUI() calls to store setters
├── start-tui.ts # TUI startup: dark mode, store, renderer
├── screen-registry.tsx # Maps screen names to components + services
├── styles.ts # Colors, Icons, alignment enums
├── screens/ # One file per screen — read for current set
├── primitives/ # Reusable layout components — read index.ts for exports
├── services/ # Injectable service interfaces
└── components/
└── TitleBar.tsx # Top bar with version + feedback email
Ink is react-dom but for terminals. It uses Yoga (Facebook's Flexbox engine) for layout.
Every <Box> is a flex container. All visible text MUST be inside <Text>.
| Browser | Ink |
|---|---|
<div> | <Box> |
<span> | <Text> |
| CSS / className | Props directly on <Box> and <Text> |
onClick | useInput() hook |
window.innerWidth | useStdout().stdout.columns |
| scroll | <Box overflow="hidden"> + manual offset |
display: block | <Box flexDirection="column"> |
display: flex | Default — every <Box> is already flex |
useStdout().stdout.columns and .rows!process.stdin.isTTY and fall back to LoggingUI--ci flag uses LoggingUI (no TUI, no prompts)start-tui.ts forces black background via ANSI escape codescolor="#000000" not color="black" (terminals render ANSI black as grey)useApp().exit()Frequently asked questions
Build beautiful, interactive terminal wizard interfaces using Ink (React for CLIs).
The source record exposes this install command: npx skills add https://github.com/PostHog/wizard --skill ".claude/skills/ink-tui". Inspect the command and pinned source before running it.
The pinned source record declares support for: claude code.
Static rules flagged read-files in the source; the page lists the matching lines and excerpts.
Alternatives
yonatangross/orchestkit
json-render component catalog patterns for AI-safe generative UI. Define Zod-typed catalogs that constrain what AI can generate, use @json-render/shadcn for 36 pre-built components, optimize specs with YAML mode, and apply the three edit modes (patch/merge/diff) for progressive updates. Use when building AI-generated UIs, defining component catalogs, or integrating json-render into React/Vue/Svelte/React Native/Ink/Next.js projects.
yonatangross/orchestkit
Mockup-to-component pipeline using Google Stitch, 21st.dev, and Storybook MCP. Accepts a screenshot, a description, or a URL and produces production-ready React components, checking existing Storybook components before generating anything new. Use when implementing UI from a mockup or screenshot. To call the MCP tool surface on its own, with no design to convert, use storybook-mcp-integration.
vasilyu1983/AI-Agents-public
Implements production-grade i18n/l10n for React, Vue, Angular, and Next.js with ICU format and RTL support. Use when setting up or debugging localisation.
event4u-app/agent-config
Use BEFORE writing or editing any non-trivial UI — inventories components, design tokens, shadcn primitives, and reusable patterns into state.ui_audit. Hard gate for the ui directive set.