charm-crush
Architecture patterns from Crush, charmbracelet's production agentic coding CLI built on bubbletea v2, lipgloss v2, bubbles v2, glamour v2, and ultraviolet. Use when building production bubbletea apps, composing charm TUI components at scale, designing agentic CLI tools, implementing streaming LLM UIs, or asking about crush internals. NOT for individual charm library basics.
Best use case
charm-crush is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Architecture patterns from Crush, charmbracelet's production agentic coding CLI built on bubbletea v2, lipgloss v2, bubbles v2, glamour v2, and ultraviolet. Use when building production bubbletea apps, composing charm TUI components at scale, designing agentic CLI tools, implementing streaming LLM UIs, or asking about crush internals. NOT for individual charm library basics.
Teams using charm-crush should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/charm-crush/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How charm-crush Compares
| Feature / Agent | charm-crush | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Architecture patterns from Crush, charmbracelet's production agentic coding CLI built on bubbletea v2, lipgloss v2, bubbles v2, glamour v2, and ultraviolet. Use when building production bubbletea apps, composing charm TUI components at scale, designing agentic CLI tools, implementing streaming LLM UIs, or asking about crush internals. NOT for individual charm library basics.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Charm Crush - Production Agentic TUI Patterns
Crush is charmbracelet's agentic coding CLI - their answer to Claude Code, built entirely with their own TUI stack. This skill captures the architecture patterns, component composition strategies, and design decisions from a production app with 10+ composed components, real-time LLM streaming, dialog overlays, and a full agent loop.
Source: `github.com/charmbracelet/crush` (FSL-1.1-MIT)
## Architecture Overview
Crush follows a clear layered architecture:
```
main.go (cobra CLI)
-> internal/app/app.go (wiring: DB, config, agents, LSP, MCP, events)
-> internal/agent/ (LLM conversations, tool execution, streaming)
-> internal/ui/ (bubbletea v2 TUI)
-> internal/permission/ (tool approval via pubsub)
-> internal/skills/ (Agent Skills open standard)
-> internal/pubsub/ (generic typed broker for cross-component messaging)
-> internal/session/ (SQLite persistence via sqlc)
```
### Key Dependencies (go.mod)
| Library | Version | Role |
|---------|---------|------|
| `charm.land/bubbletea/v2` | v2.0.2 | TUI framework |
| `charm.land/lipgloss/v2` | v2.0.2 | Terminal styling |
| `charm.land/bubbles/v2` | v2.0.0 | Reusable components (textarea, viewport, spinner, help) |
| `charm.land/glamour/v2` | v2.0.0 | Markdown rendering |
| `charm.land/fantasy` | v0.16.0 | LLM provider abstraction (Anthropic, OpenAI, Gemini, Bedrock, etc.) |
| `charmbracelet/ultraviolet` | - | Screen-buffer rendering system |
| `charm.land/catwalk` | v0.31.0 | Model registry + golden-file testing |
| `charmbracelet/x/exp/charmtone` | - | Color palette system |
## Decision Tree: How Crush Solves Common Problems
Use $ARGUMENTS to find the relevant pattern, or browse by category:
### TUI Architecture
- **"How do I structure a large bubbletea app?"** -> Read `references/tui-patterns.md` (Centralized Model pattern)
- **"How do I handle window resize?"** -> Read `references/tui-patterns.md` (Layout System)
- **"How do I compose 10+ components?"** -> Read `references/component-composition.md`
- **"How do I manage focus between panes?"** -> Read `references/tui-patterns.md` (Focus Management)
- **"How do I render streaming content?"** -> Read `references/tui-patterns.md` (Streaming Rendering)
- **"How do I do overlays/modals?"** -> Read `references/component-composition.md` (Dialog System)
### Agent Loop
- **"How does the LLM loop work?"** -> Read `references/agent-loop.md`
- **"How do I handle tool approval?"** -> Read `references/agent-loop.md` (Permission System)
- **"How do I stream LLM responses to the TUI?"** -> Read `references/agent-loop.md` (Streaming Bridge)
### Design & Styling
- **"How do I build a polished terminal UI?"** -> Read `references/design-system.md`
- **"What colors does charm use?"** -> Read `references/design-system.md` (Charmtone Palette)
- **"How do I structure styles for a large app?"** -> Read `references/design-system.md` (Styles Struct)
## Core Pattern: The Centralized Model
The single most important architectural decision in Crush. The `UI` struct in `internal/ui/model/ui.go` is the **sole bubbletea model**. Sub-components are NOT bubbletea models - they're stateful structs with imperative methods.
```
UI (the only tea.Model)
|-- Chat (stateful struct, no Update method)
|-- textarea (bubbles/v2 textarea.Model)
|-- dialog.Overlay (stack of Dialog interfaces)
|-- completions (non-standard Update returning bool)
|-- attachments (non-standard Update)
|-- status, header, pills (render methods on UI)
```
This means:
- All message routing happens in one giant `switch msg.(type)` in `UI.Update()`
- Focus state determines key routing (editor vs chat)
- Components expose methods like `HandleMouseDown()`, `ScrollBy()`, `SetMessages()` instead of `Update(tea.Msg)`
- Side effects return `tea.Cmd` from methods, not from Update
### Why This Works
Traditional Elm architecture (each component gets its own Update/View) breaks down at scale because:
1. Message routing becomes a maze of forwarding
2. Shared state requires complex message passing
3. Focus management needs a central coordinator anyway
Crush sidesteps this by making the parent the single source of truth for all state transitions.
## Rendering Pipeline: Ultraviolet Screen Buffer
Crush uses a hybrid rendering approach instead of pure string concatenation:
1. `View()` creates an `ultraviolet.ScreenBuffer` sized to terminal dimensions
2. Layout is computed as `image.Rectangle` regions via `ultraviolet/layout.SplitVertical/SplitHorizontal`
3. Components draw into sub-regions: `uv.NewStyledString(str).Draw(scr, rect)`
4. Dialogs draw last (overlay on top of everything)
5. `canvas.Render()` flattens to a string for bubbletea
This enables:
- Overlapping content (dialogs, completions popup)
- Precise cursor positioning across components
- Screen-based layout math instead of string width guessing
## Communication: Typed Pub/Sub
Agent and TUI run on separate goroutines. They communicate through a generic typed broker (`internal/pubsub`) that publishes events which bubbletea converts to `tea.Msg`. See `references/agent-loop.md` for the full pattern and event types.
## File Map
| What | Where | Read for |
|------|-------|----------|
| Main TUI model | `internal/ui/model/ui.go` | Centralized model, Update loop, layout |
| Chat component | `internal/ui/model/chat.go` | List wrapping, animation, mouse handling |
| Tool renderers | `internal/ui/chat/*.go` | Per-tool rendering (bash, file, search, etc.) |
| Dialog system | `internal/ui/dialog/` | Modal overlays, permissions, models picker |
| List component | `internal/ui/list/list.go` | Lazy-rendered scrollable list |
| Styles | `internal/ui/styles/styles.go` | Full design system |
| Agent loop | `internal/agent/agent.go` | LLM streaming, tool execution |
| Coordinator | `internal/agent/coordinator.go` | Multi-provider setup, model management |
| Tool definitions | `internal/agent/tools/*.go` | Tool implementations (.go + .md pairs) |
| Permission system | `internal/permission/permission.go` | Tool approval flow |
| Skills loader | `internal/skills/skills.go` | SKILL.md parsing and discovery |
| Pub/sub | `internal/pubsub/` | Typed event broker |
| App wiring | `internal/app/app.go` | Service initialization |
| Config | `internal/config/` | crush.json loading, provider config |
| UI architecture guide | `internal/ui/AGENTS.md` | Charm's own UI development instructions |
## Reference Files
For detailed patterns with code examples from the actual source:
- `references/tui-patterns.md` - Layout system, focus management, key handling, streaming, responsive design
- `references/agent-loop.md` - Agent loop, fantasy SDK, tool system, permission flow, pubsub bridge
- `references/design-system.md` - Charmtone colors, Styles struct, icon system, typography
- `references/component-composition.md` - Interface hierarchy, dialog stack, list composition, chat itemsRelated Skills
charm-vhs
Record terminal sessions as GIF/MP4/WebM from declarative .tape scripts with VHS. Use when creating terminal demos, recording CLI sessions, VHS tape files, or generating terminal GIFs.
charm-ultraviolet
Low-level Go terminal primitives - cell-based rendering, input handling, screen management. Use when building custom Go terminal renderers, ultraviolet, cell buffers, or performance-critical TUI work below Bubble Tea's abstraction level.
charm-pop
Send emails from the terminal with pop - TUI and CLI modes, SMTP and Resend support, attachments. Use when sending email from terminal, pop, CLI email, or piping email content from shell scripts.
charm-lipgloss
CSS-like terminal styling for Go with lipgloss v2 - styles, colors, borders, layout, tables, lists, and trees. Use when styling Go terminal output, lipgloss, terminal layout composition, or building styled tables/lists/trees in Go.
charm-huh
Build interactive terminal forms and prompts in Go with huh - input, select, confirm, multiselect, validation, theming. Use when building Go terminal forms, huh, interactive Go prompts, or form fields with validation. NOT for shell script prompts (use gum).
charm-harmonica
Physics-based animation for Go TUIs - damped spring oscillator and projectile motion. Use when adding spring animations, physics-based motion, or smooth transitions to Go terminal apps. No Ease function exists in this library.
charm-gum
Interactive shell script prompts, fuzzy filters, spinners, and styled output with gum. Use when building bash/shell script UIs, gum commands, interactive shell prompts, or CLI script workflows. NOT for Go terminal forms (use huh).
charm-freeze
Generate PNG, SVG, or WebP screenshots of code and terminal output with freeze. Use when screenshotting code, freeze, terminal-to-image, or capturing styled code snippets as images.
charm-fang
Wrap Cobra with styled help, error output, auto versioning, and manpage generation via fang. Use when building Go CLIs with fang, styled Cobra help, or adding lipgloss-rendered help pages to a Go CLI.
charm-ecosystem
Architect's guide to the charmbracelet Go TUI ecosystem - which libraries to combine, dependency hierarchy, integration patterns. Use when choosing charm libraries, planning TUI architecture, combining bubbletea/lipgloss/bubbles/huh, or asking 'which charm library for X'. NOT for specific library API details (use individual charm-* skills).
charm-bubbletea
Build terminal UIs in Go with Bubble Tea v2's Elm Architecture (Model/Update/View). Use when building Go TUI apps, tea.Model, tea.Cmd, Elm architecture, or terminal applications. NOT for pre-built TUI components (use bubbles).
charm-bubbles
Pre-built TUI components for Bubble Tea apps - spinner, text input, textarea, list, table, viewport, paginator, progress bar. Use when adding Go TUI components, bubbles, or terminal widgets to a Bubble Tea app. NOT for the core TUI framework (use bubbletea).