cli-tui
Skill41 starsChanged 7 days agoMITView on GitHub
Build or change the hive CLI's Bubble Tea TUI under cmd/hive/internal/tui -- views, modals, keybindings, async loads -- and test it with component and golden-file tests. Use when adding a view, a modal, a key, or a palette command to the TUI, when a TUI test or golden file fails, or when asked how the TUI is put together.
In this repository17 other files it gives its agents.
- AGENTS.mdAGENTS.md
- docs/AGENTS.mdAGENTS.md
- cli-autocalibrateSkill
- cli-smokeSkill
- desktop-apiSkill
- desktop-commands-auditSkill
- desktop-devserverSkill
- desktop-shipped-skillsSkill
- desktop-ui-auditSkill
- desktop-ui-perfSkill
- docs-auditSkill
- docs-pageSkill
- go-enumSkill
- release-notesSkill
- release-prepSkill
- releaseSkill
- sqlcSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 0 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 54
add a default UserCommand to defaultUserCommands (cmd/hive/internal/config/config.go).
- Very specific: line 65
All modal state lives on ModalCoordinator.
- Very specific: line 68
Do not keep modal state on a view.
- Very specific: line 86
Test behavior through the public surface: build the model, call SetSize, send messages through Update, and assert on state or on View() …
- Very specific: line 88
Always call SetSize before rendering.
- Very specific: line 112
Do not test cosmetic details in assertions.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Work on the hive TUI
The TUI is Bubble Tea v2 (charm.land/bubbletea/v2, bubbles/v2,
lipgloss/v2). For general Bubble Tea guidance, read the upstream docs; this
skill covers how this TUI is put together and the rules it is reviewed
against.
Where things live
cmd/hive/internal/tui/
├── model.go # Model, Update loop, message types, key routing
├── model_handlers.go # one handler per message or action
├── model_render.go # View composition
├── keybindings.go # KeybindingResolver (config -> action)
├── modal_coordinator.go # every modal, pending action, and stream state
├── command_palette.go # the `:` palette
├── components/ # reusable widgets: dialogs, form, status bar
├── views/ # one package per view: sessions, tasks, messages, review, shared
├── sourcepicker/ # the issue/PR source picker
└── testutil/ # RequireGolden, StripANSI, fixtures
cmd/hive/internal/styles/ # lipgloss styles and the active themeThe UI owns no business logic. It calls the service layer
(internal/hive) and shared packages in internal/, which must never import
charm (depguard fails the lint).
Views
Each view is its own package under views/, with its own model, Update,
View, SetSize, and message types. A view that needs to resolve keys
declares a small KeyResolver interface (views/sessions/key_resolver.go)
that the parent's KeybindingResolver satisfies. That interface exists to
break the import cycle between tui and the view; do not import tui from a
view.
ViewType in view.go names the views. Its String() value is the scope
name that cfg.Views.<View>.Keybindings matches against.
Keys
The precedence is in the root AGENTS.md ("Keybinding Precedence"). The rule
that matters most: a user-overridable key is never an if keyStr == "x"
block in view code. To add one:
- register an
action.Typeincmd/hive/internal/action/type.goand runmise run generate:enums; - add a default
UserCommandtodefaultUserCommands(cmd/hive/internal/config/config.go); - bind it in
defaultViewsConfig(cmd/hive/internal/config/config_views.go); - dispatch it from
model_handlers.go.
Hardcoded keys are only the layer-1 set: ctrl+c, esc, tab,
shift+tab, and modal dismissal. Document a new default on
docs/docs/cli/configuration/keybindings.md (the docs-audit skill).
Modals
All modal state lives on ModalCoordinator. A new modal is a field there, a
UIState value for "this modal is open", a key handler in model.go that
routes keys to it in that state, and a case in ModalCoordinator.Overlay.
Do not keep modal state on a view.
NewDangerousModal is the confirm dialog for anything that destroys work: the
user types the verb to enable it.
Async work
Update never blocks. Anything that touches git, tmux, the database, or the
network runs in a tea.Cmd that returns a message, and the handler applies
the result. Batch fan-out work into one completion message
(GitStatusBatchCompleteMsg) rather than one message per item. Polling is a
tick message that schedules the next tick (sessions.TerminalPollTickMsg).
Background failures cannot reach the user directly, so log them: debug for
expected or transient failures, warn for configuration problems. Show a
degraded state (a StatusMissing indicator) instead of dropping the item.
Testing
Test behavior through the public surface: build the model, call SetSize,
send messages through Update, and assert on state or on View() output.
Always call SetSize before rendering; a zero-size view renders nothing
useful.
Golden files cover rendered output (views/review/view_golden_test.go,
modal_golden_test.go):
view := New(docs, "", nil, nil, 0)
view.SetSize(80, 24)
testutil.RequireGolden(t, testutil.StripANSI(view.View()))Strip ANSI so output does not depend on the terminal's color profile. A
package whose output still depends on the theme pins one in TestMain
(styles.SetTheme with tokyo-night, as modal_golden_test.go does). Fix
timestamps in fixtures (testutil.CreateTestComment).
Golden files live in each package's testdata/. Regenerate them only after
you have read the diff and agree the new output is right:
go test ./cmd/hive/internal/tui/views/review -run TestView_ListMode -updateDo not test cosmetic details in assertions; a golden file is the place for
layout. End-to-end CLI behavior belongs in the Docker integration tests
(mise run cli:integration), never run on the host.
Verify
go test ./cmd/hive/...
mise run lint
mise run cli:dev # run the TUI against the dev config and .data/For anything that needs real tmux sessions, use mise run cli:container, or the cli-smoke skill when an agent drives it.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

