Show options
The operator cannot hold ~200 installed skills in their head. This turns the catalog from something they must remember into something they consult: a menu of what fits this moment, ranked, with nothing withheld.
The human decides. This skill's judgment goes into rank and annotations. It never goes into presence.
The two rules
Both are load-bearing, and one without the other fails:
- Never omit a candidate's name. Not because a step looks already done, not because it looks
unnecessary, not to keep the output short. A skill the evidence says already ran is ranked
normally and annotated
(ran this session). - Never invent a candidate. Every name rendered must come from the resolved catalog. Rule 1 creates pressure to fill buckets from a thin source; filling them with plausible-sounding names is the worse failure, because a menu that confidently routes to something that does not exist is worse than a short menu.
Rule 1 is not novel here. It is this plugin's existing doctrine. The
${CLAUDE_PLUGIN_ROOT}/reference/structure.md
"Every section is always present" rule holds that a section with nothing to report says so
explicitly, because "a cold reader cannot otherwise tell 'nothing to report' from 'the author
forgot', and the absence is itself load-bearing." Same reasoning, applied to options.
Omit irrelevant, never unnecessary
These are one word apart and the whole output size turns on the difference, so the test is written rather than left to judgment:
- Irrelevant → omit. The skill's domain does not apply to this session at all: songwriting skills in a code session, Kindle tooling in a research session. No reasonable operator would consider it.
- Unnecessary → keep, annotate. The skill's domain applies and the operator could reasonably run it; the model merely believes they need not. That belief is an annotation.
When unsure which side a candidate falls on, it is unnecessary. Keep it.
Resolve the candidate set
Two separate needs, resolved separately. Detail, formats, and failure behavior:
context/candidate-ladder.md.
Names. Completeness is a correctness property. The in-context skill listing is not an
acceptable sole source: it omits every disable-model-invocation: true skill outright, and when the
listing overflows its budget it drops descriptions starting with the least-invoked skills, the
forgotten ones this skill exists to surface. Ladder:
/claude-ops:inventory, if that plugin is installed. It owns whole-fleet enumeration and its bundled script already reports every installed skill including manual-only ones; reuse it rather than walking the plugin cache, whose layout is undocumented and version-keyed. Read its output from stdout, never pass--outinto the consuming project, whose documented example writes./claude-inventory.jsoninto the working directory; this skill writes nothing but its Spotlight ledger, and littering a consumer's repo to render a menu would break that. Reconcile installed against enabled. Inventory reportsinstalled_pluginsandenabled_pluginsas distinct sets and asks callers to say which they used; a skill in an installed-but-disabled plugin is named with an(plugin not enabled)annotation rather than silently listed as runnable or silently dropped. Done when the returned set contains at least one skill absent from the in-context listing, proving it reached past the listing's blind spot; if it returns nothing usable, fall to rung 2.- An operator-supplied catalog file, when the consuming project provides one. Done when a declared catalog path resolves and parses; if the project declares none, fall to rung 3.
- The in-context listing. Last resort. Done when the pool is built and the output carries the truncation disclosure; a pool from this rung without that line is an incomplete result, not a finished one.
Descriptions and stage metadata. Enrichment, not completeness. Read frontmatter where the files are reachable; otherwise use whatever descriptions the listing still carries; otherwise absent.
Absent enrichment means tier 2, never omission. A skill with no available description cannot be promoted to tier 1 (which needs one). It still appears by name in tier 2. The output shape absorbs a thin catalog without breaking rule 1.
Disclose a degraded pool. When the pool came from rung 3, or enrichment was unavailable, say so
in the output. Presenting a truncated pool as complete is the green-with-hidden-findings failure
docs/conventions/liveness-assertion/ (in the consuming marketplace) exists to forbid: a surface
fails loud or routes its findings somewhere visible, never both green and silent.
Read the trajectory
Durable state is the primary signal; the conversation is secondary. This inverts the intuitive order for a reason: a long session is exactly when the operator most needs this skill and exactly when the conversation is least reliable, because compaction drops the early turns and re-attaches only the most recent skills.
Do not build a probe. /session-flow:orient already reads branch and git state, handoff
save-points, workflow checklists, running-retro ledgers, open PRs, and work-items, a superset of
what this skill needs, in this plugin. Invoke it, or consume its briefing if it already ran this
session. A separate probe here would duplicate that read.
Slug selection for artifact-grounded reads: an explicit argument wins; else the
most-recently-modified topic slice; else the branch-derived slug. Resolve every path through the
plugin's topic-docs binding
(${CLAUDE_PLUGIN_ROOT}/reference/topic-docs.md),
the memory and contract roots are configurable, so never hardcode them.
When the memory root is unreadable or empty. Say so; do not infer. In a worktree, a sibling
lane, or a fresh clone the memory slice is invisible, so every upstream artifact reads "absent".
Inferring from that would announce that the operator skipped every upstream stage, which is the
opposite of the truth. Report cannot ground upstream stages here and leave the bucket empty with
that reason.
The five buckets
Full derivation rules and rendering: context/buckets.md.
| Bucket | Holds | Tiers |
|---|---|---|
| Now | Fits the current moment | 1 + 2 |
| Next | Two or three steps ahead on the trajectory | 1 + 2 |
| Skipped upstream | Stages upstream of the detected position whose output artifact is absent on disk. Artifact-grounded, never inferred from conversation | 1 + 2 |
| Later | Everything else in-domain: relevant to this project but beyond the Next horizon | 2 only |
| Spotlight | Exactly three, ordered least-recently-surfaced | 1 only |
Later is the catch-all that makes rule 1 true. Without it, a skill that is in-domain but
downstream, testing and review skills early in a session, fits no bucket and would have to be
dropped, silently breaking the never-omit rule. It renders tier 2 only: bare names with a count,
roughly one wrapped line. That is what lets the catch-all exist without recreating the 60-row
dumping ground an earlier cut of this design had. Anything genuinely out-of-domain is still omitted
under the irrelevant test above; Later catches relevance, not everything.
Skipped upstream is deliberately artifact-grounded: "everything upstream" is definitionally the
whole early catalog and carries no information. workflow already sets this precedent. Verify a
stage from its artifact, not from conversation vibes.
Spotlight exists because ranking alone re-shows the same five skills forever, which serves a
decision but teaches nothing. Rotation forces encounters with different corners of the catalog over
time. It reads and writes one small ledger of what it last surfaced. Path and record shape are
fixed in context/buckets.md so two sessions cannot pick different ones and
lose the rotation. It is deliberately not in ${CLAUDE_PLUGIN_DATA}, which is keyed to the
plugin id and nothing else, so a fixed filename there would be one file per machine and a
spotlight shown in one repository would suppress it in another.
Render two tiers
Per bucket:
- Tier 1. At most five, ranked. Each carries: the invocation name, one line of what it would add to this conversation (never its generic description), and when you would skip it. Annotations ride here.
- Tier 2. Everything else in that bucket, by bare invocation name, with an explicit count.
Also live now (23): /a:b, /c:d, …
Budget: the shape is the cap. Five ranked options per bucket at three lines each, plus one wrapped tier-2 line per bucket, is the whole output. Rendering every option in full is the generated cheat sheet with an extra column, which an operator reads once and never again.
One word expands any tier-2 roster to full treatment (expand now, spotlight all). That is
progressive disclosure, not filtering: nothing was withheld, only deferred a keystroke.
Boundaries. Four neighbours, four different jobs
/session-flow:workflowanswers which stage comes next and routes to exactly one owner, by its own mandate never presenting both and leaving the operator to disambiguate. That rule governs stage routing. This skill owns option surfacing, the whole set, ranked, for a human to pick from. Reach forworkflowwhen you want a decision; reach here when you want the menu./session-flow:orientreports where you stand and deliberately prescribes nothing. This skill consumes that position rather than restating it./discipline:use-your-skillscorrects the model's drift, a skill it should have fired and did not. This addresses the human's awareness. Different subject entirely.- The handoff document's §14 "Suggested skills" already recommends fully-qualified skills tied to remaining work. That is a durable artifact written for a cold reader resuming later; this is a live ephemeral menu for the operator right now.
What this skill does NOT do
- Does not decide. It ranks and annotates. Picking is the operator's.
- Does not filter by merit. "Already done" and "unnecessary" never remove an option. See the two rules. A design that ranks-then-truncates reintroduces the same gatekeeping through the cutoff.
- Does not invent names. A thin catalog yields a short menu, never a plausible one.
- Does not build its own durable-state probe. It routes to
/session-flow:orient, invoked via the Skill tool. - Does not execute what you pick. Presentation only; invoking the choice is a separate act.
- Does not enumerate a catalog in its own body. The candidate set is resolved at runtime; an embedded inventory would be a permanent token cost that rots as the fleet changes.
Gotchas
- The listing's drop-order is least-invoked first, so the skills most worth surfacing are the ones whose descriptions vanish first. Sourcing names from the listing alone quietly inverts this skill's purpose.
- A skill set to
"off"viaskillOverridesstill appears in a catalog but cannot run. Recommending it hands the operator a dead option. Annotate it if the override is visible. - Built-in commands other than a small allowlist are not
Skill-invocable. They can be named as options (/compact,/clear) but not invoked on the operator's behalf; say which is which. - An empty bucket is a real result and says so, with its reason. Silence reads as an oversight.