One page of football a day. No scroll, no bait.
Live: touchline-chelsea.pages.dev · why this exists
Touchline is a self-hostable football companion built on a simple model (borrowed from antifeed): a static site whose only database is a JSON file, plus a brain — headless Claude Code, run locally each morning — that gathers the facts, reads the day's discourse, and writes one calm, opinionated page: what happened, what's on today, and what's worth your click.
The boundary rule: Python produces facts, the brain produces prose, the site produces pixels.
touchline.config.json your club, competitions, timezone, feeds, voice
src/touchline/ facts CLI: `touchline facts` -> JSON bundle (ESPN by default)
brain/ prompt + sources + curate.sh (headless Claude Code)
site/ static reader; site/data/digests.json is the database
./brain/curate.sh # with morning coffee: facts -> brain -> validate -> commit -> deploy
./brain/curate.sh --no-deploy # same, but stop before deploying- Fork this repo.
- Edit
touchline.config.json— club name + clubcode, plus competitions, your timezone, feeds, and the voice you want the digest written in. Thecodemust match your configuredsource(step 3): the ESPN abbreviation forespn(default — e.g.MANfor Manchester United, not football-data'sMUN), the football-data.org TLA forfootball-data, or nothing at all forapi-football— it has no club codes, so the clubnamemust match its team name exactly instead. - Pick a data source in
touchline.config.json("source"):espn+thesportsdb(recommended, no key needed — ESPN for league data plus TheSportsDB's free per-team feed, which catches tour friendlies ESPN misses; setclub.thesportsdb_idto your club's numeric TheSportsDB team id),espn(no key needed),api-football(setAPI_FOOTBALL_KEY, from api-football.com), orfootball-data(setFOOTBALL_DATA_TOKEN, from football-data.org). - Install Claude Code (the brain runs
claude -p), plusuvandnode. - First deploy:
npx wrangler login, thennpx wrangler pages project create <your-project> --production-branch main(once — deploy runs non-interactively and cannot create the project), then./deploy.sh. After that, run./brain/curate.sheach morning.
Nothing runs centrally: the brain runs on your machine, with your preferences, and publishes to your Cloudflare Pages project.
uv run pytest -q # Python suite
node brain/validate.mjs # check the database
cd site && python3 -m http.server # local previewMatch pages, standings pages, PWA install, push/Telegram/email delivery, preference sync, automated scheduling. Each may return if the habit sticks.
MIT — see LICENSE.