Jeremy Steel
GitHub Product engineer
London

Product engineer · London

Jeremy Steel.

I take products from idea to live on my own: the model, the app, the tests and the release.

Explore the work
How I work
Build01
Model02
Evaluate03

Selected work

Two web products / One open-source tool
01 / Live

EasyFPL

A live expected-points model and transfer planner, scored every gameweek against a baseline.

GW5: average error 1.31 against the baseline's 1.60.

Open EasyFPL
EasyFPL home page: Your team. Your plan. Every gameweek., beside a My Team squad card
easyfpl.app · 6 Oct 2026
02 / Beta

Castled

Chess opening practice with move-by-move feedback.

Beta released behind 610 unit tests, 47 end-to-end tests and 8 production smoke checks.

Try Castled
Castled Italian Game position: an arrow shows the line's move after an off-book reply
Off-book hint · Italian Game · 6 Oct 2026
03 / Open source

AI Usage Tracker

Coding-plan quota across Codex, Claude and Z.ai, in a Windows tray utility.

Open source under MIT, with explicit freshness and local history.

View source
AI Usage Tracker interface example with synthetic demo data: Codex and Claude 5-hour and weekly quota bars
Interface example · demo data
Inspect the EasyFPL model evaluation 29 Sept 2026

EasyFPL: scoring a football model against what it actually published

A Fantasy Premier League expected-points model and planner, scored every gameweek against the exact prediction the site published and against a naive baseline. It beats the baseline on RMSE every week and on MAE only from GW4. The harness, the numbers and the limits.

The problem

Fantasy Premier League managers decide transfers, captains and chips week to week, under uncertainty about fixtures and minutes. My working thesis is that most free tools show this week's numbers, while a plan across several gameweeks around a chosen Wildcard week is something people would share. That thesis is untested: usage is only now being measured (see "Where it stands").

What I built

  • A Python model. Dixon-Coles team strengths, a minutes model with a per-team minutes cap, goals and assists allocated from team expected goals, bonus points as a team pool, and priors for promoted teams and new signings.
  • Fixture difficulty, generated in one place. It is produced in Python only; the web layer reads it and never recomputes it. Validation gates stop home and away ratings inverting, keep an absolute scale, and refuse to publish anything non-finite.
  • A Next.js app on Vercel. A fixture difficulty table, player expected points, My Team, a live mini-league page and a multi-gameweek planner.
  • A pipeline. An hourly server cron that skips the run until prices, news or minutes change, and a 24-hour data-freshness gate in the production build.

How I check it

Every completed 2026-27 gameweek is scored against the exact prediction the site published before the deadline, read back from version control, not a re-run of the model afterwards. The comparison is a deliberately simple baseline: each player's mean points over their last three appearances. Players with no actual row count as zero points and zero minutes.

GW Rows MAE: model / baseline RMSE: model / baseline Top-10 recall
GW1 561 1.95 / 1.70 2.96 / 3.31 0.00
GW2 575 1.59 / 1.54 2.41 / 3.04 0.33
GW3 553 1.58 / 1.56 2.41 / 2.74 0.00
GW4 552 1.39 / 1.59 2.37 / 2.68 0.17
GW5 554 1.31 / 1.60 2.34 / 2.70 0.00

Rows are player-fixtures scored. MAE is the average points error per player-fixture; RMSE punishes big misses harder. Lower is better for both. Top-10 recall is the share of the actual top-ten scorers (ties at tenth place included) that the model's own top ten contained.

What the table says:

  • The model beat the baseline on RMSE in all five gameweeks, and on MAE only in GW4 and GW5. In GW1 to GW3 the baseline had the lower MAE.
  • In the latest gameweek, GW5 (554 player-fixtures), MAE was 1.31 against 1.60 and RMSE 2.34 against 2.70.
  • Picking the very best players is the weak spot. Top-10 recall ran from 0.00 to 0.33 a week, and in GW5 the model's top captain pick scored 6 points against 17 for the best available.
  • Five gameweeks is a small sample. I make no claim about beating other tools or about benefit to users.

Reviewing the fixture-difficulty model

The fixture-difficulty model went through eight rounds of adversarial review by a second model before release. Round 8 ended with a SHIP verdict after an independent 10,000-case seeded sweep with zero failures, plus integrated probes of the save path. The reviewers are models, so they share blind spots. This is process evidence, not an external audit.

The planner

The planner takes a team, an optional Wildcard week and any locks (players, chips, transfers, captain), and solves transfers, captaincy and chips through GW19 with a state-graph solver. Across 24 timed solves on Vercel (four teams, every lock type) it took 9 to 15 seconds per solve, replacing a legacy engine that could take over 100 seconds.

It shipped in five increments. Each passed type-check, oracle tests, the full suite, a fresh-reviewer pass and a flag-off byte-identity check, and a single flag rolls back to the old behaviour. At ship (9 Sep 2026) the full suite had six failing tests that predated the planner work: four in the older optimiser and two in UI copy.

The optimality gap is measured on a proxy objective, so I never call a plan optimal. One Wildcard-plus-lock case took 116 seconds because it falls back to the legacy engine.

Where it stands

EasyFPL is live at easyfpl.app (it answered HTTP 200 on 29 Sep 2026). Paid users: 0. Revenue: none recorded. Monthly active users: measuring since 29 Sep 2026. Distribution started late: as of 7 Sep 2026 my own roadmap recorded that no traffic had been driven to the site yet.

Limits

  • The 2025-26 season replay is a component proxy, not the production model. The inputs needed to rebuild the production model for past weeks were not archived, and reconstructing them from finished results would leak outcomes. That proxy failed its own release gate: top-10 recall 0.08 against a 0.25 threshold. I report it alongside any accuracy claim.
  • The source repository is private. The live site and the numbers above are what I can show.
  • This is a football model and a planner. It is not an LLM system, and nothing here is a claim about LLM evaluation.

What this shows

The habit I would bring to a customer deployment: score what actually shipped, against a baseline a sceptic would accept, report the weeks it loses, and put a gate in front of every release.

02 / Systems

Live telemetry

Automated Market Making

Engineering telemetry from a market maker I built: how fast it cycles, how often it is up, and how much it handles. Measured live and published as aggregates only.

Loading telemetry…

03 / Notes

Writing

00Published posts

No posts published yet.
Future writing will appear here.

RSS feed