purr.io

Findings, not features.

AI systems that aren't allowed to invent a number, and the data engineering underneath them — each project built to answer one question and published with its receipts: pipelines, models, evals, and the parts that didn't work. Public energy data is where I prove it; the methods don't care about the domain.

Bryan Hughes · Senior AI Engineer · Chicago · bryan@purr.io

ghost.purr.io

Eidolon

seasonal · a spirit box, debugged

A spirit box sweeps radio too fast for whole words, and believers hear the dead in the gaps. This one hops nine live internet stations, plays a two-second snippet from each, and hands exactly what you heard to two language models. Speech-to-text invents confident words out of noise — the very property the ritual runs on. Skeptic mode logs every connection, prompt, token count and cent.

enter →
walker.purr.io

Agentic Dog Walker

live agent demo · a qualification gauntlet for cheap tool-calling models

A small language model with three tools plans dog-walking routes — geocoding, street routing, per-dog weather verdicts — with every tool call, validation bounce, and audit veto streamed live. Served from a retired laptop in a closet; the models are qualified by an automated gauntlet before they may appear in the picker.

visit →
rag.purr.io

geo-mini-rag

RAG · why embeddings can't resolve identifiers

Ask a retrieval system for a record by its identifier and it cannot tell you which one: the document that carries it scores 0.324 against 0.729 for an unrelated page of digits. Embeddings rank by resemblance, and identifiers don't resemble — the same failure hits SKUs, claim numbers and ticket IDs. Exact lookup everywhere ranking cannot work, plus two standard techniques built, measured, and switched off because the numbers said so.

visit →
spacing.purr.io

Well Spacing Playbook

essay · confounding, and calibrated uncertainty

Operators choose where to drill, so crowding looks beneficial until geology is held fixed — the selection-bias trap that eats observational analysis in every field. A measured answer, a calibrated P10/P50/P90 interference model, all 105,724 Alberta laterals mapped, and an honest account of where public data ends.

visit →
methane.purr.io

Methane Outliers

live pipeline · peer-relative outlier scoring · refreshes itself

Who is an outlier against their own peer group, not against a fixed threshold? Two regulators, identical rolling 12-month windows, every facility scored against operators of similar size — top offenders mapped well by well. A zero-cost ETL demo: GitHub Actions, Cloudflare R2, and bulk public data, updating on schedule.

visit →
comed.purr.io

Power Puddle, Vol. 2

batch pipeline · forecast evaluation against a naive baseline

In 2025 this project called PJM's data-center load forecast a puddle of wishful thinking. A Prefect, dbt and DuckDB pipeline grades that call a year later, rebuilt from source: fan charts of every forecast vintage, forecasts scored against a naive baseline, and the confession about the “corrupt” spreadsheet that wasn't.

visit →
kingfisher.purr.io

Kingfisher Wells

museum · entity resolution across three vendors

Three commercial data vendors, one Oklahoma county, and well locations that can't all be right. A medallion-architecture pipeline that triangulated the disagreements, preserved as an interactive map and a data-quality story.

visit →

Recent contract work

I built the data pipeline, the AI backend and the CLI test framework for a commercial oil & gas analytics product. Ask for something in plain English — horizontal Montney wells fractured with more than twenty stages, say — or define an area of interest via filters, and what comes back is assembled from statistics computed deterministically over the well data, never from the model's memory of what a Montney well is usually like.

The answer pathA query produces statistics the model works from. The model can go back for more of its own accord, as many times as it needs, and every one of those trips is fact gated.querystatsLLManalysis · charts · textagenticFACT GATEDad-hoc queries & stats

Answering is the easy half. The hard half is proving the answer is true. Every figure in a generated reply has to appear in the fact tables computed for that question, and whatever those tables do not carry is stripped out rather than reworded. The harness watches its own output too: an ephemeral drop in quality is caught and retried instead of shipped.

The web app was being built alongside it, so I wrote a CLI that calls every endpoint the way the app does. Its first job was showing the frontend developer how to use each one — what to send, what comes back — and because it drives the real server rather than a mock, it doubles as a headless tester. Further down, the pipeline feeding all of this refuses to publish a release with fewer rows than the last one. Silent data loss fails loudly.