"Post-work comprehension check: after a change is complete, generate a self-contained HTML report of what was done (context, intuition, decisions) with a quiz at the bottom that you answer — verifying the HUMAN absorbed the work, not the artifact. Non-gating by default; the quiz_policy userConfig tunes offer cadence. Also recalls prior work from the retained report library. Use when: 'quiz me', 'quiz me on this change', 'do I understand this change', 'comprehension check', 'a quiz at the bottom that I must pass', 'I want to make sure I understand everything that happened', 'what did we do on <ticket>'. Sibling to education:teach (multi-session coach) and education:explain (one-shot explainer); this verifies comprehension of COMPLETED WORK. Not artifact verification — that is verification:confirm (if installed)."
Resources
1Install
npx skillscat add melodic-software/claude-code-plugins/plugins-education-skills-quiz-me Install via the SkillsCat registry.
Purpose
Verify that the human absorbed a completed change — the object under test is the
person merging the work, never the artifact. After Claude finishes a change, generate an
HTML report of what was done (context, intuition, decisions) with a quiz at the bottom the
user answers. The failure mode this addresses: people glaze over plans and explainers, so
the human merging a PR cannot represent the change to a reviewer and their mental model of
the codebase decays, degrading future prompting.
Three value props:
- Representation accountability — can the user explain this change to a reviewer?
- Loop retention — keeping the user's mental model of the codebase current keeps their
prompting sharp. - Late intent-mismatch detection — a failed quiz surfaces "that's not what I intended"
while there is still time to fix it, before merge.
Use when: the user asks to be quizzed on completed work, or to recall past work
(quiz me, do I understand this change, what did we do on <ticket>). Skip when:
the request is to verify the artifact (does it work / is it right), to extract the user's
intent before work starts, or to coach a general subject — see "What this skill does NOT
do". This skill auto-invokes (no disable-model-invocation) so policy-driven offers can
fire; /education:quiz-me is the guaranteed path.
Effective configuration (substituted at load)
The values below substitute from this plugin's stored configuration when this skill loads.
A surviving literal ${user_config.…} placeholder means that key is unset — apply its
documented unset behavior.
| Key | Value | Unset behavior |
|---|---|---|
quiz_policy |
${user_config.quiz_policy} |
on-request — act only when invoked. Values govern OFFER CADENCE only (see "Non-gating posture"). Unknown value → treat as on-request. |
report_library_dir |
${user_config.report_library_dir} |
unset → artifacts land under ${CLAUDE_PLUGIN_DATA} (see "Retention mechanics"). Set to a corpus checkout to redirect the library root there. |
Configure via the /plugin dialog, or headless with claude plugin install education@<marketplace> --config KEY=VALUE (your installed marketplace name). A literal
non-home report_library_dir may be blocked by the hardcoded-path
guardrails — the same collision knowledge's library_dir hits (#798); adopt that issue's
path-indirection scheme for literal-path overrides once it lands.
Action router
Parse $ARGUMENTS: recall is the ONLY reserved first token. Anything else — including no
arguments — is the default action, with any argument text taken as context describing the
change to quiz on.
| Action | Purpose |
|---|---|
(default — empty, or any first token other than recall) |
Offer or generate a report + quiz for the change just completed; any argument text is context describing the change. Offer vs generate depends on who invoked it (below). |
recall <query> |
Answer "what did we do on X" from the retained report library first, git/tracker archaeology second — stating which source answered (see "Recall"). |
The default action branches on who invoked it: a user-initiated invocation
(/education:quiz-me, or "quiz me") is itself acceptance — generate the report + quiz
immediately. A model-initiated invocation that fires to satisfy quiz_policyalways/above-threshold is an OFFER — present it and wait for the user to accept before
generating anything (see "Non-gating posture"; generation is always user-confirmed).
Report contract
Produce a self-contained single-file HTML report (all CSS/JS inline, no remote fetch,
openable via file://, synthetic data only — never real secrets or tokens). Markdown
fallback where the project convention prefers it. Sections: context, intuition, decisions,
what-was-done, then the quiz at the bottom the user must answer — the canonical prompt
pattern ("a quiz at the bottom on the changes that I must pass"). Match each narrative
section's length to what the change needs: cover the substance, but do not pad with filler,
redundant summaries, or boilerplate.
- Answer key persists with the artifact. Embed the key in the report — a collapsed
<details>block in HTML, an appendix section in the markdown fallback. Grade
in-conversation in the same session; a later or compacted session grades by reading the
key back from the retained artifact, re-deriving from the report + diff only when the
key is missing. Without the embedded key a report recalled weeks later could not be
graded at all. - A failed quiz is a signal, not a gate. Surface it as a possible intent mismatch to
resolve before merge; never block the merge yourself (see "Non-gating posture"). - Reference discipline — durable pointers only. The report is self-contained.
Restrict any external reference to durable, checkout-independent pointers: PR/issue
URLs, commit SHAs or permalinks, promoted docs reachable on the default branch. Never
link memory-tier paths (.work/…) or contract-slice paths (docs/topics/…) — both are
pruned or checkout-local and will dangle. Distill ephemeral inputs (exploration/research
notes, session context) inline instead of linking them.
Retention mechanics
Artifacts NEVER land in the consuming repo's working tree. They land under a per-repo
library keyed on repo identity, not checkout path — this repo's per-ticket worktrees
are pruned after merge, so a path-keyed slug would strand every report under a dead slug
and leave recall from the main clone empty. The remote is normalized to a
protocol-agnostic host/org/repo form before hashing, so the SSH and HTTPS remotes of one
repo resolve to the same library. Derive the slug and destination:
url="$(git remote get-url origin 2>/dev/null)"
if [ -n "$url" ]; then
canon="$(printf '%s' "$url" | sed -e 's/\.git$//' -e 's#/$##' \
-e 's#^[a-z+]*://##' -e 's#^[^@/]*@##' -e 's#:#/#')"
base="$(printf '%s' "$canon" | sed -e 's#^.*[/:]##' | tr '[:upper:]' '[:lower:]' \
| tr -cs 'a-z0-9' '-' | sed 's/^-*//;s/-*$//')"
hash="$(printf '%s' "$canon" | { sha256sum 2>/dev/null || shasum -a 256; } | cut -c1-8)"
else # no remote — fall back to canonicalized project path
p="$(realpath "${CLAUDE_PROJECT_DIR}" 2>/dev/null \
|| readlink -f "${CLAUDE_PROJECT_DIR}" 2>/dev/null || printf '%s' "${CLAUDE_PROJECT_DIR}")"
base="$(basename "$p" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9' '-' | sed 's/^-*//;s/-*$//')"
hash="$(printf '%s' "$p" | { sha256sum 2>/dev/null || shasum -a 256; } | cut -c1-8)"
fi
repo_slug="$base-$hash"- Destination:
${CLAUDE_PLUGIN_DATA}/$repo_slug/quiz-me/reports/by default, or<report_library_dir>/$repo_slug/quiz-me/reports/when that userConfig is set. Thequiz-me/segment fences these artifacts off from teach's path-keyed workspaces in the
shared per-plugin data directory. - Repo-tree guard: resolve
report_library_dirto an absolute path before writing; if
it is${CLAUDE_PROJECT_DIR}or nested under it, refuse it, warn the user, and fall back
to the${CLAUDE_PLUGIN_DATA}default — reports must never land in the consuming repo's
working tree, regardless of how the userConfig is set. - Filename:
<date>-<change-slug>-<short-hash>.html(or.md) —<date>isYYYY-MM-DD,<change-slug>a kebab slug of the change (from the PR/ticket title),<short-hash>the short HEAD commit hash, so reports stay unique and sortable.
Non-gating posture
quiz_policy governs offer cadence only — no value ever auto-generates a report.
Generation is ALWAYS user-confirmed: the report + quiz is produced only after the user
accepts an offer, and a direct invocation ("quiz me") is itself that acceptance.
quiz_policy |
Offer behavior |
|---|---|
off |
Never offers. Direct invocation still works. |
on-request (default) |
Offers only when the user asks. |
always |
Suggests a quiz after each completed change. |
above-threshold |
Suggests when the change meets the threshold below. |
- Threshold (
above-threshold): the change meets ANY of — more than 5 files touched,
more than 200 changed LOC, or the governing plan records blast radius HIGH/CRITICAL.
Resolve the default branch first, then judge from the merge-base diff against its
remote-tracking ref at offer time (well-defined even after commits, and correct in a PR
worktree with no local branch):d="$(git remote show origin 2>/dev/null | awk '/HEAD branch/ {print $NF}')"; git diff --stat "$(git merge-base HEAD "origin/$d")"..HEAD. Iforiginis absent the threshold is unjudgeable — offer nothing. - Offers are best-effort, model-initiated from the description triggers and this
posture — there is no hook. An unknownquiz_policyvalue falls back toon-request.
Recall
recall <query> answers "what did we do on X" (a ticket, a change, a date). Search the
retained report library (see "Retention mechanics") FIRST; fall back to git history and
the tracker second. State which source answered.
Coverage boundary: the library holds ONLY work that was actually quizzed
(retention-at-write) — it is not a general work-history engine. When a query names work
that was never quizzed, say so and route to the git/tracker archaeology fallback rather
than implying the library is complete.
Composition
This skill is an optional post-work step; it never edits another plugin's gate sequence.
Consumers that run a staged workflow (session-flow's workflow skill, if installed) can
route to /education:quiz-me as a comprehension step by pointer — the composition lives
here and in that consumer's own on-ramps, not by mutating a shared stage list.
Gotchas
- The object is the human, not the artifact. If you find yourself checking whether the
code works, you are in the wrong skill (see "What this skill does NOT do"). - Never write to the consuming repo's tree. Reports go to the retention library only;
a report committed into the product repo is a defect — and areport_library_dirpointing
inside the repo tree is refused and defaulted, not honored. - Embed the answer key in the artifact. A report with no key cannot be graded in a
later session — the retention use case depends on it. - Don't imply library completeness on
recall. Only quizzed work is retained; name
the boundary and fall back to archaeology for the rest. - Durable pointers only in reports. A link to
.work/…ordocs/topics/…dangles the
moment the checkout is pruned; distill those inputs inline instead.
What this skill does NOT do
- Not artifact verification. "Did we build the right thing, and does it work?" — object
= the artifact — belongs toverification:confirm(if installed). This skill's object is
the human's comprehension of completed work. - Not pre-work intent extraction.
planning:interview(if installed) runs BEFORE work
to extract the USER's intent, where the user holds the answers. Here the work is done and
Claude holds the answer key; a failed quiz can surface an intent mismatch after the fact. - Not teach's
assess/exerciseactions./education:teach assessand/education:teach exercisequiz the learner on LEARNING CONTENT inside a teach workspace./education:quiz-me's object is the COMPLETED WORK of a change, with no learning
workspace. Namespacing keeps them distinct. - Not a merge gate. A failed quiz is a signal to resolve, not a block —
quiz_policy
only tunes how often a quiz is OFFERED, never whether the merge proceeds, and no report
generates without the user's confirmation.