1---
2name: charm-ecosystem
3description: "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)."
4argument-hint: "[what you're building or which libraries to combine]"
5---
6
7# Charm Ecosystem
8
9The architect's guide to charmbracelet's terminal UI ecosystem. Individual charm-* skills teach HOW to use each library. This skill teaches WHICH libraries to combine and WHY.
10
11**$ARGUMENTS context**: If a specific project type or library question is mentioned, focus on that decision path.
12
13## Ecosystem Map
14
15### Go Libraries (code you import)
16
17| Library | Import Path | Role |
18|---------|-------------|------|
19| **bubbletea** | `charm.land/bubbletea/v2` | TUI framework - Elm architecture (Model/Update/View) |
20| **lipgloss** | `charm.land/lipgloss/v2` | Terminal styling - colors, borders, layout, tables, lists, trees |
21| **bubbles** | `charm.land/bubbles/v2/*` | Pre-built TUI components - spinner, textinput, list, table, viewport |
22| **huh** | `charm.land/huh/v2` | Interactive forms - input, select, confirm, validation |
23| **glamour** | `charm.land/glamour/v2` | Markdown-to-ANSI rendering |
24| **harmonica** | `github.com/charmbracelet/harmonica` | Physics-based animation - spring oscillator, projectile |
25| **ultraviolet** | `github.com/charmbracelet/ultraviolet` | Low-level terminal primitives - cell buffers, screen management |
26| **fang** | `charm.land/fang/v2` | Cobra wrapper - styled help, auto versioning, manpages |
27
28### CLI Tools (binaries you run)
29
30| Tool | Role |
31|------|------|
32| **gum** | Shell script UI - prompts, filters, spinners, styled output |
33| **glow** | Markdown viewer - CLI and TUI browser |
34| **vhs** | Terminal demo recorder - .tape scripts to GIF/MP4 |
35| **freeze** | Code/terminal screenshot - PNG/SVG/WebP |
36| **pop** | Send email from terminal - TUI and CLI modes |
37
38### Dependency Hierarchy
39
40```
41ultraviolet (cell-level primitives)
42 |
43 +-- lipgloss v2 (styling, layout, composition)
44 |
45 +-- bubbletea v2 (framework: Elm architecture, commands)
46 |
47 +-- bubbles v2 (components: spinner, list, table, viewport...)
48 | |
49 | +-- harmonica (physics animations, optional addition to any bubbletea app)
50 | +-- lipgloss v2 (component styling)
51 |
52 +-- huh v2 (forms, standalone or embedded in bubbletea)
53 |
54 +-- bubbles v2 (huh uses bubbles internally)
55 +-- lipgloss v2 (theming)
56```
57
58Go libraries: `charm.land/*` vanity imports. CLI tools: `github.com/charmbracelet/*` or Homebrew.
59
60## Decision Tree
61
62### "I want to build a full TUI app"
63
64**Use: bubbletea + lipgloss + bubbles**
65
66The standard stack. Bubbletea provides the Elm architecture runtime, lipgloss handles all styling and layout, bubbles gives you pre-built components (list, table, viewport, spinner, textinput, progress, etc).
67
68Add huh if you need form flows. Add harmonica if you need animated transitions.
69
70### "I want shell script UI / interactive bash prompts"
71
72**Use: gum**
73
74No Go code needed. Gum provides choose, filter, input, confirm, spin, style, join, file, pager, table, log. All output to stdout for shell capture.
75
76### "I want terminal forms"
77
78**Go app: huh** (standalone or embedded in bubbletea)
79**Shell script: gum** (input, choose, confirm commands)
80
81Huh runs standalone with `.Run()` for simple cases, or embeds in bubbletea as a `tea.Model` for complex apps. Use gum when you're in bash/zsh and don't want to write Go.
82
83### "I want to render markdown in the terminal"
84
85**Programmatically (Go code): glamour**
86**View files from CLI: glow**
87
88Glamour is a library - import it, call `glamour.Render()`. Glow is a tool - run `glow README.md`.
89
90### "I want animations in my TUI"
91
92**Use: harmonica + bubbletea**
93
94Harmonica provides spring (damped oscillator) and projectile physics. Drive with `tea.Tick` at 60fps. Create `NewSpring` once, call `Update` per frame.
95
96### "I want an SSH-accessible TUI"
97
98**Use: bubbletea + wish**
99
100Wish (not covered by individual skills) wraps bubbletea for SSH serving. Wish provides SSH middleware that wraps your bubbletea handler per-connection. See the wish repo for setup.
101
102### "I want to record terminal demos"
103
104**Use: vhs** (optionally with gum for the demo content)
105
106Write a `.tape` script with Type/Enter/Sleep/Wait commands. VHS renders to GIF/MP4/WebM. Use `gum` commands in your tape for pretty interactive demos.
107
108### "I want terminal screenshots"
109
110**Use: freeze**
111
112Pipe code or use `--execute` to capture command output. Outputs PNG/SVG/WebP with syntax highlighting, window decorations, shadows.
113
114### "I want a CLI framework with styled help"
115
116**Use: fang + cobra**
117
118Fang wraps Cobra - you still write `*cobra.Command` structs. Fang adds lipgloss-styled help, auto version from build info, manpage generation, signal handling.
119
120### "I want to send emails from the terminal"
121
122**Use: pop**
123
124TUI and CLI modes. Supports SMTP and Resend API. Pipe body from stdin, attach files.
125
126### "I need cell-level terminal control"
127
128**Use: ultraviolet** (only if bubbletea is insufficient)
129
130Low-level primitives: cell buffers, screen management, input decoding. Powers bubbletea and lipgloss internally. Unstable API. Only use for custom renderers or framework-building.
131
132## Architecture Patterns
133
134### The Elm Architecture for Go Developers
135
136Bubbletea follows The Elm Architecture (TEA), a unidirectional data flow:
137
1381. **Model** - a struct holding ALL application state (like a Redux store)
1392. **Update(msg) -> (model, cmd)** - pure function: receives a message, returns new state + side effect
1403. **View(model) -> string** - pure function: renders state to terminal output
1414. **Cmd** - a function that performs I/O and returns a Msg back to Update
142
143The runtime owns the loop. You never mutate state outside Update, never call View yourself, never do I/O in Update.
144
145**Go-specific mental model**: think of it like an HTTP handler. The request is a `Msg`, the response is the new model + a `Cmd` to run next. The framework calls your handler, not the other way around.
146
147### Parent-Child Component Composition
148
149Children are just fields on the parent model. Each child has its own Update/View. Parent delegates:
150
151```go
152type parent struct {
153 header textinput.Model
154 body viewport.Model
155 footer help.Model
156}
157
158func (p parent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
159 var cmds []tea.Cmd
160
161 // Forward to all children, collect commands
162 var cmd tea.Cmd
163 p.header, cmd = p.header.Update(msg)
164 cmds = append(cmds, cmd)
165
166 p.body, cmd = p.body.Update(msg)
167 cmds = append(cmds, cmd)
168
169 return p, tea.Batch(cmds...)
170}
171```
172
173Children self-filter messages (spinners ignore wrong IDs, unfocused inputs ignore keys). Forward everything, let children decide.
174
175### Message Passing Between Components
176
177Components communicate through the parent via typed messages:
178
179```go
180// Child emits a "done" message
181type formDoneMsg struct{ name string }
182
183// Parent catches it and routes to another child
184case formDoneMsg:
185 m.body.SetContent("Welcome, " + msg.name)
186 m.state = stateMain
187```
188
189No direct child-to-child communication. Always go through the parent's Update.
190
191### When to Use What
192
193| Scenario | Use |
194|----------|-----|
195| Full interactive TUI with state | bubbletea + bubbles + lipgloss |
196| Simple form/prompt then exit | huh standalone (`.Run()`) |
197| Form inside a larger TUI | huh embedded in bubbletea |
198| One-off styled output (no interaction) | lipgloss only |
199| Shell script needs user input | gum |
200| Quick markdown preview | glow CLI |
201| Markdown in a Go app | glamour (+ viewport for scrolling) |
202
203## v2 Migration Quick Reference
204
205The ecosystem moved from `github.com/charmbracelet/*` to `charm.land/*` vanity imports.
206
207### bubbletea v1 -> v2
208
209| v1 | v2 |
210|----|-----|
211| `github.com/charmbracelet/bubbletea` | `charm.land/bubbletea/v2` |
212| `View() string` | `View() tea.View` (use `tea.NewView(s)`) |
213| `tea.KeyMsg` | `tea.KeyPressMsg` |
214| `tea.WithAltScreen()` program option | `v.AltScreen = true` in View |
215| `tea.WithMouseCellMotion()` | `v.MouseMode = tea.MouseModeCellMotion` in View |
216| `tea.WindowSizeMsg` `Width`/`Height` | Same, unchanged |
217
218### lipgloss v1 -> v2
219
220| v1 | v2 |
221|----|-----|
222| `github.com/charmbracelet/lipgloss` | `charm.land/lipgloss/v2` |
223| `lipgloss.Color("#F00")` is a type | `lipgloss.Color("#F00")` is a function returning `color.Color` |
224| `lipgloss.AdaptiveColor{}` | `lipgloss.LightDark(hasDark)` |
225| `style.Copy()` | Just assign (value type) |
226| `lipgloss.NewRenderer()` | Removed. No renderers in v2. |
227| Sub-packages at github path | `charm.land/lipgloss/v2/{table,list,tree}` |
228
229### bubbles v1 -> v2
230
231| v1 | v2 |
232|----|-----|
233| `github.com/charmbracelet/bubbles/*` | `charm.land/bubbles/v2/*` |
234| `tea.KeyMsg` matching | `tea.KeyPressMsg` + `key.Matches()` |
235
236### huh v1 -> v2
237
238| v1 | v2 |
239|----|-----|
240| `github.com/charmbracelet/huh` | `charm.land/huh/v2` |
241| `huh.NewTheme()` | `huh.ThemeFunc(fn)` |
242
243### glamour v1 -> v2
244
245| v1 | v2 |
246|----|-----|
247| `github.com/charmbracelet/glamour` | `charm.land/glamour/v2` |
248| `WithAutoStyle()` | Removed. Use `WithStandardStyle("dark")` |
249| Auto color detection | Pure output. Use lipgloss for downsampling. |
250
251## Integration Cookbook
252
253Five multi-library combinations with working code. See [references/cookbook.md](references/cookbook.md):
254
2551. **Standard TUI app** - bubbletea + lipgloss + bubbles (list with styled header/footer)
2562. **Forms in TUI** - bubbletea + huh (form then result display)
2573. **Markdown viewer** - bubbletea + glamour + viewport (scrollable rendered markdown)
2584. **Animated transitions** - bubbletea + harmonica (spring-animated position)
2595. **Scripted demo** - gum + vhs (tape file demoing a gum script)
260
261## Checklist
262
263- [ ] Import paths use `charm.land/*/v2` (not `github.com/charmbracelet/*`)
264- [ ] harmonica still uses `github.com/charmbracelet/harmonica` (no vanity import)
265- [ ] ultraviolet still uses `github.com/charmbracelet/ultraviolet` (no vanity import)
266- [ ] View returns `tea.NewView(s)` not raw string (bubbletea v2)
267- [ ] AltScreen/MouseMode set in View, not as Program options (bubbletea v2)
268- [ ] Colors use `lipgloss.Color()` function, not type literal (lipgloss v2)
269- [ ] WindowSizeMsg handled for responsive layout
270- [ ] huh forms embedded via Init/Update/View, not `.Run()`, when inside bubbletea