---
name: quiz-import
description: Turn a transcript, runsheet, notes or any source document into a Media Gallery quiz import file, and validate it against the app's own parser before handing it over. Use when the user wants quiz or exam questions generated from material about a video, audio recording or photo.
---

# quiz-import

You are writing a question file for one media item in the Media Gallery app.
The user will upload it on the album's Quizzes page. Your job ends when you
hand over a file path and the validator's counts - **uploading it is the
user's action, and so is any git.**

## Installing this skill (if you downloaded it from the gallery)

Save this file as `.claude/skills/quiz-import/SKILL.md` inside any folder
where you run Claude Code - a folder with your transcripts in it is a fine
choice. Start Claude Code there and ask it to make a quiz from a document, or
type `/quiz-import`. Nothing else is needed: the validation step below calls
the gallery, so you do not need the app's code.

## Inputs

- **The source.** A path to a transcript, notes, a runsheet or a PDF (Read
  handles PDFs directly). Inside the app's repo it is often already attached
  to the media item: attachments live at
  `uploads/<family>/<album>/attachment_<kind>_<id>.<ext>`, and study text may
  be in the item's quiz settings. If no source is given, ask for one - do not
  write questions from general knowledge.
- **How many questions**, and optionally a mix of types. With no number given,
  aim for 10-15 across all four types.

## Output

Write the file **somewhere the user will actually find it** - their Downloads
folder unless they name a path - and state the full path plainly when you
hand it over. **Never into a repository**: generated question files are the
user's content, not project files. Do not leave it in the session scratchpad
either; that folder is buried and session-scoped, and it is not a delivery.

The obvious "next to the source" is often wrong here: a source that is an
attachment lives inside `uploads/`, which is the app's storage tree, not a
place a person browses. Downloads is where a file meant for uploading through
a browser belongs.

Name it after the media item, not the attachment's stored name:
`stormwater-rag-overview-quiz.csv`, not `attachment_video_4-quiz.csv`.

## The format

One question per line, comma-separated, this header first:

```
question,questionType,correctAnswer,answer1,answer2,answer3,answer4,answer5,answer6
```

| Column | Rule |
|---|---|
| `question` | The text. Quote it if it contains a comma. Max 2000 characters |
| `questionType` | One of `true/false`, `single-select`, `multi-select`, `fill-in` |
| `correctAnswer` | An answer **number**, never answer text: `2` means answer2. Multi-select: `"1,3"` - **quoted**, it contains a comma. True/false: `true` or `false`. Fill-in: **leave empty** |
| `answer1..` | Up to 10 answers. True/false: leave all empty - the options are fixed. Fill-in: every answer column is an accepted answer |

Start the file with a provenance comment - lines beginning with `#` are
ignored by the importer:

```
# generated from <source filename>, <YYYY-MM-DD>
```

Quote any field containing a comma or a double quote. Straight quotes only.
No markdown fence around the file, no prose before or after it - the file
contents are the whole output.

## Question quality

The format is the easy part. What makes the questions worth taking:

- Every question is answerable **from the source material alone**. Nothing
  that needs outside knowledge; nothing about what the source *didn't* say.
- Distractors are plausible. A wrong answer should be something a person who
  half-listened might pick, not something obviously silly.
- Spread the types. Forty true/false rows is not a quiz. Use single-select for
  facts with one right answer, multi-select where several things were listed,
  fill-in for names, numbers and terms, and true/false sparingly.
- Fill-in answers: list every reasonable spelling or form the source supports
  (`Washington`, `Washington State`). Matching ignores case and spacing, not
  wording. Prefer single-select for numbers - a fill-in of "3.5 cents" marks
  "3.5¢" wrong.
- Multi-select is all-or-nothing when graded. Keep the correct set to two or
  three so it is fair.
- Do not number the questions in their text, and do not letter the answers -
  the app does both.

## Verify before you hand it over - mandatory

Check the file against the app's own parser. Which way depends on where you
are:

**Inside the Media Gallery repository** (there is an `app.py` and a
`check_quiz_import.py` beside you):

```
python -X utf8 check_quiz_import.py <file>
```

`-X utf8` is required (importing the app prints an emoji that crashes a
cp1252 console without it), and it needs the project's virtual environment.
Exit 0 means every row is valid; exit 1 prints each flagged row's number and
reason.

**Anywhere else** - ask the gallery to check it. Nothing is stored:

```
curl -sS -F "import_file=@<file>" https://gallery.reinowned.com/api/quiz_check
```

It answers with JSON: `ok` is true when every row is valid; otherwise
`problems` lists each flagged row's number, its question, and the reason.

Either way:

- All valid: report the path and the counts, and stop.
- Anything flagged: fix those rows in the file and check again. Repeat until
  it is clean.
- Never hand over a file that has not passed. "Mostly right" is what the
  validator exists to catch.

Both routes run the same code as the web import and its "Check file only"
button, so a file that passes here imports with nothing flagged.

## What to tell the user

The file path, the counts (`14 rows: 14 valid`), and one line reminding them:
on the Quizzes page, pick the media item, choose the file, and import - the
"keep switched off until I've read them" box is ticked by default, and
**Switch on all** at the top of the bank turns them on once they have read
through.
