Getting started
Caret is a copy-paste design system for command-line tools. You run npx caret-cli init to scaffold a new CLI, then caret add <component> for each primitive — prompts, spinners, tables, errors. The components land in your repo as plain TypeScript files; you own them from there.
Why Caret
The web has shadcn/ui. The terminal has nothing equivalent — every CLI invents its own colors, spinners, error messages, and prompts, and the result looks like five libraries glued together. Caret is the missing layer: one opinionated visual identity, one token system, one set of primitives that respect NO_COLOR, narrow terminals, and screen readers without you opting in to anything.
Install
Caret has no runtime dependency. The CLI is a one-shot installer — it scaffolds a project or copies a single component, then exits.
# scaffold a new CLI with Caret preinstalled
npx caret-cli init my-cli
# add a component to an existing project
npx caret-cli add prompt
npx caret-cli add spinner
# list every component the registry knows about
npx caret-cli listSee Install for the full breakdown of what init creates and how the registry resolves component files.
Your first CLI
After caret init my-cli, the project compiles and runs out of the box. The starter src/index.ts looks like this:
import { prompt, success, spinner } from './caret'
const name = await prompt.text({
label: 'Project name',
validate: (v) => v.length > 0 ? null : 'Required',
})
await spinner('Deploying', async () => {
await deploy(name)
}, { onSuccess: 'Deployed' })
success(`${name} is live`)Three primitives, no provider, no theme object you forgot to pass down. The rest of the manual is on this site — start with Principles for what Caret will and won't do, then Tokens for how to skin it.
How it works
Caret has four layers, top-down:
- Components — React components rendered with Ink. Each one is one file you can read in a single sitting. They write inline output (scrollback-friendly, pipe-friendly), not fullscreen.
- Tokens — colors, motion, symbols, spacing, and typography. The component layer never hard-codes hex values; everything routes through the token system, so a single
setTheme()call re-skins the entire tool. - Capability —
lib/capability.tsdetects TTY,NO_COLOR, narrow terminals, and reduced motion. Every component consults it before painting; that's why colors degrade through truecolor → 256 → ANSI 16 → plain without your code knowing. - Spec — every component is documented in
specs/<name>.mdas the source of truth. If you fork a component or port Caret to another language, the spec is what binds them.
Next
Pick a direction:
- CLI — every command, every flag.
- Principles — the ten rules every Caret decision comes back to.
- Tokens — the palette, motion, and symbol set you'll override.
- AI-native workflow — drop
caret.mdinto your repo and Claude / Cursor / Copilot produce on-brand Caret code on the first try. - Component catalog — 80+ primitives with live previews.