Michael Hospedales · Software Engineer · Miami, FL

Building for the web by day. Running a newsroom that writes itself by night.

I'm a software engineer in Miami. I build production web interfaces with React, Next.js and TypeScript — and I run autonomous AI systems on my own NVIDIA DGX Spark, including The Agentic Daily, a newsroom that researches, drafts and publishes without a human in the loop.

Now

Updated August 26, 2026

  • Running The Agentic Daily: an autonomous newsroom that researches, drafts and publishes an edition every day from my DGX Spark
  • Measuring whether my model evaluations are real — noise floors, replicates, and the improvements that did not survive them
  • Growing the homelab: vLLM and llama.cpp on Grace Blackwell, and everything that needs a second look on aarch64

Field notes

All notes →

DefaultOOMScoreAdjust=200 in the systemd user manager kills terminal-launched servers first

A production llama-server process was killed by the kernel with nothing in its own log: no assert, no stack trace, just silence, noticed only because /metrics stopped responding. The killed process carried oom_score_adj:200. The cause was not the coding-agent session that launched it — it was a systemd user-manager default, DefaultOOMScoreAdjust=200, which scores every terminal-launched process to die before system services do, even ones many times smaller. That score cannot be lowered after launch by an unprivileged process, so the fix is to run the server as a systemd system service instead, which defaults to OOMScoreAdjust=0.

Detecting which inference engine owns a port: vLLM vs. llama.cpp

Detection that infers the engine from the port number breaks the moment either engine moves. Moving llama.cpp onto the port normally used by vLLM mislabeled it, and downstream code silently wrote null. /props is a clean discriminator: llama-server serves it, and the vLLM OpenAI-compatible server has no such route and returns 404. A second gotcha in the same detour: docker ps --filter publish= does not match a container using host networking.

My LLM judge was flipping a coin a third of the time

I used a language model to pick the better of two drafts, and trusted it for months. Then I gave it two drafts from an identical configuration and asked it to choose. Here is what measuring a judge’s noise floor costs, and why every A/B result before it was unreadable.

The model ran out of room to think, and every diagnostic guessed wrong

Three times this year a reasoning model spent its whole token budget thinking and handed back empty content under HTTP 200. Three times, the code reading the result invented a different explanation — a parser bug, then an unconstrained grammar. Neither was true, and one of them fired inside a safety check.

A page transition that breathes

How this site went from a heavy ink-wipe page transition to a 300ms breath through paper — WebGL bokashi gradation, mathematical opacity guarantees, and the fail-safes that keep navigation working when the shader does not.

Come say hello

No project or budget required — I like talking about interesting problems, shop talk on agentic systems, and the occasional war story from shipping.

Get in touch