Beautifully designed components for the terminal. Yours to copy, paste, own.
A copy-paste component library for terminal UIs. Install the CLI, run glyph add chat-thread, and a chat surface drops into your repo as plain Go source you own. No glyph runtime dependency. No version pinning. No magic.
The model is shadcn/ui, ported to the terminal. The components are built for Bubble Tea in v0.1. Adapters for ratatui, Textual, and Ink follow.
go install github.com/truffle-dev/glyph/cmd/glyph@latest
cd path/to/your/project
glyph init
glyph add chat-threadThat's the whole onboarding. The third command writes Go files into internal/ui/ (or wherever your glyph.json aliases say) and runs go get for the upstream libraries the component needs.
Twenty-three components ship today: sixteen primitives from v0.1 and seven input, overlay, and data-display components from v0.2. All targeted at Bubble Tea; the registry shape is framework-agnostic and adapters for other frames are in progress.
| Component | Description |
|---|---|
theme |
Token palette every component reads from. Edit one file to retheme an entire app. |
chat-bubble |
Role-aware speech bubble with width-aware wrapping. user / assistant / system / tool. |
chat-input |
Single-line chat prompt with placeholder, cursor, focus state, submit and cancel bindings. |
chat-thread |
Vertically scrolling conversation surface. Composes chat-bubble. Arrow keys, PgUp/PgDn, Home/End. |
command-palette |
Filterable modal command picker. Substring matcher by default; swap in your own. |
markdown-viewer |
Scrollable terminal markdown. Headings, paragraphs, bullets, blockquotes, code, links. |
log-stream |
Bounded color-coded log view that tails like tail -f. Level filter, capacity ring. |
diff-view |
Unified-diff renderer with line numbers, color-coded additions and removals. Ships with a ParseUnified helper. |
notification-toast |
Stacked dismissible notifications with level-aware coloring and per-toast TTLs. |
status-bar |
Single-line three-segment status bar. Left fills from left, right anchors right, truncates left first under pressure. |
spinner |
Animated single-glyph indicator with an optional label. Five styles: dots, line, arc, pulse, bounce. |
tabs |
Horizontal labeled tab row primitive. Arrow keys or Tab cycle with wrap. Parent owns the panels below. |
panel |
Bordered container with optional title and footer. The workhorse layout primitive: wrap any view in one. |
list |
Vertical selectable list with cursor highlight, optional hints, disabled items, and internal scrolling. |
progress-bar |
Determinate progress indicator with an optional label and percentage readout. Color- and glyph-tunable. |
key-hints |
Compact footer of key-and-description pairs. The bottom-row cheatsheet every TUI grows into. |
| Component | Description |
|---|---|
text-input |
Multi-line text input with placeholder, focus, 2D cursor, Alt+Left/Right word jumps, Ctrl-U/K kill bindings. Enter inserts a newline; Ctrl-D commits. |
select |
Bounded single-choice popover with optional substring typeahead, scroll window, hint column, and inlaid title. |
modal |
Border-with-title overlay container with body, footer, and a configurable close key. Pairs with lipgloss.Place. |
confirmation |
Two-button yes/no prompt with focus-managed buttons, single-keystroke y/n shortcuts, dangerous-action styling, and prompt reflow. |
kbd |
Stateless keycap atom. Renders ctrl+k as ⌃ + K, enter as ⏎, and so on. Use inside hint rows, command palettes, modals. |
table |
Sortable, scrollable data grid with column alignment, numeric-aware sort, cursor highlight, optional row selection, and PgUp/PgDn/Home/End. |
stat-card |
Dashboard metric tile. Label, value, trend glyph, delta, sublabel, optional emphasis treatment. |
Every screenshot below is a recording of the component's own story/ binary running in a real terminal. No mockups, no Figma, no compositing — the same Bubble Tea output you get after glyph add <name>.
Browse all twenty-three with live demos at truffleagent.com/glyph.
Glyph is two things: a CLI and a static registry.
The CLI reads a local glyph.json in your repo and resolves paths via aliases:
{
"$schema": "https://truffleagent.com/glyph/schema/glyph.json",
"frame": "bubbletea",
"module": "github.com/your-org/your-app",
"aliases": {
"components": "internal/ui",
"lib": "internal/uilib",
"hooks": "internal/uihooks"
},
"theme": "default",
"registry": "https://truffleagent.com/glyph/r"
}glyph add chat-thread fetches truffleagent.com/glyph/r/chat-thread.json, walks the dependency graph (chat-thread depends on chat-bubble which depends on theme), and writes each file into the alias-resolved path. Import paths are rewritten so the files reference your module, not glyph's.
After install, the files are yours. Edit them. Refactor them. Delete the prompt prefix in chat-input.go and replace it with your project's logo. The library has no opinion.
The terminal is having a renaissance. Bubble Tea, ratatui, Textual, gum, lazygit, atuin, claude code — the list of TUIs people use daily is longer than it has been in a decade.
What's missing is a shared component vocabulary. Every team rewrites the chat surface, the command palette, the diff view, the status bar. Each rewrite is a little different, a little worse, and the team owes one more library upgrade for each one they import.
shadcn/ui solved this on the web by inverting the model. You don't import a library; you copy the source into your repo and own it. Updates are deliberate. Customization is direct. The library has no upgrade path because there is no library, only your code.
glyph applies the same shape to the terminal. Components are source files you copy. They reference a small theme module you also own. They have no runtime dependency on glyph. If glyph disappears, your app still works.
The rules that fall out of that bet:
- Copy, don't depend. Every component is downloadable as source. No glyph runtime dependency. Delete glyph after install and your app still works.
- One framework at a time. v0.1 is Bubble Tea. Adapters for ratatui, Textual, and Ink follow. We won't dilute the launch.
- Tokens, not hardcoded colors. Every component references
theme.Default. Theming a whole app is one file change. - Stories are tests are screenshots. A component without a story file doesn't ship. Stories drive the screenshot pipeline and the demo site equally.
- Quiet, not loud. No emojis, no marketing phrases, no exclamation marks. Earn attention with the work.
Twenty-three Bubble Tea components and the CLI ship today. The shape that follows:
- v0.2 — finishing form, overlay, and data. Seven landed:
text-input,select,modal,confirmation,kbd,table,stat-card. Still to come: code view with syntax highlighting (via chroma), file tree, breadcrumb. - v0.3 — first non-Bubble-Tea adapter. Likely ratatui (Rust), based on demand. The registry shape already encodes
frame, so each component re-ships as a sibling source file with the same manifest contract. - v0.4 and beyond. Textual (Python) and Ink (TypeScript). The catalog grows, the registry shape stays.
The registry contract is stable. What grows is the catalog.
truffleagent.com/glyph browses every component with a live SVG preview, the install command, the full source, and the JSON manifest.
cmd/nook/ is a terminal-native AI IDE assembled from the
catalog. Five panes, three Cursor-equivalent wedges: Ctrl+K inline edit,
Ctrl+L multi-file composer, Tab ghost-text autocomplete. Single
binary. Runs over SSH. Costs the AI calls and nothing else.
go install github.com/truffle-dev/glyph/cmd/nook@latest
export ANTHROPIC_API_KEY=sk-ant-...
nook .The spec is at docs/nook/. The AI client is a thin two-tier
wrapper (Haiku Fast, Sonnet Smart). Without the env var, the editor, picker,
project search, git pane, and terminal still work — only the AI wedges go
dark.
Four single-binary TUIs ship in examples/. Each one composes a real
subset of the catalog into one application — they are how you learn what
glyph looks like in your own app.
go run ./examples/showcase # five tabs: chat, commands, markdown, logs, diff
go run ./examples/chat-cli # agent-style chat REPL composing 13 components
go run ./examples/log-viewer # journalctl-style live feed composing 9 components
go run ./examples/dashboard # engagements control room composing 9 componentschat-cli puts a chat-input at the bottom, a chat-thread above it, a
spinner inline while a reply is in flight, a status-bar with the current
mode and message count, and pops a command-palette / modal+text-input /
modal+confirmation / select on demand. log-viewer synthesizes a steady
log feed across four sources and lets you filter by level (tabs), source
(select popover), and substring (text-input prompt). dashboard swaps
its stat-card row and table columns across three tabs (engagements,
throughput, revenue), opens a filter modal over a text-input prompt, and
fires a toast on row "open." All four binaries double as headless test
surfaces with a main_test.go that exercises every binding through
model.Update.
Each component also has its own runnable story/ binary:
go run -tags glyph_story ./components/select/story/See CONTRIBUTING.md. The fastest first contribution is a new component: copy components/chat-bubble/ as a template, replace the body, add a story file, and open a PR.
The shape of glyph is borrowed from shadcn/ui, which solved this distribution problem for React. The terminal needed the same answer.
Built on Bubble Tea by Charm.
























