◉GEMINI LABJP
●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●DEEP RES — deep-research-pro-preview-12-2025 shuts down 10/23, 7 days left. Move to deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●MCP — One write-up cut an 85,000-token tool result to 310 tokens by wrapping it in an ADK FunctionTool●FLASH — gemini-3.7-flash and 3.5-flash now route automatically to newer Flash models (10/08)●NEW — Stop Re-Reading Every Crash Report: Gre…●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●DEEP RES — deep-research-pro-preview-12-2025 shuts down 10/23, 7 days left. Move to deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●MCP — One write-up cut an 85,000-token tool result to 310 tokens by wrapping it in an ADK FunctionTool●FLASH — gemini-3.7-flash and 3.5-flash now route automatically to newer Flash models (10/08)●NEW — Stop Re-Reading Every Crash Report: Gre…
Articles/Dev Tools
⟐ Dev Tools/2026-10-14Intermediate

Stop Re-Reading Every Crash Report: Grep a Known-Bug Table First and Keep Only an Index in GEMINI.md

A routine for investigating app crash reports without making the model read every past bug in full: a one-line-per-bug lookup table, what belongs in GEMINI.md, and a grep helper you can paste in.

gemini-cli7gemini-mdcrash-analysisworkflow12indie-dev48

One morning, with a handful of wallpaper-app crash reports waiting, I noticed I was re-reading the same old bug notes again and again. As an indie developer, most of my triage time goes to confirming "I've seen this before."

So I fixed the order of investigation: grep a known-bug table first, follow the ID to its detail, and record a new bug only when nothing matches. When I hand a crash investigation to Gemini CLI, I give it that same order.

This article covers how I build the table and what I put in (and keep out of) GEMINI.md. The routine is something I run myself while maintaining Dolice's apps. I have not measured time or token savings inside Gemini CLI, so I can't give you numbers.

One bug, one line

Alongside the detailed write-ups, I keep a search-only table. Five columns are enough:

BW-009 | android | crashes at launch only in release | needed resources stripped by shrinking | add a keep rule | detail:bugs/BW-009.md
BW-014 | ios     | full-screen ad stops after navigating back | static holder keeps a destroyed screen | refresh the reference only | detail:bugs/BW-014.md

(These lines illustrate the format; swap in your own IDs and symptoms.)

Keeping it to one line means a grep hit can match on either the symptom wording or the cause wording, and the hit can be pasted straight into a conversation. Details live in separate files that you open only when needed.

Three steps to look something up

  1. Pull two or three terms from the log (exception name, class name, symptom words) and grep them.
  2. Open the detail file for the ID that matched.
  3. Only if nothing matches, assign a new ID and add one line to the table.

Step 3 includes the write-back on purpose. If investigations don't return to the table, the same re-reading happens next time.

How to add a new row

When an investigation ends in no hit, I add a provisional row even before the cause is confirmed, with a trailing ?. Once confirmed, I drop the ? and fix the cause column. If I waited for confirmation, similar reports arriving in the meantime would be counted as new. IDs are just a prefix and a running number, with no meaningful words, so I never have to renumber when my theory of the cause changes.

A grep helper you can paste in

# Put this in ~/.zshrc or similar. Change the path to your own table.
BUGS="$HOME/work/known-bugs.txt"
 
bugfind() {
  # Multiple arguments are ANDed. Case-insensitive.
  [ $# -eq 0 ] && { echo "usage: bugfind <word> [word...]" >&2; return 2; }
  local out; out=$(cat "$BUGS")
  for w in "$@"; do out=$(printf '%s\n' "$out" | grep -iF -- "$w"); done
  if [ -z "$out" ]; then
    echo "NO_HIT: record this as a new bug" >&2
    return 1
  fi
  printf '%s\n' "$out"
}

Two gotchas. grep -F treats the term as a fixed string, so terms with symbols like Foo.bar() work as-is. And returning 1 on no hit lets you branch later: "no hit means go to the new-record step."

Put an index and rules in GEMINI.md, not the table

Gemini CLI gathers GEMINI.md files from several places, concatenates them, and sends them with your prompts. The documentation lists three sources: ~/.gemini/GEMINI.md in your home directory, the current directory and its parents up to the project root, and subdirectories below the working directory. /memory show prints the full concatenated context (Gemini CLI docs).

So I assume anything in GEMINI.md rides along with every question. I don't put the table there. I write only a short procedure:

## Crash investigation procedure
- Before guessing at a cause, grep `known-bugs.txt` (the `bugfind` function, or `grep -iF`).
- Read only the detail file for the matching ID. Do not read the whole table or everything under bugs/.
- Only when nothing matches, propose a new ID and output the line to append to the table.

You can split files with the @file.md syntax, but I expect the imported content to be loaded all the same. Handing over a "search it" procedure rather than a large table should keep the conversation lighter, though I haven't measured that either.

What worked, and what didn't

What worked: the entry point to every investigation became the same. Whoever (or whatever) investigates starts with the table, so known bugs are less often mistaken for new ones.

What didn't: varying symptom wording. The same cause is reported as "crashes," "freezes," or "goes blank." I added alternative phrasings to the symptom column, which helps but doesn't fully solve it. I also added one rule: on no hit, retry once with a nearby term before recording a new bug.

Trying it, in order

  1. Turn your past bugs into one-line rows (the latest ten are enough to start).
  2. Add bugfind and use it once on a real report.
  3. Add the three-line procedure to GEMINI.md and check how it loads with /memory show.
  4. Any investigation that ended in no hit goes back into the table that same day.

Trimming tools is a separate lever from trimming standing instructions, and both matter. For the tool side, see how I decide MCP tool include/exclude; for the basics, the Gemini CLI guide.

Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

⟐ Dev Tools2026-09-29
Gemini CLI Kept Saying 'API key not valid' After I Gave It a New Key — It Was Reading an Old One From a Third Place
I switched Gemini CLI from Google login to a paid API key, and the 400 'API key not valid' error would not go away. The key can come from four places — the shell, a project .env, a home .env, and settings.json — and a short script that lights them up in order narrows the cause to one.
⟐ Dev Tools2026-09-15
The approval rules I had written never matched once — auditing my Gemini CLI policies
A deny rule I trusted for half a year had never matched. The pattern was tested against a JSON string, the folder I kept my rules in is not read, and ask_user turns into deny the moment nobody is watching. Here is the audit, and the script I wrote to keep doing it.
⟐ Dev Tools2026-08-15
Before Adding New iPhone Widths, I Had Gemini Write Out the Branches I Already Had
Adding three new screen widths to four apps turned into an extraction job, not a rewrite. Here is why I let Gemini pull the branch table out of the source and kept every pass/fail decision in deterministic code.