Skip to content
lernapps.net
Menu

Rules

Each rule is one requirement on a learning app. It lives where it acts: as a section of a skill for AI assistants, as a check, as a lint rule or as an item of the review rubric. The same rule can live in several of them, always under the same id. This page reads them from there.

Every message of a check links to its rule here, by its id: https://lernapps.net/tooling/rules/#<id>.

RuleScopeSeverity
accessiblelistingerror
app-checkablelistingerror
correct-content-supportlistinghint
dependency-licencelistingerror
entry-fitness-matcheslistingerror
entry-from-schemalistingerror
entry-links-resolvelistingerror
free-of-chargelistingerror
learner-text-germanlistingerror
learners-actlistingerror
links-resolvelistingerror
no-accountlistingerror
no-adslistingerror
no-learner-data-in-textslistingerror
no-request-before-clicklistingerror
no-trackinglistingerror
own-data-onlylistingerror
pages-reachablelistingerror
runs-in-browserlistingerror
third-party-licencelistingerror
usable-at-360pxlistingerror
app-content-guidetoolingerror, warning at listing
app-content-matchestoolingerror, warning at listing
checks-passtoolingerror, warning at listing
early-previewtoolinghint
explore-before-codetoolingerror, warning at listing
few-turns-after-plantoolinghint
fix-from-messagetoolingerror, warning at listing
lockfile-matchestoolingerror, warning at listing
plan-filetoolingerror, warning at listing
retrospective-filledtoolingerror, warning at listing
stop-at-checkpointstoolingerror, warning at listing
suppression-reasontoolingerror, warning at listing
explainer-content-validarchetype:explainererror
explainer-figure-explainsarchetype:explainerhint
explainer-figure-hides-answerarchetype:explainererror
explainer-formulas-staticarchetype:explainererror
explainer-generated-soundarchetype:explainererror
explainer-languagesarchetype:explainererror
explainer-mistakes-diagnosedarchetype:explainerhint
explainer-navigationarchetype:explainererror
explainer-only-contentarchetype:explainererror
explainer-open-pointsarchetype:explainerwarning
explainer-plausible-numbersarchetype:explainerwarning
explainer-quote-sourcedarchetype:explainerwarning
explainer-readable-without-jsarchetype:explainererror
explainer-scope-matchesarchetype:explainerwarning
explainer-stable-idsarchetype:explainerwarning
explainer-structure-by-sectionsarchetype:explainererror
explainer-structure-completearchetype:explainererror
explainer-structure-deptharchetype:explainererror
interactive-app-validarchetype:interactiveerror
interactive-architecture-currentarchetype:interactiveerror
interactive-core-contractarchetype:interactiveerror
interactive-playthroughs-passarchetype:interactiveerror
keep-the-presetarchetype:explainer, archetype:interactive, archetype:quizerror
pages-from-gh-pagesarchetype:explainer, archetype:interactive, archetype:quizerror
prefer-built-in-blockarchetype:explainerhint
quiz-answers-checkedarchetype:quizhint
quiz-bank-validarchetype:quiz, archetype:explainererror
quiz-clear-questionarchetype:quiz, archetype:explainerwarning
quiz-feedback-explainsarchetype:quiz, archetype:explainerhint
quiz-fitting-typearchetype:quiz, archetype:explainerhint
quiz-further-readingarchetype:quizwarning
quiz-number-precisionarchetype:quiz, archetype:explainerwarning
quiz-only-dataarchetype:quizerror
quiz-own-wordsarchetype:quizwarning
quiz-plausible-optionsarchetype:quiz, archetype:explainerwarning
quiz-stable-idsarchetype:quizwarning
start-page-explainsarchetype:interactivehint
storage-through-wrapperarchetype:explainer, archetype:interactive, archetype:quizerror
strict-typescriptarchetype:explainer, archetype:interactive, archetype:quizerror
topic-has-exercisesarchetype:explainererror
vue-component-browser-globalsarchetype:explainer, archetype:interactiveerror
vue-component-exercise-contractarchetype:explainererror
vue-component-importsarchetype:explainer, archetype:interactiveerror
vue-component-no-html-injectionarchetype:explainer, archetype:interactiveerror
vue-component-no-networkarchetype:explainer, archetype:interactiveerror
vue-component-nojsarchetype:explainererror
vue-component-props-validarchetype:explainererror
vue-component-sizearchetype:explainererror
vue-component-testedarchetype:explainererror
vue-component-tutor-tablearchetype:explainerhint

Accessible to WCAG 2.1 AA

accessible · listing · error

  • WCAG 2.1 AA: labels, contrast, keyboard, text alternatives.
  • Deviate only where the idea needs it (typing game against the clock); then say what is missing, in plain German, in the entry's limits.
  • With limits: lernapps check --entry reports warnings; without: errors.

Told in skills/tooling/lernapps-cli/references/platform-rules.md; checked by the check check/rules/accessible.ts.

The published app can be opened and checked

app-checkable · listing · error

  • Opens at the entry's url; a built app from its bundle (index.html).
  • Page does not load, build fails, no browser, check stops → only this rule is reported. Fix, check again.
  • Opens in a browser but the check fails → issue at https://github.com/lernapps/tooling/issues with the message.

Told in skills/tooling/lernapps-cli/references/platform-rules.md.

Help keep the content correct

correct-content-support · listing · hint

  • Computable answers: generate exercises, test answers with a checker.
  • Name a source for facts. Where it fits; never a listing condition.

Told in skills/tooling/lernapps-cli/references/platform-rules.md; judged by the rubric item in review/rubric.md.

Only dependencies with an open licence

dependency-licence · listing · error

  • dependencies only with these licences, transitively: MIT, MIT-0, ISC, 0BSD, BSD-2-Clause, BSD-3-Clause, Apache-2.0, MPL-2.0, BlueOak-1.0.0, Zlib, Unlicense, CC0-1.0, CC-BY-4.0, Python-2.0.
  • Build tools: devDependencies.

Told in skills/tooling/lernapps-cli/references/platform-rules.md; checked by the check check/rules/dependency-licence.ts.

Fitness values as measured

entry-fitness-matches · listing · error

  • fitness.storage, fitness.thirdParty from what the app does; lernapps check --report <file> measures it.
  • Anything in localStorage or sessionStorage, also what the app only reads on loading and keeps after an input (an assistant chosen for the tutor, an answer being written) → storage: device; loads from another server after a click → thirdParty: on-click.

Told in skills/tooling/lernapps-cli/references/platform-rules.md; checked by the check check/rules/entry-fitness-matches.ts.

Fill the entry from the published schema

entry-from-schema · listing · error

  • Fetch the entry schema each time; never from memory or another app.
  • Every value from the creator's answers, the plan or the app; never invented.

Told in skills/tooling/lernapps-cli/references/platform-rules.md.

Every link of the entry resolves

entry-links-resolve · listing · error

  • Each topic: path of an existing page, relative to the app's url; <page>#<section> names an element id there.
  • Check against the deployed app: lernapps check --entry <file>.

Told in skills/tooling/lernapps-cli/references/platform-rules.md; checked by the check check/rules/entry-links-resolve.ts.

Free of charge

free-of-charge · listing · error

  • Every part free: no payment, paid upgrade or ending trial.

Told in skills/tooling/lernapps-cli/references/platform-rules.md; judged by the rubric item in review/rubric.md.

German always, every declared language complete

learner-text-german · listing · error

  • Texts for learners, teachers, parents: German, plain (short sentences, active voice, no jargon).
  • More languages only where the archetype supports them (explainer, quiz: languages, German first); each declared language complete, no other.
  • Texts out of code: in the content (explainer YAML, quiz bank) or message files (src/messages/de.json, shown with translator from @lernapps/tooling/i18n).

Told in skills/tooling/lernapps-cli/references/platform-rules.md; checked by the lint rule lint/rules/learner-text-german.ts; judged by the rubric item in review/rubric.md.

Learners do something themselves

learners-act · listing · error

  • Every page or screen asks learners to try, practise or decide. Reading alone is not enough.

Told in skills/tooling/lernapps-cli/references/platform-rules.md; judged by the rubric item in review/rubric.md.

No account

no-account · listing · error

  • Whole app usable without sign-up or login.

Told in skills/tooling/lernapps-cli/references/platform-rules.md; judged by the rubric item in review/rubric.md.

No ads

no-ads · listing · error

  • No advertising, sponsored content or product placement.

Told in skills/tooling/lernapps-cli/references/platform-rules.md; judged by the rubric item in review/rubric.md.

Nothing about a particular learner in public texts

no-learner-data-in-texts · listing · error

  • No name, class, school, grade, picture or other detail of a real learner in app, entry, README, plan or commit message, even if the creator mentions one. Made-up names in exercises.

Told in skills/tooling/lernapps-cli/references/platform-rules.md; judged by the rubric item in review/rubric.md.

No request to another server before a click

no-request-before-click · listing · error

  • Bundle fonts, scripts, pictures at build time.
  • Other servers (video, map) only after the learner's click.
  • No other servers' URLs in code; at a click-to-load line suppress the lint message with this reason.

Told in skills/tooling/lernapps-cli/references/platform-rules.md; checked by the check check/rules/no-request-before-click.ts; checked by the lint rule lint/rules/no-request-before-click.ts.

Collect nothing, set no cookies

no-tracking · listing · error

  • No cookies, analytics, tracking pixels, server storing data.
  • Stored data stays on the device (localStorage, or sessionStorage while the tab is open) and serves only the app.

Told in skills/tooling/lernapps-cli/references/platform-rules.md; checked by the check check/rules/no-tracking.ts; judged by the rubric item in review/rubric.md.

Touch only the app's own data in the browser

own-data-only · listing · error

  • Every app on lernapps.net shares one origin with the other apps and the platform.
  • Own data: keys of localStorage and sessionStorage, IndexedDB databases and caches named lernapps:<id>:…, <id> the app's id in the catalog (entries/<id>.yaml).
  • Also every app's: the learner's settings for every app (lernapps:settings:<key>, a key without a colon) and for every app of the page's archetype (lernapps:settings:<archetype>:…, the archetype of <meta name="lernapps-archetype">); never another archetype's. settings is never an app's id.
  • Never read, write or remove other keys; never clear(); never caches.match() without cacheName.
  • Built with this tooling: createStorage("<id>") from @lernapps/tooling/storage; settings with createSettings("<id>", "<archetype>").
  • lernapps check puts another app's data into the browser and reports every access to it, before a click.

Told in skills/tooling/lernapps-cli/references/platform-rules.md; checked by the check check/rules/own-data-only.ts; judged by the rubric item in review/rubric.md.

Every page is reachable from the start page

pages-reachable · listing · error

  • Every built page linked from the start page or a page it leads to; the listing checks only those.
  • Pages nobody should reach: out of the build. Reached otherwise on purpose: <meta name="robots" content="noindex">.
  • 404.html at the root needs no link.
  • On a URL the checks visit at most 100 pages (hint); check the bundle for all.

Told in skills/tooling/lernapps-cli/references/platform-rules.md; checked by the check check/rules/pages-reachable.ts.

Runs in the browser, without installation

runs-in-browser · listing · error

  • Opens and works at its URL in a current browser. No app store, download or extension.

Told in skills/tooling/lernapps-cli/references/platform-rules.md; judged by the rubric item in review/rubric.md.

Name source and licence of others' content

third-party-licence · listing · error

  • Others' content (texts, pictures, quotes) only with a licence that allows it; source and licence next to it.

Told in skills/tooling/lernapps-cli/references/platform-rules.md; judged by the rubric item in review/rubric.md.

Usable at 360 px

usable-at-360px · listing · error

  • Every page at 360 px width: no horizontal scrolling, every control reachable.
  • Deviate only where the idea needs it (keyboard required), in limits as under accessible.

Told in skills/tooling/lernapps-cli/references/platform-rules.md; checked by the check check/rules/usable-at-360px.ts.

Keep the app's content guide

app-content-guide · tooling · error · warning at listing

  • Keep .agents/skills/app-content/SKILL.md with its fixed headings.
  • After the plan is confirmed and before content: replace every placeholder ("FILL IN") with concrete instructions for writing new content: files, ids, data files, an example of this app. Not how the app works, no general advice.
  • A content decision changes (pattern, figure type, source rule) → change the guide in the same commit.
  • lernapps check checks the file and its headings always, and that no placeholder is left once the plan is in Commit.
  • App older than the guide: lernapps update adds the skeleton (skill lernapps-cli).

Told in guidance/workflow-rules.md; checked by the check check/rules/app-content-guide.ts.

The content guide says what was built

app-content-matches · tooling · error · warning at listing

  • Every pattern it names is used; no pattern is used that it does not name.
  • Curriculum, competencies, chapters, pages or rounds match the content.
  • Its procedure for a new chapter or round names the current files.
  • An agent without your conversation can add the next chapter or round from it alone.

Told in guidance/workflow-rules.md; judged by the rubric item in review/rubric.md.

Run the checks before you push

checks-pass · tooling · error · warning at listing

  • lernapps check passes before every push. The hooks run it too; CI runs the same command and keeps its report as the artifact validation-report.

Told in skills/tooling/lernapps-cli/SKILL.md.

Show a first look early

early-preview · tooling · hint

  • In Code, as soon as the first screen or page shows real content: send the creator a short "Zwischenstand".
  • Show screenshots, desktop and 360 px. On the creator's machine also the address of npm run dev, started in the background.
  • No checkpoint, no question: go on in the same message. The creator may stop you or ask for a change.
  • Example: "Zwischenstand: So sieht die erste Seite aus. Ich baue weiter; sag Bescheid, wenn etwas nicht passt."

Told in guidance/workflow-rules.md.

No code before the plan is confirmed

explore-before-code · tooling · error · warning at listing

  • No code and no lernapps create until the creator has confirmed the plan with a yes.

Told in guidance/workflow-rules.md.

Work on your own after the plan

few-turns-after-plan · tooling · hint

  • After the confirmation, ask only what you cannot decide.
  • Else choose, mark "(guess)" under "Key decisions" and list it in the retrospective.

Told in guidance/workflow-rules.md.

Fix failed checks, never bypass them

fix-from-message · tooling · error · warning at listing

  • Fix the cause the message names.
  • Never bypass a hook: no --no-verify, no acceptance such as ARC42_CONSISTENT without a finding shown.
  • Never delete a test to make it pass.

Told in skills/tooling/lernapps-cli/SKILL.md.

Commit the lock file with every dependency change

lockfile-matches · tooling · error · warning at listing

  • Change dependencies with npm install, never in package.json alone; commit package-lock.json with it.
  • A git pin (github:…#<commit>) moves in both files together.

Told in skills/tooling/lernapps-cli/SKILL.md; checked by the check check/rules/lockfile-matches.ts.

Keep the plan file

plan-file · tooling · error · warning at listing

  • Each plan in .vibe/plans/, with every section and front matter key of its template.
  • Never change the plan of an earlier piece of work.
  • Set phase when you enter a phase. Tick each task box when it is done.
  • Never edit prePushFailures or failedChecks: the hook and the check write them.

Told in guidance/workflow-rules.md; judged by the rubric item in review/rubric.md.

Fill the retrospective

retrospective-filled · tooling · error · warning at listing

  • At the end of Commit, fill every part with facts: phases reached, creator turns after the plan, where you guessed. No names.
  • Failed checks need no entry: the check counts them in failedChecks.

Told in guidance/workflow-rules.md; judged by the rubric item in review/rubric.md.

Stop at the creator's checkpoints

stop-at-checkpoints · tooling · error · warning at listing

  • Checkpoints: research, confirm the plan and the content method, publish. Stop at each and wait for the answer.
  • Checkpoint list: open the listing pull request first (it publishes nothing), then show it and its result and wait.
  • A message sent before the checkpoint's question is no yes.
  • Example: "Die App ist fertig und geprüft. Soll ich sie jetzt veröffentlichen?"

Told in guidance/workflow-rules.md.

Suppress only in place, with the reason

suppression-reason · tooling · error · warning at listing

  • Lint: only on the line, with the rule named and the reason after --: // oxlint-disable-next-line lernapps/no-request-before-click -- the video loads after a click.
  • Types: only // @ts-expect-error -- <reason>; never @ts-ignore or @ts-nocheck.
  • The review reads every suppression.

Told in skills/tooling/lernapps-cli/SKILL.md; checked by the lint rule lint/rules/suppression-reason.ts.

The content validates

explainer-content-valid · archetype:explainer · error

  • Schema-valid; ids unique per level; references exist (data file, image, component, page or section link); placeholders declared; formulas only from the command list.
  • Build names each problem with file, line, block path.

Told in skills/archetypes/lernapps-explainer/references/rules.md.

The figure shows what the text says

explainer-figure-explains · archetype:explainer · hint

  • Each figure shows what the text next to it explains. The caption says what to look at; alt says what it shows.

Told in skills/archetypes/lernapps-explainer-design/references/rules.md; judged by the rubric item in review/archetypes/explainer.md.

The figure does not give the answer away

explainer-figure-hides-answer · archetype:explainer · error

  • A task's figure shows the given values, never the answer.

Told in skills/archetypes/lernapps-explainer-design/references/rules.md.

Formulas as formulas

explainer-formulas-static · archetype:explainer · error

  • Every formula in a formula block or $…$; never plain text (W = G * p / 100) or a picture. MathML for screen readers.

Told in skills/archetypes/lernapps-explainer/references/rules.md; judged by the rubric item in review/archetypes/explainer.md.

The property test passes

explainer-generated-sound · archetype:explainer · error

  • given, where: where holds often; answer defined and in format for every draw; no mistake can equal it.
  • Failure names the seed: narrow given or change the mistake; never the comparator.

Told in skills/archetypes/lernapps-explainer/references/rules.md.

German first, every language complete

explainer-languages · archetype:explainer · error

  • languages, German first.
  • Every learner text (content, data files, component props) in each, no other. Build fails otherwise.

Told in skills/archetypes/lernapps-explainer/references/rules.md.

Typical mistakes with their message

explainer-mistakes-diagnosed · archetype:explainer · hint

  • Computed tasks list real mistakes. Each message says what went wrong and how to fix it ("Du hast vergessen, durch 100 zu teilen", not "Falsch").

Told in skills/archetypes/lernapps-explainer-design/references/rules.md; judged by the rubric item in review/archetypes/explainer.md.

Every page in one chain

explainer-navigation · archetype:explainer · error

  • Navigation is the runtime's: from the order lists; every page in one chain, reachable from the start page.
  • Prose links: paths from the app root.
  • lernapps check finds unreachable pages (pages-reachable) and entry topics with a missing #<section> (entry-links-resolve).

Told in skills/archetypes/lernapps-explainer/references/rules.md.

Write only the content

explainer-only-content · archetype:explainer · error

  • Write: YAML of app, chapters, pages, data; images in src/images/; components with logic and tests in src/components/.
  • src/main.ts, index.html, e2e/explainer.e2e.ts, config as generated (keep-the-preset). Any other file in src/ fails the build.
  • Not expressible → "Where I had to guess", never code around the runtime.

Told in skills/archetypes/lernapps-explainer/references/rules.md.

An open task checks what the material teaches

explainer-open-points · archetype:explainer · warning

  • 2 to 5 points, each one sentence a learner can check with yes or no; together what a good answer needs.
  • A point of the content names its section (source), and its content is there; a point of form has kind: form.
  • The model answer has every point, in the words of the class.

Told in skills/archetypes/lernapps-explainer/references/rules.md; judged by the rubric item in review/archetypes/explainer.md.

Numbers that fit the story

explainer-plausible-numbers · archetype:explainer · warning

  • Ranges fit the thing: prices in whole cents, people whole, a bicycle 150–1500 €.
  • Preconditions rule out misfits (90.91 people).

Told in skills/archetypes/lernapps-explainer-design/references/rules.md; judged by the rubric item in review/archetypes/explainer.md.

Quotes exact, with their origin

explainer-quote-sourced · archetype:explainer · warning

  • Quote exactly. Name its origin (author, work, year), source and licence.

Told in skills/archetypes/lernapps-explainer-design/references/rules.md; judged by the rubric item in review/archetypes/explainer.md.

Every page readable without JavaScript

explainer-readable-without-js · archetype:explainer · error

  • Every fact in a block, visible without JS. No meaning only inside an exercise or component.
  • Every component a nojs text: what it shows, its content.
  • lernapps check opens every explainer page again with JS off, bundle and deployed (listing and review too): headings, formulas, figures visible, figures named; every "Lösung" and nojs text not empty.

Told in skills/archetypes/lernapps-explainer/references/rules.md; checked by the check check/rules/explainer-readable-without-js.ts; judged by the rubric item in review/archetypes/explainer.md.

The scope says what the pages teach

explainer-scope-matches · archetype:explainer · warning

  • scope of each page in your own words, never copied from the material; scope in src/app.yaml with what does not belong to it.
  • Each page's scope says what the page teaches, no more and no less; "Gehört nicht dazu" names what a learner or tutor might expect but the material does not teach.

Told in skills/archetypes/lernapps-explainer/references/rules.md; judged by the rubric item in review/archetypes/explainer.md.

Keep the ids

explainer-stable-ids · archetype:explainer · warning

  • Short, telling ids ("prozentwert", "regel") for chapters, pages, sections, exercises; keep them when texts change (entry topics, teachers' links).
  • New content, new ids; never reuse a removed one.

Told in skills/archetypes/lernapps-explainer/references/rules.md; judged by the rubric item in review/archetypes/explainer.md.

Structure only by sections

explainer-structure-by-sections · archetype:explainer · error

  • Every heading = a section block with id, title.
  • A Markdown heading (#, ##, underlined) in a text fails the build.

Told in skills/archetypes/lernapps-explainer/references/rules.md.

Every chapter and page listed once

explainer-structure-complete · archetype:explainer · error

  • At least one chapter.
  • Every chapter folder in chapters of src/app.yaml, every page file in pages of its chapter.yaml, exactly once, in reading order.

Told in skills/archetypes/lernapps-explainer/references/rules.md.

Chapter, page, two section levels

explainer-structure-depth · archetype:explainer · error

  • Sections at most two deep. No heading levels set: they follow from nesting. More levels = two apps.

Told in skills/archetypes/lernapps-explainer/references/rules.md.

The description and the playthroughs validate

interactive-app-valid · archetype:interactive · error

  • src/app.yaml and every playthrough valid against their schemas; German first, every language complete.
  • Unique ids; at least one playthrough; each step expects a state or an announcement; playthrough routes exist.
  • Build names each problem with file and line.

Told in skills/archetypes/lernapps-interactive/SKILL.md.

The architecture is valid and current

interactive-architecture-current · archetype:interactive · error

  • docs/arc42/: generic part and extension as create/update wrote them, unchanged outside the app sections.
  • App part describes the code: every part of src/ has its block, every block its code.
  • arc42 validate --strict and arc42 diff --staged pass; the review checks it says what the code does.

Told in skills/archetypes/lernapps-interactive/SKILL.md; judged by the rubric item in review/archetypes/interactive.md.

The core keeps its contract

interactive-core-contract · archetype:interactive · error

  • src/core/index.ts exports start(seed, route), step(state, input); tick(state, dt) as a function if it moves on its own.
  • Every route starts; nothing throws; same seed, route, inputs, ticks → same states.

Told in skills/archetypes/lernapps-interactive/SKILL.md.

Every playthrough plays as written

interactive-playthroughs-pass · archetype:interactive · error

  • After each step the state has the expected fields; the browser shows the expected announcement.
  • Failure → fix core or playthrough, whichever is wrong; never delete a playthrough.

Told in skills/archetypes/lernapps-interactive/SKILL.md.

Extend the preset, change nothing of it

keep-the-preset · archetype:explainer, archetype:interactive, archetype:quiz · error

  • vite.config.ts is export default lernapps(), with only the app's own settings as generated (lernapps({ plugins: [quiz()] })).
  • tsconfig.json extends @lernapps/tooling/tsconfig.json as generated.
  • The hooks come from the package (prepare in package.json); never replace one.
  • Never turn a lint rule off or lower its severity.

Told in skills/tooling/lernapps-cli/SKILL.md.

Publish from gh-pages, served from its root

pages-from-gh-pages · archetype:explainer, archetype:interactive, archetype:quiz · error

  • GitHub Pages serves the branch gh-pages from /: usually https://<owner>.github.io/<repo>/; only repos of the lernapps organisation at https://lernapps.net/<repo>/.
  • Previews of pull requests go below pr-preview/ on that branch: leave the setting.
  • Hosted elsewhere → the entry's url points there.

Told in skills/process/lernapps-github/SKILL.md.

A component only where no block fits

prefer-built-in-block · archetype:explainer · hint

  • Built-in blocks and exercises first. A component only for what none can express; say why in the plan.

Told in skills/archetypes/lernapps-explainer-design/references/rules.md; judged by the rubric item in review/archetypes/explainer.md.

Check every fact

quiz-answers-checked · archetype:quiz · hint

  • Check every marked option, number and info against the linked article before you commit.
  • A source does not open → say so in the plan, mark it "not checked"; never fill it from memory.
  • Learners report errors through .github/ISSUE_TEMPLATE/inhaltsfehler.yml.

Told in skills/content/lernapps-content-questions/SKILL.md.

The question bank validates

quiz-bank-valid · archetype:quiz, archetype:explainer · error

  • Valid against the schema. Build also checks: exactly one correct in single choice, at least one in multiple choice; unique ids and options.
  • Broken bank: one line per problem (position, id); fix in src/quiz.json. Explainer exercise: named by file and block path.

Told in skills/content/lernapps-content-questions/SKILL.md.

One clear question at a time

quiz-clear-question · archetype:quiz, archetype:explainer · warning

  • One thing per question, answerable before reading the options.
  • Positive; avoid "nicht", never two negations. No trick questions.
  • Plain, short sentences in every language (learner-text-german).

Told in skills/content/lernapps-content-questions/SKILL.md.

Background and explanation say why

quiz-feedback-explains · archetype:quiz, archetype:explainer · hint

  • Every option has an info of 1–3 sentences about the option, true either way ("Der Nil fließt durch mehrere Länder Afrikas und mündet in Ägypten ins Mittelmeer."). A wrong option's info also says why it does not fit.
  • explanation: 1–3 sentences why the answer is right; for true-false, number, ordering and matching also the background.
  • number: typical wrong numbers as mistakes (answer, message). Any question: an optional hint, not the answer.
  • A wrong answer's message (and an exercise component's reason) says what does not fit and where to look, never the solution itself: the solution comes after the answer, with "Lösung" or the tutor.

Told in skills/content/lernapps-content-questions/SKILL.md; judged by the rubric item in review/archetypes/quiz.md.

The type that fits the question

quiz-fitting-type · archetype:quiz, archetype:explainer · hint

  • One fact among things of a kind: single-choice; several facts: multiple-choice; estimate a size: number; compare sizes or dates: ordering; connect: matching; judge a statement: true-false.
  • Mix the types. The type must accept every answer the text allows (ordering only for a fixed order).

Told in skills/content/lernapps-content-questions/SKILL.md.

Every question links to further reading

quiz-further-reading · archetype:quiz · warning

  • At least one link per question, best the German Wikipedia (https://de.wikipedia.org/wiki/...).
  • title names the page ("Uluru (Wikipedia)").
  • HTTP 429 → tell the creator which; mark the facts "not checked" in the plan; go on.

Told in skills/content/lernapps-content-questions/SKILL.md.

Numbers with unit and rounding

quiz-number-precision · archetype:quiz, archetype:explainer · warning

  • The text says how exact the answer must be ("Bis zu 100 m daneben zählt noch als richtig"); tolerance matches it.
  • The unit goes into unit, not into the answer.
  • Sources differ → the tolerance covers them.

Told in skills/content/lernapps-content-questions/SKILL.md.

Write only the question bank and its images

quiz-only-data · archetype:quiz · error

  • Change only src/quiz.json and add image files to src/images/. index.html, src/main.ts, e2e/quiz.e2e.ts, config as generated (keep-the-preset).
  • Bank cannot say it → "Where I had to guess", never code around the runtime.

Told in skills/archetypes/lernapps-quiz/SKILL.md.

Write in your own words

quiz-own-words · archetype:quiz · warning

  • Take facts, never sentences: Wikipedia is CC BY-SA (copying needs attribution and relicenses).
  • info and explanation: new, shorter, plainer, for the app's school year. Sources in sources (third-party-licence).

Told in skills/content/lernapps-content-questions/SKILL.md.

Options a learner could believe

quiz-plausible-options · archetype:quiz, archetype:explainer · warning

  • Wrong options are real things of the same kind (a river for a river), with true background.
  • Options alike in length and form. No "Alle genannten", "Keine davon" or jokes. Three or four options.

Told in skills/content/lernapps-content-questions/SKILL.md.

Keep the ids

quiz-stable-ids · archetype:quiz · warning

  • Short, telling id ("grand-canyon"); keep it when the text changes (shared links #frage-<id>).
  • New question, new id; never reuse a removed one.

Told in skills/archetypes/lernapps-quiz/SKILL.md.

The start page explains the app

start-page-explains · archetype:interactive · hint

  • The static start page says what learners train, for whom, and how to begin.

Told in skills/archetypes/lernapps-interactive-design/SKILL.md; judged by the rubric item in review/archetypes/interactive.md.

Store only through the preset's storage

storage-through-wrapper · archetype:explainer, archetype:interactive, archetype:quiz · error

  • Only createStorage from @lernapps/tooling/storage, named after the app's id in the catalog (own prefix lernapps:<id>:, rule own-data-only; works when storage is blocked).
  • At most 100 kB under the prefix (keys and values, 2 bytes per UTF-16 unit). Beyond, save returns false and the app keeps working.
  • A setting of the learner that holds for every app or every app of the archetype: createSettings("<id>", "<archetype>"), saved only where the learner chose it ("app", "archetype" or "all"); the app's own goes first.
  • Keep the learning state, not growing histories.
  • What only a reload must not lose, such as an answer being written, lasts while the tab is open: createStorage("<id>", { type: "sessionStorage" }) (sessionStorage, same prefix and limit).
  • Never localStorage, sessionStorage, IndexedDB or cookies directly.

Told in skills/tooling/lernapps-cli/SKILL.md; checked by the lint rule lint/rules/storage-through-wrapper.ts.

TypeScript only, strict

strict-typescript · archetype:explainer, archetype:interactive, archetype:quiz · error

  • Every source file is TypeScript; no JavaScript files.
  • Never any: use unknown and narrow it, or write the type.
  • Type the creator's data; validate it at build time.

Told in skills/tooling/lernapps-cli/SKILL.md.

Every page has exercises

topic-has-exercises · archetype:explainer · error

  • Every page has at least one exercise that practises what the page explains, with solution or feedback; best in a last section "Übung".
  • The schema requires it; start, chapter and glossary pages are generated. The review judges the fit.

Told in skills/archetypes/lernapps-explainer-design/references/rules.md; judged by the rubric item in review/archetypes/explainer.md.

Browser globals only once mounted

vue-component-browser-globals · archetype:explainer, archetype:interactive · error

  • window, document, localStorage etc. only in onMounted or later unmount hooks (server render has none).

Told in skills/archetypes/lernapps-explainer/references/rules.md; checked by the lint rule lint/rules/vue-component-browser-globals.ts.

An exercise component has its logic module

vue-component-exercise-contract · archetype:explainer · error

  • Emits answer → src/components/<Name>.ts with pure, deterministic generate(seed, props), check(task, answer), solution(task), wrong(task), reason(task, answer, props, lang); property test passes.
  • Emits no answered (the old contract): the explainer draws "Prüfen" and checks; a component draws none.
  • Block lists examples with at least one accepted and one rejected, { answer, seed? } in the shape of check (no seed: seeds 1–50), incl. another correct answer where the text allows.
  • Declares prop seed: number, shows generate(seed, props). The explainer gives the seed, shows "Aufgabe Nr.", "Neue Aufgabe", keeps ?<id>=<n>: never draw a seed or offer "next" inside.
  • Also exports describe(task, props, lang) → { task, solution } (restricted Markdown, task exactly as shown) and about = { task, answer, correct, mistakes } (texts by language). The tutor reads only these (the tutor page, no-JS text).
  • Any exercise may carry examples: { accepted, rejected }; generated: expressions of given and answer, per seed (e.g. reverse(answer)).
  • With template, params, mistakes and show (all four or none, rule vue-component-tutor-table): check accepts the solution and rejects each mistake's answer, params gives the same names for every task, each placeholder of template is one of them.

Told in skills/archetypes/lernapps-explainer/references/rules.md.

Imports only from the allowed packages

vue-component-imports · archetype:explainer, archetype:interactive · error

  • Only vue, @lernapps/app-templates, @lernapps/tooling/storage, i18n, a11y, own folder. Types from anywhere.
  • Interactive: also the app's src/ files and its dependencies.

Told in skills/archetypes/lernapps-explainer/references/rules.md; checked by the lint rule lint/rules/vue-component-imports.ts.

No code or HTML from strings

vue-component-no-html-injection · archetype:explainer, archetype:interactive · error

  • No eval, new Function, innerHTML, v-html: the template renders.

Told in skills/archetypes/lernapps-explainer/references/rules.md; checked by the lint rule lint/rules/vue-component-no-html-injection.ts.

No network

vue-component-no-network · archetype:explainer, archetype:interactive · error

  • No request, no URL import: props or bundle.

Told in skills/archetypes/lernapps-explainer/references/rules.md; checked by the lint rule lint/rules/vue-component-no-network.ts.

Every component block has its nojs text

vue-component-nojs · archetype:explainer · error

  • Every non-exercise vue-component block: nojs in every language (exercise: from describe): what it shows and does, with content; same meaning without JS.
  • Schema requires it; lernapps check finds empty or hidden ones (explainer-readable-without-js).

Told in skills/archetypes/lernapps-explainer/references/rules.md.

Props as the component declares them

vue-component-props-valid · archetype:explainer · error

  • defineProps<{ … }>() with types; each block passes exactly the declared props, of their types.

Told in skills/archetypes/lernapps-explainer/references/rules.md.

Within 20 kB

vue-component-size · archetype:explainer · error

  • Own code max 20 kB gzip. More → split, or a new block: write it into the retrospective.

Told in skills/archetypes/lernapps-explainer/references/rules.md.

A test per component

vue-component-tested · archetype:explainer · error

  • src/components/<Name>.test.ts per component, testing its logic: other right answers the text allows, typical wrong ones with reasons, edge cases. Run by lernapps check.

Told in skills/archetypes/lernapps-explainer/references/rules.md.

An exercise component declares its exercise for the tutor

vue-component-tutor-table · archetype:explainer · hint

  • The logic module also exports template(props, lang): the task once, {name} for each input; params(task, props, lang): the inputs by name ({ G: 1260, p: 15 }), numbers or texts, the same names for every task; mistakes(task, props): per about.mistakes, in order, the answer it gives, undefined where none; show(answer, task, props, lang): an answer as text, short ("C", "3 Kästchen").
  • The tutor page then has the task once, the mistakes as F1, F2 … and a table of every number (inputs, solution, each mistake), like generated. Without them: each number's describe as far as 64 kB allow, and the build's hint names the block.
  • Example: src/components/ProzentFeld.ts of the template.

Told in skills/archetypes/lernapps-explainer/references/rules.md.