agentleFS
exiaoexiao/meta-skills/skill-tester/SKILL.md

skill-tester

Skill4 starsChanged 4 months agoApache-2.0View on GitHub

Test a lesson or course skill by self-play, one agent as instructor and student. Use for run lesson transcripts or QA the course. For web apps use dogfood.

  • Reads credentials

11 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

8 rules. 0 are common, 6 are distinctive, and 2 are very specific to this project.

  • 0

    Common

    Most of the 11 edited versions we read keep these.

  • 6

    Distinctive

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Test an interactive course by RUNNING it, not reviewing it.

    line 10
  2. Distinctive:

    After a lesson rewrite or new lessons, when the owner wants to SEE the lessons run rather than read a findings memo.

    line 22
  3. Very specific:

    If the user asks that each lesson be run by "a blank/raw subagent with NO system prompt" (the most faithful test, mirrors a Cursor paste …

    line 33
  4. Distinctive:

    INSTRUCTOR: follow the lesson file exactly, one step per message, run/narrate the demo, use the lesson's actual prompts and ASCII visuals, …

    line 45
  5. Very specific:

    When the owner asks for "a blank raw subagent with no system prompt" per lesson (Eric did, June 2026, treat it as a HARD requirement), …

    line 58
  6. Distinctive:

    Verify with a real rendered screenshot (BrowserVision), confirm the parchment/serif look landed in pixels, not just a DOM grep.

    line 98
  7. Distinctive:

    Read-only subagents get NO edit toolset beyond writing their own transcript files.

    line 114
  8. Distinctive:

    Don't cherry-pick. The whole point vs the findings-style test is that EVERY lesson ships raw, snags and all.

    line 117

“Common” is measured: kept by at least 6 in 10 of the 11 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

skill-tester: self-play lesson transcripts to surge

Test an interactive course by RUNNING it, not reviewing it. Each lesson file is "instructions to an AI on how to teach." A faithful test executes those instructions against a simulated student and captures the whole conversation. Publish every transcript raw so a human can read exactly how each lesson plays out and where it snags.

This is different from the QA skills you already have:

  • dogfood / adversarial-ux-test, browser automation against a deployed web app.
  • synthetic-userstudies + interactive-lesson-design/references/synthetic-lesson-testing.md produce ranked FINDINGS plus a couple of highest-signal transcripts. NOT full raw runs.
  • skill-tester: full turn-by-turn transcript of EVERY lesson, all published raw.

When to run

After a lesson rewrite or new lessons, when the owner wants to SEE the lessons run rather than read a findings memo. Run against the freshest source (pull origin, use a worktree; local checkouts go stale).

Step 1: Grab the freshest source

Pull the repo, add a worktree on the default branch, confirm the lesson count matches the latest merged PR. Read CLAUDE.md / LESSON-FORMAT.md / the skill spec so the instructor half follows the real teaching rules (e.g. "one step per message, STOP and wait, DO the demo live, keep messages short").

Variant: RAW blank-subagent self-play (no system prompt)

If the user asks that each lesson be run by "a blank/raw subagent with NO system prompt" (the most faithful test, mirrors a Cursor paste where the model carries no SOUL), do NOT use delegate_task (its subagents inherit the framework system prompt). Drive two direct proxy model calls per lesson with system= OMITTED. Full method + the termination-regex trap + the run-backgrounded pattern: references/raw-blank-subagent-selfplay.md; ready runner: scripts/run_selfplay.py. Otherwise use the parallel delegate dispatch below.

Step 2: Self-play dispatch (parallel, read-only)

Group lessons (e.g. by capability arc, ~4 each) and dispatch one read-only subagent per group via delegate_task, toolsets ["terminal","file"], instructed NOT to edit anything except its own output files. Each subagent, per lesson, writes a VERBATIM transcript where it plays both roles:

  • INSTRUCTOR: follow the lesson file exactly, one step per message, run/narrate the demo, use the lesson's actual prompts and ASCII visuals, STOP after each step.
  • STUDENT: a CALIBRATED persona (see below). Reacts in good faith, sometimes hits a snag, asks a clarifier, or pastes a plausible result.

Per-lesson transcript format: a # Lesson N: title heading, a one-line claimed magic moment, the turn-by-turn body with **INSTRUCTOR:** / **STUDENT:** labels covering the WHOLE lesson, then a ### Where it snagged tail (1-3 real friction bullets, or "clean run"). Label every file SYNTHETIC.

Step 2 variant: RAW blank subagent (no system prompt) per lesson

delegate_task subagents carry the full SOUL/persona system prompt, so they do NOT faithfully reproduce how a lesson runs when pasted into a bare Cursor/Claude chat. When the owner asks for "a blank raw subagent with no system prompt" per lesson (Eric did, June 2026, treat it as a HARD requirement), bypass delegate_task and call the Messages API directly through the local proxy with NO system param (an empty-string system is rejected with a 400). Instructor = blank model fed only the pasted lesson file; student = separate blank model given its persona as the FIRST USER message. Working runner: scripts/run_selfplay.py. Full why + the false-stop termination gotcha + backgrounding: references/raw-blank-subagent-selfplay.md.

Step 3: Calibrate the persona (the decision everything hinges on)

The most fragile beginner persona is a FALSE FLOOR, it over-drives fixes and patronizes the real audience. State the REAL audience explicitly before running (for an AI course it's typically a ChatGPT/Claude-literate PM: knows what a system prompt is, can install an app and run a setup command). Assume competence. Keep skill-independent findings (silent-failure bugs, missing-prerequisite fallbacks, overgeneralizations that lose a skeptic); discount false-floor-only complaints. Detail: this pattern is shared with interactive-lesson-design/references/synthetic-lesson-testing.md.

Load this skill BEFORE you build the first page, not after (hard-won)

The dark-mode rule below is the #1 repeat miss: a session builds a surge report from memory, defaults to dark mode, ships it, and Eric corrects it, the SAME rejection he already made on the aps-testing-report. The rule lives in this skill precisely so you don't re-learn it by getting corrected. So: the instant the task is "skill-test / QA a course AND publish to surge," read this SKILL.md FIRST, before writing any HTML. The warm-palette rule applies to ANY surge artifact Eric receives from this work, the raw transcripts page AND a separate findings/ scorecard report, not just the transcripts page. There is no Eric-facing surge deploy that should be dark mode; if you catch yourself hand-writing a --bg:#0c0d10-style dark :root, stop and pull the warm tokens from references/build-transcripts-page.md.

Step 4: Publish raw to surge

Build a page hosting ALL transcripts raw, collapsible per lesson, grouped by arc, with a SYNTHETIC warning header. Use Eric's visual identity (~/.hermes/VISUAL-IDENTITY.md), NOT dark mode. He explicitly rejected the dark aps-testing-report look, default to his warm editorial palette (parchment #f5f4ed, EB Garamond serif headlines weight 500, terracotta #c96442 accent, General Sans body, JetBrains Mono code). references/build-transcripts-page.md has the exact tokens; scripts/build_transcripts.py already ships with them. Deploy:

python3 build_transcripts.py
cp index.html 200.html
surge . <name>-transcripts.surge.sh

Verify with a real rendered screenshot (BrowserVision), confirm the parchment/serif look landed in pixels, not just a DOM grep. Surge can 504 on a cold first hit, retry after a few seconds.

If asked to PR this into the PUBLIC skills repo (exiao/skills)

Sanitize first, the public mirror bans personal data. Strip before committing: the name "Eric", personal surge URLs (*.surge.sh), the VISUAL-IDENTITY.md reference, specific PR numbers / commit SHAs, and /Users/... paths. Ship a NEUTRAL default theme in the public build script with a note to swap in your own :root tokens (the private copy keeps the warm palette baked in). Public category names differ: it's skills-meta there too, but verify via skills_list. Bump the README skill counts (category + total). Push as exiao via gh-as exiao. Grep the whole skill dir for leaks before committing: grep -rniE "eric|surge\.sh|VISUAL-IDENTITY|/Users/|<project-names>".

Pitfalls

  • Local repo checkout is usually STALE. Always work from origin/<default> in a worktree.
  • Read-only subagents get NO edit toolset beyond writing their own transcript files.
  • Long URLs / code blocks force horizontal scroll on mobile, the build script sets white-space:pre-wrap; word-break:break-word and overflow-wrap:anywhere so they wrap.
  • Don't cherry-pick. The whole point vs the findings-style test is that EVERY lesson ships raw, snags and all.
  • The build script resolves test-output/ relative to ITS OWN location, not the cwd. Run it from its directory, or put test-output/ beside the script. Smoke-test artifacts get re-staged by git add even after trash, unstage with git rm --cached before commit.
  • Speaker turns must wrap CONSECUTIVE lines, not just the label line. The renderer keeps a turn_open flag and close_turn() on the next heading/hr/speaker so a multi-line INSTRUCTOR/STUDENT block stays inside ONE bubble. The naive "wrap only the **SPEAKER:** line in a <p class='turn'>" version leaks follow-on lines out as top-level paragraphs a real fidelity bug gemini-code-assist caught on exiao/skills#158. Don't regress it.
  • read/write with encoding="utf-8". Transcripts carry smart quotes, emoji, and the full-width colon :; bare read_text()/write_text() throws on Windows CP1252.
  • The runtime copy and the public-repo copy of this script DRIFT. When you fix review comments on one, port the identical fix to the other (and to ~/.hermes/skills). Diff the three before declaring done; the public mirror lagged the runtime by two builds this session.

Drift check: does the published page still match the SOURCE?

The transcripts are a DERIVED artifact (self-play of repo lessons, which were generated from an upstream source like Notion). "Does the page match the source?" really means "are the repo lessons still current with the source?" To check after the owner says they updated the source:

  • Pull each source page (e.g. Notion via NOTION_API_KEY, page IDs often live in a repo helper script's MAP); dump plain text per lesson. Recursive Notion block fetch is SLOW (~2-3 min for 20 pages), run it backgrounded, don't inline-timeout.
  • Compare last_edited_time per page against the lesson-generation date / merge date. Pages edited AFTER the lessons were generated are the drift set.
  • Titles/structure usually still align; the drift is in DEMO specifics (example tools, exact prompts) and the voice spine. Report the drift set + per-lesson delta; the real fix is REGENERATE the changed repo lessons from current source, then re-run transcripts for those, then rebuild, not just re-running transcripts off stale lessons.

Verify with a DETERMINISTIC audit, never the subagents' self-verdict

Self-play subagents reliably self-report "clean run" / "pauses handled silently" even when you ask them to flag bugs, they graded their own homework every section this session. Their verdict is NOT proof. After the transcripts land, run an independent programmatic audit:

  • Walk every transcript, track the current speaker (**INSTRUCTOR:** / **STUDENT:**), and grep INSTRUCTOR-attributed lines for the failure pattern (e.g. a spoken stop., a leaked director's-note phrase). Print line-anchored hits; zero hits across all 20 = verified.
  • Filter benign matches (the word "stop" in ordinary English, "stops being a black box" or a worktree path that contains the string) so the audit doesn't false-positive.
  • Then spot-confirm the POSITIVE change actually landed (e.g. grep the re-threaded voice line in the relevant transcripts), not just that the bug is absent. This "subagent does the run, parent does the deterministic check" split is the whole point of re-running skill-tester to confirm a fix, without the audit you've just produced 20 more unverified files.

Lesson-design smell to flag (interactive "instructions to an AI" courses)

A stage direction like STOP (telling the teaching AI to pause/wait) reads as the instructor SHOUTING it at the student when a model follows the script literally, it leaks into spoken output. The fix is never "fewer STOPs" (one per step is the correct pacing mechanism); it's making the direction unmistakably silent. The phrasing that WORKED this session (verified by a fresh self-play run + grep audit showing zero leaks across 20 lessons): a director's-note blockquote > 🎬 **Director's note (never say aloud):** <action>, plus rewording the rules-block line to "Pause and wait ... never say them (or the word 'stop') aloud." Apply it with a deterministic transform script (regex over ^\*\*STOP\.\s*(.+?)\*\*$) so all lessons convert identically, then update the format guide (LESSON-FORMAT.md) so generated lessons inherit the convention, then re-run + audit. Also re-thread any voice/theme SPINE the upstream source carries (e.g. a recurring "there's no magic" line) into the lessons that dropped it add it to the Name It / What Just Happened beat in each lesson's own voice; verify it survives into the fresh transcripts. Don't over-cut: templated closings and the one-per-step pacing are the scaffold a model needs, not bloat, only fix the genuine leak.

Cold-open disorientation: lessons must ORIENT before they demo

A lesson that opens straight into "Watch this, I'm going to create real files", no overview, no "here's what we're covering," no statement of which lesson this is, leaves the learner lost. Eric pasted aps lesson 2 into Cursor and said "I copied the lesson and I have no idea what it's doing" (June 2026). Root cause: the format guide's "No setup check, open cold on the first real step" rule, plus the Magic Moment line living ABOVE "Instructions for Claude" (it's a guide for the model, never spoken), so the model's literal first utterance is a file-writing demo with zero framing.

The fix Eric asked for, as an explicit flow: (1) here's what we're covering today (overview), (2) here's the bite-sized lesson, (3) the magic moment teased, (4) then the demo. Implement as a Step 0: Orient block the instructor says BEFORE any demo, then waits: name the lesson ("Lesson N of M: <title>", with the day/arc), one-sentence "what we're covering," one-sentence tease of the magic moment coming, then a "sound good?" hand-off. Add a CRITICAL RULES line: "Open with Step 0 (orientation) BEFORE any demo. Never start by writing files."

Calibrate against the REFERENCE course before going heavier than it: check how github.com/exiao/claude-code-course lessons actually open (e.g. lessons/06-brainstorm-features.md). That course does NOT use a separate Step 0, but its Step 1 still avoids cold-demo disorientation two ways the aps lessons missed: (a) it opens with a conversational TRANSITION

  • ORIENTATION ("Now that we've learned to plan, let's go big...") instead of "Watch this"; (b) it opens by ASKING the student something rather than immediately demoing. So there are two valid fixes, Option A: match the reference (no Step 0; make Step 1 open with a transition and an ask, not a demo); Option B: the explicit Step 0 overview ramp Eric described. B is more structure than the reference does; surface the tradeoff and let the owner pick rather than silently picking B. Whichever is chosen, apply it to ALL lessons and update LESSON-FORMAT.md (replace the "open cold on the first real step" rule) so generated lessons inherit it, then re-run + audit.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.