The content source of truth for Katalume — every practice problem on the site lives here as a folder, is proven correct by CI, and is synced into the product database on merge.
- Add a folder under
problems/<slug>/(see layout below) on a branch. - Open a PR. CI runs
tools/validate.py, which executes the reference solution against every stored testcase — a problem that cannot pass its own tests cannot merge. - Merge to
main. The sync workflow rebuilds the import bundle and upserts it into the backend (POST /api/import/problems, service-token auth). The problem appears on the site, keyed by its immutable slug.
problems/<slug>/
meta.yaml title, difficulty, category, tags, limits, editorial fields
problem.md the statement rendered in the arena (markdown)
starter.py code preloaded into the editor
solution.py reference solution — must pass every testcase
testcases.json [{"input", "expectedOutput", "isPublic", "explanation"?}]
See SCHEMA.md for the full field reference.
Solutions define solve(payload) — payload is the parsed JSON input and
the return value is the answer (JSON-serializable; floats rounded to 4
decimals). This is the exact contract of the in-browser runner
(python-runner.worker.mjs): no stdin/stdout, no sys, imports restricted to
the sandbox allowlist (json, math, re, collections, itertools,
functools, heapq, bisect, random, statistics, string, decimal,
fractions). The validator enforces all of it.
| Difficulty | Hidden + public testcases |
|---|---|
| Easy | 5–10 |
| Medium | 20–30 |
| Hard | 40–80 |
At least one testcase per problem is isPublic: true — it becomes the visible
sample in the arena.
python3 tools/validate.py # validate the whole catalog
python3 tools/validate.py <slug> # validate one problem
python3 tools/export.py # build build/problems.jsonNo dependencies beyond CPython 3.10+.