chmod 644 and 755, never 777: the permission bits that decide what's safe to run
The 777 that 'fixes' a permissions error is a footgun with a delay on it. Here's how to read the bits and set them on purpose instead.
Appearance preferences are saved in this browser only.
Built with JEKYLL_ENV=production.
Changes require deployment.
| Layout | default |
| Collection | none |
| Path | hacks.md |
| URL | /hacks/ |
Real fixes for real problems — the dev kind and the life kind — with the failed attempts left in.
A real fix for a real problem. Every hack here was actually run, and every one ships with the dead end that came before it. If it didn’t work, it isn’t here — it became a Field Note about why.
The 777 that 'fixes' a permissions error is a footgun with a delay on it. Here's how to read the bits and set them on purpose instead.
Before you paste alias ls='ls --color' into your .bashrc, ask the shell what 'ls' already means. It usually means more than you think.
You found an API key in a committed file, deleted the line, and committed the fix. The key is still there. It was also scraped seconds after you pushed.
Every file starts with a tiny signature that says what it is. Here's how to read it in the shell without a hex editor — and the one keystroke that trims the ...
Which IP hammered the server? Which word repeats? There's a three-stage pipeline for that — and it gives a confidently wrong answer the first two ways you ty...
One character — a trailing slash — decides whether rsync copies a directory or its contents. Add --delete and that same slash decides whether you back up you...
A tarball made with `tar czf x.tar.gz *` has no top-level folder, so it scatters loose files into whatever directory unpacks it. Here's the version that does...
'It worked last week' is a bug report with a timestamp. git bisect turns 400 commits into ~9 tests to find the exact one that broke it — and git bisect run d...
You ran git reset --hard, your commits vanished, and your stomach dropped. They're not gone. git reflog is a private undo log git keeps behind your back — in...
You're mid-change and someone needs a hotfix on main. The reflex is stash, switch, fix, switch back, pop, pray. git worktree checks out the other branch in i...
find | xargs is the first thing you reach for and the first thing that betrays you the day a filename has a space in it. Here's the safe version, with both f...
A script that makes a temp dir and then errors out leaves the temp dir behind. One trap line fixes that — and one wrong trap line tries to rm -rf the root. B...
By default bash shrugs off a failed command and keeps going. Three flags change that — and then bite you twice. Both bites, and both fixes, stay in.
Type make help, see every command the project knows — plus the two failures that make people quit make before it earns its keep.
One command installs a real Linux kernel on Windows. Here's the command, the in-distro check, and the two failures that eat your first morning.
Name your servers once, type ssh web1 forever — plus the ordering gotcha that silently logs you in as the wrong user.
Your CV in LaTeX, in git — minus the dozen build files every compile spits out and the one ordering mistake that commits them anyway.
The survival subset keeps a session alive while you walk away. This is the sequel: getting the layout back after the machine reboots out from under you — and...
The six-line survival config gets you living in tmux. These are the next few lines — each one earns its place by killing one specific daily annoyance.
fzf's whole trick is list | fzf | act. Here are four functions that turn that trick into muscle memory, plus the two ways they bite back.
Add -m and fzf hands back several lines instead of one. That changes the rule we spent the last hack drilling in — quote everything — into knowing when NOT to.
tmux has a hundred-page manual. You need nine commands and a six-line config. Here they are, in the order you'll learn them.
Three lines of shell beat a $9/month developer-workflow app. The bar was on the floor.
Ten aliases, real keystroke math, and one cautionary tale about force-push.
The container died mid-`bundle install` on an ffi build that no longer exists. One bundle lock command fixed it — and the real trap is what you do next.
Two YAML files take your extension from push to Marketplace — plus the headless-display crash that fails every integration test until you fix it.
Excel truncates at a million rows. grep and awk don't care how big the file is — here's the month-end close that fits on one screen.
Skip the 30-minute tutorial. Here are the twelve commands you'll actually type, plus the daemon error that greets everyone on day one.
Treat prompts like code: a file, a structure, a check. Plus the one-character path mistake that makes Copilot silently ignore every rule you wrote.
Four commands to a running React app, a counter that actually counts, and the two error messages that will greet you on the way — with the real fix for each.
A gum menu makes deploy.sh hard to fat-finger. The trick is keeping the dangerous part underneath answerable by a robot, not a human.
A script that works from the repo root and explodes from a subdirectory isn't flaky — it's reading the wrong path. Pin it to its own location instead.
CI cached the whole work/ folder to go faster. It went faster and shipped last week's build. Here's the failure and the layout that fixes it.
FTP-only host, GitHub repo, no money for a fancy pipeline. The CI recipe that bridges them — and the deploy script bug that quietly nukes your live site mid-...
Push a folder, get a website — plus the apex DNS records and the one-line CNAME file everyone fills in wrong.
Rename a post, keep the old link working, and let CI catch the 404 before a reader does.
Get the Front Matter extension building and reloading on your machine — and find out why the guide's npm run dev:ext does nothing and your dev copy fights th...
GitHub Actions hands every job a token. It does not hand that token to the gh CLI. Here's the one-line bridge — and the failure that made it obvious.
macOS still ships bash 3.2. CI runs bash 5. The gap is associative arrays — here's the failure and the fallback, both run for real.
One log.sh, sourced everywhere — plus the readonly crash that happens the second two files pull it in, and the four-line guard that stops it.
You set backup_files to false. jq read it back as true. The // operator is the culprit, and the fix is one line.
The script worked locally and hung in CI. The fix is one word — timeout — plus the set -e gotcha that turns a survivable stall into a dead job.
Five commands to a Django project on GitHub, and the .gitignore that stops you from publishing your SECRET_KEY to the whole internet.
Your script read error['status']['details'] for a year. Then the tool moved the field, and CI died with KeyError. The fix is one helper.
Stop pasting a wall of instructions into the chat box. Put the prompt in a file, build the request with jq, and fix the newline that breaks the body.
Your setup doc already contains every command. Stop copy-pasting them one block at a time — extract them into runnable files in one pass.
One Liquid loop plus forty lines of vanilla JS turns your collections into a filterable, sortable index page.
Group a collection's docs by folder in a sidebar — and find out why the obvious pop trick prints your filenames as folders.
Most data worth having is locked in HTML that was never meant to be queried. Here's the scraper, the dedup trick, and the one malformed row that kills the wh...
Templates tell authors which fields exist. Placeholders fill them in correctly — and grep finds the 600 files that drifted before anyone wired that up.
The whole loop from empty folder to a working command in the palette — and the one-line mismatch that makes your command vanish.
Your robots.txt looks right and crawlers still read it wrong — because Jekyll never rendered the line that matters.
The fix for 'works on the new Ruby' isn't upgrading. It's pinning the four gems that quietly require 3.0 — and knowing which line in the log to read.
Reclaim the top of the viewport on scroll down, get the nav back on scroll up — and the one-pixel jiggle that breaks the naive version.