Skip to content

feat(cli): a context enables only the commands of the profiles it names, and kates lists, completes and refuses by them - #387

Merged
bmscomp merged 2 commits into
mainfrom
feat/cli-profiles
Oct 18, 2026
Merged

bmscomp merged 2 commits into
mainfrom
feat/cli-profiles

Conversation

@bmscomp

@bmscomp bmscomp commented Oct 17, 2026 •

Copy link
Copy Markdown
Owner

Why

kates shows every command to everyone. A chaos engineer, a performance tester and someone deploying the stack each use a fraction of the 54 top-level commands, and the hand-written help hid the deploy family entirely. A context can now name the command profiles its user works in. kates then lists, completes and runs only those commands, and refuses the rest with the exact command that enables them.

A context with no profiles, which is every context today, enables every command, so nothing changes until someone sets profiles.

What a profile enables

Profile Enables
performance advisor, badge, benchmark, cost, dashboard, explain, flow, gate, lab, profile, replay, report, scenario-diff, schedule, test, top, trend, tune, watch, webhook
integrity dashboard, explain, kafka, migrate, replay, report, scenario-diff, schedule, test, top, watch, webhook
chaos chaos, cluster, disruption, flow, report, resilience, test, watch
topology cluster, diff, doctor, kafka, snapshot
security kyverno, security
deploy auto, clean, deploy, detect, doctor, kyverno, migrate, operator, operators, versions

Always enabled: audit, changelog, completion, ctx, docs, health, help, init, mcp, plugin, ports, status, theme, tldr, upgrade, version, and plugins. A subcommand follows its top-level command. commandProfiles in cli/cmd/command_profiles.go is the one table; a test fails when a command is missing from it.

How it looks

$ kates ctx profiles set chaos topology
  ✓ Context 'lab' enables chaos, topology

$ kates ctx profiles
  ○ performance      advisor        badge          benchmark      cost
                     dashboard      explain        flow           gate
  …
  ● chaos            chaos          cluster        disruption     flow
                     report         resilience     test           watch

  ● topology         cluster        diff           doctor         kafka
                     snapshot
  …
    Details:         kates ctx profiles <profile>...
    Change them:     kates ctx profiles set [profile...]
    Every command:   kates ctx profiles set all

$ kates ctx profiles topology
  ● topology         enabled
                     cluster        Kafka cluster information and…  (also chaos)
                     diff           Compare Kafka cluster state between two con…

$ kates tune types
  ✖ kates tune needs the performance profile
    Enabled:    chaos, topology (context "lab")
    Enable it:  kates ctx profiles set performance chaos topology
    Run once:   KATES_PROFILES=all kates tune types …
  • kates names the profiles above Quick Start and drops the help lines of commands they don't enable. Shell completion offers only enabled commands, and reads --context from the line being completed.
  • kates ctx profiles lays each profile's commands out in columns that line up across profiles. It marks the selected profiles with ● and dims refused commands. Named profiles, or all, give one line per command with what it does and the other profiles that enable it; -o json gives the same as data.
  • kates ctx profiles set [profile...|all] replaces the profiles. With none named, in a terminal, it opens a huh checklist with the ticked profiles first. Without a terminal it refuses rather than guess.
  • KATES_PROFILES overrides the context's profiles for one call or one shell; KATES_PROFILES=all enables everything.
  • Not affected: kates mcp, which is always enabled and whose process never hides a command, so the CLI docs resource agents read keeps every one. kates ctx set keeps a context's profiles, and ctx export/ctx import carry them.

Worth a look

  • The root hook is now PersistentPreRunE so it can refuse; kafka connect's own hook chains it. One test called the hook directly and was updated.
  • The root help gains a Deployment section with the deploy family fix(cli): drop the generated "All commands:" section from root help #90 left out to keep the help short. A deploy profile would list nothing without it. It also gains lines for ctx profiles, ports, mcp and upgrade, diff now says it compares two clusters, and the Security and Kyverno lines line up.
  • Context now holds a slice, so two tests that compared contexts with != use reflect.DeepEqual.
  • Refusing (rather than only hiding) was the requested behaviour. Scripts are only affected once someone sets profiles on the context they use, and KATES_PROFILES=all lifts it.

Second commit: what a review of the shipped profiles found

fbace69 fixes what a second review of the profiles turned up:

  • Refusal: the fix lines go to stderr, so kates … -o json leaves stdout empty. "Run once" keeps --context, so pasting it no longer runs against the current context.
  • Help of a refused command (kates tune --help, kates help tune, bare kates tune) still prints and exits 0, then the same note on stderr. The help path honours --plain and KATES_PLAIN, and a broken ~/.kates.yaml is warned about once.
  • Unknown profile names enable nothing, alone or mixed with known ones; a context naming only typos used to enable every command. They stay listed after the known ones, so the typo shows.
  • Alignment: the kates header is left out when no profiles are set. Its values line up with the help's descriptions (column 17), and kates ctx profiles lines its Context and Profiles values up with the grid (column 21).
  • kates tldr lists only enabled entries, names the profiles when it hides some, and says how to see every entry when a filter hides them all. Its "Compare two runs" line is now kates report diff, and its titles are indented again.
  • kates ctx import keeps a context's profiles when the file names none. kates ctx stops calling contexts "connection profiles", and book 10 says profiles are not access control and links the API key scopes.
  • MCP eval: the human-side setup runs with KATES_PROFILES=all.

The repository's squash message setting joins both commits' messages, so give the squash an explicit message when merging.

Tests

Run locally, all passing:

  • cd cli && go test ./... and go vet ./..., also with KATES_PROFILES=chaos in the environment, with KATES_ASCII=1 LC_ALL=C, and with CLICOLOR_FORCE=1.
  • python3 -m unittest discover -s eval/mcp -p 'test_*.py' (240 tests).
  • golangci-lint run --new-from-rev=origin/main ./... (0 issues) and govulncheck ./....
  • scripts/check-cli-style.sh and scripts/check-cli-compat.sh.
  • Backend ./mvnw test -Dquarkus.grpc.codegen.skip=true -Dquarkus.http.test-port=0 (1,466 tests), because cli/** sets ci.yml's code filter. Run for the first commit; the second touches nothing under kates/. The gRPC sources were copied from the main checkout, since codegen can't run on this Mac; kates.proto is unchanged.
  • Book: check-book-style.sh, gen-version-matrix.sh --check, gen-chart-table.sh --check, check-book-contrast.py, check-mermaid.sh, a scratch HTML render with check-book-fragments.py (7,470 fragment links, with the new scopes link), and a scratch PDF render. The added lines use only characters the book already has (…, ●, ✖).
  • Rendered in an 80-column pseudo-terminal: the profile list, details, refusal, root help header and the checklist (opened, then cancelled with the config byte-identical).

New tests in command_profiles_test.go cover:

  • the table against the registered commands;
  • the refusal messages and --context in the fix;
  • the help filter and header (where the profiles come from, ≤ 80 columns);
  • the grid's column alignment and the hint column;
  • the details view and its JSON;
  • ctx profiles set, including "" and ,;
  • ctx set keeping the profiles;
  • through the test binary run as kates: a refusal that reaches no server, and completion under KATES_PROFILES and under --context.

The *IT tests, the Kind integration tests and the Docker builds run only in CI.

Merges cleanly with the open PRs that touch the same files: #386, #380, #378, #375.

…es, and kates lists, completes and refuses by them

kates listed every command to everyone, in a hand-written help that left
out the deploy family. A context can now name the command profiles its
user works in: performance, integrity, chaos, topology, security or
deploy. commandProfiles in command_profiles.go maps each top-level
command to the profiles that enable it. A subcommand follows its parent,
and the commands every profile needs (ctx, health, help, ports, mcp and
a few more) are always enabled, as are plugins. A context with no
profiles, which is every context today, enables every command.

With profiles set, kates names them above Quick Start and lists only
their commands' lines, shell completion offers only those commands, and
any other command is refused before it calls the Kates API. The refusal
exits 1 and gives the two ways out: the kates ctx profiles set line that
enables the command and keeps the others, and KATES_PROFILES=all for one
call. KATES_PROFILES overrides the context's profiles for a call or a
shell. The check runs in the root PersistentPreRunE, which replaces
PersistentPreRun; kafka connect's own hook chains it. Completion reads
--context from the line being completed, since cobra parses no flags
for __complete. kates mcp is always enabled and its process never hides
a command, so the CLI docs resource agents read keeps every one.

kates ctx profiles lays each profile's commands out in columns that line
up across profiles, marks the enabled profiles, and dims the commands
they refuse. Named profiles, or all, list each command with what it does
and the other profiles that enable it; -o json gives the same as data.
kates ctx profiles set takes profiles or all; with none named, in a
terminal, it opens a huh checklist, the ticked profiles first because
huh scrolls the list to the first ticked option. kates ctx set keeps a
context's profiles, and kates ctx show has a Profiles column.

The root help gains a Deployment section with the deploy family #90 left
out, since a deploy profile has nothing to list without it, and lines for
ctx profiles, ports, mcp and upgrade. diff is described as the cluster
comparison it is, and the Security and Kyverno lines line up.

Tests cover the table against the registered commands, the refusal and
its messages, the help filter and header, the grid's alignment, the
details view and its JSON, kates ctx profiles set, and kates ctx set
keeping the profiles. Run as kates through the test binary, they cover a
refusal that reaches no server, and completion under KATES_PROFILES and
under --context. TestMain unsets a developer's own KATES_PROFILES. Book
10 gets a Command Profiles section, doc_entries.yaml two entries and tldr
one.
…profile enables nothing, and kates help and tldr follow the profiles

A refusal printed its three fix lines on stdout, so `kates … -o json |
jq` read text. They now go to stderr with the error, through profileFix.
Its Run once line kept no --context, so pasting it ran the command
against the current context; it now keeps it, like the Enable it line.
The help of a command the profiles refuse (kates tune --help, kates help
tune, bare kates tune) still prints, then the same note and fix lines on
stderr, and exits 0. The help path honours --plain and KATES_PLAIN, and
loadConfig warns about a broken ~/.kates.yaml once a process, since the
help and the pre-run both load it.

A context whose profiles were all unknown names (a typo, a teammate's
newer name) enabled every command, while a mix of known and unknown names
narrowed to the known ones. Unknown names now enable nothing, alone or
mixed, and stay listed after the known ones, so the typo shows in the
header, the refusal and kates ctx profiles. The warning says Unknown
profile.

The kates header is left out when no profiles are set, since nothing is
filtered. Its lines put their values at column 17, where the help's
descriptions start, and name the profiles' source as the refusal does.
kates ctx profiles puts its Context and Profiles values at column 21,
where the grid's commands start.

kates tldr lists only the entries the profiles enable, names the profiles
when it hides some, and says how to see every entry when a filter hides
them all. Its "Compare two runs" line named kates diff, which compares
two clusters; it is kates report diff. Its category titles are indented
under the title again. Completion offers all only as the first profile.

kates ctx calls contexts contexts, not connection profiles, and book 10
says profiles are not access control and points at the API key scopes.
kates ctx import keeps a context's profiles when the file names none, as
kates ctx set does. The MCP eval's human-side setup runs with
KATES_PROFILES=all, since it needs commands of several profiles; TASKS.md
and its test say so.
@bmscomp
bmscomp merged commit 6f4cf61 into main Oct 18, 2026
58 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant