Blog
Thoughts on code, tools, and lessons learned along the way.
I went on a trip. My Mac mini stayed home and kept texting me.
I left town for a few days. The Mac mini stayed back, ran on its own, took orders from my phone, and pinged me about everything. This is what that felt like.
Read moreBuilding vaultctl: the password vault where my own server can't read your passwords
A self-hosted, zero-knowledge password vault. One Go binary, three clients, one constraint that quietly shaped every other decision in the codebase.
Read morethe slow request my APM never told me about
A user was hitting six-minute page loads and my APM had nothing on it. Turns out APMs cap trace duration. Here is what I reached for instead.
Read morePointing vinelabs.de at my Mac mini through a Cloudflare Tunnel
I had a domain. I had a homelab. A Cloudflare Tunnel was the simplest way to make them point at each other, without opening a single port on my home router.
Read moreMy Raspberry Pi could not carry the dream. A 2018 Mac mini could.
I wanted a small army of agents running 24x7 and a place to host all my homelab apps. The Pi was never going to do it. A colleague handed me his 2018 Mac mini and the whole thing took shape in one sitting.
Read moreI treated skills like dotfiles. Then they started spawning subagents.
My CLAUDE.md was turning into a Frankenstein .bashrc. Skills landed and my first instinct was 'dotfiles for Claude'. Half right. Dotfiles sit, skills move.
Read moreHow Git Worktrees Killed My Stash-Hotfix-Rebase Dance
The old stash, checkout, hotfix, rebase, pop routine is a quiet war crime against your evening. One git worktree later, hotfixes stopped scaring me, and AI agents made it the most quietly powerful habit in my workflow.
Read moreWhy My One-Line Installer Worked Everywhere Except WSL
From three-day onboarding to docker compose to a one-line interactive installer, until one Windows developer hit a CRLF wall in WSL. Here is the full arc and the fix.
Read moreHow I ended up buying vinelabs.de
I bought a domain on a Sunday afternoon I had not planned to buy. The trigger was a composer.json author field. The realisation was that shipping eight packages under my personal GitHub username reads like a hobby.
Read moreThe Shopware plugin that grew into a library
Started as a small Shopware 6 plugin for Germany's XRechnung 3.0 e-invoice format. Ended as a PHP monorepo with a framework-agnostic core, four adapters, and four CMS plugins. Nobody asked. I built it anyway.
Read moreMCP is the USB-C of AI tools, and most devs are still using their AI assistant like it is 2023
A quiet protocol shift is happening in AI tooling. Most devs missed it. Why MCP matters, the high-profile breaches that should have your attention, and the rubric I run before installing any new server.
Read moreThe disk that filled itself
Homelab box said 100 percent full, du said half the disk was free. Docker was holding open a log file I had rm'd months ago. lsof +L1 untangles the knot.
Read moreThe webhook that worked in Postman and nowhere else
Two bootstrap paths in one app drifted apart. The HTTP entrypoint loaded the webhook signing secret, the queue worker did not, and a silent-skip guard hid the cause behind a misleading 401.
Read moreThe 20,000-line PR that was actually 47 lines: building ClearPR
How one 20,000-line Prettier PR pushed me to build ClearPR, a self-hosted GitHub App that strips formatting noise, reviews against your own rules, and remembers past feedback.
Read moreI blocked Tor exit nodes, then I opened Tor Browser
I deployed a hardened Tor exit node firewall on a SaaS production box, opened Tor Browser to confirm, and the site loaded. The IPv4 fortress was perfect. The IPv6 side door was wide open. This is the script, the punchline, and the rewrite that became TorShield.
Read moreThe node_modules That Wouldn't Die
An internal app deploy kept importing an old Vite plugin export. The lockfile was right, the build was wrong. The culprit was older than the bug.
Read moreThe Sentry signup nobody could finish
A colleague signed up on our self-hosted Sentry and never got the email. I had been getting Sentry mail forever, so I assumed he was missing something. He was not. DMARC was silently dropping every message to our Workspace inboxes, and the 'workaround' I shared with him broke too. Here is the bug, the lie my inbox had been telling me, and the shell command that finally got him in.
Read moreThe sed that didn't stick
A failing nightly backup, a sed hotfix that worked once, and the next morning's cron that failed anyway. Node's require cache had eaten my patch.
Read moreCross-Posting My Blog to dev.to and Hashnode: What I Got Wrong
I figured cross-posting my Astro blog to dev.to and Hashnode would take an afternoon. It turned into four PRs, three failure modes, and a few API surprises.
Read moreI Mistook gpt-oss for an Image Generator. Now My Mac Runs FLUX Offline.
I asked gpt-oss for an image, realised it cannot do that, and ended up with FLUX running on my Mac through Draw Things and a tiny curl pipeline. A full walkthrough so you do not repeat my mistakes.
Read moreBuilding a per-repo wiki that actually gets read
The docs existed. The CI/CD was already automated. And yet I was still getting pinged before every deployment. Honest field notes on why a per-repo wiki finally broke the loop, and the hidden .wiki.git repo nobody talks about.
Read moreWhy I Stopped Arguing About Docker Port Conventions
A colleague raised port conflicts in the daily. A suffix vote lost to the 16-bit limit. A prefix rule worked but still felt wrong. Then docker-compose.override.yml.example made the whole debate go away.
Read moreSetting Up a MinIO CDN with Nginx Reverse Proxy on Docker
A practical walkthrough for self-hosting an S3-compatible CDN with MinIO, Docker Compose, and Nginx - including the small config bits everyone seems to miss until presigned URLs start failing.
Read moreThe day I realised I had never tested a production backup
I had been running test-backup drills for months and felt covered. But I had never pulled a real production snapshot into a lab and restored it. The afternoon I finally did is the story behind this post.
Read moreThe second half of shipping a CLI: Homebrew tap, Scoop bucket, and the SHA dance
What happens after you publish to npm? For Mac and Windows users, mostly nothing. Here is the packaging side-quest of getting ipwhoami onto brew and scoop.
Read moreBuilding docling-server: a one-command document API for our AI pipeline
Why I wrapped docling into a full Docker Compose setup with FastAPI, Celery, and nginx — so our AI project could stop worrying about messy PDFs, Word files, and scanned junk, and just get clean markdown back.
Read moreBuilding mcp-pool: one week, eleven MCP servers, one shared OAuth library
How a single Stripe MCP server turned into a monorepo of eleven, and why half the engineering effort went into not writing the same OAuth flow six times.
Read moreI upgraded our 2.5-year-old self-hosted Sentry without losing a single byte
A self-hosted Sentry instance, 2.5 years behind, 0 bytes of swap free, 4 mandatory version hops, 78 containers, and one afternoon where I learned that enabling a feature and using a feature are not the same thing.
Read moreA short history of the CLI I built to stop curling IP APIs
It was supposed to be a weekend CLI. Then the name got stolen, the providers started disagreeing with each other, the rate limits hit back, and somewhere along the way the simple tool grew its own self-hosted backend.
Read moreMy family thinks WhatsApp can send anything. So I wrote a Python CLI.
A 2005 wedding video, an 8 GB .VOB file, a family WhatsApp group with unreasonable faith, a small privacy grudge against Google, and the weekend Python CLI that came out of it.
Read morejquery.verticalScroll.js: a love letter to jQuery, written ten years later
I saw Apple's iPhone page in 2016, thought 'I can build that in jQuery,' and somehow I'm still maintaining it in 2026. Zero stars. Zero regrets.
Read moreMy .zshrc is 350 lines and I mass-replaced every core Unix command
A 350-line .zshrc, a 68-line .bash_aliases time capsule from the Linux era, a secret gist, and the story of a developer who can't let go of a shell config.
Read moredfree: stop digging with your hands, you've got an axe now
A short story about running out of server space because of academy videos, and the shell tool I wrote so I'd never hear 'Vineeth, we can't upload anymore' again.
Read moreBuilding agent-sessions: a universal session manager for the AI CLI era
Five AI coding agents, five incompatible session formats, one terminal UI to browse them all — and the reverse-engineering it took to get there.
Read morediskdoc and dockit: same problem, two languages, different answers
I built two disk cleanup CLIs — one in Rust with a TUI, one in Go with risk scoring. Here's what each language and design taught me that the other couldn't.
Read moreBuilding backupctl: what it took to replace a cron job with a backup service
How a cron-and-restic setup outgrew itself, and the NestJS backup service I built to replace it — with two war stories I didn't see coming.
Read moreHello World — Welcome to My Blog
First post on my new portfolio blog. A quick intro about what to expect and why I decided to start writing.
Read more