Writing anki cards
Like everyone else, I'm sharing my agent stuff.
npx -y skills add msewell/agent-stuff --skill writing-anki-cardsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Generates high-quality Anki flashcards from source material and adds them directly to Anki via AnkiConnect. Produces atomic cloze and Q/A cards, skips duplicates safely, and returns a succinct run report. Use when the user asks to create Anki cards, flashcards, or spaced-repetition prompts from notes, articles, docs, or text.
SKILL.md
12.3 KB, as published. Nobody here has run it
Writing Anki Cards (Add-Only)
This skill is add-only: generate cards and insert notes into Anki. Do not run review/update/delete workflows.
Non-negotiable integrity rules
- No shortcuts. Every single card that will be added to Anki must be reviewed before it is added.
- Evaluator required once for every chunk/card. Run the evaluator exactly once on each drafted chunk, read its card-by-card verdict, and rewrite the chunk before adding. Do not run repeated evaluator loops after the rewrite unless the evaluator failed/incompletely reviewed the chunk or the user explicitly requests another pass. If the evaluator cannot be run, stop and ask the user how to proceed; do not add unreviewed cards.
- No mechanical card derivation. Do not use scripts, regexes, templates, heading extraction, table extraction, sentence clozing, or other automated transformations to derive card contents mechanically from the source. Scripts may be used only for source metrics, YAML validation, AnkiConnect preflight, duplicate checks, and insertion—not for deciding card prompts or answers.
- Do not imply completion of steps that were skipped. The final report must accurately reflect which chunks were evaluated and whether any cards were not reviewed.
SKILL_DIR="$(dirname "$SKILL_PATH")"
PIPELINE="$SKILL_DIR/scripts/anki_add_pipeline.py"
REFS="$SKILL_DIR/references"
Quick start
- Ensure Anki is running with AnkiConnect.
- Save source to
/tmp/source.txtand run the source gate. - Read the card formulation principles.
- For each chunk: manually generate → evaluate every card once → rewrite → move on.
- Merge only reviewed chunks, preflight, add notes, return report.
Prerequisites
- Anki + AnkiConnect (2055492159)
python3,jqpyyaml:python3 -m venv .venv && source .venv/bin/activate && pip install pyyamlpiCLI (for the per-chunk evaluator)
Canonical workflow
1. Save source material to /tmp/source.txt.
2. Run source gate — always, regardless of source size. Produces a chunk plan and source metrics YAML before any cards are written. See Source gate below.
3. Read card formulation principles using the read tool — mandatory before writing any cards:
- Card formulation principles
- Advanced techniques
read "$REFS/01-card-formulation-principles.md"read "$REFS/02-advanced-techniques.md"
4. For each chunk — manually generate → evaluate every card once → rewrite → move on:
a. Manually formulate cards from that chunk's source sections → write /tmp/anki-chunk-N.yaml.
Do not mechanically derive cards with scripts, regexes, heading/table extraction,
sentence clozing, or template expansion. Card prompts and answers must come from
deliberate card-design judgment.
b. Run the per-chunk evaluator on /tmp/anki-chunk-N.yaml → read the full free-form output,
including the card-by-card verdict for every card.
See Per-chunk evaluator below.
c. Rewrite /tmp/anki-chunk-N.yaml completely based on evaluation output.
Do not make surgical edits — the evaluator may identify structural issues
(missing coverage, ratio drift, systematic patterns) that require adding or
removing cards, not just editing existing ones.
d. Confirm every card remaining in /tmp/anki-chunk-N.yaml has either an evaluator OK
verdict or was rewritten in response to evaluator feedback. The post-rewrite chunk does
not need a second evaluator pass. If any card was neither reviewed by the evaluator nor
rewritten in response to evaluator feedback, do not merge or add that chunk.
Process each chunk to completion before starting the next. Do not stop mid-source unless the user explicitly approves an early exit.
5. Merge all reviewed chunks:
cat /tmp/anki-chunk-*.yaml > /tmp/anki-notes.yaml
6. Run preflight:
python3 "$PIPELINE" preflight --deck "<deck>"
7. Run add pipeline:
python3 "$PIPELINE" add-notes \
--deck "<deck>" \
--notes-file "/tmp/anki-notes.yaml" \
--source-identity "<source-url-or-path-or-title>" \
--source-text-file "/tmp/source.txt"
8. Return succinct report from script output.
Source gate (step 2)
Always run — for sources ≤2,500 words, produce a single-chunk plan.
- Count total words in
/tmp/source.txt. - List section headings with approximate word counts.
- Group sections into ~2,500-word semantic chunks. If total ≤2,500 words, one chunk covers the full source.
- Compute per-chunk card targets (5–10 cards per 1,000 words).
- Write
/tmp/anki-source-metrics-<hash>.yaml:
source_hash: "6f0fa16a8c25"
total_words: 8303
sections:
- heading: "§1. Introduction"
words: 225
- heading: "§2. Manifesto"
words: 300
- Write
/tmp/anki-chunk-plan-<hash>.yaml:
source_hash: "6f0fa16a8c25"
total_words: 8303
card_target_min: 41
card_target_max: 83
chunks:
- id: 1
sections: "§1–§5"
approx_words: 2100
card_min: 10
card_max: 21
status: pending
The hash is the first 12 characters of sha256(normalized_source_identity + "\n" + normalized_source_text) — the same value the pipeline script computes internally.
Per-chunk evaluator (step 4b)
After writing /tmp/anki-chunk-N.yaml, build and run the evaluator once. This is mandatory
for every chunk and every card before anything is added to Anki. A rewritten chunk does not
need to be evaluated again unless the evaluator failed/incompletely reviewed it or the user
explicitly requests another pass.
Template: Evaluator prompt
PROMPT=$(python3 -c "
import sys
t = open(sys.argv[1]).read()
c = open(sys.argv[2]).read()
print(t.replace('{{CHUNK_YAML}}', c))
" "$REFS/03-evaluator-prompt.md" "/tmp/anki-chunk-N.yaml")
timeout 200 pi --mode json --no-session --no-skills --no-extensions \
--no-tools --no-context-files \
--model opencode-go/glm-5.1 "$PROMPT" 2>/dev/null \
| jq -rj 'select(.type=="message_update" and .assistantMessageEvent.type=="text_delta") | .assistantMessageEvent.delta'
The evaluator returns three sections: a card-by-card verdict, a chunk-level synthesis (coverage gaps, ratio, systematic patterns, interference), and a concrete action list. Read all three before rewriting the chunk. Evaluate the feedback critically — the evaluator can be wrong, over-strict, or miss domain context. Accept findings that improve clarity and retrieval; push back on those that would make cards worse.
If the evaluator fails, times out, or cannot review the full chunk, stop and ask the user whether to reduce chunk size, change evaluator model, or abort. Do not add cards from a chunk that has not received evaluator review.
Notes YAML contract
Notes files are YAML lists. Always double-quote all field values — this single rule
prevents all YAML parse errors (colons in values, boolean-like words, and {{...}} syntax
are all safe inside double quotes).
# Section comments are native in YAML — use them freely
# === Chunk 1: §1–§5 Foundations (2,100 words) | target: 10–21 cards ===
- modelName: Cloze
fields:
Text: "Warmth is judged before {{c1::competence}}."
Back Extra: "Example: In a kickoff meeting, a technically strong answer can still land poorly if it sounds dismissive before trust exists."
tags: [warmth-competence]
- modelName: Basic
fields:
Front: "Why lead with warmth?"
Back: "Competence-first signaling reads as cold before trust is established."
tags: [warmth-competence]
Rules:
modelNamemust beClozeorBasic.Clozefields:TextandBack Extra.Basicfields:FrontandBack.tags: optional flow sequence[tag1, tag2].
Clarifying examples on card backs
Where applicable, include a brief clarifying example on the back side of the card:
- For
Basic, put it inBack. - For
Cloze, put it inBack Extra.
Use examples when they make an abstract idea concrete, distinguish likely-confused concepts, show application, or clarify a "why/how" answer. Omit examples for simple facts, dates, names, already-concrete definitions, or cases where the example would become the thing being memorized. Keep examples short and subordinate to the answer; do not turn the prompt into "give an example" unless example generation is itself the skill being trained.
Source-independent and self-contextual wording (required)
Cards must be comprehensible in isolation. Assume the reviewer sees only the card prompt
(Front for Basic, Text for Cloze) — not deck name, tags, or source metadata.
Before keeping a card, run this check: if this prompt appeared alone in a mixed-deck review session, would the topic be unambiguous? If not, add topic context directly to the prompt (prefix, field label, or context woven into the sentence).
Do not reference the source artifact.
❌ "this guide", "the guide", "this article", "the author says", "in the text/document", or any proper name unique to a worked example in the source (system names, fictional entities, organisation names used only as examples).
✅ Rewrite to domain wording with explicit topic context when needed: "In threat modeling…", "For REST APIs…", "In electronics…", "When designing…"
Script boundaries
Do not write or use scripts to generate card prompts, cloze deletions, Basic fronts/backs, or other note contents from the source. Mechanical extraction creates plausible-looking but unreviewed cards and is prohibited.
The add pipeline script is allowed only after all card contents have been manually written, evaluated, and rewritten as needed.
What the script guarantees
- AnkiConnect/version preflight
- Model/field preflight (
Basic:Front,Back;Cloze:Text,Back Extra) - Deck preflight + auto-create if missing
- Deterministic source hash (
sha256(normalized_identity + "\n" + normalized_text)) - Stable source tag + batch tag; tag sanitization
- YAML checklist at
/tmp/anki-add-run-<hash>-<deck>.yaml - Resume semantics (
pending|in_progress|done|failed) - Duplicate preflight (
canAddNotesWithErrorDetail) - Batched insertion (default execution chunk size: 25)
- Newline normalization (
\n→<br>in all fields) - Soft warnings:
Front/Text> 220 chars;Back/Back Extra> 600 chars
Density and card-type calibration (default targets)
- Cards per 1,000 words: 5–10
- Cloze:Basic ratio: 2:1 to 3:1
Calibration checks:
- Below density → under-extraction; above → over-splitting or low-value cards.
- Outside ratio range → rebalance unless source structure strongly justifies it.
- Atomicity and single-answer retrieval take priority over hitting numeric targets.
Resume commands
python3 "$PIPELINE" resume-status --checklist "/tmp/anki-add-run-<hash>-<deck>.yaml"
Re-run the same add-notes command to resume unfinished execution chunks.
Duplicate policy
Skip non-addable notes and continue. Do not fail the run for duplicates.
Fallback (manual API reference only)
If script use is impossible: version, modelNames, modelFieldNames, deckNames,
createDeck, canAddNotesWithErrorDetail, addNotes.
Final response format
- Deck:
<deck> - Total words (accurate):
<n> - Section word-count min/max:
<min>/<max> - Source metrics file:
/tmp/anki-source-metrics-<source-hash>.yaml - Chunk plan file:
/tmp/anki-chunk-plan-<source-hash>.yaml - Chunks planned/completed:
<n>/<n> - Chunks evaluated:
<n>/<n> - Document card target min/max:
<min>/<max> - Generated:
<n> - Attempted:
<n> - Added:
<n> - Skipped (duplicates/non-addable):
<n> - Failed:
<n> - Warnings:
<n> - Source tag:
<source::...> - Batch tag:
<batch::...> - Checklist file:
/tmp/anki-add-run-<hash>-<deck>.yaml