references/agents/work-recap-scout.md
You are a work-recap scout. Your job is to gather the evidence for a recap explainer: what actually happened in this repository over a given window, with pointers precise enough that the explainer can teach from them. You extract and quote; you do not interpret, rank, or editorialize.
Dispatch context supplies: `{window}` (a date range, relative window, or since-ref), `{repo-root}`, and `{run-dir}` (scratch path for your output file).
## What to gather
Work through these sources for the window, cheapest first:
1. **Git activity** — `git log` over the window (subjects, shas, dates, authors), and for the substantial commits, a stat-level view of what they touched. Group obviously-related commits (a feature branch's commits, a fix and its follow-ups) rather than listing them flat.
2. **Merged and open PRs** — only when a PR interface is reachable (a `gh` CLI that responds, a connector/MCP tool). This portion is capability-gated: when no interface is reachable, note "PR evidence unavailable" in one line and move on — never treat the missing interface as an error and never guess PR state from branch names.
3. **Project docs** — plans, brainstorms, and solution docs added or modified in the window (`<root>/plans/`, `docs/brainstorms/`, `<root>/solutions/`, or wherever this repo keeps them). These carry the *why* behind the git activity — quote the decision or problem statement, not the whole doc.
## Output
Write an **evidence file** to `{run-dir}/recap-evidence.md`: at most 120 lines. For each notable piece of work in the window:
- What changed, in one line, with the sha(s) or PR number and date
- Why, when a doc or commit body says so — quoted, with the source (`file:line` or sha)
- The main files/areas touched
Order by date. Bundle minor mechanical commits (version bumps, typo fixes) into a single "housekeeping" line rather than enumerating them. If the window is empty — no commits, no doc changes — write nothing and report exactly that.
Return only a gist: 3-5 lines summarizing the window's shape (how much work, the 2-3 headline items), plus the evidence file's absolute path — or the empty-window report.
references/check-in.md
# Check-in
The check-in is the active-recall section of the explainer: a `Check yourself` section at the end of the artifact where the reader answers first and reads the answers after. It is static text in the document. The run asks the reader nothing about it — no offer, no prediction turn, no exercise posed in chat — so a user who switches away never comes back to a waiting question.
## Include or omit
The request wins in both directions: an explicit ask for a check-in, quiz, or exercises includes the section whatever the material; an explicit "no quiz" or equivalent omits it. When the request is silent, include the section when retention is the point — a hard or unfamiliar concept, a gnarly or consequential diff, a dense recap window with decisions worth recalling later — and omit it when comprehension is the point and retention is incidental: a routine recap before a meeting, a small mechanical diff, a topic the user signals they only need to skim. When the material and the request disagree, the request wins. Do not announce a justification either way.
The reader does not change the decision. An artifact rendered for another reader gets the same test, because the section exercises whoever reads the document.
## Shape
- One section headed `Check yourself`, placed last: after the explanation and before the HTML footer.
- Two to four numbered questions, listed first. Then the answers under an `Answers` label, numbered to match, so a reader can attempt every question before any answer is in view.
- Each answer states what a correct response contains and names the gap a plausible wrong answer exposes. One correction per question — do not lecture past the gap.
- Static only: no forms, scripts, click handlers, or collapsing widgets. The label and spacing set the answers apart; nothing hides them.
## Question kinds
Design questions to expose understanding, not recall of the artifact's phrasing. Use the kinds the material supports:
- **Apply:** a small scenario the concept decides ("given X, what happens / what would you choose?").
- **Explain-back:** restate the core mechanism in your own words; the answer names the pieces a complete restatement carries.
- **Boundary:** a case where the concept does not apply, or where the naive reading fails.
- **Change (diff mode):** what the change does and why it was made; the answer names the intent behind the hunks, not the hunks.
- **Recap recall (recap mode):** why a notable change in the window was made, or what its consequence was.
references/destinations.md
# Destinations and Close
Everything the destination phase does: the destination menu, the action to fire for each option, each destination's sub-flow, the audience re-render offer, and the improvement observations the run closes on. SKILL.md names this file as a required read before the destination phase renders anything, and keeps the stop classes that must hold even if this file is never opened. Detection is by capability: probe the current session's tools and context; a missing binary, env var, or unloaded MCP tool is not proof of absence when a connector could supply the capability. Local file is the always-present floor.
## The menu, and what fires for each option
Size and detect the menu per `references/orchestration.md`'s menu section: it decides which destinations are visible, that only one publisher is offered, and what to do when the visible set exceeds the host's option cap. If the user names a publisher that the one-preferred-publisher rule kept off the menu, honor it by the bypassed-menu path below (full warning, then explicit confirmation), never as though the menu had warned them — it didn't.
When the user picks an option, fire its action rather than acknowledging the choice in prose:
- **Claude Artifact** (HTML only) — create an artifact from the canonical explainer per that destination's section below.
- **Publish publicly to ht-ml.app** (HTML only) — label it Recommended, and state in the option description that the page is public and may be indexed, crawled, copied, or archived. Then follow the ht-ml.app sub-flow below, passing the complete canonical HTML to the resolved publisher. Do not assume a particular skill exists, and do not add a ce-explain-specific publisher. On a menu bypass, give that same warning in chat and get explicit confirmation after it; the pre-warning request does not count as confirmation. If confirmation cannot be obtained, do not publish; preserve the canonical HTML and report its local `$RUN_DIR/explainer.html` path.
- **Local file** — copy it out of `$RUN_DIR` to the path the user names, then offer to open it where the platform exposes `open` / `xdg-open` / `start`; otherwise print the absolute path.
- **Publish to Proof** (markdown only) — publish per that destination's section below and surface the share URL; on failure retry once, then report and move on.
- **Send to Thinkroom** (only when a Thinkroom capability is detected) — send per that destination's section below.
- **Leave it** — report the `$RUN_DIR` path, noting it is temporary and does not survive reboot; nothing else is written.
## Audience mismatch — offered before the destination's own consent gate
Some destinations put the artifact in front of other people: ht-ml.app, Proof, and Thinkroom, but not Claude Artifact, which stays private until the user shares it. When a personally-composed artifact is headed to one of those, offer once to re-render it for that audience per the compose-time reference before sending. Take their answer and proceed either way; never re-render unasked, and never block the send on it.
**This offer comes first**, before any publish warning or confirmation the destination requires. Consent must attach to the artifact actually being published, and the adapted rendering differs materially: it names a person where the personal one says "you". Ask one question at a time: settle the rendering, then run the destination's own consent gate. When the destination needs no confirmation, this is the only ask.
## Improvement observations
Things the composition surfaced as improvable are routed by type once the destination is settled — offered, never auto-fired. "Settled" means the artifact was sent, the user declined, or the run stopped at an unanswered consent gate; in that last case the run ends there and these offers are skipped. Never raise them while any of the asks above is still open — the destination question, the audience re-render offer, or a publisher's consent gate.
**User-runnable invocation rendering.** Only the user-run handoff below uses printed invocation syntax. Default to `/ce-polish`; use `$ce-polish` only when the active host is Codex or explicitly documents dollar-prefixed skill invocation. On oh-my-pi (`omp`), use `/skill:ce-polish`. Render only the invocation as inline code and output one form only.
- **New-capability ideas** — offer first; on acceptance invoke the `ce-ideate` skill via the skill-invocation primitive with the observations as seed context, rather than telling the user to run it.
- **Code-clarity findings** — offer first; on acceptance invoke the `ce-simplify-code` skill via the skill-invocation primitive with the observations and the files they concern, rather than telling the user to run it.
- **UI/UX polish opportunities** — present the observations in chat and tell the user to invoke `ce-polish` themselves using the rendering rule above; it is user-invoked only (`disable-model-invocation`), so never fire it via the skill primitive.
- **A repo doc the evidence contradicts** — grounding reads plans and solution docs, so a recap or diff routinely surfaces one that is now stale, superseded, or contradicted by what shipped. Offer first; on acceptance invoke the `ce-compound-refresh` skill via the skill-invocation primitive, naming the doc and the evidence that supersedes it. Do not edit the doc here — this skill teaches, it does not maintain repo memory.
## Claude Artifact
Offered for HTML output when the session is Claude Code and its Artifact tool is present. Give the tool the canonical `$RUN_DIR/explainer.html`, follow its current contract, and confirm the returned URL or reference to the user. The tool owns any adaptation needed for its artifact runtime; do not pre-process the HTML for it.
## Publish publicly to ht-ml.app
This is the preferred HTML publisher when the Claude Artifact adapter is not selected. ht-ml.app accepts the complete standalone HTML document and works through ordinary HTTP, independent of the agent harness.
Before publishing, the destination option itself must state: **the page is public and may be indexed, crawled, copied, or archived**. Whenever ht-ml.app is chosen without that warned option in front of the user — their initial request selected it and the menu was skipped, or they named it after the one-preferred-publisher rule kept it off a menu that *was* shown — state the same full warning in chat and ask for explicit confirmation after the warning before any publish; “this is public” is not the complete warning, and the initial request itself does not count as confirmation. Only a warned menu selection or explicit post-warning confirmation permits publishing. If confirmation cannot be obtained, do not publish; preserve the canonical `$RUN_DIR/explainer.html` and report its local path. Never publish headlessly or infer consent from the fact that an explainer was requested. If the content is sensitive, route to Local file instead.
After the user selects the warned option or explicitly confirms after the warning:
1. Prefer any ht-ml.app or general HTML-publishing capability detected in the current session. When it is a skill, invoke it through the platform's skill-invocation primitive with the canonical `$RUN_DIR/explainer.html` and the user's public-publishing confirmation; otherwise call the detected tool, connector, or browser capability directly. Follow that capability's current contract. Do not assume a particular skill name or installation path.
2. When no publisher is installed, use a reachable web or HTTP interface to follow ht-ml.app's agent-facing instructions at `https://ht-ml.app/llms.txt` (or its linked API help) and publish the complete canonical HTML. The explainer is already composed; do not select a template or redesign it.
3. Surface the returned URL. Treat any returned update credential as a secret: do not print it in chat or embed it in the page. On failure, retry once after a short wait, then report the error and fall back to the canonical local-file path.
## Local file
1. Ask nothing extra if the user already named a path; otherwise accept the path from their menu answer's free-text.
2. Copy the artifact out of the run dir to that path (`cp "$RUN_DIR/explainer.html" <path>` — or `explainer.md` for a markdown run), creating parent directories if needed.
3. Where the platform exposes a browser-opening primitive (`open` on macOS, `xdg-open` on Linux, `start` on Windows), offer to open it; otherwise print the absolute path.
## Publish to Proof (markdown output only)
Proof ingests markdown, so this option renders only when the run resolved `output:md`. Invoke the `ce-proof` skill via the platform's skill-invocation primitive when it is installed, passing the artifact path, a title (`Explainer: <subject>`), and identity `ai:compound-engineering` / `Compound Engineering`; surface the returned share URL. When the skill is not installed but the Proof web API is reachable, POST the markdown per that API. On failure: retry once after a short wait, then report plainly that the upload didn't succeed and why, and fall back to the local-file path. One-way publish; the run-dir file stays canonical.
## Send to Thinkroom
Offered only when a Thinkroom capability is detected — a Thinkroom skill in the session's skill list, a reachable MCP tool, or a documented CLI that responds. Use whatever interface that capability exposes to create/share a document from the explainer content, following that interface's own contract for title and body format. Surface the returned document reference. When the send fails, report it and fall back to the local-file path. Never guess at a Thinkroom API shape when no capability is detectable — the option simply doesn't render.
references/explainer-html.md
# Explainer HTML Rendering
How an explainer renders as HTML. Load at compose time, not earlier. The explainer is a personal teaching artifact — these rules keep it self-contained, readable, and honest about its own provenance. It is not a plan artifact: no navigation region, no R/U-ID anchors, no contract sections.
## Hard invariants
- **Single self-contained HTML5 file.** No companion `.css`, `.js`, or `.svg` files. CSS lives in `<style>`. SVG lives inline. Images are base64 data URIs or inline SVG. No external requests of any kind — explainers must read identically offline and inside CSP-restricted viewers, so unlike the plan-artifact convention there is **no webfont exception**: use a system font stack.
- **All metadata appears as visible text — single source of truth.** The visible `<h1>` is the title. A visible header `<dl>` uses the exact field labels `Date`, `Input shape`, and `Subject`; `Input shape` is exactly one of `concept`, `diff`, `idea`, or `recap`, and `Subject` names the topic, ref, or recap window. When grounding fell back to model knowledge, the same header also carries the label `Unverified — from model knowledge, not checked against current sources`. When the run rendered for another reader, the header carries one more row labelled exactly `Rendered for`, naming that reader; a personal rendering omits the row entirely rather than saying "the user". No hidden machine-readable copy: no JSON script block, no `data-*` mirror, no `<meta>` duplication. This header is what a future library layer indexes, so do not rename the fields, prettify the enum values, or invent additional rows beyond these.
- **Display-only.** No forms, no click handlers, no interactive quizzes, no "submit" affordances, no scripts. The check-in, when present, is the static `Check yourself` section that `references/check-in.md` owns: questions first, then their answers, all visible text.
- **ASCII identifiers.** Class names and element IDs are ASCII-only.
- **Composition signal.** A visible footer names the composition timestamp and the composing skill: `Composed 2026-07-02 by ce-explain`.
## Show-n-tell: match the form to the material
Show, then tell — every explainer leads with something to look at, chosen by what the material actually is. One visual per load-bearing concept; never decoration.
| Material | Show |
|----------|------|
| Architecture, relationships, boundaries | Inline SVG diagram (boxes and labeled arrows; halo/contrast so labels stay legible) |
| Code behavior, a diff's mechanics | Annotated snippet: the real lines, with margin notes explaining the *why* per hunk |
| A process, lifecycle, or state change | Numbered flow or state strip |
| A window of work (recap) | Timeline: date-ordered entries, each with what changed and why it mattered |
| A comparison or trade-off | Two-column contrast, prose verdict underneath |
Diagrams complement prose; they never replace it. A reader who skips every visual still gets the full explanation in text.
## Voice — personal by default, adapted on request
Default: the user personally. Second person, and no orientation they already have. In a shared repo this still means naming *other* contributors in third person — second person is reserved for the user, and a personal recap of team work uses both.
When intake resolved another reader, render for that reader instead. What changes:
- **No second person.** The subject goes to third person when a name is available — recap mode's commit authors, or a name the user supplied — and impersonal ("the retry path was rewritten") when none is.
- **Minimum orientation added.** One or two sentences of what the project or area is, where the personal rendering would assume it. Add only what the reader cannot follow without.
- **Nothing else changes.** Same depth, same real code from evidence, same `Unverified` label when it applies, same one-sitting length.
- **The form does not become a status update or a deck.** A share-out request often sounds like one ("something for the #eng channel"), and rendering for that reader is right — but they are getting the explainer, at full depth, not a summary. Adapting the audience never licenses thinning the content.
## Reading ergonomics
- Hold prose to ~70ch (`max-width` on text blocks); full-width only for diagrams and code.
- Lead each section with the point, then the mechanism, then the caveat.
- Dense is good; long is not. The explainer is one sitting's read — cut background that doesn't change understanding.
- **When the evidence exceeds one sitting** (a busy recap window is routinely 50+ commits), select rather than truncate: lead with the few threads that changed how the project works, carry the rest as a compact roll-up, and say plainly what you set aside so the reader knows the timeline isn't the whole log. Never silently drop the tail.
- Code samples: real code from the grounding evidence where it exists, invented minimal examples only for external topics, always syntax-highlighted with inline `<style>` classes.
## Post-compose audit
Before presenting: no external URLs anywhere in the file; metadata header complete and visible; every visual has a prose equivalent; the file opens correctly standalone (`open <path>`).
references/explainer-markdown.md
# Explainer Markdown Rendering
How an explainer renders as markdown — the fallback format when intake resolved `output:md`. Load at compose time, not earlier. Content rules match the HTML reference; only the presentation medium differs.
## Hard invariants
- **YAML frontmatter carries the metadata:** `title`, `date`, `input_shape` (concept / diff / idea / recap), `subject`, `unverified: true` when grounding fell back to model knowledge, and `rendered_for: <reader>` when the run rendered for another reader (omitted entirely for a personal rendering). Field names are stable — a future library layer indexes them.
- **Pure markdown.** No HTML elements, no `<details>`, no inline styles.
- **Display-only.** No interactive exercise or quiz content. The check-in, when present, is the static `## Check yourself` section that `references/check-in.md` owns: questions first, then their answers, all visible text.
- **Repo-relative paths** for any file reference; never absolute paths.
## Show-n-tell in markdown
Markdown's visual affordances are narrower than HTML's — compensate, don't skip:
| Material | Show |
|----------|------|
| Architecture, relationships, boundaries | Fenced `mermaid` block (`flowchart TB`) |
| Code behavior, a diff's mechanics | Fenced code block per hunk with a one-line *why* comment above each |
| A process, lifecycle, or state change | `mermaid` state/sequence diagram or a numbered list |
| A window of work (recap) | Date-ordered list, each entry: what changed and why it mattered |
| A comparison or trade-off | Pipe-delimited table, prose verdict underneath |
Never hand-draw box-drawing/ASCII diagrams — mermaid or prose. Diagrams complement prose; a reader who skips them still gets the full explanation in text.
## Voice — personal by default, adapted on request
Default: the user personally. Second person, and no orientation they already have. In a shared repo this still means naming *other* contributors in third person — second person is reserved for the user, and a personal recap of team work uses both.
When intake resolved another reader, render for that reader instead. What changes:
- **No second person.** The subject goes to third person when a name is available — recap mode's commit authors, or a name the user supplied — and impersonal ("the retry path was rewritten") when none is.
- **Minimum orientation added.** One or two sentences of what the project or area is, where the personal rendering would assume it. Add only what the reader cannot follow without.
- **Nothing else changes.** Same depth, same real code from evidence, same `unverified` flag when it applies, same one-sitting length.
- **The form does not become a status update or a deck.** A share-out request often sounds like one ("something for the #eng channel"), and rendering for that reader is right — but they are getting the explainer, at full depth, not a summary. Adapting the audience never licenses thinning the content.
## Reading ergonomics
- Lead each section with the point, then the mechanism, then the caveat.
- Dense is good; long is not — one sitting's read.
- **When the evidence exceeds one sitting** (a busy recap window is routinely 50+ commits), select rather than truncate: lead with the few threads that changed how the project works, carry the rest as a compact roll-up, and say plainly what you set aside so the reader knows the timeline isn't the whole log. Never silently drop the tail.
- Real code from the grounding evidence where it exists; language-tagged fences always.
references/intake.md
# Intake
Classify the request into exactly one input shape — concept, diff, idea, or work-recap window — before any grounding runs, and resolve its audience. Parse by reasoning over the user's prompt; do not depend on argument-token substitution mechanics, which vary by harness.
## Flag tokens
Tokens exist so automation and chained calls can force a decision. Plain language is the ordinary way a person invokes this skill and is not a lesser path — most requests carry no token at all and must classify just as reliably.
| Token | Example | Effect |
|-------|---------|--------|
| `diff:<ref-or-range>` | `diff:abc1234`, `diff:main..HEAD`, `diff:PR#42` | Forces diff mode on that change |
| `since:<window-or-ref>` | `since:monday`, `since:7d`, `since:v2.1.0` | Forces recap mode over that window |
| `output:<md\|html>` | `output:md` | Overrides the artifact format (default `html`) |
| `audience:<who>` | `audience:team`, `audience:"the design review"` | Renders for that reader instead of the user personally |
**A `word:value` pair is a flag only when it reads as one.** It leads the request or stands alone, carries no space after the colon, and — the decisive test — **the request still makes sense with it removed. If stripping it would garble the sentence, it was never a flag.** Leave it in the request text and classify by meaning. Ordinary technical prose is full of colons, and a flag parser that eats them silently changes what the user asked for:
- "walk me through the diff: why did we split the parser" — stripping `diff:why` leaves "walk me through the did we split the parser". Garbled, so this is prose. Classify by meaning (a diff request about the parser split), and never let the bogus ref `why` outrank that.
- "explain how we pick the audience: engineers vs designers" — a concept request about audience selection, rendered personally. Not an `audience:` flag naming "engineers".
- "teach me how our renderer decides output: html or terminal escape codes" — prose. Note this one fails quietly if mis-parsed, because `html` is already the default format, so nothing visible contradicts it.
- `diff:main..HEAD`, or `audience:team` leading a request — genuine flags: nothing is left to garble.
- A token in flag position beats inference. A colon inside prose does not.
- `diff:` and `since:` together conflict — say so and ask which mode the user wants.
- An unrecognized `<word>:<word>` token (including conventional-commit prefixes like `feat:` appearing inside a topic) is not a flag — it passes through verbatim as request text. The same holds for a *recognized* token that fails the reads-as-a-flag test above.
- A token with an empty or missing value is not a flag — treat it as prose.
- `output:` with an unknown value: drop the token, note `Ignored unknown output: value '<value>' — using html`, and continue.
## Inference (no forcing token)
Classify the remaining text by shape:
- **Diff** — the request names a resolvable change: a sha, branch, PR, "the last commit", "what you just did", "this change".
- **Recap** — the request asks what happened over time ("what did I do this week", "catch me up", "prep me for standup"), **or names a time window and little else** ("since last Monday", "last week", "the past 3 days", "this sprint"). A bare window is a recap request, not a topic to be explained — do not read "since last Monday" as a concept called "since last Monday".
- **Idea** — the request presents a proposal or notion of the user's to be understood: "explain my idea of X", "what would Y imply". The idea is a fixed given (see SKILL.md Boundaries).
- **Concept** — everything else: a topic, pattern, subsystem, or external subject to learn.
**Resolving the window (recap mode).** A window arrives either as a token value (`since:monday`) or as prose ("since last Monday", "the past 3 days") — resolve both the same way, to a concrete date range, and name that resolved range in the artifact's `Subject`. `since last Monday` and `since:monday` mean the same thing; a colon must not change the answer. Fall back to the last 7 days only when the request names no window at all, and never silently substitute that default for a window the user did name — if a named window can't be resolved confidently, say what you used.
**Tiebreak — concept vs diff:** when the request is plausibly both (a repo topic that also names an identifiable recent change, e.g. "explain the retry logic we just added"), a concretely resolvable change wins: diff mode, with the concept as framing context. A topic with no resolvable change is a concept.
**Repo footprint check (concept mode):** a concept grounds in the repo only when it actually touches it. An external subject (a language feature, an interview topic, a paper) gets no repo grounding — do not force it.
## Audience resolution
Audience is orthogonal to input shape — resolve it for every shape, including recaps.
- **Default: the user personally.** Absent a signal, do not ask and do not adapt.
- **Another reader** when the `audience:` token is present, or when the request plainly says someone else will read it — "write this up for the team", "I'm sharing this with <person/group>", "for the design review", "a share-out", "something I can post in <channel>". The test is whether the *artifact itself* lands in front of other people. Carry the named reader forward verbatim; the rendering rule lives in the compose-time reference.
- Wanting to *speak* from the material is not an audience signal. "Prep me for standup", "catch me up before the meeting", "walk engineering through it — get me ready", and "so I can explain it to them" all stay personal: the user is still the reader. That resolves the case, so no re-render note is needed.
- **A request to share is not a request for a status update.** "Something I can drop in the #eng channel about this week's work" reads like a status-update ask in ordinary usage, and this skill does not write status updates. Honor the *audience* and refuse the *form*: render the explainer for that reader at full depth. Decline only if the user wants the terse update itself rather than an explainer for it — and say which you're doing.
- Ambiguous between personal and another reader (for example, "write up what shipped this week"), default to personal and say in one line that it can be re-rendered for a reader. Do not spend a blocking question on this.
## Operational-question gate
Not every *concept by inference* wants the teaching flow this skill runs — many just want a direct answer. When such a request (no `diff:`/`since:` token, no wording that plainly asks to learn or build like "teach me how X works") reads as one better answered in chat — e.g. diagnosing or operating current behavior ("why is X doing Y", "is X configured right") — answer it directly. Then offer to teach it only when a real underlying concept sits behind the question that the user would plausibly want to learn — not as a reflexive add-on to every answer — phrased plainly, e.g. "Want me to actually walk you through how this works? I can build you a visual explainer to keep." Create the run directory and profile the repo only if they take it. A request that plainly wants to learn, or that carries a build signal, skips the gate and is taught in full.
references/orchestration.md
# Orchestration: asking, dispatching, scratch, and menu shape
Required read before the first blocking question, the first subagent dispatch, or the run-directory creation in the grounding phase — whichever comes first. The skill body carries the phase order and the ordering rules; `references/destinations.md` carries the destination phase's menu and per-option routing.
## Interaction method
When you must ask the user a question, use the host's blocking question tool already in the current tool list (match by capability, not by a host-specific name). Presence in the current tool list is proof the tool exists; never call a user-facing question tool to discover whether it exists. If a matching tool is listed but unloaded, use the host's tool-discovery primitive to load that capability — do not search for another host's tool name. Fall back to numbered options on the host's user-visible chat surface only when no such tool is in the list or a real question call errors. In the fallback, stop and wait for the user's reply. Never silently skip the question. Ask one question at a time.
## Model tiers
Dispatch is tiered by task shape, never hardcoded to a model name:
- **Extraction tier** — the work-recap scout: search-and-quote work. Use the platform's cheapest capable model when the harness exposes a known override; otherwise inherit.
- **Ceiling tier** — the explainer composition, including its `Check yourself` section. This runs in the main conversation on the orchestrator's model; nothing is dispatched for it.
**Degradation rule.** When the platform's subagent primitive cannot select per-agent models, dispatch scouts on the inherited model and keep their read budgets. When the platform has no subagent primitive at all, run the scout work inline with the same budgets. When a dispatch fails, treat a concurrency or active-agent-limit error as backpressure — retry after a slot frees; a launch that fails for a reason that survives correcting the invocation runs that scout's work inline with the same budgets, disclosed in one line.
## Run directory
The skill body carries the ownership-checked block that creates `$RUN_DIR`; run it from there so this file cannot drift from it.
## Grounding by input shape
**Repo-touching inputs** (a concept with footprint in this repo, a diff, a recap): use the project's active instructions already in context and go directly to the diff, call-sites, current source, or commits. Read `CONCEPTS.md` when canonical vocabulary matters. If the topic cannot be scoped from the input and existing context, allow one targeted root or workspace probe.
**Diff mode:** resolve the change (the `diff:` ref, or the most recent substantial change when the request points at one implicitly) and gather its evidence — the diff itself, the files it touches, any plan or solution doc that motivated it.
**Recap mode:** seed the scout with `references/agents/work-recap-scout.md` (extraction tier), passing the resolved window, the repo root, and `$RUN_DIR`. It returns an evidence summary with commit shas and `file:line` pointers, and writes `recap-evidence.md`. **Empty window** (no git activity, no doc changes): say so, offer to widen the window, write no artifact, and end the run after the user responds.
**External concepts** (no footprint in this repo): skip repo grounding entirely — do not force repo context into the output. Research with whatever web tools are reachable. When none are, you may explain from model knowledge, but the artifact must label that content **Unverified — from model knowledge, not checked against current sources** in its metadata header.
**Idea mode:** the idea is a fixed given. Explain its implications, mechanics, and trade-offs for the user's understanding. Never scope it (`ce-brainstorm`'s job), never generate and rank alternatives (`ce-ideate`'s job).
## Destination menu shape
Detect destinations by capability — probe the agent's own toolset and session context, never a closed list, and never treat a missing binary, env var, or unloaded MCP tool as proof a destination is unavailable when a connector could supply it. Local file and Leave it are ungated and always offered. For default HTML runs, offer one preferred publisher: Claude Artifact when running in Claude Code with its Artifact tool present; otherwise ht-ml.app. Do not show both by default, but honor an explicit user request for either. Offer only what is detected; absence hides an option silently.
Count visible options against the platform's cap first (Claude Code's `AskUserQuestion` allows up to 4 explicit options; Codex's `request_user_input` only 2-3): when the visible set exceeds the cap, render a numbered list in chat with "Pick a number or describe what you want." and wait instead.
SKILL.md
---
name: ce-explain
description: "Create a durable visual teaching artifact for something worth learning. Use when the user wants to be taught, wants a deep explainer, wants to understand a substantial change, or wants a work recap built for retention. Not for ordinary Q&A, operational diagnosis, or a concise trade-off that belongs in chat. For learning, not repo docs or verdicts."
argument-hint: "[a concept, a diff ref, an idea, or 'what happened this week?'] — or invoke bare to be asked"
---
# Explain It To Me
Teach the user one thing well: a concept, a change, an idea, or a window of their own recent work. Agent-driven development removed the learning that writing code by hand used to provide; this skill is the replacement. What to explain is the input this skill was invoked with, present in the current prompt or conversation — whether the user asked directly or a calling skill passed it.
**Done:** a durable artifact exists at `$RUN_DIR`, the user has seen it, and the destination they chose has been honored (or declined). A run that correctly ends without an artifact — the operational-question gate answered it in chat, an empty window, a bare invocation the user did not answer — is equally done.
**Note: The current year is 2026.** Use this when weighting external sources and dating artifacts.
**Read `references/orchestration.md` before the first blocking question, subagent dispatch, or run-directory creation** — it owns the per-harness ask tool, the model tiers and their degradation rule, grounding by input shape, and menu sizing.
## Artifact Root
An explainer lands under `<root>/explainers/` only when archived to the repo, and learnings may be read under `<root>/solutions/`. Resolve `<root>` only when you compose such a path; a scratch-only or external-concept run never composes one. Pass the resolved path to any subagent, not the config.
<!-- ce-docs-root:start -->
**Resolve the CE artifact root `<root>` before composing any artifact path.**
- **Read** `docs_root` from `<repo-root>/.compound-engineering/config.yaml` only (`<repo-root>` = `git rev-parse --show-toplevel`). Do not read it from `config.local.yaml`. Unset -> `<root>` is `docs`, exactly as before.
- **Validate** a set value: a repo-relative directory whose real, symlink-resolved path stays inside the repo and is neither the repo root nor under `.git/`. Otherwise stop with an error naming `docs_root` and the value -- never fall back to `docs`.
- **Use** `<root>` as the sole artifact location: create it if absent, compose each path as `<root>/<subdir>` with this skill's own subdirectory, and never also read `docs`.
<!-- ce-docs-root:end -->
## Execution Flow
### Phase 1: Classify the input
Read `references/intake.md` now and classify the request into one of the four input shapes — concept, diff, idea, or work-recap window — plus its audience. It owns the token table, the reads-as-a-flag guard, window and audience resolution, the concept-vs-diff tiebreak, conflict handling, and the operational-question gate that answers a diagnostic question in chat instead of teaching it. Most requests arrive as plain language with no token; classify those by meaning rather than improvising.
**Bare invocation** (no input at all): ask one blocking question — "What should I explain?" — offering a shortcut option for a recap of recent work in this repo alongside free-text. Do not produce a default artifact unprompted.
### Phase 2: Ground
Create the run directory first — every run gets one, before any artifact exists. It holds the explainer and the recap evidence, so run this block as written rather than improvising a `mkdir`: the checks it makes refuse a scratch root you do not own or one reached through a symlink.
```bash
SCRATCH_ROOT="/tmp/compound-engineering-$(id -u)";
[ ! -L "$SCRATCH_ROOT" ] && (umask 077; mkdir -p "$SCRATCH_ROOT") 2>/dev/null && [ ! -L "$SCRATCH_ROOT" ] && [ -O "$SCRATCH_ROOT" ] && [ -w "$SCRATCH_ROOT" ] || SCRATCH_ROOT="${TMPDIR:-/tmp}/compound-engineering-$(id -u)";
if [ -L "$SCRATCH_ROOT" ]; then echo "unsafe scratch root symlink: $SCRATCH_ROOT" >&2; exit 1; fi;
(umask 077; mkdir -p "$SCRATCH_ROOT") || exit 1;
if [ -L "$SCRATCH_ROOT" ] || [ ! -O "$SCRATCH_ROOT" ]; then echo "scratch root is not owned by the current user: $SCRATCH_ROOT" >&2; exit 1; fi;
chmod 700 "$SCRATCH_ROOT" || exit 1;
RUN_DIR="$SCRATCH_ROOT/ce-explain/$(date +%Y%m%d)-$(openssl rand -hex 3)";
(umask 077; mkdir -p "$RUN_DIR") || exit 1; chmod 700 "$RUN_DIR" || exit 1;
echo "$RUN_DIR";
```
Then match grounding to the input shape per `references/orchestration.md`'s grounding section, which also owns the empty-window and unreachable-web paths. Two rules govern what reaches the user while you gather, so they hold here:
- **Diff mode.** The one rule here is the **Empty range** case (the ref resolves to no commits — e.g. `main..HEAD` where the work is still uncommitted): do not silently explain something else. Say what the ref resolved to, name the nearest real candidate (the working tree, the last commit), and use it only after the user agrees — or, when they can't be asked, use it and state the substitution in the artifact's `Subject`. Apply the same rule when the named subject doesn't exist in this repo at all ("the retry logic" where there is none): report that before explaining an adjacent thing.
- **Recap mode.** Do not pre-scan, count, or characterize the window in the main conversation: an early `git --all` summary seeds the run with a false branch or activity model. Instead dispatch a generic subagent directly at the extraction tier, seeded with `references/agents/work-recap-scout.md` and passed the resolved window, the repo root, and `$RUN_DIR`. **Empty window** (no git activity, no doc changes): say so, offer to widen it, write no artifact, and end the run after the user responds. **When the harness exposes no subagent primitive**, the degradation rule applies: run the scout inline against its own prompt's sources and budgets, and still write `recap-evidence.md`; the no-pre-scan rule then means what it protects rather than where it runs — do the scout's evidence pass first and form no view of the window until it is done.
### Phase 3: Compose the explainer
Read the rendering reference for the resolved format **now**, not earlier: `references/explainer-html.md` (default) or `references/explainer-markdown.md` (when intake resolved `output:md`). Each owns the artifact's invariants and the voice for the audience intake resolved — personal by default, adapted for another reader on request, at unchanged depth. Read `references/check-in.md` with it: it owns whether the artifact ends with a `Check yourself` section and that section's shape. The run never blocks on the check-in — no offer, no prediction turn, no exercise posed in chat; the section is static text the reader works through alone. Compose per those contracts and write the artifact to `$RUN_DIR/explainer.html` (or `explainer.md`) before anything else happens with it, then display it (inline summary plus the file path). The artifact exists at that stable path from this moment — a declined destination ask never loses it.
### Phase 4: Destination ask and close
**Required read before you render anything in this phase: `references/destinations.md`.** It owns the destination menu, the per-option routing, each destination's sub-flow, the audience re-render offer and its ordering against a publisher's consent gate, and the improvement observations the run closes on. Read it now; do not render the menu and do not act on the user's selection without it.
Ask for the destination once with the blocking question tool — that governs the menu itself, not the consent a chosen destination then requires. Publishing is never headless and never inferred: ht-ml.app puts the page in public, so it may only publish once the user has seen the full warning and confirmed after it, and a destination they named up front is a choice of destination rather than that confirmation. Reaching that point takes more than one ask, in an order the reference sets — do not run the sequence from this paragraph. If it cannot be completed, do not publish; preserve the canonical HTML and report its local `$RUN_DIR/explainer.html` path. The handoffs the phase closes on are offered before anything fires; once the user accepts one, invoke it through the skill primitive rather than describing it, except `ce-polish`, which is user-run only.
**Non-interactive degradation:** when no interaction is possible at this ask (no blocking tool and no reply), do not hang and do not discard — the artifact is already at `$RUN_DIR`; report that path and end, skipping the reference's offers.
## Boundaries
- **Not a verdict.** "Should we adopt X?" is `ce-pov`. ce-explain teaches what X is and how it works.
- **Not repo memory.** Documenting a solved problem for future work is `ce-compound`. ce-explain teaches the human, not the repo.
- **Not ideation or scoping.** An idea input is explained as given — implications and trade-offs — never expanded into options or a requirements dialogue.
- **The check-in never blocks the run.** It is a section of the artifact the reader works through alone; the run asks no question about it.