Replace mindless scrolling with something actually useful — practice and learn coding, one drill at a time.
Code Drills is a mobile app that delivers bite-sized coding challenges and lessons so you can turn idle moments into real learning.
Pick a language, pick a level, and drill.
No subscriptions, no distractions, just pure coding practice on the go.
This isn't meant to replace building projects - it's for those moments when you can't access your computer but want to keep your coding skills sharp.
your ai-agent is coding fast, better catch up...
Community-contributed content lives under two top-level directories:
challenges/
<language>/
<language>_challenges.json
topics/
<language>/
<language>_topics.json
img/
languages/
<language>/
| Language | Directory |
|---|---|
| Python | python/ |
| SQL | sql/ |
| JavaScript | javascript/ |
| Rust | rust/ |
| AI + ML | ai+ml/ |
Each file covers four levels:
| Level | Description |
|---|---|
new |
No prior experience assumed |
beginner |
Basic syntax and concepts |
intermediate |
Real-world patterns and problem-solving |
advanced |
Performance, idioms, deeper internals |
See the examples/ folder for annotated reference files:
examples/challenge_example.json— challenge formatexamples/lesson_example.json— topic/lesson formatexamples/ai+ml_challenge_example.json— AI + ML challenge format (multiple choice)examples/ai+ml_lesson_example.json— AI + ML lesson format with image support
{
"language": "python",
"levels": [
{
"level": "new",
"challenges": [
{
"id": "py-new-1",
"language": "python",
"level": "new",
"title": "...",
"description": "...",
"starterCode": "...",
"hint": "...",
"solution": {
"code": "...",
"steps": [
{ "title": "...", "explanation": "..." }
]
}
}
]
}
]
}For ai+ml challenges, use choices instead of starterCode:
"choices": [
{ "text": "...", "correct": true },
{ "text": "...", "correct": false },
{ "text": "...", "correct": false },
{ "text": "...", "correct": false }
]{
"language": "python",
"levels": [
{
"level": "new",
"topics": [
{
"id": "py-new-datatypes",
"language": "python",
"level": "new",
"title": "...",
"description": "...",
"estimatedMinutes": 8,
"lessons": [
{ "title": "...", "body": "...", "code": "...", "runnable": true }
]
}
]
}
]
}For ai+ml lessons, image is supported on each lesson object and lessons with code must set "runnable": false.
The local review UI lets contributors review and update lesson and challenge JSON without editing the raw files by hand.
Install uv if it is not already available, then run the following from the repository root:
uv run streamlit run content_review.pyOpen the local URL printed by Streamlit, normally http://localhost:8501.
- Filter lessons and challenges by language, level, topic, and review queue.
- Review source content, edit every existing text field, and save changes directly to its source JSON file.
- Inspect copyable JSON and language-aware code snippets, including each snippet's runnable status.
- Preview lesson images, inspect their paths, and update an image path when needed.
- Mark an item reviewed with or without source changes. Reviewed items are omitted from the default queue and remain available in the
Reviewedqueue. - Validate all content JSON after a save.
Review status is stored only in .content-review-state.json, which is ignored by Git and does not alter app content.
This script reads all language-specific challenge and topic JSON files,
deduplicates entries by id, and writes two merged files into an output/
directory at the repository root (excluded from version control via .gitignore).
Deduplication rule: if an output file from a previous run already exists,
its entries are loaded first and take priority. New entries whose id already
appears in the existing output are skipped, so manual edits to the output files
are preserved across re-runs.
# Merge both challenges and lessons (default)
python scripts/merge_content.py
# Merge challenge files only
python scripts/merge_content.py --challenges
# Merge lesson/topic files only
python scripts/merge_content.py --lessons| File | Contents |
|---|---|
output/challenges.json |
All challenges from every language, flat list keyed by challenges |
output/lessons.json |
All topics (with nested lessons) from every language, flat list keyed by topics |
We welcome challenge and topic contributions! Read CONTRIBUTING.md for step-by-step instructions, naming conventions, and the review process.
See privacy-policy.md.
MIT © Federico Raimondi
