Problem
~/.cprof.json is edited by hand or through a dozen subcommands, and one part
of it is genuinely awkward to write: the statusline block. lines is a
nested array of segment names, bar, thresholds, colors and
weekly_threshold each have their own rules, and the only feedback is cprof doctor telling you afterwards that a value was rejected and what it fell back
to. There is no way to see what a setting does before committing to it.
Proposed behavior
cprof config opens a panel over the whole configuration — profiles, rules,
repository pins, the default, fallback and the statusline — with a preview pane
showing what the highlighted setting does. For a statusline row that preview is
the real rendered line, with your glyphs, colours, width and segments:
┌─ cprof config ─────────┐┌─ preview ──────────────────┐
│ profiles ││ ⚑ work │ [Opus 5] │ cprof │
│ rules ││ Context ▓▓▓▓░░░░░░ 39% │
│> statusline.bar.width ││ Usage ▓▓░░░░░░░░ 18% │
│ statusline.colors ││ │
│ fallback ││ width: 10 ←→ to change │
└────────────────────────┘└─────────────────────────────┘
cprof config undo restores the previous configuration.
Alternatives considered
- Statusline only. Narrower and with the same preview payoff, since the
statusline is the only config with something to show. Rejected: the panel
should cover the whole config.
- A wizard, or
config set/config get/config edit. Less machinery and
more in character with the rest of the tool, but neither shows what a setting
does before you commit to it, which is the point.
- A TUI written in pure bash 3.2. Keeps
jq as the only dependency, at the
cost of several hundred lines of raw-mode handling, key decoding, a redraw
loop and a restore that must survive every exit path — a missed restore
leaves the user's shell with echo off, a worse failure than any cprof has
today. Rejected in favour of letting fzf own the loop.
- gum or dialog instead of fzf. gum is sequential prompts, not a panel;
dialog is the closest to a boxed panel but the least likely to be installed
on a Mac and has a clumsy shell interface. fzf brings the preview pane, which
is the feature that justifies a dependency at all.
Additional context
Decisions already taken (in the brainstorm, recorded in the design doc):
whole config rather than statusline only; a panel rather than a wizard; fzf
as an optional dependency, with the panel absent rather than degraded when
it is missing; destructive operations in scope behind typed confirmation;
immediate writes with a one-step backup and cprof config undo.
This reverses a prior decision. The clauth evaluation listed a TUI among the
things cprof should not adopt, with in-place credential swap, auto-switch, an
MCP delegate and a daemon. It is revisited because the config surface has grown
since — the statusline block did not exist then — and because this is an
optional layer over the existing commands, not a new way to run the tool. cprof
stays fully usable and scriptable with no fzf installed.
Architecture, in one line: everything editable becomes a row generated
from the config by jq — id, value, kind, constraint, action — and screens are
filtered row lists. fzf owns the loop and calls back into three normal CLI
entry points: --rows, --preview and --apply. Adding a setting to the
panel is then a row definition rather than new drawing code, which is what
keeps it in step as the config grows.
Why that matters for testing: the untestable surface is exactly one
function, the fzf invocation. Row generation, preview rendering, validation,
apply and undo are all CLI entry points the suite drives with no TTY, the way
it already drives statusline --stdin. The rule to hold while building it: if
a behaviour can only be reached by pressing a key, it is in the wrong place.
The risk worth naming. Destructive rows — remove --purge, login,
share — touch credential directories, symlinks and the keychain, inside a
screen whose purpose is fast movement. Mitigations are specified: never the
default selection, typed confirmation naming the profile, a second confirmation
for --purge, and login handed to the real subcommand because it opens a
browser.
Open questions for the plan: whether row ids are a documented stable
surface or explicitly internal; whether --rows emits tab-separated fields or
JSON; how rule reordering works, since it is a different interaction from
editing a value; and whether the panel may show usage figures at all, given
that would make it the first surface that could fetch from the network
(recommendation: cache-only, never fetch).
Rollout: not a release on its own. The first version can cover the
statusline block and the default profile, with the remaining screens added as
rows and no further architecture — which front-loads the live preview, the part
that has to feel right for the rest to be worth building.
Problem
~/.cprof.jsonis edited by hand or through a dozen subcommands, and one partof it is genuinely awkward to write: the
statuslineblock.linesis anested array of segment names,
bar,thresholds,colorsandweekly_thresholdeach have their own rules, and the only feedback iscprof doctortelling you afterwards that a value was rejected and what it fell backto. There is no way to see what a setting does before committing to it.
Proposed behavior
cprof configopens a panel over the whole configuration — profiles, rules,repository pins, the default, fallback and the statusline — with a preview pane
showing what the highlighted setting does. For a statusline row that preview is
the real rendered line, with your glyphs, colours, width and segments:
cprof config undorestores the previous configuration.Alternatives considered
statusline is the only config with something to show. Rejected: the panel
should cover the whole config.
config set/config get/config edit. Less machinery andmore in character with the rest of the tool, but neither shows what a setting
does before you commit to it, which is the point.
jqas the only dependency, at thecost of several hundred lines of raw-mode handling, key decoding, a redraw
loop and a restore that must survive every exit path — a missed restore
leaves the user's shell with echo off, a worse failure than any cprof has
today. Rejected in favour of letting fzf own the loop.
dialog is the closest to a boxed panel but the least likely to be installed
on a Mac and has a clumsy shell interface. fzf brings the preview pane, which
is the feature that justifies a dependency at all.
Additional context
Decisions already taken (in the brainstorm, recorded in the design doc):
whole config rather than statusline only; a panel rather than a wizard;
fzfas an optional dependency, with the panel absent rather than degraded when
it is missing; destructive operations in scope behind typed confirmation;
immediate writes with a one-step backup and
cprof config undo.This reverses a prior decision. The clauth evaluation listed a TUI among the
things cprof should not adopt, with in-place credential swap, auto-switch, an
MCP delegate and a daemon. It is revisited because the config surface has grown
since — the
statuslineblock did not exist then — and because this is anoptional layer over the existing commands, not a new way to run the tool. cprof
stays fully usable and scriptable with no fzf installed.
Architecture, in one line: everything editable becomes a row generated
from the config by jq — id, value, kind, constraint, action — and screens are
filtered row lists. fzf owns the loop and calls back into three normal CLI
entry points:
--rows,--previewand--apply. Adding a setting to thepanel is then a row definition rather than new drawing code, which is what
keeps it in step as the config grows.
Why that matters for testing: the untestable surface is exactly one
function, the fzf invocation. Row generation, preview rendering, validation,
apply and undo are all CLI entry points the suite drives with no TTY, the way
it already drives
statusline --stdin. The rule to hold while building it: ifa behaviour can only be reached by pressing a key, it is in the wrong place.
The risk worth naming. Destructive rows —
remove --purge,login,share— touch credential directories, symlinks and the keychain, inside ascreen whose purpose is fast movement. Mitigations are specified: never the
default selection, typed confirmation naming the profile, a second confirmation
for
--purge, andloginhanded to the real subcommand because it opens abrowser.
Open questions for the plan: whether row ids are a documented stable
surface or explicitly internal; whether
--rowsemits tab-separated fields orJSON; how rule reordering works, since it is a different interaction from
editing a value; and whether the panel may show usage figures at all, given
that would make it the first surface that could fetch from the network
(recommendation: cache-only, never fetch).
Rollout: not a release on its own. The first version can cover the
statusline block and the default profile, with the remaining screens added as
rows and no further architecture — which front-loads the live preview, the part
that has to feel right for the rest to be worth building.