base ast query asks it questions. The difference from grep is that the map knows what a call is, so “everything that calls this” is an answer rather than a text match that also finds the comments.
Map an app once
--target, or from inside the app without it. Tree-sitter covers more than thirty-five languages.
Why it works. The extraction walks the directory, parses each file, and writes entities and relationships to that app’s own map at <app>/.base-ast/ast.ttl. One map per app, not one shared index, which is why two apps in one workspace never overwrite each other’s.
The gotcha. Until an app has been mapped once, nothing queries it and nothing will map it for you. That first run is manual by design.
The four questions
Why it works. Each of these is a different edge in the map rather than a different search.
--calls is walking call edges, which is why it finds the caller in a file that never mentions the function by the name you typed.
Next rung. Everything has a short form: base a q -c "auth" is base ast query --contains "auth". -f, -i and -t cover file, imports and target. --calls has no short form.
Querying another app
--target, the query reads the map belonging to where you are standing. Asking about apps/portal from the workspace root returns nothing rather than an error, which reads exactly like “there is no such function”. If a query comes back empty, check where you are before you conclude anything.
Staying current
Once an app has a map, it refreshes on its own after each turn: a hook re-runs the sync for the app you are in and any app you edited. The gotcha. The refresh is debounced by twenty seconds and never waited on, so a burst of fast turns can skip one. Nothing is lost when that happens, because skipped apps are queued for the next one, but a map can be a few seconds behind mid-burst. Force it withbase sync --ast if that matters.
An app that has never been synced stays unmapped forever. The refresh only maintains maps that already exist.
Where the map lives
<app>/.base-ast/ast.ttl, beside the app, outside both tiers, never merged into graph.nq.
.base-ast/ writes its own .gitignore, so the map excludes itself from version control. Whoever clones the repository has no map until they run base sync --ast themselves, which takes seconds and produces paths that are right for their machine.
If you have seen an “AST graph not yet populated” hint on a workspace you know is mapped, that was a real bug: the hint checked the pre-migration path while queries checked the correct one, so it fired forever no matter what you did. It is fixed as of the shipped release, and the check now resolves the same way queries do. Verified from source at
4866996.A current hint means the workspace genuinely has no map. base ast list settles it either way.Repairing the graph’s view of a map
Next
Querying the graph
Asking open questions, and walking the graph node by node.
Code reference
Every
base ast and base sync flag.