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.

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:
- 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.
- 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.
- Find existing utilities. Before writing a new helper, check if there’s a utility that already does it.
rg --type py "your_query"andrg --type ts "your_query"are the fast searches. - 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.
The cost of skipping the search
Three failure modes that come up when the agent skips the search step:
- 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.
- 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.
- 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
- Don’t add a TODO without first reading existing TODOs. If similar work is in flight, surface the conflict.
- Don’t write a new utility without rg-grep for prior art. Five existing utilities becomes six — drift.
- Don’t rename a function without grep for call sites. The rename breaks callers silently.
- 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
| # | Step | Tool | Confirms |
|---|---|---|---|
| 1 | Recent commits | git log --oneline -20 | Prior attempts? |
| 2 | Recent commits on file | git log --oneline -20 -- path | File-specific history |
| 3 | Repo-wide search | rg -t lang "query" | Pattern usage |
| 4 | Definition | rg -t lang "^def name\b|^const name" | Source of truth |
| 5 | Callers | rg -t lang "name\(" | Who’s affected |
| 6 | Comments / decisions | rg -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:
- 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.
- 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.
- 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
- Hermes Agent docs
- ABS companion: Git Commands an AI Agent Should Know
- ABS companion: Terminal Commands Versus Python: When an Agent Should Write a Script
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.



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.