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.

homelabmac-minintfytailscaleself-hosting
Read more

Building 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.

gocryptographyzero-knowledgeself-hostingopen-sourcejourney
Read more

the 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.

debuggingprofilingapmproductionphp
Read more

Pointing 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.

homelabcloudflare-tunnelmac-miniself-hostingvinelabs
Read more

My 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.

homelabmac-minitailscaledockerclaude-codeself-hosting
Read more

I 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.

claude-codeskillsdotfilesdeveloper-workflowai-agents
Read more

How 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.

gitworktreesdeveloper-workflowai-agentsgraphite
Read more

Why 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.

shell-scriptingwslwindowsinstalleronboardingdocker
Read more

How 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.

personalbrandingastrocloudflare-pagesmonorepo
Read more

The 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.

phpxrechnungshopwareopen-sourcee-invoicingmonorepo
Read more

MCP 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.

mcpai-toolingclaudesecuritysupply-chain
Read more

The 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.

debugginglinuxdisk-fulldockerself-hostedops
Read more

The 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.

debuggingwebhooksbootstrapqueue-workersfail-fastops
Read more

The 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.

typescriptnestjsgithub-appai-reviewtree-sitteropen-source
Read more

I 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.

toriptablesipsetipv6linuxsecurityops
Read more

The 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.

dockerdeploymentgitci-cdops
Read more

The 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.

sentryself-hosteddmarcsmtpops
Read more

The 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.

dockernodebackupopsopen-source
Read more

Cross-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.

blogautomationgithub-actionsdevopsself-hosting
Read more

I 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.

macaifluxdraw-thingslocal-llmimage-generation
Read more

Building 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.

docsgithub-actionsdevopsteam-processonboarding
Read more

Why 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.

dockerdevopscomposeworkflow
Read more

Setting 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.

minionginxdockerself-hostingdevops
Read more

The 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.

backupdocker-composedatabasesopsopen-source
Read more

The 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.

clihomebrewscooppackaginggithub-actionsrelease-please
Read more

Building 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.

doclingfastapicelerydockerai-pipelineopen-source
Read more

Building 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.

typescriptmcpoauthmonorepoai-toolingopen-source
Read more

I 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.

sentryself-hosteddevopsupgradedockerjourney
Read more

A 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.

clinodeipgeolocationopen-sourcejourney
Read more

My 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.

pythonffmpegclimediaopen-sourcejourney
Read more

jquery.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.

jquerypluginjavascriptscssopen-sourcejourney
Read more

My .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.

shellzshdotfilesdevtoolspersonaljourney
Read more

dfree: 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.

shellclidevopsdisk-cleanupopen-source
Read more

Building 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.

typescriptcliai-toolinghexagonal-architecturereactopen-source
Read more

diskdoc 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.

rustgoclidockertuiopen-source
Read more

Building 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.

nestjshexagonal-architecturebackupresticopen-sourcejourney
Read more

Hello 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.

introblogpersonal
Read more