These instructions apply to AI assistants working on the MC-Test App repository. Use them together with the Serena memories for this project. Keep changes reliable, traceable, and understandable for students without an IT background.
- Goal: Maintain, improve, validate, and export multiple-choice question sets, learning objectives, mini glossaries, analytics, and study materials.
- UI language: The app UI is German by default. UI wording must be concise, action-oriented, and understandable for media-literate students without technical prerequisites.
- Prompt language: External LLM prompts in
prompts/must be written in US English and must be self-contained. - Safety: Do not use real personal data. Do not hardcode API keys, secrets, passwords, or local-only credentials.
- Transparency: Treat AI as an assistant. Do not imply that generated question sets are automatically correct without validation.
- Repo hygiene: Preserve unrelated user changes. Do not revert work you did not make unless explicitly asked.
- Serena MCP is available for this repository. Use it for project memory, symbol lookup, and efficient code understanding when relevant.
- Start rediscovery from
mem:core; it links to the most important topical memories. - Important topical memories include:
mem:conventionsmem:tech_stackmem:ui_streamlitmem:llm_workflowmem:exports_markdownmem:legal_privacy_public_appmem:i18n_mode_terms_2026_06mem:home_view_ux_2026_06mem:question_view_practice_ux_2026_06mem:workflow_dialogs_pseudonym_ux_2026_06mem:performance_load_testing_2026_06mem:task_completion
- Update Serena memories when architecture, supported export targets, Streamlit conventions, prompt rules, security rules, or stable UX decisions change.
- Keep memories dense and durable. Do not store secrets, private data, or transient debugging notes.
- Framework: Streamlit.
- Python: 3.10-3.12. Python 3.14 is not supported.
- Streamlit target: Streamlit 1.58.
- Prefer modern Streamlit APIs:
- use
width="stretch"orwidth="content"; - avoid
use_container_width; - use
st.htmlorst.iframefor new HTML/CSS snippets; - avoid new
st.components.v1.htmlusage.
- use
- Use
st.htmlfor pure CSS/style injection whenever possible so style-only snippets do not create visible layout height. - Data storage: SQLite in
db/mc_test_data.dbfor sessions and statistics. - SQLite is hardened for one Streamlit process with thread-local connections, WAL mode,
busy_timeout, write transaction serialization, and retry/backoff for lock/busy errors. For multiple processes/replicas or very high peak load, PostgreSQL remains the safer target architecture. - Question content: JSON and Markdown files in
data/; temporary user uploads indata-user/.
app.py: Streamlit entry point.main_view.py: main user UI, question flow, summary, timer/pacer, legal entry points, and most interaction behavior.components.py: reusable dialogs and workflow pieces.admin_panel.py: admin UI and maintenance actions.config.py: question-set discovery, loading, and normalization.database.py: SQLite persistence for users, sessions, answers, feedback, bookmarks, statistics, recovery secrets, and cleanup.audit_log.py: admin/login audit writes.user_question_sets.py: validation and lifecycle of uploaded temporary question sets.validate_sets.pyandquestion_set_validation.py: CLI/content validation.pdf_export.py,export_jobs.py, andexporters/: PDF, CSV/analysis, Anki, and arsnova.eu export behavior.prompts/: external LLM prompts for question-set generation, micro learning objectives, and postproduction QA.data/: bundled question sets and learning objectives.docs/: public and internal documentation. EDULEARN26 references should point todocs/mc-test-paper/mc-test-edulearn26.pdf.
New question sets must use the canonical top-level structure:
{
"meta": {},
"questions": []
}Required fields per question:
questionoptionsanswerexplanationweighttopicconcept
Recommended or optional fields:
cognitive_levelmini_glossaryextended_explanation
Validation rules:
- Use English canonical keys for new sets. German legacy aliases such as
frage,optionen, andloesungare compatibility only. answeris zero-based and must point intooptions.optionsshould contain 3-5 answer choices.weightmust be1,2, or3.meta.title,meta.question_count, andmeta.languageare required and must be consistent.meta.languageuses ISO 639-1 values such asdeoren.question,explanation, andtopicmust be non-empty strings.conceptmust be present. If needed, use the topic as a conservative fallback.mini_glossary, when present, should contain 2-6 useful entries and can be an object or list depending on the existing set pattern.- Keep topics coherent. Avoid over-fragmentation; validators warn differently about minimum topic counts.
meta.difficulty_profile,meta.time_per_weight_minutes, andmeta.test_duration_minutesare checked by validators and should be meaningful.
Use these three levels consistently across JSON, learning objectives, explanations, and analytics:
- Reproduktion / Recall: facts and definitions. Typical verbs: name, list, describe, define, identify, reproduce, state.
- Anwendung / Use in context: calculations, matching, determining, recognizing in context. Typical verbs: apply, calculate, determine, assign, select, use, recognize.
- Strukturelle Analyse / Reasoning: justification, evaluation, diagnosis, derivation. Typical verbs: analyze, justify, evaluate, diagnose, derive, infer.
Create learning objectives strictly from prompts/KI_PROMPT_MICRO_LEARNING_OBJECTIVES.md.
- One learning objective per question.
- One verb per objective. Avoid verb chains.
- Choose the correct cognitive level.
- Cluster objectives into 5-10 higher-level goals.
- Sort topics logically from basic to complex.
- File naming:
data/questions_<Set>_Learning_Objectives.md. - Keep
cognitive_levelin the JSON aligned with the learning objectives.
- Use Markdown to improve readability, but keep exports robust.
- Math belongs in
$...$or$$...$$. - Do not place LaTeX inside backticks.
- Avoid raw
<and>in formulas; use\\langleand\\rangle. - Safe HTML may include
code,sub,sup,strong, andem. - Never allow scripts, event handlers, unsafe attributes, or active HTML.
- Markdown tables can be acceptable in question stems, but are fragile in answer options and export targets. Do not rely on table rendering in answer options for Anki or arsnova.eu.
- Preserve useful Markdown/HTML where supported, but content must remain readable when advanced formatting is flattened.
When improving a question set, work in this order:
- Run a schema check:
python validate_sets.py data/<set>.json. - Fill missing required fields, especially
concept; correctmeta. - Reduce length bias. Correct answers must not be systematically longer or shorter than distractors.
- Balance
mini_glossaryentries to 2-6 useful entries where possible. - Create micro learning objectives in
data/questions_<Set>_Learning_Objectives.md. - Review clusters, objective order, and verbs.
- Sync
cognitive_levelwith learning objectives. - Run final validation and reduce warnings where practical.
Quality rules:
- Check the indexed correct answer for subject-matter correctness.
- Distractors should be plausible and on the same semantic level as the correct answer, but clearly wrong.
- Avoid trick answers without a valid didactic reason.
- Keep explanations short, clear, and student-friendly.
extended_explanation, when present, should be more detailed but still easy to follow.
- All external prompts in
prompts/are US English. - Prompts must be self-contained and must not assume knowledge of MC-Test, Streamlit, this repository, local paths, or prior chat context.
- Generated JSON uses English keys regardless of content language.
- Content language is controlled by the user request and
meta.language. - The question-set prompt must target the canonical JSON schema, not Anki, arsnova.eu, spreadsheet, Markdown, or legacy app-specific formats.
- App prompt previews are rendered read-only. Raw copy/download controls are the authoritative transfer path.
- The generation workflow is:
- generate canonical question-set JSON;
- save and validate it;
- generate micro learning objectives from the saved JSON;
- run question-set QA postproduction;
- run learning-objectives QA postproduction.
- Prompt tests must guard against reintroducing app/repo assumptions, Kahoot, arsnova.click, or wrong target schemas.
- Dark mode is the only app theme. Optimize all visual changes for dark-theme contrast first.
- Avoid excessive frames, borders, and nested-looking panels. Prefer unframed sections, typography, whitespace, and subtle dividers.
- Use borders only for repeated items, dialogs/modals, or genuinely framed tools.
- Keep vertical margins compact but not cramped. Labels, buttons, headings, timer/pacer blocks, and answer options must not overlap.
- Button labels must remain vertically centered.
- Widget keys must be unique and stable, especially repeated jump, bookmark, export, answer-option, and navigation controls.
- Never nest
st.expanderblocks. - On mobile, avoid triggering the virtual keyboard for controls that are not truly editable.
- Use targeted
data-testidCSS only where needed. Verify computed styles and element centers, not only visible text. - Streamlit hot reload can leave stale injected CSS. If a rule is missing from DOM
<style>tags, restart the local Streamlit server before judging the visual result. - Protect active tests against accidental reloads with
beforeunloadwhere possible. Browser dialogs cannot reliably use custom text.
- The redesigned start page is the preferred view. Do not reintroduce the removed classic view without a product reason.
- Do not add a heavy app frame around the start page.
- Keep a subtle divider between CTAs and lower controls.
- The lower section label is
Language & project info. - Legal controls live under a separate
Legallabel. Do not duplicatelegalin the project-info label. - English app name wording is
MC Testwithout a hyphen. - Avoid decorative folder/info icons on main buttons unless they carry functional meaning.
- Ready-made question-set labels may include flag icons for quick language scanning, but labels must remain readable without relying only on flags.
- Legal buttons should sit side by side on mobile when width allows.
- Desktop question metadata should be compact and side by side where possible: Topic, Concept, Cognitive Stage. Mobile may stack.
- The answer-choice area should have a subtle divider above it.
- The answer prompt and horizontal radio buttons should be centered relative to the question content, not the viewport edge.
- Radio button spacing should be generous enough for scanning and touch use.
- On question changes, scroll back to the top of the question view. Track the actually rendered
frage_idx. - In Learning Mode, after submitting an answer and showing immediate feedback, scroll toward the Next button area rather than to the page top.
- Dynamic bottom spacing is needed after visible feedback so short explanations still allow the Next button to reach the intended viewport position.
- Use about
96pxtop offset for Next-button and question-expander scroll targets; smaller offsets can let Streamlit chrome clip titles or buttons. - Opening question expanders should pull the expander heading upward only in the question view.
- The detailed-explanation button is a special rerun case; use a one-shot session flag and scroll to an anchor before the expander after rerender.
- Learning Mode feedback labels should be consistent and calm: localized equivalents of
Deine Antwort,Richtig, andErklärungshould use one helper/CSS pattern. - The standard explanation block after an answer should remain unframed: use a subtle divider plus a label, not a bordered container.
- The LLM-generation dialog should favor readability over framed decoration.
- Use a clear divider before the step chooser, such as
Choose the step (1-4) you want to work on now.or the localized equivalent. - In dark mode, dialog headings and body text need explicit contrast checks.
- Pseudonym reservation must be a guided workflow: choose pseudonym, optionally set a recovery secret, confirm the secret, explain its purpose, and support re-login with a reserved pseudonym.
- Recovery secrets are not recoverable plaintext. They may be confirmed at creation time, but storage and verification must remain hash-based.
- Keep pseudonym and recovery wording concrete and student-friendly. Avoid account-management jargon when possible.
- The public Streamlit deployment must expose both a legal notice/imprint and a privacy policy from the start page.
- German labels:
ImpressumandDatenschutzerklärung. - English labels:
Legal NoticeandPrivacy Policy. - Other locales must expose both concepts, with English fallback wording if no locale-specific wording exists.
- Keep legal entry points grouped under
Legal, separate fromLanguage & project info. - Legal notice content was seeded from the arsnova.eu imprint. Re-check the authoritative source before future updates to institution, contact, or responsible-party details.
- The privacy policy must be fact-based for this app:
- Streamlit frontend/runtime;
- SQLite session/statistics storage;
- question-set uploads/content;
- pseudonym usage;
- reserved-pseudonym recovery secrets stored as hashes;
- feedback/statistics workflows.
- Do not claim analytics, ads, or marketing tracking unless they are actually implemented.
- State that MC-Test does not set app-owned tracking or marketing cookies. Technically necessary Streamlit/session cookies or browser storage may be used by the hosting/runtime layer.
- Legal/privacy copy is a product implementation, not legal advice. The operator must review it before relying on it in production.
- Supported export targets:
- PDF;
- CSV/analysis;
- Anki (
.apkg/.tsv); - arsnova.eu JSON.
- Kahoot and arsnova.click have been removed. Do not restore related prompts, UI copy, tests, docs, or export paths.
- Anki export must not create nested ABCD numbering or structures that can reorder answer options.
- arsnova.eu export should map as much didactic value as the schema allows: title, description, topics, difficulty profile, mini-glossary summary, explanations/notes, timers, and supported Markdown/HTML.
- PDF exports must share the app's Markdown/HTML rendering improvements. Visually check report PDFs when rendering changes.
- Common card structure:
<div class="card-container"><div class="question"><div class="answer-content">
- Local demo/admin login may use
.envwithMC_TEST_ADMIN_KEY=""for the "Albert Einstein" demo login. - Cloud/admin secrets come from
st.secrets. - Never commit
.streamlit/secrets.toml;.streamlit/secrets.example.tomlis the template. - Do not version local databases, generated reports, downloads, or
tmp/artifacts. - If a secret was committed, rotate it outside the repo. History rewrite is a separate destructive maintenance task.
- DB reset/admin maintenance is destructive. Always warn about backups; see
docs/ADMIN_PANEL_ANLEITUNG.md. - Use
db_write_transaction(conn)for write paths that need serialized SQLite writes. - Do not swallow SQLite lock/busy errors before retry handling can work.
- Use the load-test script for concurrency checks:
python scripts/qa/load_test_users.py. - The load-test default uses a temporary SQLite DB. Use
--live-dbonly deliberately because it changes real data.
- For question JSON changes: run
python validate_sets.py data/<set>.json. - For all question sets: run
python validate_sets.py. - For code changes: run focused tests first. If the blast radius is unclear, run
pytest -qorpython -m pytest -q. - For i18n or wording changes: run
python scripts/i18n/check_i18n.py. - Locale files may contain flat keys with dots inside nested sections, for example
summary_view.export_testbericht_expander.exam. The i18n lookup supports this pattern; add or run regression tests such astests/test_i18n_lookup.pywhen touching dotted locale keys. - For prompt changes: run prompt architecture/preview tests and verify US English, self-contained prompts with no app/repo assumptions.
- For Streamlit UI changes: browser-test the affected workflow on desktop and mobile. Check layout, dark-theme contrast, timer/pacer behavior, prompt preview, export dialogs, and reload protection.
- For export/Markdown changes: test Markdown-heavy stems and options, and verify relevant PDF, Anki, and arsnova.eu expectations.
- For docs-only changes: check links and paths; keep
AGENTS.md,CONTRIBUTING.md,README.md, anddocs/STYLE_GUIDELINES.mdaligned.
- Start app:
streamlit run app.py. - Start on another port:
streamlit run app.py --server.port 8502. - Prefer local-only binding for temporary verification:
streamlit run app.py --server.address 127.0.0.1 --server.port 8502. - Install dependencies:
pip install -r requirements.txt. - Full tests:
python -m pytest -q. - Prompt tests:
python -m pytest tests/test_prompt_architecture.py tests/test_prompt_preview.py -q. - i18n check:
python scripts/i18n/check_i18n.py. - Validate one set:
python validate_sets.py data/questions_<Set>.json. - Validate all sets:
python validate_sets.py. - Compile touched Python files when useful:
python -m py_compile main_view.py components.py export_jobs.py. - Search quickly with
rg, for example:rg -n "Kahoot|arsnova.click|use_container_width|st.components.v1.html".
- Edit releases or changelog files only on explicit request.
- For releases, update
CHANGELOG.mdand any matching release notes requested by the user.
- Port 8501 busy: start on another port, for example
streamlit run app.py --server.port 8502. - Local-only browser checks: add
--server.address 127.0.0.1to avoid exposing the dev server on the network. - Paths with spaces: quote paths in shell commands.
- PDF export: requires GTK3/Pango/Cairo support on the host.
- Streamlit layout looks stale: restart the local server and reload the browser before judging injected CSS.
End of agent instructions.