agentleFS
colonyopscolonyops/hive/.agents/skills/cli-tui/SKILL.md

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.

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
  1. Very specific:

    add a default UserCommand to defaultUserCommands (cmd/hive/internal/config/config.go).

    line 54
  2. Very specific:

    All modal state lives on ModalCoordinator.

    line 65
  3. Very specific:

    Do not keep modal state on a view.

    line 68
  4. Very specific:

    Test behavior through the public surface: build the model, call SetSize, send messages through Update, and assert on state or on View() …

    line 86
  5. Very specific:

    Always call SetSize before rendering.

    line 88
  6. Very specific:

    Do not test cosmetic details in assertions.

    line 112

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

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 theme

The 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:

  1. register an action.Type in cmd/hive/internal/action/type.go and run mise run generate:enums;
  2. add a default UserCommand to defaultUserCommands (cmd/hive/internal/config/config.go);
  3. bind it in defaultViewsConfig (cmd/hive/internal/config/config_views.go);
  4. 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 -update

Do 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.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.