guide · computers

Search the Codebase Before Fixing Anything

Before fixing any bug, search the codebase for prior attempts, related patterns, and existing utilities. The agent's most expensive mistake is fixing the wrong layer. A 4-step search workflow.

July 14, 2026 · By Alastair Fraser

A friendly retro robot holding a giant magnifying glass over a sprawling codebase that looks like a city plan, shining the magnifying glass on three glowing search-result spots. Below the magnifying glass, the robot holds a small fix-it tool that is visibly secondary to the search. A banner across the bottom reads FIX LATER, SEARCH FIRST.

The 4-step search workflow

When the agent sees a bug or behavior change to address, the fix isn’t the first thing. The first thing is search the codebase for prior context. Four steps:

  1. Find prior attempts and their failure. Are there TODOs, FIXMEs, or commented-out attempts that addressed this? Did a recent commit regress something working? The git log is the first place to look.
  2. Find related patterns. If the bug is “X doesn’t update on Y event,” find every existing handler for “Y event” and see how they update X-like state. The convention is already chosen.
  3. Find existing utilities. Before writing a new helper, check if there’s a utility that already does it. rg --type py "your_query" and rg --type ts "your_query" are the fast searches.
  4. Find the consumer / caller. Understand who calls the function you’re about to change. A “fix” that breaks a caller is worse than the original bug.

After these four searches the agent has:

  • A reading-list of what to know.
  • A pattern to follow.
  • A confirmation that no helper already exists.
  • A list of callers to verify.

Then — and only then — does the fix get written.

Three failure modes that come up when the agent skips the search step:

  1. Fixing the wrong layer. The agent writes a workaround in the input layer when the bug is in the parser. The fix passes the test, the bug returns in production.
  2. Reinventing an existing utility. The agent writes a 20-line helper for what already exists as a 1-line call to a utility function. The duplication creates drift.
  3. Breaking a caller. The agent “fixes” a function by tightening its signature. Callers that depended on the loose form now throw.

Each of these is recoverable but costs time. Skipping the search step adds an investigation pass after the “fix” has shipped — always more expensive than searching first.

The tools in order

For a Python codebase:

# 1. Recent commits
git log --oneline -20

# 2. Search the AST (faster than grep for some patterns)
rg -t py "the_symbol_or_string" --max-count 50

# 3. Find the def / class definition
rg -t py "^def the_function\b|^class TheClass\b"

# 4. Find callers
rg -t py "the_function\(" --invert-match "def the_function"

For TypeScript/JavaScript (the Astro site):

git log --oneline -20
rg -t ts -t tsx -t js "theSymbol"
rg -t ts -t tsx -t js "function theFunc\(|const theFunc ="
rg -t ts -t tsx -t js "theFunc\(" --invert-match "function theFunc\("

For Markdown content (the guide articles):

git log --oneline -20 -- src/content/posts/the_slug.md
rg "the term" --type md src/content/posts/

The git log step is universally the first — it tells you whether someone tried this and walked it back.

The “prior attempt” check

A common shape that sinks fixes: the bug is real, but a prior commit fixed it temporarily and was reverted because the fix caused a regression. The git log --all view shows that:

git log --all --oneline -- path/to/file

The --all flag shows commits across every branch, including dropped ones. A “fixed in X, reverted in Y” pattern appears as two commits in the log. Reading the revert’s reasoning in the commit body gives the team memory of why the original fix was wrong.

The “is this a real bug or a design decision?” check

Some “bugs” are actually design decisions documented in code comments. Before fixing:

git log --all --oneline -p -- path/to/file | rg -B 2 -A 5 "the relevant comment"

If the comment block says “intentional: see #N,” the agent doesn’t fix — the agent surfaces the design decision to the operator.

What the agent does NOT do without searching

  1. Don’t add a TODO without first reading existing TODOs. If similar work is in flight, surface the conflict.
  2. Don’t write a new utility without rg-grep for prior art. Five existing utilities becomes six — drift.
  3. Don’t rename a function without grep for call sites. The rename breaks callers silently.
  4. Don’t delete a file without rg-grep for imports / references. A dead import in another module still compiles; the runtime exception is downstream.

Verification checklist

#StepToolConfirms
1Recent commitsgit log --oneline -20Prior attempts?
2Recent commits on filegit log --oneline -20 -- pathFile-specific history
3Repo-wide searchrg -t lang "query"Pattern usage
4Definitionrg -t lang "^def name\b|^const name"Source of truth
5Callersrg -t lang "name\("Who’s affected
6Comments / decisionsrg -B 2 -A 5 "relevant_text"Is this intentional?

When the codebase itself is the bug

Sometimes the search reveals that the codebase doesn’t have the helper, the pattern, or the convention that should exist. That’s information too. Three reactions ranked by blast radius:

  1. Note it, defer the fix. Flag the gap in the agent’s research output to the operator; don’t expand scope to address it on the same task.
  2. Patch in a small utility at the same layer. If the work requires the helper and the gap is small, add it; commit it as a separate logical change to keep revert-ability.
  3. Refactor the calling layer instead. Highest blast radius — only when the gap is at the abstraction boundary and the operator approves.

The agent doesn’t pick option 2 or 3 on its own. Option 1 is the default unless explicitly asked otherwise. The search may surface the gap, but the agent does not silently grow the change.

Sources

Last verified: 2026-07-14 against the ABS site repo at /srv/abs-site and the Python repo at /opt/abs-backend/ on this VPS.

Sources

#search#fix#agent#discipline#pattern

Submit a take

Have a different read on this? Drop a comment below — your email isn't published, and I read every one. Nothing leaves the site until I approve it.

Your email address will not be published. Required fields are marked.