drillion
TL;DR: self-hosted Python practice with a UI that stays out of your way. No streaks, no leaderboard nonsense, no badges and no engagement bait. Made by a neurodivergent engineer. It is simple, and it runs your code in a sandbox.
Longer: drillion is a local web app with 189 short Python tasks, each tagged with the concept it drills so you can go straight at whatever you're worst at. No login, no account, no server except the one on your laptop. Tasks are folders of Markdown and Python. Your progress is a single SQLite file you can copy, back up and carry.
Every solve() says what it takes, so the editor knows what your value can do. Completions,
signatures and type errors come from a language server running next to the grader, on your
machine, and nothing is sent anywhere.
But why?
I have tried some learning platforms. Some stuck better than others, and there were plenty of things I did not like about all of them, the gamification and the ratings above all. I simply do not care about them. I came for one thing: to keep my Python sharp and learn new things, not to chat about it with peers.
I took heavy inspiration from Exercism, HackerRank and, surprisingly, Anki, and built it from scratch.
Core ideas I'm keeping in mind during the development:
- A clean UI that does not gate the task. Nothing stands between opening drillion and writing code.
- Categorisation. Every task is tagged with the concept it drills, and a tag spans many tasks, so you can go straight at the thing you are worst at instead of grinding a track in order.
- Anki-like progression. A task comes back before you forget it, with a daily cap so a backlog cannot bury you.
- An editor that behaves like an IDE without the complexity of one. Every
solve()is typed, so completions, signatures and inline type errors are real as they come from a language server running next to the grader, on your machine. - Hints unlock and they are not free. Three per task, escalating from a nudge to the same idea worked through on different data. After half an hour with no submission, drillion suggests taking one as you cannot brute-force something you are unaware of.
- Grading is the real. Your code is spliced into the task's own pytest file and run.
- YOUR progress. One SQLite file on your disk, stamped with a schema version, and a build refuses to rewrite a file a newer one wrote rather than quietly mangling it. Settings turns it into a backup you can carry, and can erase the lot if you want to start over.
- It is free, and it stays free. No tier, no voucher, no account, no telemetry, open-source.
One consequence worth stating plainly: 189 tasks ship as executable Python, and task.py
runs on import. Shipping tasks as code is what makes the sandbox necessary, so graded code
is confined by the kernel and you do not have to take my word for it. What running it
does to your machine, below, is the detail.
Install
You do not need Python, and you do not need to know what a virtual environment is. Pick your system below, run two commands, and drillion opens in your browser at http://127.0.0.1:8765. It runs on your machine, so nothing is uploaded and there is no account.
Linux, macOS, or Windows with WSL
Open a terminal. Install uv, which is the one tool drillion needs:
curl -LsSf https://astral.sh/uv/install.sh | sh
Close the terminal and open a new one, so it picks up the new command. Then:
uvx drillion
The first run takes a minute while it fetches Python and drillion. After that it starts in seconds.
Windows
Open PowerShell from the Start menu. Install uv:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
Close PowerShell and open it again, then:
uvx drillion
One difference worth knowing: the code you submit is sandboxed less tightly on Windows than on Linux and macOS. Windows blocks what it can write, but not what it can read. SECURITY.md says exactly which half is which.
Using it day to day
- Stop it: press
Ctrl+Cin the terminal window. - Start it again:
uvx drillion, in any terminal. - Update: nothing to do.
uvxfetches the current version each time. - Your work is kept between runs, and an update never overwrites it.
Want a permanent drillion command instead of typing uvx every time? Either of these
installs one:
uv tool install drillion # uv tool upgrade drillion to update
pip install drillion # the same, if you already have Python 3.13+ and no uv
Docker
Same on every system, if you already run Docker:
docker run -p 127.0.0.1:8765:8765 -v drillion:/data ghcr.io/vazome/drillion
Open http://127.0.0.1:8765 yourself, since the container never opens a browser. The image carries
the tasks and the page; the named volume keeps your work across upgrades.
compose.yaml is the same thing plus restart: unless-stopped, so drillion comes
back after a reboot; save that one file anywhere and docker compose up -d.
Commands
drillion # serve the web UI (default)
drillion selfcheck # solve every task with its own reference, proving the set still works
drillion doctor # say why a task folder would be skipped
Your progress
Everything drillion owns lives under one root: tasks/, which is where your code is saved, and
progress.sqlite3, which holds your cards, notes and archived solutions. From a clone that root is
the checkout. Installed, it is a per-user data directory that the first run seeds from the tasks
inside the wheel. In Docker it is the volume at /data. An upgrade never writes over a root that
already has tasks in it, so nothing you have written is at risk.
See docs/configuration.md for the environment variables and the Docker
bind-mount recipe.
Existing progress.json files are imported automatically on first access and kept untouched.
After import, SQLite is the source of truth, and the retained JSON is only a snapshot from before
the upgrade.
Settings → Back up writes everything you would miss to one file: your cards, notes, log and
archive, plus the code you have written in every task. Restore it on another machine or after a
reinstall and you pick up where you left off. A restore replaces what is there now, and saves
what it replaced to backup-before-restore.zip in the same root first.
Settings → Danger zone is the way back to a first run: it deletes the stored progress and
puts every task back to its stub. You confirm it by typing erase progress, and it writes
backup-before-reset.zip in the same root before it does anything, which is the only way to
undo it.
Settings → Editor turns Vim keys on if you use them everywhere else. That one lives in the browser rather than in your progress, so a backup does not carry it.
What running it does to your machine
drillion runs Python on your computer: the code you write, and the code that ships inside the 189 tasks. So it is worth saying plainly what that costs you.
-
Your submissions are confined by the kernel. Landlock on Linux, an
sandbox-execprofile on macOS, a restricted token at low integrity on Windows. On Linux and macOS graded code reads only the interpreter, the system libraries and the tasks, writes only to a scratch directory deleted after the run, and cannot open a network connection. Windows confines the writes but not the reads or the network.drillion doctorprints the tier you actually got, read back from a process that tried it. -
Nothing leaves your machine. No account, no telemetry, no fonts or scripts fetched from anyone. The server binds
127.0.0.1, and refuses a request from a page it did not serve, so a website you happen to have open cannot drive your local drillion. -
What you downloaded can be checked. Every release carries provenance naming the workflow run that built it, attached to the release itself:
gh attestation verify drillion-0.5.1-py3-none-any.whl --repo vazome/drillion gh attestation verify oci://ghcr.io/vazome/drillion:0.5.1 --repo vazome/drillion
SECURITY.md is the whole picture, including which half of it Windows does not cover, and how to report something.
Docs
- How a sitting works, and why: the learning loop, what the ladder is, and the grading rules.
- Configuration: environment, data root, Docker, release verification
- Authoring a task: tiers, difficulty, tags, the folder format
- CONTEXT.md: the vocabulary the code, the API and the UI all use
- DESIGN.md: the UI brief;
web/README.mdfor the frontend - docs/adr/: decisions worth their own page
Contributing
The most useful contribution is a new task. Open an issue with the New task template first, then read CONTRIBUTING.md for the dev loop and the contract a task is graded against, and AGENTS.md for how the project decides things. Bugs and ideas go in Issues; a vulnerability goes through SECURITY.md, which also spells out what running drillion does to your machine.
License
MIT. See LICENSE. 89 of the 189 tasks adapt a problem from Exercism's Python track
(also MIT) and one from MBPP (CC-BY-4.0); each names its origin in a source: field and an
attribution footer, and NOTICE reproduces the notices that travel with them.
Metadata
Release files for drillion 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| drillion-0.7.0.tar.gz | 5.5 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| drillion-0.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 10.9 MB
Release files / drillion-0.7.0.tar.gz
| Download URL | drillion-0.7.0.tar.gz |
|---|---|
| Size | 5.5 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
25341a411b03745db389df07e9dbb7f42b612ababa620593e3fefa558be68114
|
|
BLAKE2b-256 checksum How to use checksums |
4c187a145d93569feb3842535be291c55f65e9e411b1e2d9fe5f6fd08d39635e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.
Transparency logRelease files / drillion-0.7.0-py3-none-any.whl
| Download URL | drillion-0.7.0-py3-none-any.whl |
|---|---|
| Size | 5.4 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0d8f0cb33e3b7647324aa6295d600760bf3da84026757074cd540067b5f2112a
|
|
BLAKE2b-256 checksum How to use checksums |
bfff9e41f342d9a6e86027320ce6ec8551b14860b9db2189b89d81d68b2f9484
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.
Transparency log