readers · git:20260927.3d17d27 · 2026-09-27 · sha256 ad6473e27193429c

readers git:20260927.3d17d27A

Immutable. This exact content never changes and is served at /api/v1/blob/ad6473e27193429c.

---
name: readers
description: Open a reader panel. Instruction-bound amnesiac sub-agents read the abstract or introduction and report what they carried away, set against the author's intended points. Use when those sections change or the writing loop marks the panel stale.
allowed-tools: Read, Glob, Grep, Bash, Agent
---

# /readers — Reader Panel

## What it answers, and what it does not

It answers **what a first-time reader believes, remembers and could reuse** after reading a part of the manuscript,
set against the points the author wants carried (the intent card). It is how "does the contribution come across"
becomes something counted rather than asserted.

It does not answer whether the paper is good, whether a sentence changed its meaning (the author judges that), or
which single word is hard (word-level agreement with the author was too low to use). An eight-reader panel separates
only large differences; do not report a one-round rise or fall as a result. The script prints these limits in every
report.

## Before running

1. **Intent card.** The author's statement of who the reader is and the two to four points (M1, M2, ...) the reader
   should carry away. The writing loop names it in `target.intent_card`. If it lives outside the workspace's
   `human/` folder it is a draft, and the report says so. Do not write it for the author; draft it only when asked,
   and label it a draft. The template at `experimental/writing-loop/templates/intent-card.md` has further sections
   (advantage sentence, narrative order, experiment roles, the scan and its acceptance checks); this skill reads
   only the reader and the points.
2. **Directed questions** (optional, recommended): one per suspected misreading or per point you need confirmed,
   as `id<TAB>question` lines. Free-text summaries overstate misreadings; a directed question confirms one.
   Always consider one about reuse and one about which field the work belongs to.

## Steps

1. Build the packet. From a loop workspace (records which sentences, at which commit, the panel reads):

   ```
   python3 .claude/skills/readers/scripts/build-reader-packet.py --workspace <workspace> --out <dir> [--questions q.tsv] --aux <main.aux>
   ```

   Or from any file: `--text <file> [--bib refs.bib]`. Citations stay in author-year form; they are never replaced by
   a placeholder. Give `--aux` (the compiled draft's `.aux`) so cross-references show the numbers the page shows;
   without it they read "(number omitted)" and the prompt tells readers so. A placeholder the page does not have
   draws readers' complaints: in one panel most of "what got in the way" was about it.

2. Open the readers as sub-agents: two personas (`prompt_R1.txt`, `prompt_R2.txt`) × two models (a small and a
   larger one) × samples per cell. Eight (two samples) is the floor and shows only large differences; use sixteen
   (four samples) whenever the question is how many readers carried a given point, since a cell repeated on the
   same text agrees only moderately with itself. Personas and directed questions can live in the loop workspace
   (`target.readers.personas`, `target.readers.questions`) so every run asks the same thing. Give each sub-agent the prompt file's content verbatim and nothing else. Save
   each reply unedited as `<dir>/outputs/<persona>_<model>_<n>.json`, e.g. `R1_haiku_1.json`. Each reply carries
   the packet id the prompt names; a reply for another packet, or a copy of another reply, is rejected. Rebuild the
   packet into a new directory for a new version rather than over an old one.

3. Check the outputs; an incomplete output is not a reading and is named, not repaired:

   ```
   python3 .claude/skills/readers/scripts/check-reader-output.py --packet <dir>/packet.json --outputs <dir>/outputs
   ```

4. Judge the intent points. Two judges, independently: you, and a separate sub-agent given the readers' `remember`
   and directed answers with the reader names shuffled and the version not named. Each writes
   `reader<TAB>point<TAB>judge<TAB>✓|△|✗|≠` rows to `<dir>/judgments.tsv`. A reader carries a point only when at
   least two judges wrote ✓; judges who disagree count as not carried, and a pair with one judge is not judged.
   Give each judge the facts of every point (who or what did it, the number), not only its name: `≠` is a point said
   but credited to the wrong thing, and a judge told only the point's name grades it ✓. Mix a set of answers whose
   grade you know into the judging (one correct, one misattributed, one reversed, one bare number per point is
   enough), write their grades to `<dir>/injected.tsv` as `reader<TAB>point<TAB>truth`, and pass `--injected`:
   more than two misses records the panel as a failure.
   The tally cannot tell two judge names written by one hand: the second judge must be a separate sub-agent that
   has not seen the first judge's rows.

5. Tally, and record the run in the workspace:

   ```
   python3 .claude/skills/readers/scripts/tally-readers.py --packet <dir>/packet.json --outputs <dir>/outputs --judgments <dir>/judgments.tsv
   ```

   To compare two versions, run a full panel on each and pass `--compare-packet/--compare-outputs/--compare-judgments`;
   the report puts a two-sided Fisher p beside each point. Run the current version's panel twice and pass the second
   as `--repeat-outputs/--repeat-judgments`: a change no larger than the two runs' spread is reported as inside the
   noise. Judge `blank_reader.json` (written beside the packet, reader id `BLANK`) like any reader: a point it
   carries is scored by copying the first paragraph, and the report says so.

6. Report to the author in three lines per scale (whole text, then paragraphs): what you want the reader to carry
   (the intent card), what the readers carried (the tally, counts with their denominators), and what the text added
   that the author did not intend (misreadings, points the readers took that are not on the card). Mark every
   machine-produced reading as a draft. The author decides what is a gap.

   Counts in the report come from the scripts, not from your own reading of the outputs: how many readers
   qualified is the `qualified N of M` line of `check-reader-output.py`, and a panel is a reading of this version only
   when `tally-readers.py` says it recorded it (`已记为这一版的读者组`). A panel judged with sheets or scripts of your
   own still ends with both; if the tally did not record it, say the panel was not run on this version. One panel
   skipped both, reported sixteen qualified readers where there were fifteen, and the loop kept calling the last
   recorded panel stale.

## Where the output goes

`report.md` beside the packet. Real runs on unpublished work stay in the private workspace; never commit reader
outputs or packets to a public repository.

## Fail closed

Each script exits 2 when there is nothing to read, check or tally. A panel with fewer than eight qualified readers,
or fewer than two personas or two models, is recorded as a failure rather than as a reading of the version.