Writing
Notes from production
Long-form, practical posts on the systems I build: real-time messaging, WhatsApp, Postgres and Elasticsearch at scale, AI agents and how to evaluate them.
Testing a medical triage agent with LangWatch Scenario and pytest
How I test a medical triage AI agent with LangWatch Scenario: a simulated user, judge criteria, scripted and free-running conversations, in pytest and CI.
Building a reliable WhatsApp Cloud API webhook receiver at scale
How to build a WhatsApp Cloud API webhook receiver that holds up: signature checks on the raw body, fast 200s, dedup, per-contact ordering and media handling.
Backpressure in Elixir: sending millions of WhatsApp messages without falling over
Designing a bulk WhatsApp send engine in Elixir: demand-driven Broadway pipelines, per-number token buckets, retries with jitter and batched status tracking.
How to partition a 1 TB PostgreSQL table without downtime: the default-partition method
Partition a live 1 TB Postgres table without downtime: attach it as the DEFAULT partition, copy history out with Oban jobs, then swap in one short transaction.
PostgreSQL partitioning in practice: partition keys, pruning, indexes and retention
How PostgreSQL partitioning behaves in practice: choosing the key and size, checking pruning with EXPLAIN, indexes, keys, retention and the Ecto gotchas.
Letting AI agents run code safely in Elixir with tv-labs/lua
How tv-labs/lua gives AI agents a sandboxed Lua runtime inside Elixir: exposing safe functions, setting limits and wiring code execution into the agent loop.
Serving MedGemma 27B on Modal: FP8, vLLM sleep mode and 21-second cold starts
How I self-host MedGemma 27B as a scale-to-zero, OpenAI-compatible API on Modal: FP8 quantisation, GPU snapshots, two vLLM bugs and Gemma 3 tool calling.
Designing AI agents that know when to hand over: to other agents, to rules, to humans
A practical architecture for AI agents that hand over safely: multi-agent transfers, a deterministic rules engine for high-risk calls, sandboxed tools, evals.
Simulation evals: letting an LLM play the user to test your chatbot before real users do
How to build simulation evals for LLM chatbots: persona-driven simulated users, LLM-as-judge rubrics, error rates for high-stakes flows and a feedback loop.
CPUSim: the CPU simulator I built for Zanichelli
I was reminded today of CPUSim, a browser CPU simulator I built for Zanichelli in 2020 to show students how machine code runs, one glowing register at a time.
Keeping custom state across the Überauth OAuth flow in Elixir
Überauth now uses the OAuth state parameter for CSRF protection, so custom state gets overwritten. Keep it in the session between request and callback instead.