- Decision note: lipgloss, bubbletea, bubbles, huh, fang v2 and colorprofile, fang used narrowly, own diary console handler, stdlib daily writer - STACK.md Supporting Libraries rows for the six modules
6.6 KiB
Decision: the console runs on charm's v2 stack, logging stays on stdlib slog
Date: 2026-10-21 Status: Accepted Context: Phase 19.8 (console commands overhaul: D-01, D-02, D-05, D-08 and the CONTEXT discretion item on the console handler), 19.8-RESEARCH.md Standard Stack, Alternatives Considered, Package Legitimacy Audit and the probes quoted there
Decision
The console layer (modules/bonfire) and the new logging module (modules/diary) adopt charm's v2 libraries on the charm.land vanity paths. Log routing itself stays on the standard library's log/slog.
- Modules and versions. All six were checked with
go list -m -versionson 2026-10-21; each is the newest tag, so the research pins stand:charm.land/lipgloss/v2v2.0.6: styles, layout andlipgloss/v2/tablefor list, help, errors, tables and log lines.charm.land/bubbletea/v2v2.1.0: program runtime for the live spinner, process and progress views.charm.land/bubbles/v2v2.2.1:spinner(MiniDot, the framesbonfirealready draws),progress(the cyan-to-green bar),keyandhelp.charm.land/huh/v2v2.0.3: Ask, Confirm, Choice and Secret on an interactive terminal, with accessible mode.charm.land/fang/v2v2.0.1: cobra error rendering hook and Windows VT enabling.github.com/charmbracelet/colorprofilev0.4.3: imported directly forcolorprofile.Writerandcolorprofile.Detect(already a transitive dependency of all of the above).
- v2, not SSU's v1 pins. SSU (
/media/nvme/dev/pxpx/ssu) pinsgithub.com/charmbracelet/lipglossv1.0.0,bubbleteav1.3.0 andbubblesv0.20.0. fang v1 already depends on acharm.land/lipgloss/v2beta, so v1 widgets plus any fang would compile two lipgloss majors into every binary, and the v1 line is maintenance-only. SSU's widgets are ported with the v2 renames:View()returnstea.View, key events aretea.KeyPressMsg, the progress gradient isprogress.WithColors/WithDefaultBlend, and widths are set withSetWidth. - Who imports them. Only
modules/bonfire(all five charm libraries plus colorprofile) andmodules/diary(lipgloss and colorprofile) import charm modules. Plugins and other framework modules reach them throughbonfire.Outputanddiary.For, never directly. - fang is used narrowly.
fang.Executeruns withfang.WithoutVersion()(its-v/--versionwould collide with the verbosity flags),fang.WithoutManpage()(it would add a hiddenmancommand to the list and to duplicate checks),fang.WithoutCompletions(), andfang.WithErrorHandlerset to bonfire's own error renderer. The help and list layouts are bonfire's own Artisan layouts (D-14); fang's help func never reaches subcommands because bonfire sets a help func on every command. - Color is applied at the writer. lipgloss v2
Renderalways emits ANSI, so--ansi,--no-ansi,NO_COLOR,TERM=dumbandFORCE_COLORare applied throughcolorprofile.Writerwith a profile that bonfire detects. - The diary console handler is our own lipgloss-styled
slog.Handler. charm's slog logger module (charm.land/log/v2v2.0.1) is rejected: it failstesting/slogtest(WithGrouptreated as a prefix, empty attributes printed, attributes of empty-key groups not inlined), and it brings its own level and prefix model that duplicates diary's component levels. This settles the CONTEXT discretion item. - Daily files use a stdlib writer of about 120 lines (one file per day,
name-YYYY-MM-DD.log, retention by days, mode 0640).gopkg.in/natefinch/lumberjack.v2, which SSU uses, is rejected: it rotates by size, has no per-day naming, and would need its own note. - Fan-out and GORM. The
stackdriver is the standard library'sslog.NewMultiHandler(Go 1.26+), and GORM logs through gorm's ownlogger.NewSlogLogger(already in gorm v1.31.2). No logging library is added. - Cost. The probe measured about +2.1 MB on a stripped binary (
-trimpath -s -w): 2,527,495 bytes for cobra and x/term alone, 4,649,223 bytes with lipgloss/table, bubbletea, the bubbles spinner and progress, huh and fang. - Toolchain fit. The module go directives are at most 1.26 (lipgloss 1.25.0, bubbletea 1.26.0, bubbles 1.25.0, huh 1.25.8, fang 1.25.0) and fit this module's
go 1.27.0. Minimal version selection keepsgithub.com/spf13/cobrav1.10.2,github.com/spf13/pflagv1.0.9 andgolang.org/x/textv0.42.0 (fang asks for older cobra and pflag). - YAML rule.
gopkg.in/yaml.v3enters the module graph only as testify's indirect test dependency of fang and huh. Nothing in this repository imports it; YAML stays ongoccy/go-yaml. - Package legitimacy. The MSD package-legitimacy seam rejects the Go ecosystem, so the six modules were checked by hand against proxy.golang.org (
@latest,.mod,@v/list) and thecharm.landgo-import meta tags, whose origins aregithub.com/charmbracelet/*. Verdict: approved. fang is young (two v2 tags, repository first tagged 2025-06-18), which is acceptable because it is used only for the error hook. - Install order. Plan 19.8-01 installs
charm.land/lipgloss/v2andgithub.com/charmbracelet/colorprofilewith the code that imports them (the palette and the diary console handler); plan 19.8-02 installs bubbletea, bubbles, huh and fang with the widgets.go mod tidydrops requirements that no package imports, so each plan adds only what it uses.
Rejected alternatives. SSU's v1 pins were rejected for the two-majors problem above. charm.land/log/v2 was rejected for the slogtest failures and the duplicated level model. lumberjack was rejected because it rotates by size and names files differently. A hand-written fan-out handler (SSU's MultiHandler) was rejected in favour of slog.NewMultiHandler, which clones records, honours Enabled and joins errors.
Related dependencies
- Standard library only for logging:
log/slog(NewMultiHandler,JSONHandler,TextHandler,DiscardHandler,LevelVar),testing/slogtestfor handler conformance tests,osandpath/filepathfor the daily writer. - gorm.io/gorm v1.31.2 (already required) for
logger.NewSlogLogger. - github.com/spf13/cobra v1.10.2 (already required) stays the command parser under bonfire.
Consequences
- Every application binary grows by about 2.1 MB once plan 19.8-02 lands the widgets.
- Removing the stack later means rewriting bonfire's widgets and diary's console handler; D-01 and D-02 are rated costly for that reason.
- Plugins never import charm modules directly, so a later change of styling library touches only
modules/bonfireandmodules/diary. - A check in the plan's acceptance criteria (
go listover every package's imports) keeps the import boundary honest.