Skip to main content
Settings
Color Mode
Theme Skin
Background

Appearance preferences are saved in this browser only.

Environment
Current Environment Production

Built with JEKYLL_ENV=production. Changes require deployment.

Quick Links
Theme & Build
Jekyll v3.10.0
Last Build Jul 18, 18:52
Page Location
Page Info
Layout section
Collection none
Path news/hacks.md
URL /news/hacks/
61 articles

Hacks

Real fixes for real problems — the dev kind and the life kind — with the failed attempts left in.

Filter:
ci-cd security
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...

shell security
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...

security web-dev
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 ...

git security
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...

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

git ci-cd
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...

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

shell security
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 ...

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

git security
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...

shell data
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 ...

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

shell
rsync without nuking the wrong directory: the trailing sl...

One character — a trailing slash — decides whether rsync copies a directory or its contents. Add ...

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

shell git
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...

shell git
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 ...

Featured Stop stashing to switch branches: check out two at once with git worktree
shell 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...

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

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

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

shell ci-cd
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...

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

shell security
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...

shell git
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...

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

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

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

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

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

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

shell git
Stop retyping the same 12 git commands: a .gitconfig alia...

Ten aliases, real keystroke math, and one cautionary tale about force-push.

shell jekyll
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...

ci-cd web-dev
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...

shell data
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...

shell ci-cd
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...

git web-dev
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...

web-dev
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 ...

shell ci-cd
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...

shell ci-cd
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...

shell ci-cd
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...

ci-cd jekyll
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 ...

jekyll security
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...

ci-cd jekyll
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.

jekyll web-dev
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...

git ci-cd
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...

shell ci-cd
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...

shell ci-cd
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...

shell data
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...

shell ci-cd
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 ...

git data
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...

ci-cd data
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...

web-dev data
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...

shell ci-cd
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...

jekyll web-dev
A searchable, sortable Jekyll sitemap from your collectio...

One Liquid loop plus forty lines of vanilla JS turns your collections into a filterable, sortable...

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

web-dev data
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, ...

shell jekyll
Front Matter Placeholders: Stop Frontmatter Drift Before ...

Templates tell authors which fields exist. Placeholders fill them in correctly — and grep finds t...

web-dev
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 ...

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

jekyll docker
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...

jekyll web-dev
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...