Repository navigation
plugin: hooks find the graph from the path a tool touched (#1453) - #1624
Merged
Merged
Conversation
…e session directory Every hook looked for .axiomcode/out/graph.sqlite in the session's working directory only. Agents work from a directory with no graph and reach indexed trees by absolute path, so the hooks almost never spoke. hooks/_where.py finds the repository for each event: from the Read / Edit / Write file_path, the Grep / Glob path, the graph tools' repo, or a shell command's `cd` and existing path arguments. It walks up from the real path to the nearest main or per-language graph, and falls back to the working directory only when the tool named no path. Found roots are cached per directory for the session; "no graph" is not cached, so a graph built mid-session is seen at once. - enrich.py, direct.py, changes.py, refresh.py use it; state, budget and log files live in the repository's .axiomcode. - A file whose language has its own graph is answered from it. - direct.py is silent on a shell read whose files are all non-source. - orient.py finds the graph from an absolute path in the prompt, counts .cs files (#1453), and does not report "no graph" for a workspace holding an indexed project. tests/hooks_from_path.py: 26 checks with near-miss controls (no graph above, a path above the root, a symlink out of the indexed tree).
swapnilpaliwal-sd
requested review from
JaredHLZhang,
Whua689 and
suyashpaliwal26
as code owners
September 28, 2026 08:48
…utput is skipped The Java source walk pruned every directory named `build` by name (EXCLUDED_DIRS), so a real package such as src/main/java/app/build was never parsed and every call into it was unresolved. Case 62 carried the gap in its blessed .edges golden; only CI's bytecode oracle saw the two missing StepBuilder edges. A `build` directory is now skipped by the Java walk only when it is a Gradle project's or module's output: a `build` beside build.gradle(.kts) or settings.gradle(.kts), anchored on its owner the way `target` is anchored on a pom.xml (utils/generated-output.ts isGradleBuildOutput). The refresher's file table (ax_fresh.py) applies the same rule, so freshness and the language count agree with the parser. Case 62 now resolves both StepBuilder edges (.edges, .type-use re-blessed, .oracle added); case 63 gets its missing .oracle golden; new case 64 is a Gradle project with a root and a module build/generated source (skipped) and a `build` package in each (read).
This was referenced Sep 28, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1453
What was wrong
Every hook (orient, direct, enrich, changes, refresh) looked for
.axiomcode/out/graph.sqlitein the session's working directory only. Agents rarely work there. They start in a directory with no graph and read, grep and edit files in indexed trees by absolute path. Measured over 190 agents: 2,115 graph calls, and the hooks injected 3 times in total. One was a directive fired by acatof a Markdown file. The other two were orientation loads. There were 0 Read or Grep enrichments. 308 of 309 sessions had a working directory with no graph.Two smaller defects in the same place:
direct.pyfiltered a Read by source extension but not a shell read, socat NOTES.mdgot the directive.orient.pycounted no.csfiles (csharp: the prompt hook never says a C#-only tree has no graph yet, because orient.py's extension list omits .cs #1453). It also told a workspace directory holding an indexed project that it had no graph.The change
New
hooks/_where.pyfinds the repository for each event:file_path, Grep/Globpath, the graph tools'repo, and for a shell command its lastcdand path arguments that exist..axiomcode/lang/<lang>/out/graph.sqlite).A path with no graph above it stays silent, even when the working directory has one, because a search of another tree says nothing about this graph. A symlink into an indexed tree answers from the real graph. A symlink out of it stays silent.
Each hook uses it:
.axiomcode, so they are kept per repository.refresh.pyalso refreshes the repositories the session worked in on events that name no path.orient.pyalso finds the graph from an absolute path in the prompt.Found roots are cached per directory for the session. "No graph" is not cached, so a graph built mid-session is seen on the next read. An uncached walk is under 1 ms.
Tests
tests/hooks_from_path.py: 26 checks, all passing. The layout is a workspace with no graph, an indexed project inside it, an unindexed copy, and symlinks.path=,sed -nby absolute path,cd <project> && grep, and a relative path.catof a non-source file, and a 5-file C# tree.directive.py,enrich_budget.py,enrich_lines.py,mcp_first.py,hosts.py,no_symlink.py, andrefresh.pyfor Python, Java and C#.python_names.pyhas one failure. It fails the same way on the unchanged base.Smoke (Python, Java and C# project copies, fresh index)
Setup: a headless session whose working directory has no graph. The task was to Read one file in an indexed copy by absolute path, then Grep a name there. Before is the installed plugin; after adds this branch with
--plugin-dir.entry (http))Hook latency (median of 20 runs, Read enrichment): 118 ms before with the working directory in the repo. After: 105 ms with it in the repo, 109 ms with it outside. The path lookup is 0.2 ms.
Deep scan deferred: the corpus-wide regression gate was not run for this change.