A minimal JavaScript demo of calling an LLM from your own code using the OpenAI-compatible chat completions endpoint via OpenRouter, covering API keys, model selection, and request structure. It walks through the JSON response, pointing out finish reasons, reasoning tokens, cost fields, and provider routing...
After a BOINC workload change pushed a homelab container’s memory usage past its monitoring threshold, I switched from keyword-based checks in Uptime Kuma to its JSON query feature, which applies JSONata expressions to fetched JSON metrics. I walk through the setup, and show a conditional query combining memory and CPU values...
Prompted by Manuel Schipper’s piece on technical leaders and AI, I document my current workflow for using LLMs in web development. This approach keeps context small and explicit โ frequent clearing, markdown summaries passed between stages, no background agents or MCPs โ supported by a personal library of prompt playbooks that encode my stack and conventions. Work proceeds in discrete stages (exploration, plan, AI and human plan review, implement, checking) so problems surface at the document level before code gets written...
Client-side JavaScript errors go unnoticed by keyword-based uptime checks like Uptime Kuma’s, which is how a broken weather widget slipped past monitoring on one of my sites. I walk through building Faultsy, a lightweight alternative to Sentry: a browser script captures uncaught errors and unhandled promise rejections, reports them to a small Node server via sendBeacon(), and exposes per-site error counts as JSON that Uptime Kuma can monitor. The project is on GitHub and still under active development...
I explain the browser’s same-origin policy, covering what counts as an origin, why the restriction exists, and how it blocks JavaScript from reading cross-origin responses. I then introduce CORS as the mechanism servers use to permit specific origins via Access-Control-Allow-Origin headers...
My Ansible playbook for SSH hardening fails on a newly provisioned Ubuntu 26.04 LTS VPS because that release ships sudo-rs, whose password prompt differs from the classic sudo prompt that Ansible matches against, causing a privilege-escalation timeout. A fix has landed upstream in Ansible but hasn’t reached my version yet, so I fall back to Ubuntu 24.04 LTS, mentioning a passwordless SSH Ansible user as an alternative...
In this walkthrough, I set up a VS Code Dev Container, beginning with my use of Remote-SSH on homelab LXCs and my goal of running AI coding agents like Claude Code in an isolated, easily recreated environment. I cover writing a Dockerfile and devcontainer.json, how the extension automatically handles the VS Code server and workspace bind mounts, and the difference between UI and workspace extensions, including declaring them in the config for reproducible setups. I leave handling SSH keys for pushing code to a future post...
Trying the Ghostty terminal, I hit a problem over SSH to a Synology NAS: arrow-key history recall and clear don’t work, because Ghostty sets TERM to xterm-ghostty and Synology lacks the matching terminfo. The practical fix is overriding TERM to xterm-256color via an ssh config SetEnv entry, which can be wildcarded across multiple hosts. The terminfo installation method Ghostty officially recommends fails on Synology’s minimal DSM...
A follow-up to my earlier article on AI-assisted coding, describing my move from autocomplete tools to agentic coding with Cline, Claude Code, and Gemini CLI. I cover token costs, comparisons between Claude, OpenAI, DeepSeek, and Gemini models, and practical tips such as plan-then-act workflows, guardrails, and keeping context lean...
I walk through building a simple Firefox extension that adds a right-click menu option to open an image in a new tab with its query parameters stripped, useful when CDNs serve resized or converted versions instead of the original. I cover the manifest, permissions, and background script, plus how to test the extension via about:debugging and enable it in private windows, with brief notes on publishing to the Add-ons store...
A walkthrough of end-to-end testing a web app with Cypress, which I demonstrate against a small Express app with customers and orders. I cover installing Cypress, writing tests for navigation, deletions and cascading deletes, element selection with data-test attributes, custom assertions using invoke and then, running tests in the browser, and handling state resets between runs...
In this beginner-level walkthrough, I tidy up a Node/Express app whose server.js has grown unwieldy by moving routes into separate files with Express Router. I show how to mount routers as middleware with app.use, note that a routes folder is a common convention, and highlight the gotcha that the mounted path prefix gets stripped from the request URL. A consistent naming convention for route groups makes the split easier, and sample code is available on GitHub...
I take a look at JavaScript’s reduce() method, walking through how the accumulator works with examples like summing and finding the maximum in an array, and explaining why reduce counts as a “functional” array method...
After the Porkbun DNS plugin for Nginx Proxy Manager stopped working, my homelab Let’s Encrypt certificates no longer renewed automatically, so I now download certificate bundles directly from Porkbun and install them manually. Along the way there’s background on SSL, DNS challenges, and securing internal services that aren’t reachable from the public internet. The manual approach requires repeating the renewal process every 90 days...
A look at Node’s built-in test runner from my perspective as a long-time Mocha and Chai user, showing how to write and run basic tests with node:test and node:assert. Coming from Mocha requires few changes, though test files need to live in a test directory to be picked up. I weigh the convenience of a bundled runner against lock-in to a particular runtime...
I reflect on my use of LLMs for coding, weighing concerns about training data, accuracy, energy use, and data leakage against the practical benefits. I describe trying GitHub Copilot, Codeium, and local models via Ollama, and settling on Codeium for code completion alongside web chatbots for code discussions. I also cover how AI has changed my practice, including writing clearer code, favoring well-established technologies, and adopting new libraries more readily...
The ‘show all’ button on The Rest Is History podcast’s episodes page is broken, and there’s no JSON endpoint behind the player, so the episode list has to be scraped from the page’s HTML. Using Cheerio, a jQuery-like library for the server, I show how to select the playlist’s list items and extract each episode’s title and link, ending with a complete working script...
Using ntfy.sh, shell commands can trigger a push notification to a phone or watch via curl when they finish. I demonstrate chaining long-running commands like rsync with && and || to send success or failure messages, running everything in the background with nohup, and redirecting the curl output to a log file...
I walk through self-hosting Enclosed on a VPS as a secure alternative to emailing password-protected zip files. I cover the Docker Compose setup behind Nginx Proxy Manager, along with configuring authenticated logins, a step the official docs leave under-explained, so only I can upload files while recipients download them without an account...
When my home internet connection can’t reach DockerHub, I work around it by pulling the Jellyfin image I need on a laptop tethered to a phone hotspot, then moving it to the server as a file using docker save and docker load. The post also includes a short explanation of how container images are built from layers described by a manifest...