Version
codebase-memory-mcp 0.10.8
Platform
Windows (x64)
Install channel
GitHub release archive / install.sh / install.ps1
Binary variant
standard
What happened, and what did you expect?
I understand non-git repos aren't currently watched, just throwing this in there to be helpful:
A project indexed from a directory that is not a git repository is never refreshed again. It stays frozen at its first index for the life of the database, and nothing in the API indicates this.
and poll_project() has:
/* Skip non-git projects */
if (!s->is_git) {
return;
}
The problem is not that these projects go stale. It is that going stale is invisible, and a stale graph produces confident wrong answers rather than obviously missing ones. A search_graph for a function that exists on disk returns:
total: 0
hint: "No nodes match this pattern. Check spelling or try a broader regex."
That is indistinguishable from a true negative, so a caller - especially an LLM agent - concludes the symbol does not exist and acts on it. Meanwhile index_status reports "status": "ready" with no last-indexed timestamp and no watched/unwatched flag.
Expected: either non-git roots get some refresh path (an mtime scan fallback), or - much cheaper - the API exposes the coverage, so a caller can decide whether to trust the answer and run an index or whatnot as needed.
Suggested fix:
- Surface it. Add a
watched: true|false field and a last-indexed timestamp to index_status. Callers can then tell "no results" from "no results, and this project has not been checked since Tuesday." This is small and fixes the dangerous part — the silence.
- Fallback scan. For non-git roots, poll a stat-walk signature (
path:size:mtime folded into a hash) on the same adaptive interval already used for git roots. git_dirty_signature() in watcher.c already does essentially this for dirty paths; the non-git case needs the same idea applied to the whole tree.
Additional Context:
Found while building an out-of-process freshness gate to work around this. Happy to test a patch — I have reproductions for both the git and non-git paths.
Reproduction
-
Create a plain directory that is not a git repository:
mkdir /tmp/nogit && cd /tmp/nogit
cat > app.py <<'EOF'
def alpha():
return 1
def beta():
return alpha() + 1
EOF
(No git init - that is the whole point.)
-
Index it:
codebase-memory-mcp cli index_repository --repo-path /tmp/nogit
-
Confirm the graph is populated:
codebase-memory-mcp cli search_graph --project <name> --name-pattern '.*alpha.*'
# -> 1 result
-
Append a function to the file:
printf '\ndef gamma_uniquename():\n return beta() * 2\n' >> app.py
-
Wait as long as you like — minutes, hours, a server restart — then:
codebase-memory-mcp cli search_graph --project <name> --name-pattern '.*gamma.*'
Actual: total: 0, with the "check spelling" hint. Permanently — no poll interval ever covers this project.
Expected: the new function is found, or the response indicates the index may be stale.
Doing the same thing in a git init-ed directory behaves correctly: the
watcher notices and reindexes.
Logs
Diagnostics trajectory (memory / performance / leak issues)
Project scale (if relevant)
No response
Confirmations
Version
codebase-memory-mcp 0.10.8
Platform
Windows (x64)
Install channel
GitHub release archive / install.sh / install.ps1
Binary variant
standard
What happened, and what did you expect?
I understand non-git repos aren't currently watched, just throwing this in there to be helpful:
A project indexed from a directory that is not a git repository is never refreshed again. It stays frozen at its first index for the life of the database, and nothing in the API indicates this.
and
poll_project()has:The problem is not that these projects go stale. It is that going stale is invisible, and a stale graph produces confident wrong answers rather than obviously missing ones. A
search_graphfor a function that exists on disk returns:That is indistinguishable from a true negative, so a caller - especially an LLM agent - concludes the symbol does not exist and acts on it. Meanwhile
index_statusreports"status": "ready"with no last-indexed timestamp and no watched/unwatched flag.Expected: either non-git roots get some refresh path (an mtime scan fallback), or - much cheaper - the API exposes the coverage, so a caller can decide whether to trust the answer and run an index or whatnot as needed.
Suggested fix:
watched: true|falsefield and a last-indexed timestamp toindex_status. Callers can then tell "no results" from "no results, and this project has not been checked since Tuesday." This is small and fixes the dangerous part — the silence.path:size:mtimefolded into a hash) on the same adaptive interval already used for git roots.git_dirty_signature()inwatcher.calready does essentially this for dirty paths; the non-git case needs the same idea applied to the whole tree.Additional Context:
Found while building an out-of-process freshness gate to work around this. Happy to test a patch — I have reproductions for both the git and non-git paths.
Reproduction
Create a plain directory that is not a git repository:
(No
git init- that is the whole point.)Index it:
Confirm the graph is populated:
Append a function to the file:
Wait as long as you like — minutes, hours, a server restart — then:
Actual:
total: 0, with the "check spelling" hint. Permanently — no poll interval ever covers this project.Expected: the new function is found, or the response indicates the index may be stale.
Doing the same thing in a
git init-ed directory behaves correctly: thewatcher notices and reindexes.
Logs
Diagnostics trajectory (memory / performance / leak issues)
Project scale (if relevant)
No response
Confirmations