Skip to content
Back to skills

Hard Cheese

ASecurity

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.

  • 18 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 19, 2026
developmentpythongitapibackend

Works with

  • terminal
  • api

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned October 4, 2026

npx -y skills add paulnsorensen/easy-cheese --skill hard-cheese --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Hard Cheese?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Hard Cheese
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/paulnsorensen-hard-cheese/badge)](https://www.skillsdirectory.com/skills/paulnsorensen-hard-cheese)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: hard-cheese
description: 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.
license: MIT
metadata: {dispatches-agents: true}
---

# /hard-cheese

The gate reduces **epistemic debt**. This debt exists when code passes checks, but the author cannot explain it.

## Inputs

```text
/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 of `HEAD`. An explicit slug overrides the SHA.
- `--socratic-cap N` sets the maximum number of retries. The gate then marks the artifact `FAILED` and returns a non-zero status. The default is `3`. Vibecheck has no limit, but easy-cheese prevents infinite loops.
- `--passing-score N` sets the minimum SOLO score for PASS. Use a value from `1` through `5`. The default is `3`. The gate treats a previous PASS below this value as stale.
- `--no-judge` enables log-only mode. Record the user's explanation with `status: 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`](../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

1. **Resolve scope.**
   - Set `diff_base = origin/main` and `diff_head = <short-sha of HEAD>`.
   - Load `.cheese/specs/<slug>.md` as the optional intent reference when it exists. The diff remains the source of truth.
   - Use the short SHA of `HEAD` when no slug exists.
   - If the diff against `origin/main` is empty, return `0` with `"nothing to gate on"`. Do not write an artifact.

2. **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>
   ```

   The command prints one JSON object and exits `0` for every state. Read its `state` field.
   For `previously_passed`, print `"previously passed"` and stop. Continue to step 3 for `stale` or `new`.
   A nonzero exit status is an input error; its stderr line is JSON with `error` and `exit_code`.
   A result is stale when `HEAD` changes or the last PASS score is too low.

3. **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 HEAD
   ```

   Show 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`.

4. **Record the user's explanation** as free text. Do not provide coaching or example answers. The explanation is the artifact under test.

5. **Start the judge sub-agent** in a fresh context. Use the same pattern as the `/cook` fan pathway.
   - Use `references/judge-prompt.md` as the system prompt.
   - Provide the passing score, diff summary, optional spec excerpt, the `targets` JSON from `rank-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`.

6. **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 from `targets_addressed`. When `targets` is empty or absent, skip the anchoring requirement and expect an empty `targets_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>"
   ```

7. **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:

```yaml
---
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:

```markdown
| 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 `reviewer` at `powerful` power and `high` effort. 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.md` as the system prompt.
- Give the judge the diff summary, the optional spec excerpt, the `targets` JSON, and the explanation. Require a JSON reply. Prohibit repository writes.
- **Parse the JSON output.** On a parse error, log an `ERROR` attempt 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

> Sankaranarayanan, S. (2026). *Mitigating 'Epistemic Debt' in Generative AI-Scaffolded Novice Programming using Metacognitive Scripts.* Proceedings of the 13th ACM Conference on Learning at Scale. <https://arxiv.org/abs/2602.20206>

The implementation uses the open-source VS Code extension from the paper's author:

<https://github.com/sreecharansankaranarayanan/vibecheck>

This `SKILL.md`, `references/judge-prompt.md`, and each artifact include the attribution. Thus, the citation stays with the audit trail.

## Divergence from the paper

Hard-cheese has three differences from vibecheck:

**1. Judge errors.** Vibecheck fails closed. The modal blocks code application until the judge recovers or the user retries.

Hard-cheese fails open. The gate records an `ERROR`, prints a warning, and returns `0`.

This policy prevents API failures from blocking pull request work.

**2. Telemetry content.** Vibecheck records the length of an explanation. It never records the text of an explanation.

Hard-cheese records the complete text of every explanation in the local artifact. The `.gitignore` file excludes `.cheese/`, so this text remains on the author's machine.

Tell the user about this retention before `--no-judge` records the first explanation.

**3. Prompt wording.** Vibecheck's prompt states its three questions without a lead sentence.

Hard-cheese adds a purpose-first lead sentence and a pointer to the ranked regions. The paper's three questions stay verbatim.

Add each new difference to this section.

## Composition with `--auto`

`--hard` and `--auto` can operate together. Terminal `/plate --hard` pauses automation once before publication, after `/plate` verifies the final artifacts.
The user responds to the prompt. PASS permits publication. FAILED stops publication. ERROR uses the documented fail-open behavior.

Commit-only `/plate --hard` does not run the gate. That path shares nothing. See `references/composition.md` for new pull requests and non-TTY behavior.

## Output

When the gate ends, print:

```
Hard-cheese artifact: .cheese/hard-cheese/<slug>.md
Status: PASS | FAILED | LOGGED | ERROR
Score: <n>/5 (<SOLO level>, pass ≥ <passing-score>)
Attempts: <n>
```

The `Score` line reports the latest judged attempt. Omit this line for LOGGED mode or an ERROR without a scored attempt.

Then print one applicable message:

- On PASS: `Ready to share for review.`
- On FAILED: `Cap exhausted. Improve understanding of the change before sharing.`
- On LOGGED: `Telemetry only — judge skipped via --no-judge.`
- On ERROR: Print one warning that identifies the failure. Include `Fail-open divergence active — gate exited 0; you may share for review at your discretion.`

## Preferred tools and fallbacks

| Need | Prefer | Fallback |
| --- | --- | --- |
| Diff inspection for the user-facing summary | `delta` | `git diff --unified=3` |
| Ranking the hunks for the prompt | `rank-hunks` bundle command | none — skip the ranked regions and note the gap |
| Reading the spec (when present) | bounded file read per [`code-intelligence-routing.md`](../cheese/references/code-intelligence-routing.md) | host file read |
| Spawning the judge | host sub-agent primitive (`Agent()` or harness equivalent) | none — without sub-agent spawn, run `--no-judge` mode and tell the user the judge is unavailable |
| GitHub / PR context (out of scope here) | n/a | n/a |

## Rules

- Run the judge sub-agent in fresh context. Do not use the code-writing context to grade the author's understanding.
- Do not coach the user before the answer. The explanation is the artifact under test.
- Show only the judge's Socratic questions after a FAIL. Do not add hints.
- Show the ranked regions; add no question or hint before the first attempt.
- Pass the user's explanation to the judge unchanged.
- Always run the freshness check. A changed `HEAD` requires a new attempt sequence.
- Record every ERROR attempt. Show a warning for each judge failure.
- Do not call a GitHub tool or a pull request tool. The gate operates before code enters review.
- Apply the shared voice rules from `../age/references/voice.md`. Report the result. Classify the residual risk as `certain | speculating | don't know`.
- Do not describe FAILED as `"almost passing"`.

## References

- `references/judge-prompt.md` defines the SOLO Taxonomy rubric, judge prompt, and JSON output.
- `references/composition.md` defines the complete `--hard` and `--auto` matrix.
- [`references/commands.md`](references/commands.md) lists the generated bundle commands.

## Agent resolution

Resolve the fresh judge through [`../cheese/references/agent-resolution.md`](../cheese/references/agent-resolution.md).

| Work | Preferred types | Permissions/isolation | Minimum power | Effort | Fallback |
| --- | --- | --- | --- | --- | --- |
| Grade the explanation | reviewer | no-tool or read-only, fresh-context | powerful | high | compatible reviewer, then general |

The canonical hard-cheese audit includes the shared `agent_resolution` block.

Files in this skill

  • SKILL.md12.9 KB
  • references/commands.md721 B
  • references/composition.md2.5 KB
  • references/judge-prompt.md7.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.