The code graph¶
Veska parses your repository with tree-sitter and stores it as a graph: nodes (the things in your code) connected by edges (the relationships between them). Everything else - search, blast radius, the wiki, promotion checks - is a query over this graph.
Nodes¶
A node is a single addressable thing: a function, method, type, file, route, command, and so on. Every node carries enough to locate it in your source:
- a stable id,
- a kind (e.g. function, type, file),
- a name,
- a file path and line range (
line_start/line_end).
When a tool returns a node, those fields are what let your editor or agent jump straight to the definition - no guessing function names.
Edges¶
An edge connects two nodes with a kind that names the relationship - a call edge from one function to another, a containment edge from a file to the symbols it defines, and so on. Edges are what make structural questions answerable: "what calls this?", "what would break if I change this?", "where does control enter this package?"
Querying the graph¶
You rarely touch the graph directly. You query it through tools and commands:
| Want to… | Use |
|---|---|
| Find a symbol by name | eng_find_symbol / veska symbol |
| See a file's symbols | eng_get_file_nodes / veska file-nodes |
| Trace callers/callees | eng_get_call_chain / veska calls |
| Estimate change impact | eng_get_blast_radius / veska blast |
| Search by meaning | eng_search_semantic / veska search |
See the CLI reference and MCP tools reference for the full surface.
Adding a node or edge kind
Kinds are open-ended (nodes.kind / edges.kind are unconstrained text),
so new kinds need no database migration - they ripple through a handful of
domain and query sites instead. This is an internals detail; see the design
set if you're extending Veska.
Next: Promotion & staging - how the graph stays current as you edit and commit.