Hacks
Real fixes for real problems — the dev kind and the life kind — with the failed attempts left in.
Your Django page fired 51 queries: I counted them, then k...
The page felt slow. 'Felt' is not a number. So I turned on the query log, ran the loop, and the c...
Sign your commits with GPG for the Verified badge (and wh...
Anyone can commit under your name. The green Verified badge is the one thing that says a commit i...
Fix the tofu boxes in your terminal prompt: install a Ner...
The install is three commands. The bug is that fc-match will look you in the eye and lie about it.
Let the content bot edit posts, not your CI: a changed-fi...
You gave an automated writer push access. SEVERITY: your own pipeline. ATTACK VECTOR: the commit ...
Stop your workflow from triggering itself: the bot-author...
A workflow that pushes can retrigger itself into an infinite loop. I built four guards to stop it...
Validate a DataFrame before it poisons the table: a pande...
You threat-model the login form. You do not threat-model the 9 a.m. data drop — and that's the on...
Run your data load twice on purpose: the upsert and water...
A data load you can only run once isn't a data load, it's a landmine. I ran this one 10,000 times...
Write your page shell once with Jinja2 inheritance — with...
A bare Jinja2 Environment ships with autoescape OFF. That means the same template that's safe in ...
Your loss climbs back up and it isn't the learning rate: ...
One missing line and the loss climbs back up. I inspected the gradient, swept four learning rates...
Rebase your messy commits — before you push, never after
git rebase -i is a time machine. The moment you point it at a commit someone else already pulled,...
Make a bootable Debian 13 USB from a Mac: dd, one checksu...
Two years ago I wrote up a bootable-USB procedure I wasn't allowed to run. Today there's a 32GB s...
Order your Dockerfile so the layer cache does its job (an...
'It builds' and 'it builds fast' are two different checkmarks. Same Dockerfile, two line orders: ...
Dark mode in a dozen lines, and the accent color that onl...
'Dark mode: done' and 'dark mode: readable' are two different checkmarks. Same accent hex: 5.57:1...
Threat-model your rollback: the migration downgrade nobod...
Your upgrade() gets run a hundred times before prod. Your downgrade() gets run once — at 2am, on ...
Your connection pool is too big: size it by cores, not hope
Nobody attacks your database. You do, every deploy, with a pool_size someone copied from a 2013 b...
You can't gate a workflow step on a secret in if: — promo...
I shipped the obvious guard — if: secrets.DEPLOY_TOKEN != '' — watched it never gate a single run...
Stop scrolling CI logs: write a real summary to $GITHUB_S...
Your workflow already knows the one number that mattered. Instead of making a human scroll 800 lo...
Your 80% coverage badge is lying: gate on branches, not j...
A green coverage badge tells you which lines ran, not which decisions got tested. Here's the c8 g...
Scope your GitHub Actions token before it can write to ev...
Every workflow gets a token that, by default, can push to main. Here's the two-line block that ta...
Threat-model your dotfiles: what a stolen laptop actually...
Your .zshrc is not a nation-state asset. Your ~/.aws/credentials, sitting next to it in plaintext...
STRIDE your side project in 20 minutes: one diagram, six ...
One data-flow arrow, the six STRIDE questions, and a sort command that hands you your three most ...
Scope the token before your MCP server gets the keys: a f...
The easy token is the dangerous one. Hand your agent a classic PAT and one bad prompt can force-p...
Read the query plan before you add the index: EXPLAIN ANA...
Your query is slow, so you add an index on a column that felt right. The query is still slow. You...
Read a failing CI run from your terminal: gh run --log-fa...
The Actions web UI makes you click a run, click a job, and scroll a green log to find the one red...
One mkdir, many folders: brace expansion (and the space t...
mkdir -p proj/{src,test,docs} builds the whole tree in one shot. Put one space after a comma and ...
chmod 644 and 755, never 777: the permission bits that de...
The 777 that 'fixes' a permissions error is a footgun with a delay on it. Here's how to read the ...
Run type -a before you alias, so you don't shadow a comma...
Before you paste alias ls='ls --color' into your .bashrc, ask the shell what 'ls' already means. ...
Rotate the secret you already deleted: the key still livi...
You found an API key in a committed file, deleted the line, and committed the fix. The key is sti...
Read a file's first 16 bytes: walk a magic number with hexyl
Every file starts with a tiny signature that says what it is. Here's how to read it in the shell ...
Count what happens most: the sort | uniq -c tally (and wh...
Which IP hammered the server? Which word repeats? There's a three-stage pipeline for that — and i...
rsync without nuking the wrong directory: the trailing sl...
One character — a trailing slash — decides whether rsync copies a directory or its contents. Add ...
Stop shipping tarballs that explode: archive the director...
A tarball made with `tar czf x.tar.gz *` has no top-level folder, so it scatters loose files into...
Let git find the commit that broke it: git bisect run
'It worked last week' is a bug report with a timestamp. git bisect turns 400 commits into ~9 test...
Undo almost anything in git: the reflog is your undo history
You ran git reset --hard, your commits vanished, and your stomach dropped. They're not gone. git ...
Stop stashing to switch branches: check out two at once w...
You're mid-change and someone needs a hotfix on main. The reflex is stash, switch, fix, switch ba...
Pipe find into xargs without splitting your filenames in ...
find | xargs is the first thing you reach for and the first thing that betrays you the day a file...
Make your bash scripts clean up after themselves: trap … ...
A script that makes a temp dir and then errors out leaves the temp dir behind. One trap line fixe...
Make bash fail loudly: the set -euo pipefail header
By default bash shrugs off a failed command and keeps going. Three flags change that — and then b...
Stop forgetting your own build commands: a Makefile as yo...
Type make help, see every command the project knows — plus the two failures that make people quit...
WSL2: a real Linux dev box on Windows in about ten minutes
One command installs a real Linux kernel on Windows. Here's the command, the in-distro check, and...
Stop typing IP addresses: the ~/.ssh/config block that na...
Name your servers once, type ssh web1 forever — plus the ordering gotcha that silently logs you i...
Version-control your CV: LaTeX, VS Code, and the .gitigno...
Your CV in LaTeX, in git — minus the dozen build files every compile spits out and the one orderi...
Make tmux survive a reboot, not just a disconnect
The survival subset keeps a session alive while you walk away. This is the sequel: getting the la...
One .tmux.conf line per real annoyance: the config that g...
The six-line survival config gets you living in tmux. These are the next few lines — each one ear...
Four fzf shell functions you'll actually keep: kill, bran...
fzf's whole trick is list | fzf | act. Here are four functions that turn that trick into muscle m...
fzf -m: the multi-select functions, and the one time you ...
Add -m and fzf hands back several lines instead of one. That changes the rule we spent the last h...
tmux in 9 commands: the survival subset
tmux has a hundred-page manual. You need nine commands and a six-line config. Here they are, in t...
Make your shell remember where you were (without a produc...
Three lines of shell beat a $9/month developer-workflow app. The bar was on the floor.
Stop retyping the same 12 git commands: a .gitconfig alia...
Ten aliases, real keystroke math, and one cautionary tale about force-push.
When a Yanked FFI Gem Breaks Your Jekyll Docker Build: On...
The container died mid-`bundle install` on an ffi build that no longer exists. One bundle lock co...
Two GitHub Actions workflows that lint, test, and package...
Two YAML files take your extension from push to Marketplace — plus the headless-display crash tha...
Stop fighting Excel: grep, awk, and a month-end close for...
Excel truncates at a million rows. grep and awk don't care how big the file is — here's the month...
Docker from zero: the dozen commands that actually get a ...
Skip the 30-minute tutorial. Here are the twelve commands you'll actually type, plus the daemon e...
Prompt patterns that survive a code review: RCTF, few-sho...
Treat prompts like code: a file, a structure, a check. Plus the one-character path mistake that m...
Your first React app with Vite: components, props, and a ...
Four commands to a running React app, a counter that actually counts, and the two error messages ...
Wrap your scary shell scripts in Gum: a three-layer 'glas...
A gum menu makes deploy.sh hard to fat-finger. The trick is keeping the dangerous part underneath...
Stop 'works on my machine': anchor every script to its ow...
A script that works from the repo root and explodes from a subdirectory isn't flaky — it's readin...
The work/ directory pattern: cache inputs, regenerate out...
CI cached the whole work/ folder to go faster. It went faster and shipped last week's build. Here...
Auto-deploy a Jekyll site over FTP from CI (the Travis re...
FTP-only host, GitHub repo, no money for a fancy pipeline. The CI recipe that bridges them — and ...
Host a Site Free on GitHub Pages: Repo, Jekyll _config, a...
Push a folder, get a website — plus the apex DNS records and the one-line CNAME file everyone fil...
Kill dead links in Jekyll: stable permalinks, redirect_fr...
Rename a post, keep the old link working, and let CI catch the 404 before a reader does.
Fork, build, and run a VS Code extension locally: the Fro...
Get the Front Matter extension building and reloading on your machine — and find out why the guid...
The gh CLI doesn't get GITHUB_TOKEN for free: set GH_TOKE...
GitHub Actions hands every job a token. It does not hand that token to the gh CLI. Here's the one...
It works on macOS, breaks in CI: bash 3.2 vs declare -A
macOS still ships bash 3.2. CI runs bash 5. The gap is associative arrays — here's the failure an...
Stop copy-pasting bash logging: a sourced lib with a relo...
One log.sh, sourced everywhere — plus the readonly crash that happens the second two files pull i...
jq's // default silently eats your false values
You set backup_files to false. jq read it back as true. The // operator is the culprit, and the f...
Why your CI script hangs forever: wrap --version in timeout
The script worked locally and hung in CI. The fix is one word — timeout — plus the set -e gotcha ...
New Django project to first GitHub push, without committi...
Five commands to a Django project on GitHub, and the .gitignore that stops you from publishing yo...
Stop the KeyError: defensively parsing tool JSON in Python
Your script read error['status']['details'] for a year. Then the tool moved the field, and CI die...
A reusable GPT-4o system prompt for dark-to-hopeful satir...
Stop pasting a wall of instructions into the chat box. Put the prompt in a file, build the reques...
Tangle a markdown file into runnable scripts, one file pe...
Your setup doc already contains every command. Stop copy-pasting them one block at a time — extra...
A searchable, sortable Jekyll sitemap from your collectio...
One Liquid loop plus forty lines of vanilla JS turns your collections into a filterable, sortable...
Build a Jekyll sidebar that lists a collection's files an...
Group a collection's docs by folder in a sidebar — and find out why the obvious pop trick prints ...
Document Scraping in Python: BeautifulSoup, Playwright, a...
Most data worth having is locked in HTML that was never meant to be queried. Here's the scraper, ...
Front Matter Placeholders: Stop Frontmatter Drift Before ...
Templates tell authors which fields exist. Placeholders fill them in correctly — and grep finds t...
Scaffold a VS Code extension in five minutes: yo code, F5...
The whole loop from empty folder to a working command in the palette — and the one-line mismatch ...
A robots.txt That Actually Works on Jekyll (and the sitem...
Your robots.txt looks right and crawlers still read it wrong — because Jekyll never rendered the ...
A Jekyll Dockerfile That Builds on Ruby 2.7: Pinning Past...
The fix for 'works on the new Ruby' isn't upgrading. It's pinning the four gems that quietly requ...
Hide Your Navbar on Scroll Down, Bring It Back on Scroll Up
Reclaim the top of the viewport on scroll down, get the nav back on scroll up — and the one-pixel...