Graph Model & Providers
- Provider
- Node
- Edge
- File
- Stats
- Query
- SQLiteProvider
- FixtureProvider
Relevant source files · 3
Everything the agent knows about a repository — its files, symbols, and the relationships between them — arrives through one small package: internal/graph. The agent never touches the filesystem or a database directly for code facts; instead it asks a Provider, an interface that abstracts "a codegraph index rooted at some repository" Provider. This abstraction is what makes astrolabe testable end to end: the real pipeline runs against a SQLite index built by the external codegraph CLI, while tests and the agent's reference harness can swap in an in-memory fixture. The agent consumes the interface via its tools, as described in Agent Tools & Budget.
How it works
The data model is deliberately minimal — four value types plus a query. A Node is a single indexed symbol (function, type, route, …) carrying its identity (ID, QualifiedName), location (FilePath, StartLine/EndLine), and presentation metadata (Signature, Docstring, IsExported) Node. Edge is a directed, typed relationship between two node IDs — calls, contains, and friends — with the line where the relationship originates Edge. File and Stats are self-describing: an indexed file with its language, and a files/nodes/edges count triple File Stats. Filtering is expressed through Query, where zero-valued fields mean "no filter": constrain by node kinds and/or file path Query.
The Provider interface is the contract every backend must honor. Open guarantees an index exists and prepares the backend for reads (implementations are explicitly allowed to shell out to the codegraph CLI to build a missing index); Close releases resources; and four read methods — Files, Nodes, Edges, Stats — expose the index Provider. Notably, reading source text is not part of the interface. It is a separate SourceFunc type, so backends stay read-only with respect to the working tree while the agent wires in a simple os.ReadFile-based implementation, ReadSource, which clamps ranges and rejects inverted ones SourceFunc.
SQLiteProvider: the production backend
SQLiteProvider reads a codegraph SQLite database at <repo>/.codegraph/codegraph.db SQLiteProvider. Its configuration is three fields: the repo root, the codegraph binary name (defaulting to "codegraph" on PATH), and a Sync flag — when Sync is false, Open never invokes the CLI and fails if no index already exists, which is how tests that pre-build the index opt out of shelling out. A Logger field receives index build/sync progress.
Open does all the lifecycle work, instrumented as a codegraph.open span. If the database file is missing it either fails (no Sync) or runs codegraph init to build one; if the file exists and Sync is on, it attempts a best-effort codegraph sync — and a sync failure (say, a lock held by another process) is only a warning, since the existing on-disk index is still perfectly readable Open. Subprocess invocations go through runCodegraph, which runs the CLI under a 10-minute timeout from the repo root, records duration/exit-code/success span attributes, and wraps failures with the CLI's combined output runCodegraph. Once the index is settled, Open opens the SQLite file in read-oriented fashion — busy_timeout pragma, a pool capped at 4 connections — and pings it before handing the handle to the read methods Open.
The read methods are thin SQL projections. Files selects the ordered file list, Edges selects all edges, and Stats is a single query of three subselect counts. Nodes is the only one that translates a Query: it builds a WHERE clause from kind IN (...) and file_path = ? conditions dynamically and returns nodes ordered by file path and start line Nodes.
FixtureProvider: the test backend
FixtureProvider is an in-memory provider that serves canned nodes, edges, and files with no codegraph binary or database involved FixtureProvider. Constructed via NewFixtureProvider, its Open/Close are no-ops, and Nodes applies the same Query semantics as the SQLite backend (kind and file-path filtering) over a linear scan. It returns defensive slices.Clone copies so callers can't mutate the fixture, and it adds one convenience beyond the interface: NodeByID for direct lookup in tests Nodes. The sample repository described in Test Fixture (Sample Repo) is the source of the canned data used with this provider.
Relationships
graph TD
subgraph "internal/graph"
Provider["`**Provider** (interface)`"]
SQLiteProvider["`**SQLiteProvider**`"]
FixtureProvider["`**FixtureProvider**`"]
Node["`Node`"]
Edge["`Edge`"]
File["`File`"]
Stats["`Stats`"]
Query["`Query`"]
SourceFunc["`SourceFunc / ReadSource`"]
end
Agent["`internal/agent.Agent`"]
Codegraph["`codegraph CLI`"]
DB[("`.codegraph/codegraph.db`")]
SQLiteProvider -- "implements" --> Provider
FixtureProvider -- "implements" --> Provider
Provider -- "returns" --> Node
Provider -- "returns" --> Edge
Provider -- "returns" --> File
Provider -- "returns" --> Stats
Provider -- "accepts" --> Query
Edge -- "links" --> Node
SQLiteProvider -- "invokes" --> Codegraph
SQLiteProvider -- "reads" --> DB
Agent -- "queries via tools" --> Provider
Agent -- "reads source via" --> SourceFuncReference
| Symbol | Kind | What it does | Location |
|---|---|---|---|
Provider |
interface | Read contract for a codegraph index: Open/Close plus Files, Nodes, Edges, Stats. |
internal/graph/graph.go |
Node |
struct | One indexed symbol: identity, location, signature, docstring, export flag. | internal/graph/graph.go |
Edge |
struct | Directed, typed relationship between two node IDs, with originating line. | internal/graph/graph.go |
File |
struct | An indexed source file and its language. | internal/graph/graph.go |
Stats |
struct | Index summary: file, node, and edge counts. | internal/graph/graph.go |
Query |
struct | Node filter by kinds and file path; zero fields mean "no filter". | internal/graph/graph.go |
SourceFunc / ReadSource |
func type / func | Working-tree source reads, kept out of Provider so backends stay read-only. |
internal/graph/graph.go |
SQLiteProvider |
struct | Production backend: manages the codegraph CLI lifecycle and reads the SQLite index. | internal/graph/sqlite.go |
FixtureProvider |
struct | In-memory provider for tests serving canned data; adds NodeByID. |
internal/graph/fixture.go |
Generated by astrolabe from commit ecc180b3 (tag 0.4.0).