add-content
Skill1 starsChanged 25 days agoMITView on GitHub
Turns a learner's material (photos, PDF, pasted text, notes) into AI Tutor cards and lessons in content/, validates them with make validate and commits the result. Use when the user asks to add, create, import or extend cards, a lesson or a chapter from their material.
- Installs packages
- Commits and pushes
We split this skill into the rules it gives an agent
19 rules. About 0 are common, 7 are distinctive, and 12 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈7
Distinctive · estimate
This author's own choices. Worth a look.
12
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 16
Run make validate. If .venv is missing, run make setup first.
- Very specific: line 18
Read content/program.yaml and every file in content/chapters/.
- Very specific: line 22
Photos and screenshots: read them with vision and transcribe to plain text first, in page order.
- Very specific: line 23
PDF: use the text layer (pdftotext -layout file.pdf - if it is installed, or your own PDF reader).
- Distinctive: line 24
Plain text and notes: use them as given. Notes often skip context.
- Distinctive: line 32
Write everything in your own words.
- Very specific: line 33
Write cards in the language the learner studies in.
- Very specific: line 40
Existing ids are permanent: Never rename, reuse or delete one, and do not edit existing cards unless asked: changing an existing card's …
- Distinctive: line 44
Check every card against this list:
- Very specific: line 86
Run make validate and repeat until it exits 0.
- Distinctive: line 95
Check the rungs of each new card (closed kinds it will actually get, in order):
- Very specific: line 100
No new warning: lines compared with the baseline.
- Very specific: line 126
If the user asked for a pull request, first git switch -c content/<lesson-id>.
- Distinctive: line 135
Never change, reuse or delete an existing chapter, lesson or card id.
- Very specific: line 136
Never edit the answer material of existing cards (answer, option, distractors, accepted, key_mode) unless the user asked for that exact …
- Distinctive: line 137
Never copy copyrighted text verbatim into cards.
- Distinctive: line 138
Never invent facts, numbers or sources.
- Very specific: line 139
Never weaken the validator, the contract or their tests (app/content.py, scripts/validate_content.py, tests/) to make content pass.
- Very specific: line 140
Never change files outside content/ in this workflow.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Add content
Turn material into cards that pass make validate, without touching anyone's existing progress. The field reference is docs/content-contract.md; the exercise rules are docs/exercises.md. Read both once before your first card.
Interactive or not. By default you show the user a table of proposed cards and wait for their edits (step 6). Skip that wait when the user said "proceed without asking" (or equivalent), or when nobody can answer: a headless run, CI, or another agent running you as a batch job. Everything else, including the final report, stays the same.
Scope. Change only files under content/. Do not change exercises switches here: if the material needs different exercise kinds, finish the cards and recommend the choose-exercises skill.
1. Get a green baseline
- Run
make validate. If.venvis missing, runmake setupfirst; if that fails on the client dependencies,python3.12 -m venv .venv && .venv/bin/pip install -r requirements-dev.txtis enough. - The baseline must exit 0. Keep its coverage table and warnings: you compare against them later. If the baseline already fails, stop and report the errors. Do not fix content you were not asked to touch.
- Read
content/program.yamland every file incontent/chapters/. Note the chapters, lesson ids, card ids, the exercise switches in effect per chapter, and which facts are already covered.
2. Read the material
- Photos and screenshots: read them with vision and transcribe to plain text first, in page order. Where a word, number or symbol is unreadable or ambiguous, mark it
[unreadable]and never guess. Re-check names, numbers, dates and units against the image before using them. - PDF: use the text layer (
pdftotext -layout file.pdf -if it is installed, or your own PDF reader). A scanned PDF without text is a set of images: handle it as photos. Keep page numbers forsource. If the user named pages or a chapter, use only those. - Plain text and notes: use them as given. Notes often skip context; complete a statement only from the material itself, never from what you believe the author meant.
- Vocabulary lists: one card per entry. The prompt asks for the meaning (or the word),
optionis the short translation, and the distractors are other entries of the same part of speech from the same list.
3. Extract facts
- List atomic statements: one checkable fact each (a definition, a cause, a number, a name, a rule, a step in a sequence).
- Keep a fact only if the material states it. Do not add facts from your own knowledge, do not "correct" the source silently, and do not fill gaps with plausible numbers. If the source looks wrong or contradicts itself, leave that fact out and report it.
- Drop opinions, anecdotes, examples that carry no fact of their own, and facts already covered by an existing card (report them as skipped).
- Write everything in your own words. Never copy sentences from copyrighted material; terms, names, numbers and formulas are fine.
- Write cards in the language the learner studies in. If it differs from
languageinprogram.yaml, say so in the report.
4. Plan lessons and ids
- Lessons: 1 to 10 cards each (a hard limit); aim for 4 to 8, grouped by sub-topic, in a sensible learning order. More material means more lessons.
- Placement: append a new lesson to the end of the best-matching chapter's
lessons. For a new topic, createcontent/chapters/<chapter-id>.yaml(idequal to the file name, atitle,lessons) and add the id tochapters:incontent/program.yamlwhere it belongs in the course. - Ids: lowercase letters, digits and hyphens, at most 64 characters, describing the content:
what-is-an-embedding,embeddings-basics. Card ids are unique across the whole program, and so are lesson ids. Before using one, check it is free:grep -rn "id: <candidate>$" content/. - Existing ids are permanent. Never rename, reuse or delete one, and do not edit existing cards unless asked: changing an existing card's
answer,option,distractors,acceptedorkey_moderesets that card for every learner.
5. Draft the cards
Check every card against this list:
- One fact. The card asks one thing. No "and", no two-part answers unless the fact is an enumeration (then
key_mode: all_ofwithacceptedlisting the parts; such a card has no cloze). - Verifiable. The answer is stated in the material.
sourcesays where (Course notes, week 3,Textbook ch. 4, p. 81; useOriginal textonly for text you wrote from scratch). - Prompt is a question that can be answered without seeing any options, and does not contain the answer.
- Answer is one full, short sentence. If the chapter enables
assemble, give it 4 to 8 words where it reads naturally. - Option is short (1 to 5 words) and appears word for word inside
answer. That makes it the cloze key. - Exactly 3 distractors, each with the same number of words as
option, the same grammatical form and a similar length. Each is plausible to someone who has not learned the card and clearly wrong according to the material. No synonyms or partial truths of the right answer, no "all of the above", no jokes. Distractors are the only text you invent. - Cloze works: besides the option, at least 3 words of
answerremain, and the option appears inansweronly once. - Hint (optional) nudges without giving the answer away. Note (recommended) adds the why or a common confusion in one or two sentences.
Words are counted by whitespace, punctuation included: Paris. is one word.
A card that passes every check, from the demo course (content/chapters/foundations.yaml). The option is inside the answer, and every distractor has the option's four words, so the card supports choice, cloze and, at 8 words, assemble:
- id: what-is-an-embedding
prompt: What is a token's embedding?
answer: A token's embedding is a list of numbers.
option: a list of numbers
distractors: [a short written definition, its position in text, a compressed image file]
hint: Think of coordinates in a space with many dimensions.
note: >-
Each token id is mapped to a learned vector, and these numbers are what the rest of
the network actually computes with.
source: Original textYAML pitfalls: quote a value that contains : or #, starts with ', ", [, {, *, &, !, |, >, % or @, or reads as a boolean, number or null (yes, no, on, 1e5, null). Use >- for long notes. A key written twice in one card is an error.
6. Confirm with the user
Show one table per lesson and stop until the user replies:
| # | Lesson | id | Prompt | Answer | Option | Distractors |
Under it, list facts you skipped and why, and any [unreadable] spots. Apply the user's edits, then continue. In a non-interactive run, or after "proceed without asking", skip the wait and include the same table in the final report.
7. Write and validate
- Write the YAML.
- Run
make validateand repeat until it exits 0. Compare with the baseline. Output looks like this:
chapter cards choice cloze assemble foundations 17 17 17 12Each number counts the chapter's cards whose data supports that kind, whether or not the chapter enables it. Your new cards should raise
cardsby their number,choiceby the same number and, by the same amount,cloze. A smaller rise inclozemeans some option is not word for word in its answer, or the distractors' word counts differ from the option.assemblerises only for answers of 4 to 8 words.Check the rungs of each new card (closed kinds it will actually get, in order):
.venv/bin/python -c "from app.content import load_program; p = load_program('content'); [print(l.id, c.id, *p.rungs(ch.id, c)) for ch in p.chapters for l in ch.lessons for c in l.cards]"- No new
warning:lines compared with the baseline. Fix the cards, not the switches.
| Error or warning | Fix |
invalid YAML (...), duplicate key '...' | Fix indentation or quoting at the reported line; remove the repeated key. |
unknown field 'x' | Remove it or correct the spelling. The allowed fields are in docs/content-contract.md. |
missing required field 'x' | Add it (id, prompt, answer for cards; id, title, cards for lessons). |
id: String should match pattern ... | Lowercase letters, digits and hyphens only, at most 64 characters. |
uses a reserved prefix (review-, practice-) | Choose a lesson id that does not start with them. |
duplicate card id / duplicate lesson id | Choose a new id for your item; never rename the existing one. |
distractors: provide exactly 3 or omit the field | Write exactly three. |
distractors: '...' is also a correct answer to this card | Replace that distractor with a wrong one. |
options must be distinct | Two buttons read the same after lowercasing and removing accents; reword one distractor. |
key_mode all_of requires every accepted key in the answer | Put every key in answer, or correct accepted. |
a lesson needs 1 to 10 cards | Split the lesson. |
must not be blank | Fill the field or remove it if optional. |
no enabled closed exercise is possible — ... | Do what the message says for that card: add 3 distractors, or give the answer 4 to 8 words when the chapter enables assemble. |
chapter '...' is listed but chapters/....yaml does not exist, not listed in program.yaml chapters, must match the file name | Keep program.yaml chapters:, the file names and each chapter's id in agreement. |
warning: option has N words but the longest distractor has M | Shorten the option or lengthen the distractors to the same word count. |
warning: <kind> is enabled but no card in this chapter supports it | Make the cards support it (see the checklist), or recommend choose-exercises to the user. |
make validate is the gate for content. make test also passes on any course that validates without warnings: tests/test_demo_content.py checks that whatever is in content/ loads without errors or warnings, and skips its demo-specific checks once the course is no longer the bundled demo. Never edit tests to make content pass.
8. Report and commit
git status --shortmust list only paths undercontent/.- If the user asked for a pull request, first
git switch -c content/<lesson-id>. Thengit add content/andgit commit -m "content: add <lesson title> lesson"(orchapter). For a pull request, thengit push -u origin content/<lesson-id>andgh pr create --fill. Otherwise do not push. - Report to the user:
- the cards added, as the table from step 6, with the file and lesson they went to;
- the final
make validateoutput, verbatim, and what changed against the baseline; - the facts skipped and why, unreadable spots, and doubts about the source;
- anything to decide next (exercise switches, a language mismatch, the demo-course test).
Never
- Never change, reuse or delete an existing chapter, lesson or card id.
- Never edit the answer material of existing cards (
answer,option,distractors,accepted,key_mode) unless the user asked for that exact change. - Never copy copyrighted text verbatim into cards.
- Never invent facts, numbers or sources. If the material does not say it, it is not a card.
- Never weaken the validator, the contract or their tests (
app/content.py,scripts/validate_content.py,tests/) to make content pass. - Never change files outside
content/in this workflow.
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- JoviDeCroock/pracht★ 106same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository5 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- choose-exercisesSkill
- deploySkill
- setup-serverSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
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.

