Hard Cheese
Checks whether an author can explain a code change before review. Use when the user requests `/hard-cheese`, `/cheese --hard`, or an understanding check. Use it before a pull request or through the `--hard` pipeline flag. Do not use it for reviews, test hardening, or fixes.
- Skill ID
- paulnsorensen/easy-cheese/hard-cheese
- Publisher
- paulnsorensen
- Repository
- easy-cheese
- Installs
- 0
- Files
- 5
- License
- MIT
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
paulnsorensen/easy-cheese/hard-cheeseInstalls these files- SKILL.md
- references/commands.md
- references/composition.md
- references/judge-prompt.md
- scripts/hard-cheese.pyz
What this skill tells the agent
/hard-cheese
The gate reduces epistemic debt. This debt exists when code passes checks, but the author cannot explain it.
Inputs
/hard-cheese [<slug>] [--socratic-cap N=3] [--passing-score N=3] [--no-judge]Arguments:
<slug>identifies the artifact at.cheese/hard-cheese/<slug>.md. This argument is optional. Without it, use the short SHA ofHEAD. An explicit slug overrides the SHA.--socratic-cap Nsets the maximum number of retries. The gate then marks the artifactFAILEDand returns a non-zero status. The default is3. Vibecheck has no limit, but easy-cheese prevents infinite loops.--passing-score Nsets the minimum SOLO score for PASS. Use a value from1through5. The default is3. The gate treats a previous PASS below this value as stale.--no-judgeenables log-only mode. Record the user's explanation withstatus: LOGGED. Do not start the judge sub-agent. This mode is the easy-cheese equivalent of the optional JSONL telemetry mode in vibecheck. It retains more content. See## Divergence from the paper.
Invocation modes
| Mode | How the gate runs | Where the gate sits |
|---|---|---|
| standalone | The user runs /hard-cheese <slug> before a pull request. | Outside the pipeline. No upstream skill is required. |
| propagated | /plate --hard runs /hard-cheese <slug> after the final writes and before publication. | At the verified-artifacts to share-for-review boundary. |
--hard passes through /cheese → /mold → /cook → /press → /age → /cure → /plate. Only /plate runs /hard-cheese.
See `../cheese/references/harness-portability.md` for portability requirements. It covers helper resolution, sub-agent dispatch, GitHub operations, and handoff transitions. Use the bundle or repository helper first. Use ${CLAUDE_SKILL_DIR} only as an optional host fallback. The handoff blocks define the portable contract because slash commands are host renderings, not the control model.
Flow
- Resolve scope.
- Set
diff_base = origin/mainanddiff_head = <short-sha of HEAD>. - Load
.cheese/specs/<slug>.mdas the optional intent reference when it exists. The diff remains the source of truth. - Use the short SHA of
HEADwhen no slug exists. - If the diff against
origin/mainis empty, return0with"nothing to gate on". Do not write an artifact.
- Freshness check. Run the freshness check before you run the gate:
python3 skills/hard-cheese/scripts/hard-cheese.pyz freshness-check \
--slug <slug> --passing-score <n>Exit 0 for previously_passed. Print "previously passed" and stop. Continue to step 3 for stale or new. A stale result has exit status 2. A new result has exit status 3. A result is stale when HEAD changes or the last PASS score is too low.
- Rank the hunks, then compose the vibecheck prompt. Keep it faithful to Sankaranarayanan 2026. Use "share for review" to keep the gate implementation independent.
Run rank-hunks before you compose the prompt:
python3 skills/hard-cheese/scripts/hard-cheese.pyz rank-hunks \
--base origin/main --head HEADShow the ranked regions next to the diff summary, one line per hunk, as path:start-end — reasons. Put the changed lines from every ranked region in the 80-line diff summary before other context. Make no judge call before the first attempt.
Before this is shared for review, explain in your own words what this change is for. How does <feature or fix> work? Why does it produce the desired behavior? What state, control flow, or invariants does it rely on? Start with the highlighted regions.
Show a diff summary with the prompt. For /plate, also show the complete final evidence:
- the final artifact inventory,
- each
{target, backend, verified}completion row, - the tracked artifact diff,
- the quality gate result.
Stop with a non-zero status when /plate omits one of these four values. Stop with a non-zero status when a completion row has verified: false.
- Record the user's explanation as free text. Do not provide coaching or example answers. The explanation is the artifact under test.
- Start the judge sub-agent in a fresh context. Use the same pattern as the
/cookfan pathway.
- Use
references/judge-prompt.mdas the system prompt. - Provide the passing score, diff summary, optional spec excerpt, the
targetsJSON fromrank-hunks, and user's explanation. - Require this JSON object:
{score, level, pass, feedback, socratic_qs, targets_addressed}.
See references/judge-prompt.md for the full system prompt and output shape.
Skip this step when the user sets --no-judge. Mark the attempt status: LOGGED, write the artifact, and return 0.
- Process the judge result.
- Mark the attempt PASS when
score >= <passing-score>. - Mark the attempt FAIL when
score < <passing-score>. Show the Socratic questions; at least one question anchors to a ranked hunk fromtargets_addressed. Whentargetsis empty or absent, skip the anchoring requirement and expect an emptytargets_addressed. Return to step 4 while retries remain. - Mark the attempt ERROR when the judge fails. Print a warning and return
0. See## Divergence from the paper.
Append the attempt row:
python3 skills/hard-cheese/scripts/hard-cheese.pyz append-attempt \
--slug <slug> --status <PASS|FAIL|ERROR> --score <n> \
--feedback "<judge feedback>" --explanation "<user explanation>"- Process an exhausted limit. Set the artifact
status: FAILED. Print the artifact path and return a non-zero status. Stop downstream chains.
Artifact
.cheese/hard-cheese/<slug>.md contains the audit trail. The .gitignore file excludes .cheese/, so the audit trail remains local.
Each file starts with this YAML frontmatter block:
---
slug: <slug>
attribution: Sankaranarayanan 2026 / vibecheck
rubric: SOLO Taxonomy (1-5), pass threshold = <passing-score>
passing_score: <n>
divergence: fail-open on judge error (vibecheck fails closed)
diff_base: <sha>
diff_head: <short-sha>
status: PASS | FAIL | FAILED | LOGGED | ERROR
attempts: <n>
---append-attempt writes the attempt log as this six-column markdown table:
| timestamp | head_sha | status | score | feedback | explanation |
| --- | --- | --- | --- | --- | --- |
| 2026-06-25T10:00:00+00:00 | a1b2c3d | FAIL | 2 | "Unistructural: lists steps but no causal link" | <user explanation verbatim> |
| 2026-06-25T10:05:00+00:00 | a1b2c3d | PASS | 4 | "Relational: explains why invariant holds" | <user explanation verbatim> |Each invocation appends attempts and does not overwrite rows. If HEAD changes, append new rows below the earlier rows.
Sub-agent contract — fresh judge
- Use fresh context for every invocation. The code-writing context can bias the judge.
- Resolve a no-tool or read-only
revieweratpowerfulpower andhigheffort. Use the shared agent resolver. - The shared resolver pins each reviewer to
powerful. Do not lower this value for the judge. - Use a general worker only with no-write enforcement. Set
degraded: true. - Use
references/judge-prompt.mdas the system prompt. - Give the judge the diff summary, the optional spec excerpt, the
targetsJSON, and the explanation. Require a JSON reply. Prohibit repository writes. - Parse the JSON output. On a parse error, log an
ERRORattempt and fail open.
The gate requires a host sub-agent feature. Without this feature, recommend /hard-cheese --no-judge to record the explanation without a grade.
Attribution
More from paulnsorensen
Use this skill in a project
Open any RiverX project, search the Skills panel for paulnsorensen/easy-cheese/hard-cheese, and install it in one click.
