Skip to main content
  1. Posts/

Four review claims sounded right. Each took two minutes to disprove.

··1323 words·7 mins·
Nick Liu
Author
Nick Liu
Building infrastructure for Facebook Feed Ranking at Meta. Previously at Walmart, Twitter, AWS, and eBay. MS in Computer Science at Georgia Tech.
Table of Contents
Hardening My Dotfiles - This article is part of a series.
Part 4: This Article
After a month of overhauling my dotfiles with AI in the loop, the real value was not "the AI writes my configs". It was two much more boring properties: the research side keeps finding things I cannot see, and I verify every claim it makes before acting. Skip the first and you only ever fix problems you already knew about. Skip the second and a plausible-sounding wrong answer walks you into a ditch.

The loop
#

claim fails verification

breadth research on the desktop side
(changelogs, issues, ecosystem)

local verification, claim by claim,
on the machine itself

decisions converge through structured
questions: options, tradeoffs, defaults

implement

tests are mandatory,
not optional

PR, with CI as the final gate

discard it,
with evidence

claim fails verification

breadth research on the desktop side
(changelogs, issues, ecosystem)

local verification, claim by claim,
on the machine itself

decisions converge through structured
questions: options, tradeoffs, defaults

implement

tests are mandatory,
not optional

PR, with CI as the final gate

discard it,
with evidence

The two arrows that matter are the verification one and the discard one. Here is what flowed through them in one month.

Verification beats plausibility
#

Four review claims from the month, all of which sounded reasonable, all of which died on contact with the machine:

The claimThe two-minute disproof
yazi --version does not parse the config, so it is useless as a canary”replayed a broken config through YAZI_CONFIG_HOME: broken exits 1, clean exits 0
“the tmux throwaway-server check will pollute resurrect’s saved sessions”ran it three times; the save directory did not change at all
tmux.conf is missing bind C-a send-prefixit is on line 43
“you should add this rg option”the option was already in the config; the reviewer had not read the file
# claim: yazi --version does not parse the config
# method: replay a broken config in isolation, watch the exit code
YAZI_CONFIG_HOME="$broken" yazi --version; echo "$?"   # 1
YAZI_CONFIG_HOME="$clean"  yazi --version; echo "$?"   # 0
# claim: tmux.conf is missing send-prefix
grep -n 'send-prefix' ~/.tmux.conf    # 43:bind C-a send-prefix

A plausible answer and a correct answer look identical on the page. The only visible difference is whether you ran the check, and the check consistently costs about two minutes. That ratio, two minutes against a wrong config shipped, is the entire economics of the verification habit.

But the research side finds real gold
#

If the previous section makes the AI sound like a liability, here is the other direction, because both halves of the loop earn their keep.

The research pass discovered that my entire ripgrep config had been dead the whole time: RIPGREP_CONFIG_PATH was never exported. A config file, carefully maintained, read by nothing.

export RIPGREP_CONFIG_PATH="$HOME/.config/ripgrep/config"

The more important discovery was that enabling it blindly would have caused an incident. The dormant config contained output flags like --pretty and --context. The moment the config went live, every scripted and piped rg call on the machine would inherit pretty-printing and context lines. So activation had to start with a cleanup, and the principle went into the file as a comment:

# Output Format
# =============
# Deliberately EMPTY: this config shapes what gets searched, never how
# results print. Output flags (--pretty/--column/--context) would leak
# into piped and scripted rg calls the moment the config is active.

The same research flow also uncovered that herdr splits its config reading between client and server under --remote, something a month of local usage had not surfaced. That one gets its own post next in this series.

The dormant-tool pattern, three times in one month
#

The dead ripgrep config was not a one-off. The same shape appeared three times:

  • A mergiraf merge driver, fully defined in git config, whose activating gitattributes line was never written. Dormant for a year.
  • television installed, with zero wiring into the shell.
  • The ripgrep config above, never exported.

Installed but not wired is the most expensive kind of tool: you paid the full selection cost and collected none of the return. All three now have pairing tests, on the principle that a definition and its activation must exist together or the check goes red:

# mergiraf must be wired end-to-end: the attributes line without the
# driver (or vice versa) is a dormant config.
run_test "mergiraf attributes/driver pairing" \
    "grep -q 'merge=mergiraf' $HOME/.config/git/attributes && \
     grep -q 'merge \"mergiraf\"' $HOME/.config/git/config"

television additionally got a role declaration, so it does not blur into fzf’s territory:

# television's explicit role: full-text CONTENT search entry point
# (fzf owns filename/history flows — no overlap, one entry each)
if command -v tv &> /dev/null; then
    alias tvt='tv text'
fi

Who does what: the delegation economics
#

The division of labor that settled in: the frontier model plans, verifies, and commits. Cheaper models run well-specified batch work. In practice that meant opus ran audits and migrations, including the bootstrap idempotency audit that surfaced 12 defects in one pass (one of them a nested-symlink bug that got reproduced in a sandbox before anyone touched the fix). sonnet handled mechanical batches: README splitting, doc generation, migrations.

Small config edits stayed in the main loop, because writing a delegation spec for a two-line change costs more than the change.

The trust signal that actually moved the needle was not capability. It was whether an agent stops. One agent was asked to modify a README section that had, unbeknownst to the spec, already moved into docs/. It declined to guess, came back, and asked. Delegation volume went up after that, because an agent that halts on spec-reality mismatches is one you can hand bigger specs.

The multi-agent hazard that actually happened
#

Two Claude sessions were working on the same yadm repo. Each swept the other’s staged files into its own commit. This happened twice, and the second time is the instructive one: a file staged in advance got carried away by two unrelated commits in the same evening.

The root cause is not a bug anywhere. All sessions share the single yadm index, and yadm commit takes everything currently staged, regardless of who staged it. The tool behaves exactly as documented. The information “who staged this” simply does not exist in the system, so no tool-side fix is possible.

Which is why the fix is procedural, and why it graduated from “remember to check” to a mandatory step after the recurrence:

yadm diff --cached --name-only

Before every commit, no exceptions, plus a one-committer-at-a-time rule. A mistake that recurs in the same evening does not get fixed by resolving to remember harder. It gets fixed by an extra line in the procedure.

The month in numbers
#

About 30 single-concern commits across five PRs (#54, #63, #64, #66, #69). The test suite grew from 74 checks to 105. Six documentation pages got extracted. And every incident in this post exists in the suite as a named test, which by now is the house style of this whole series.

Lessons
#

  • A plausible answer and a correct answer are indistinguishable until you run the check. The check costs two minutes; budget for all of them.
  • Research and verification are the same loop running in opposite directions. One finds what you cannot see, the other kills what is not true.
  • Installed but not wired is worse than not installed. Pair every definition with its activation in a test.
  • A config file decides what gets searched, never how results print. The second half of that sentence is where the incident was hiding.
  • Judge an agent by whether it stops when the spec and the repo disagree. The one that asks is the one that gets more work.
  • When a process error recurs on the same evening, stop relying on memory and add a line to the procedure.

References
#

Hardening My Dotfiles - This article is part of a series.
Part 4: This Article

Related

Running six agents made tab patrol my biggest time sink. So: a herdr trial.

Once I had six Claude Code sessions open at once, the most expensive part of my workflow was not writing code. It was patrol: cycling through tabs to see which agent was still running and which one had been sitting on a question for ten minutes. tmux has no concept of any of this. To tmux, every pane is a rectangle of terminal, equally interesting, equally mute. herdr’s pitch lands exactly on that pain: panes are still real terminals, but a sidebar shows each agent’s live state. So it got a one-month trial, with exit conditions written down before it started. The verdict lands on August 16, and this post is honest about still being inside the window.

Stop burning your best model's tokens on grep

··1070 words·6 mins
I kept slamming into my Claude subscription's usage limits, and the workload didn't feel heavy enough to explain it. The culprit was allocation, not volume: my main session ran on the most capable model available, and that model was also doing the grep runs, the batch edits, and the yes/no verification passes. Flagship reasoning, billed at flagship rates, spent on work a model a tenth the price does identically well. 🧪 Tested with Claude Code 2.1.x · macOS Where the tokens actually go # Two things surprised me when I looked at my consumption honestly.

Git worktrees gave each Claude agent its own sandbox. And scattered my sessions.

··978 words·5 mins
I run four or more Claude Code agents at once, and until recently they all shared one working tree. Two agents editing the same repo means one of them eventually builds against the other's half-finished changes. Git worktrees fix that cleanly. What nobody warned me about is that the fix multiplies a different problem I already had: forgetting which folder a session lives in. Taming Claude Code Sessions · Part 5 of 6 1 2 3 4 5 6 🧪 Tested with Claude Code 2.1.x · macOS The symptom # With several agents in one directory, the working tree is shared mutable state. Agent A refactors a partial, agent B runs the build, and B’s “failure” is really A’s work in flight. I had been dodging this by scoping agents to different subdirectories, which works until it does not.