BOOST-D05Shipped
Fix search: truncate & width-clamp results
Today boost search is the worst screen in the app: a single result can dump a 2,000-character description with literal, unrendered \\n\\n escapes, while names are padded to a fixed 30 columns that waste half the row. Clamp each row to the live terminal width, collapse whitespace/escape artifacts, and ellipsize. This one fix turns a wall of noise into a scannable list.
layoutComplexity MImpact High★★★★★
commands/discovery.py · search
BOOST-D06Shipped
Glass-panel box primitives
The web system frames everything in rounded glass; the CLI frames nothing. Add rounded box-drawing primitives (╭─╮ │ ╰─╯) with dim --line borders and an optional title, mirroring the web .glass/.window surfaces. Reusable chrome for doctor, info, snapshot and success summaries.
layoutComplexity MImpact Med★★★★☆
core/output.py · new panel()
BOOST-D07Shipped
Relevance visualization in search
Results are "ranked by heuristic relevance" but the ranking is invisible — every row looks equal. Render a tiny gradient relevance bar or score glyph per hit and visually separate curated from GitHub-wide matches, so the eye lands on the best result first.
layoutComplexity MImpact Med★★★★☆
commands/discovery.py · search
BOOST-D08Shipped
Width-aware, right-aligned tables
table() is a naive ljust that ignores terminal width and left-aligns numeric columns. Make it width-aware (shrink the widest text column to fit), right-align counts with tabular figures, and add dim column separators — matching the web's font-variant-numeric: tabular-nums stat blocks.
layoutComplexity MImpact Med★★★☆☆
core/output.py · table()
BOOST-D09Shipped
Terminal-window chrome for preview / cat
The web guide renders skills inside a titled window with traffic-light dots (.window .dots). Give preview/cat the same treatment: a titled frame with the skill name in the bar, so a rendered SKILL.md in the terminal matches the screenshots on the site.
layoutComplexity MImpact Med★★★★☆
commands/info.py · preview/cat
BOOST-D23Shipped
trending had the same overflow as search
Grading the un-touched commands surfaced a sibling of D05: boost trending piped raw catalog descriptions straight into table(), so a single 300-char description blew the table across the pane. Fixed by clipping each description through out.truncate() to the width left after the name/installs/last columns — the same helper the search fix introduced.
layoutComplexity SImpact High★★★★☆
commands/discovery.py · cmd_trending
BOOST-D24Shipped
Width-aware shared table()
out.table() backs ~28 call sites, and several overflowed: taps padded the NAME column to the widest repo (K-Dense-AI/claude-scientific-skills = 44 cols) and then printed full URLs, so wide catalogs wrapped. Now table() is width-aware itself — when a row would exceed the terminal it shrinks the widest text column and clips its cells with an ellipsis (ANSI-aware, so colored cells keep their color and close cleanly), while numeric columns are right-aligned like tabular figures and never truncated. Narrow tables render byte-identical to before; the logic only engages on overflow or multi-row number columns. Delivered test-first: dedicated unit coverage for _numeric_col, _clip_visible, _fit_widths, and the integrated render keeps the mutation gate green.
layoutComplexity LImpact Med★★★★☆
core/output.py:table() / _fit_widths / _clip_visible
BOOST-D27Shipped
Finish the wrap-law rollout across the CLI's remaining hand-rolled spots
A narrow-pane audit across all 80 commands fixed the concrete overflow bugs it found — a hardcoded textwrap width in info/preview/explain, two argparse usage lines with no metavar, help text that split a backtick-quoted command across lines, five "nothing here" screens that overflowed unwrapped, and a print_help command column painted in raw 16-color CYAN instead of the Aurora accent role — and added wide-character measurement (unicodedata.east_asian_width) to visible_len()/_clip_visible() so table() stays aligned when a cell holds CJK or an emoji. Three related gaps remain, deliberately left rather than folded into that pass because each is a wider, riskier sweep on its own:
1. dim(" text")'s embedded 2-space indent has no wrap path. 39 call sites (bmad's hint lines, schedule status, impact's caveat, …) hand-embed a leading " " because dim() prints flush-left by contract; passing wrap=True today would silently drop that margin on the first wrapped line (the tokenizer discards leading whitespace). One of the 39 measurably overflows a 60-column pane by a single character (schedule status's enable hint) — not worth an inconsistent one-off fix. dim() needs a real indent/margin parameter (mirroring kv's lead-column math) before any of the 39 can safely opt into wrapping.
2. empty_state() adoption is 7 of ~35 "nothing to show" screens. This pass converted cohort/replay/pulse/who's overflowing messages to the standard helper; roughly 28 more (hooks, hallmarks of "no taps configured", no skills installed across five modules, …) still print via ad hoc out.info("no X"). None of them currently overflow (wrong, see Shipped below), so converting all 28 in one shot would be a same-behavior refactor risking 28 screens' worth of rendered-text drift for no measured bug — better done a few at a time, verified against real content.
3. Wide-character width stopped at visible_len()/_clip_visible(). truncate() (plain-text clipping before coloring) and search_layout()'s column-budget math still count with len(), not display width — so a skill description containing an emoji would still truncate mid-character or throw off a search row's column budget. Not observed in real catalog data (skill names/taps are near-universal ASCII slugs), and widening it touches layout-budget code, not just measurement, so it stayed out of the audit's contained fix.
Shipped, with each gap measured at 60 and 120 columns before and after. 1. dim() takes an indent margin, and a leading run of spaces in the message counts as the same margin, so every dim(" hint") site can opt into wrapping unchanged: the margin is kept on the first and every continuation line, and the wrap budget pays for it. 24 prose hints now pass wrap=True (bmad, compact, create, policy, completions, schedule status, mcp, impact's caveat, install's MCP offer, pin/unpin, trust), plus chat's hand-rolled muted wrap, which became dim(note, wrap=True, indent=2). Lines that carry a path, an arrow to a path, or an unquoted command stay unwrapped as data. Each of the 24 was rendered at 60 and 120 columns. All 24 are byte-identical at 120. Ten of them overflowed a 60-column pane before, at 61 to 109 columns (bmad on's autopilot note was 109 and install's permissions hint was 81). All ten now fold to 60 columns or less, and no backtick span is split. Non-wrapping output is byte-identical everywhere. 2. 17 more "nothing to show" screens use empty_state(), with each em-dash remedy split into its → hint: taps, update, snapshot list, profile list, focus, context status, log, log --crashes, tag --list, quarantine --list, hooks list, attest, test, decay, impact, recommend and trending. out.empty_state( call sites under boost_cli/commands went from 13 to 30. The card's "none of them currently overflow" was wrong: measured in display columns at 60, trending was 68, recommend 66 and log --crashes 62 before, with taps exactly at 60 and snapshot list/focus at 58. All now fit, and tests/functional/test_cli_empty_states.py pins each of them. Action outcomes such as "nothing to change" and "nothing registered" are not empty listings and were left as they are. 3. This gap was already fixed before this card was picked up: 74c4aac9 made truncate() delegate to _clip_visible() and sized search_layout() with visible_len(), and test_output.py's CJK clipping tests pin it. A search row with a CJK name and an emoji description measures 59 columns at 60.
layoutComplexity MImpact Med★★☆☆☆
core/output.py · dim(indent=) + empty_state() call sites