CLI Layering

August 28, 2026 · View on GitHub

Decided 2026-08-15 (discussion session; alongside intake 260815-a5vf rk send/rk await). run-kit (rk) and fab-kit (fab) are the only two CLIs. A third "tmux management" binary was considered and rejected: the substrate verbs are only valuable with rk's conventions present (@rk_pane_agent_state, hooks, reconcilers), a third binary would add a third axis of version skew and distribution overhead, and the hexokit rename already broadens rk's identity beyond the web dashboard.

The model

LayerToolOwns
Substraterktmux conventions (the @rk_* option registry), agent instrumentation (agent setup/agent hook, the @rk_pane_agent_state lifecycle), pane interaction verbs (mux send/mux await; future capture/kill/process), server hygiene (guard shim, reaper, layout snapshots, tmux.conf scaffold) — with the daemon, web UI, and desktop shell as consumers of this layer, not its definition
Choreographyfabchanges, stages, dispatch records, provider/profile resolution, confidence scoring, memory indexes, PR metadata — everything keyed to a change or a pipeline stage

Delegation rules

  1. Each tool delegates to the other for facts the other layer owns; neither reimplements the other's layer. Both directions exist and both are correct: fab consumes substrate facts from rk (agent state, gated sends), rk consumes choreography facts from fab (fab agent --print for launcher resolution in riff, fab pane map for the change/stage join in sessions).
  2. fab → rk delegation is capability-probed and fail-open: command -v rk gates every use; absence degrades to raw tmux / fab's internal builders, never to an error. fab-kit remains installable without rk; its skills carry the degraded path.
  3. Machine-invoked entry points are contracts: commands baked into installed artifacts (hook lines in agent settings, the guard PATH shim, shell rc sourcing) keep their invocation names working permanently — renames ship with hidden aliases, and installers write the new form going forward.
  4. What fab may assume of rk when present: the @rk_pane_agent_state schema per agent-state.md; the rk mux send/rk mux await contracts (gate matrix, probe-verified delivery, report words) once 260815-a5vf ships; rk notify's fail-silent contract.

rk command surface — grouping plan

Root noise is reduced by two mechanisms: families (for human-facing verbs, mirroring fab config/fab pane) and hiding (for machine-invoked plumbing — zero migration cost). Only obvious groupings; flagship conversation verbs stay flat.

The rk mux family (tmux substrate)

MemberFromCost
rk mux sendnew (260815-a5vf)free — lands here directly, nothing shipped
rk mux awaitnew (260815-a5vf)free
rk mux reaprk reaperrename + deprecation alias
rk mux snapshot list|show|restorerk snapshot …move + deprecation alias (3-level depth has fab pane window-name precedent)
rk mux guardrk tmux-guardmove + permanent hidden root alias (installed PATH shims exec the literal name; rk agent setup writes the new form going forward)
rk mux init-confrk init-confmove + deprecation alias (it scaffolds tmux.conf/tmux.d — a mux concern)
(future) rk mux capture, rk mux kill, rk mux process, rk mux panesfab pane migration sweepafter a5vf proves the pattern

Why mux, not pane or tmux: pane is too narrow for the server-level members (reap, snapshot, guard); tmux reads as if it runs tmux itself and collides with the guard fronting the real binary; mux is short, distinctive, and umbrella-wide.

The rk agent family (instrumentation)

MemberFromCost
rk agent setuprk agent-setuprename + deprecation alias (human-typed)
rk agent hookrk agent-hookmove + permanent hidden root alias (installed settings hooks carry the literal command line; setup writes the new form going forward)

role stays at root — it marks the operator window, an operator-workflow verb, not instrumentation.

Hidden plumbing (visible today, machine-invoked)

shell-init (sourced from shell rc) becomes hidden; help-dump already is. The permanent aliases above (agent-hook, tmux-guard) are hidden. skill stays visible — agents discover it by name and the toolkit skill standard governs it.

Stays flat (deliberately)

  • Conversation verbs: present, notify, riff — flagship, established, typed constantly.
  • Lifecycle core: serve (default), daemon (already a family), url, status, doctor, update.
  • Client families: desktop, code-server, remote — already families; no super-family.

Net effect at rk -h: ~23 visible root commands → ~15.

Conformance: every surface change above must pass the shll toolkit standards check (shll standards — help-dump, ten principles, skill topic pages) before landing.

fab command surface — the split

fab familyLayerDisposition
pane send, pane awaitsubstratesuperseded by rk mux send/await (260815-a5vf); operator + helper guidance migrate, then delete (fab-kit follow-up change)
pane ready, pane deliver, pane capture, pane kill, pane processsubstrate mechanicsrk grows canonical twins over time; fab's copies become dispatch-internal (pane arm must work rk-less), dropped from skill-facing guidance
pane openchoreographystays — provider/profile resolution from fab config
pane maphybridlong-term: rk owns enumeration (rk mux panes), fab enriches with change/stage; today rk's server consumes fab pane map for the join
pane window-namemechanics generic, convention fab'sstays until the marker convention itself moves (rk's native channel is @rk_win_flair + status pyramid)
change, status, dispatch, score, resolve, resolve-agent, preflight, log, memory-index, impact, pr-meta, batch, operator, agent, config, workspace commands (init, sync, setup, upgrade-repo, update, doctor), kit-path, skill, shell-initchoreography / fab-internalstay in fab

Execution plan

Each part is one fab change, sized for a single pipeline run, and names its repo — the operator coordinates across both repos on one tmux server. Parts marked (released) gate on the dependency being shipped in a release (brew-installable), not merely merged: the consuming repo's agents run the installed binary. Every run-kit part that touches the CLI surface intrinsically includes the standards audit (shll standards), the help-dump test, and rk skill topic-page updates — not listed per-row.

#PartRepoDeliversDepends on
1mux family + send/awaitrun-kitrk mux parent (shared -L), rk mux send, rk mux awaitmerged as 260815-a5vf (PR #617)
2agent familyrun-kitin flight as 260815-r2wp-agent-family (apply + review done) — rk agent setup/rk agent hook; agent-hook stays as permanent hidden alias (installed hook lines); setup writes the new form— (parallel-safe with 1; overlaps on root.go + help-dump test — sequence or rebase)
3mux consolidation, low-riskrun-kitmux reap (← reaper), mux snapshot (← snapshot), mux init-conf (← init-conf), deprecation aliases; hide shell-init1
4guard moverun-kitmux guard (← tmux-guard) with permanent hidden root alias; rk agent setup regenerates shims to the new form; doctor states updated1 (light overlap with 2 in agent setup)
5fab pane send/await retirementfab-kitfab-operator + _cli-agents/_cli-external migrate to rk mux send/await with a raw-tmux fallback when rk is absent; delete the two CLI verbs (internal builders stay — dispatch delivery uses them)1 (released)
6substrate twinsrun-kitrk mux capture, rk mux kill, rk mux process — mechanics ported/twinned from fab pane, agent-state-aware where applicable1
7guidance re-pointfab-kit_cli-external/_cli-agents point capture/kill/process at rk; fab's pane copies demoted to dispatch-internal (kept for rk-less pane arm), dropped from skill-facing guidance5, 6 (released)
8pane-map splitrun-kit + fab-kitrk mux panes (native enumeration + agent state); rk's server drops the cached fab pane map join in sessions.go (kills the StatusDot 5s-lag class); fab enriches enumeration with change/stage6

Sequencing summary: 1 → {3, 4, 6} in any order; 2 anytime; 5 after 1 releases; 7 after 5+6 release; 8 last. Parts not yet drafted enter the pipeline via /fab-draft (queue without activating) or the backlog, whichever the operator is driving from.

Non-goals

  • No third binary, ever, for this layer split.
  • No big-bang rename of shipped rk commands — every move ships with its alias per rule 3.
  • No rk reimplementation of provider/profile resolution (that is fab's; riff keeps delegating).