
Migrating this site to EmDash
This site has changed CMS more times than I can count since 2003. This time I moved to EmDash on Cloudflare, and the reason is that most of my building now happens alongside an AI agent.
Read moreI've been writing online at various sites since 2003, mostly about a wide variety of topics including web development, tech, food and whatever else I feel like writing and sharing.

This site has changed CMS more times than I can count since 2003. This time I moved to EmDash on Cloudflare, and the reason is that most of my building now happens alongside an AI agent.
Read more
I wanted a simple dashboard that showed me events as they happened, so I wrote a quick little Astro app. It grew into Get Butters: a real-time event feed with a REST API, a CLI, insight cards and push alerts.
Read more
Once four agents can edit the same repo, architecture stops being the hard problem and coordination starts. The five roles I run and what each one is forbidden to touch, why every handoff goes through a file, a worktree script so agents stop racing, and the failure modes worth naming.
Read more
Saying "done" costs a model nothing, which means it carries no information. A definition of done has four machine-checkable parts: source boundaries, acceptance criteria written as observations, verification commands the agent does not own, and a list of claims it must refuse to make without evidence.
Read more
Guide on setting up Dozzle with authentication on Coolify for secure, real-time Docker container logs, CPU, and memory monitoring.
Read more
A one-shot QA pass is a demo. Put it on a cron and it files the same issue every morning until the qa-bot label is a landfill. Here is the loop that makes the queue drain instead of grow: a spec in version control, fingerprinted issues, a reconciler with no opinions, and auto-close when the flow goes green.
Read more
A practical framework for giving production agents the right evidence, the right limits, and a measurable definition of done.
Read more
Most MCP tutorials assume a standalone process. Here's how to expose one as just another Astro API route using Streamable HTTP — same auth, same deploy pipeline, no second app to maintain.
Read more
Extending the Datastar chat widget with the browser's native SpeechRecognition API — no new backend, no transcription service, just one more way to fill the same signal.
Read more
Take the Astro + Datastar + Vercel AI SDK stack from this series and run it entirely on your own machine with Ollama — no API key, no per-token cost, no data leaving your laptop. It's a one-import change.
Read more
Stream typed, structured data from the Vercel AI SDK and watch a card build itself field by field in a Datastar UI — using streamText with output, the v6 replacement for streamObject. No React.
Read more
My dialer QAs itself: Claude Code logs in, dials a list of Twilio test numbers — a voicemail, an IVR, a simulated gatekeeper — records what happened vs. what should have, and files GitHub issues for another agent to fix.
Read more
Turn the streaming chat widget into an agent that calls tools — and stream the tool-call status live into the conversation. Astro, Datastar, and the AI SDK v6 ToolLoopAgent, no React.
Read more
A full multi-turn chat widget with live token streaming — where the server owns the conversation and the DOM is just the view. No React, no useChat, no client framework.
Read more
A small, genuinely useful build: a button that streams an AI summary of the current page into a panel, using Astro, Datastar, and the Vercel AI SDK — no React, no client framework.
Read more
The Vercel AI SDK's useChat only ships React, Vue, and Svelte bindings. Here's the small, reusable pattern for streaming AI tokens into a plain Datastar UI instead — no framework required
Read more
The Vercel AI SDK's useChat only ships React, Vue, and Svelte bindings. This six-part series builds real AI apps — chat, agents, structured output, local models — with no client framework at all, using Astro, Datastar, and one small streaming pattern
Read more
You don't need OneSignal or Firebase to send push notifications. Web push with VAPID keys is built into every modern browser — here's the full setup in Astro: service worker, subscribe flow, SSR endpoints, and sending from the server.
Read more
How I wired up a tiny TLDR tool that takes a URL, extracts the article, and streams a Markdown summary back to the browser in real time — using Astro SSR, Datastar for reactivity, and the Vercel AI SDK for the model call.
Read more
I've been a big fan of HTMX + Alpine for a long time, the combination just lets you create powerful reactive web apps, but recently I've made the decision to move from HTMX + Alpine to Datastar for various reasons and the result means a better experience for users.
Read more