CKWatson is an educational game about chemical kinetics. The game is organized in "puzzles". Each puzzle starts off with a few reactants. Within a given set of all substances possibly present, the player's goal is to figure out all elementary reactions involved with the chemical process when the reactants are mixed together.
Elementary [reactions], my dear Watson!

Binary dependencies. This project uses uv as the package manager and just for convenience. Optionally, Redis enables server-sent events (SSEs) and more production-ready rate-limiting & caching. If you don't have them available yet, are on macOS, and have installed Homebrew, you can install both binaries in one go this this command:
To clone the repository and initialize the virtual environment, run these commands:
It's recommended (but not strictly necessary) to start a Redis server first: redis-server.
To run CKWatson, just run just run. The terminal should say:
Start playing by navigating to that URL.
The easiest way to run CKWatson, without even cloning this repo, is to hit this button and deploy to render.com:
Where's the Procfile? Back in 2016, I used Heroku for deploying CKWatson. When I looked again in mid-2025, but I had the easiest experience with Render (and they have a free tier), so I switched. This means the Procfile has been replaced with the render.yaml.
You can still self-host CKWatson. Read on.You can either run CKWatson as a single container or with Redis using Docker Compose.
To run CKWatson as a single container:
- Build the image: docker build -t ckw .
- Start a container: docker run -p 80:80 --rm --name ckwatson ckw
To run CKWatson with Redis, simply use docker-compose up.
I will be using minikube in this walkthrough. I will be using the local Docker Registry as the source of the Kubernetes image.
Note: For production or remote clusters, push your image to a container registry and set imagePullPolicy: IfNotPresent or Always in the deployment YAML. The provided YAMLs now include resource requests/limits and health checks for better stability.
- If you see ImagePullBackOff, ensure you ran eval $(minikube docker-env) before building.
- For production, set up resource limits and health checks (already included in the YAMLs).
- For Redis security in production, set a password and update the deployment and app config accordingly.
Here's the folder structure:
- kernel does the chemistry.
- puzzles stores definitions of puzzles. Admin can add puzzles to the game using the create page.
- web powers the web app.
CKWatson follows the WSGI convention, a Python standard (PEP-3333) for building web servers. We achieve this by using the Flask framework.
Since a plotting job can take a while, we allow users to see status updates in the "messages" view of each job. These messages are streamed as server-sent events (SSEs) via the Flask-SSE extension.
Other significant extensions to Flask that CKWatson employs include:
- Flask-Caching for caching computation results.
- Flask-Limiter for rate-limiting. This is more of a security measure than it is a feature.
- Flask-Compress for gzipping responses. This significantly reduces the bandwidth usage of our job results, which contains many SVG plots.
On the frontend side, CKWatson uses Bootstrap 5 for styling.