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...
Scanned 9/2/2026
Install to Claude Code
npx -y skills add melodic-software/claude-code-plugins --skill quiz-me --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Quiz Me?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/melodic-software-quiz-me)More formats (shields.io, HTML) on the badges page.
---
description: "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)."
argument-hint: "[recall <query>] (empty = quiz me on the change just completed)"
user-invocable: true
disable-model-invocation: false
metadata:
workflow-stage: anytime
summary: Generate a post-change report with a quiz verifying you absorbed the work
---
## 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_policy`
`always`/`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.
- **Questions are diff-sourced.** Author each quiz question from the change's actual diff
and the report sections that explain it, never from generic topic knowledge a reader
could answer without having followed this change.
- **Each question carries a source anchor, and a miss routes to it.** Anchor every
question to the report section that teaches its answer (a report-internal anchor, or a
durable pointer per the reference discipline below). On a missed question, send the
reader to that exact section — the skimmed material, quoted or linked — before any
retry; the miss's job is routing, not scoring.
- **The answer key is fresh-context authored.** Produce or verify the embedded key with a
fresh-context pass that reads only the report and the diff, not the authoring
conversation, so grading tests what the artifact actually supports rather than what its
author remembers meaning. Where no fresh sub-agent surface is available, re-derive the
key from the artifact alone before embedding it.
- **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:
```bash
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. The
`quiz-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_dir` to 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>` is
`YYYY-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`. If
`origin` is 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 unknown `quiz_policy` value falls back to `on-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 a `report_library_dir` pointing
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/…` or `docs/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 to `verification: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` / `exercise` actions.** `/education:teach assess` and
`/education:teach exercise` quiz 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.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!