{"slug": "my-coding-agent-kept-searching-the-same-repo-again-and-again-so-i-gave-it-a", "title": "My coding agent kept searching the same repo again and again, so I gave it a memory", "summary": "A developer built Engram, a tool that indexes a code repository into a FalkorDB graph and feeds Claude Code a roughly 200-token map of likely locations before its first tool call, cutting a sample click bug fix from 4 tool calls and 112,298 tokens to 2 calls and 75,733 tokens. The developer's own measurements across 83 sessions and 32,713 tool calls found 31% were searches and 44% of file opens re-read a file already seen in the session. The writeup also reports that an early benchmark was invalidated because the agent read the injected bug via git diff, and that a 1,600-token context injection raised token use until it was cut to a six-line map.", "body_md": "I use Claude Code every day. And one thing kept bugging me.\n\nI gave it a small bug in a CLI library. Before it touched anything, it made 32 tool calls. grep, sed, cat, grep again. That one run used 1,052,132 input tokens. For a tiny fix.\n\nSo I went and counted my own sessions. 83 sessions, 32,713 tool calls. 31% of them were the agent just searching. The median was 24 searches before the first edit. And 44% of the time it opened a file, it had already read that file in the same session.\n\nThe next day, similar question, same repo. It did the same search again.\n\nThat's what I built Engram for, in the Graph Hacks hackathon (WeMakeDevs × FalkorDB).\n\nEngram turns a repo into a graph in FalkorDB. Three kinds of things go in:\n\n``` php\n(:File)-[:DEFINES]->(:Symbol)-[:CALLS]->(:Symbol)\n(:File)-[:IMPORTS]->(:File)\n(:Person)-[:AUTHORED]->(:Commit)-[:TOUCHED]->(:File)\n(:File)-[:CO_CHANGES {count, weight}]->(:File)\n(:Agent)-[:RAN]->(:Session)-[:READ|EDITED]->(:File)\n(:Session)-[:LEARNED]->(:Lesson)-[:ABOUT]->(:File|:Symbol)\n(:Session)-[:CLAIMS {since}]->(:File)\n```\n\nThen, before the agent makes its first tool call, it gets a short map. Around 200 tokens. Just where to look.\n\nThis is the real map it gave Claude Code for one click bug (\"`click.Choice([\"Apple\", \"Banana\"], case_sensitive=False)` rejects `apple`\"):\n\n```\n[engram] Likely locations for this task (code graph, confidence high):\n- src/click/types.py:406-424 Choice.normalize_choice\n- src/click/exceptions.py:51-52 ClickException.format_message\n- src/click/types.py:381-386 Choice.to_info_dict\n- src/click/types.py:495-515 Choice.shell_complete\nTests: tests/test_types/test_Choice.py\n```\n\nWithout Engram, the agent did grep, grep, sed, then the edit. 4 tool calls, 112,298 tokens.\n\nWith Engram: read the file, edit, done. 2 tool calls, 75,733 tokens. Tests passed in both.\n\nHonestly this part taught me more than the parts that worked.\n\n**My first benchmark was fake.** The agent fixed every bug super fast. Too fast. Then I read one of its answers and it said it \"reverted the uncommitted edit\". It had just run `git diff` and seen the bug I injected. So every run now gets a fresh copy with a single commit, the agent only sees a bug report like a user would write it, and a fix only counts if the whole test suite passes.\n\n**More context made it worse.** My first version gave the agent 1,600 tokens of code and history up front. Tokens went up, not down. Whatever you inject gets re-read on every turn after that, so in a 6-turn session that's around 10k tokens. I cut it down to a map of 6 lines. Claude Code has to Read a file before editing it anyway, so pasting code in never saved a single call.\n\n**Bugs hide where names don't match.** At first I matched words from the bug report to function names. That found the buggy function in the top 3 only 5 times out of 12. Bugs sit in big functions and private helpers. In networkx, the report says `dijkstra_path_length` but the bug is in `_dijkstra_multisource`, three calls down. That's not something grep finds. It's a graph walk:\n\n``` php\nMATCH p = (s:Symbol {id: $api})-[:CALLS*1..4]->(n:Symbol)\nWHERE all(x IN nodes(p)[1..size(nodes(p)) - 1] WHERE size(x.callNames) <= 6)\nRETURN n.qualname, min(length(p)) AS hops\n```\n\nAfter that, on networkx the buggy function was in the top 10 for all 6 bugs. No LLM involved.\n\n**Memory made it worse too, at first.** I stored \"the test command that worked\" after each task. But I stored the exact command (\"pytest tests/test_types.py\"), not the general one. So the next task ran the wrong tests, they passed, and the agent got confused. Now it stores the general command and the graph picks the right tests for each edit.\n\n**The graph doubled itself.** On a bigger repo I saw the same function listed twice in a map. Two indexers had run at the same time and both inserted everything. I reproduced it: 19,508 symbols instead of 9,754. The fix ended up being one Cypher write, because FalkorDB runs writes on a graph one at a time, so only one process can win:\n\n```\nMERGE (l:IndexLock {k: 1})\nWITH l, (l.owner IS NULL OR l.at < $stale) AS free\nSET l.owner = CASE WHEN free THEN $me ELSE l.owner END,\n    l.at    = CASE WHEN free THEN $now ELSE l.at END\nRETURN l.owner = $me AS got\n```\n\nI ran Claude Code (claude-haiku-5-5) on 12 real bugs I injected into pallets/click, 3 times each, in 4 setups. 144 runs.\n\n| Setup | Fixed | Input tokens | Tool calls | Time | \n|---|---|---|---|---|\n| Claude Code | 36/36 | 137.6k | 5.1 | 16.4 s | \n| + codebase-memory-mcp (47k★) | 36/36 | 126.9k | 4.7 | 13.4 s | \n| + Engram | 35/36 | 103.5k (−25%) | 3.6 (−29%) | 12.7 s (−23%) | \n\nOn networkx (128k lines, 6 bugs): −24% tokens, −40% tool calls, −36% time.\n\nWhat actually goes away is the searching. Search calls per bug went from 3.4 to 1.7.\n\nAnd yes, it missed one fix out of 36. That was my fault. The map showed a 5-line wrapper function and only mentioned the real function as \"the next call\", so the agent fixed the wrapper. I changed it so the real function gets its own line. I didn't re-run the whole benchmark after that, so I'm keeping 35/36.\n\nInjected bugs are one thing. I wanted to see it on code I never touched, with bugs real people reported.\n\nyt-dlp: 1,128 Python files, 248k lines, years of community patches. I indexed it as of 30 April (took 4 seconds) and took every fix after that which closes a GitHub issue. Engram only gets the issue the user wrote, and I check it against what the maintainers actually changed.\n\nOne small thing I learned here: in a GitHub issue the title matters most. A long description full of words like \"download\" and \"video\" was drowning out the one useful word in the title. Now title words count double.\n\nIf two agents try to edit the same file, the second one gets stopped. This is the actual message Engram's hook sent back when a second agent session tried to edit a yt-dlp file the first one had claimed:\n\n```\nEngram: yt_dlp/extractor/bandcamp.py is being edited by claude-code-agentC right now.\nWork on something else or wait; do not edit this file.\n```\n\nSame trick as the index lock, one Cypher write.\n\nI needed the graph to answer before every single prompt, without the agent waiting. Multi-hop walks and PageRank come back in milliseconds (my queries take 1 to 40 ms). One query after each edit joins git history, what this session edited, and the call graph, in about 11 ms. Locks between agents are just writes. One graph per repo, many repos in one instance. And FalkorDBLite, their embedded build, means people don't need Docker at all. It uses 43 to 60 MB of RAM with two repos loaded.\n\n```\ncurl -fsSL https://raw.githubusercontent.com/ManojRakshu/engram/main/install.sh | sh\n```\n\nNo Docker, no API keys, and Engram itself never calls an LLM. It connects to Claude Code, Cursor, Codex, Gemini CLI, VS Code and any MCP client it finds.\n\nCode, the benchmark harness and all the raw results are here: [github.com/ManojRakshu/engram](https://github.com/ManojRakshu/engram). There's also a [30-second version of the video](https://youtube.com/shorts/aSS2mSwJzmI).\n\nI'm curious: what does your agent waste the most calls on? Searching, re-reading files, running the wrong tests? Tell me, that's what I want to measure next.\n\n*I used Claude Code as a coding assistant while building this.*", "url": "https://wpnews.pro/news/my-coding-agent-kept-searching-the-same-repo-again-and-again-so-i-gave-it-a", "canonical_source": "https://dev.to/manoj_shetty/my-coding-agent-kept-searching-the-same-repo-again-and-again-so-i-gave-it-a-memory-481g", "published_at": "2026-10-18 11:11:26+00:00", "updated_at": "2026-10-18 11:15:12.624102+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "ai-infrastructure"], "entities": ["Engram", "Claude Code", "FalkorDB", "WeMakeDevs", "Graph Hacks", "networkx", "click"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/my-coding-agent-kept-searching-the-same-repo-again-and-again-so-i-gave-it-a", "markdown": "https://wpnews.pro/news/my-coding-agent-kept-searching-the-same-repo-again-and-again-so-i-gave-it-a.md", "text": "https://wpnews.pro/news/my-coding-agent-kept-searching-the-same-repo-again-and-again-so-i-gave-it-a.txt", "jsonld": "https://wpnews.pro/news/my-coding-agent-kept-searching-the-same-repo-again-and-again-so-i-gave-it-a.jsonld"}}