Ingest A Repository

Parse a local checkout into files, symbols, and structural edges, re-run it incrementally as the code moves, and read back whether the graph is current.

Ingest reads a checkout on your machine, extracts its files and symbols, resolves the structural edges between them, and lands the result as rows and edges in your workspace. The steps below cover the first ingest, the re-ingests that follow it, and the check for whether the graph still matches your checkout.

Before You Start

  • The CLI installed and signed in — dots auth whoami should print your identity and company.
  • A local checkout. Ingest reads the working tree on disk; it does not clone from a remote.
  • Authority to write the graph in the active company.

1. Run The First Ingest

SH
dots repo ingest ./my-project

The path is resolved to an absolute path, and everything derived from it is scoped to your active company.

What happens next depends on where you are pointed. Against the local daemon the ingest runs in the background and the command returns immediately. Against a hosted API the checkout is parsed locally, and the resolved graph is uploaded as one compressed object along with the file contents it indexed — scrubbing and content-hash signing run server-side, so the raw bodies travel with the graph. A durable job applies it, and the command polls to completion before printing the written counts. If source must never leave the machine, run against a self-hosted instance or the local daemon.

2. See What Landed

Ingest writes into three Dotabases, and they are ordinary Dotabases:

SH
dots rows list git-repositories --level scan
dots rows list repo-files --level scan
dots rows list code-symbols --level scan

--level scan keeps each row's identity — id, title, icon — and drops everything else, which is what a survey of a machine-generated collection wants: code-symbols is by a wide margin the largest of the three, and reading it whole is a great deal of text for a question the id already answers. Without the flag a listing lands at summary, one tier wider, and --level full restores the whole record once you know which row you want.

One Git Repository row per repository, one Repo File row per source file, one Code Symbol row per function, method, class, interface, type, constant, enum, or variable. Connecting them are the parser's five structural edges — a repository contains files, a file defines symbols and imports_module other files, a symbol calls and inherits from other symbols.

To find a specific symbol's row, search the :

SH
dots search "resolveActor" --dotabase code-symbols

The human id it returns is what the query verbs take. Search answers at summary for the same reason a listing does, so a hit is identity plus classification rather than a whole symbol record — which is all this step needs. Pass --level full when you want to read the symbol instead of traverse from it.

3. Know What Is Not There

A file the extractor does not handle produces no row at all, so check what it covers before reading an absence as a fact about your code:

  • Languages. TypeScript, TSX, JavaScript, JSX, and Python. A file in any other language produces no row at all rather than an empty one. Type declaration files and Python stubs are skipped deliberately.
  • Ignored files. In a git checkout, enumeration runs through git, so .gitignore is respected without any configuration on your part. A directory that is not a git checkout falls back to a glob with built-in exclusions for node_modules, dist, build, coverage, and the usual virtual-environment folders — that fallback does not read .gitignore.
  • Ambiguous references. When a call or import could resolve to several candidates and there is no way to choose, no edge is drawn. A missing is the parser declining to guess.

4. Re-ingest As The Code Moves

Run exactly the same command:

SH
dots repo ingest ./my-project

Re-ingest is incremental and does not rebuild anything. Each file is fingerprinted by a hash of its content — not its modification time — so every path is classified as unchanged, changed, added, deleted, or renamed, and only what actually moved is touched. A re-ingest against an unchanged tree reads no file bodies and writes nothing.

Rows keep their identity across re-ingests, so links you drew by hand survive the code changing underneath them.

A deleted file is retired, not erased. Its row keeps its id and gains an archived stamp, and only the parser's own structural edges are retired with it. Anything else pointing at that row — a manual link, a provenance edge, an agent's inference — still resolves, so deleting code leaves the rest of the graph intact and a traversal recorded earlier still names its endpoints.

5. Check Whether The Graph Is Current

A stale graph returns answers that no longer match the code, so check before trusting a traversal. The Git Repository row records the commit its structural graph was completed at. Compare it to your checkout's HEAD; an agent connected over MCP gets the same answer from the detect_changes tool, which reports each ingested repository's last ingested commit without mutating anything.

When the graph is behind, re-running the ingest is the refresh — dots repo ingest is the single refresh path. Content-hash incrementality keeps a re-run over a mostly unchanged checkout cheap: files whose hashes match are skipped, and only the moved files re-extract.

6. Optional Passes

Two per-repository opt-ins, both combinable:

SH
dots repo ingest ./my-project --embed-symbols --enrich

--embed-symbols embeds this repository's code symbols so they are semantically searchable. Symbols are not embedded by default, which keeps one repository's opt-in from turning on embeddings everywhere. It needs an embedding provider on the target runtime; without one it is a clean no-op — symbols stay pending and embed on a later run, and the ingest itself never fails over it.

--enrich infers cross-context edges between this repository's code and your docs and plans using a language model. It is bounded and cost-capped and needs an LLM provider. On the hosted path it runs as a durable follow-on job enqueued after the graph applies, so the ingest command returns before enrichment finishes — do not read the command's completion as enrichment being done.

Enriched edges are recorded as agent-created and held to a confidence floor with stated reasoning, and they use different edge types from the parser's, so an inference is never mistaken for a parsed fact.

--no-wait returns as soon as the hosted apply job is durably queued instead of polling it to a terminal result. The job runs regardless; the printed job id is how you find it later.

Confirm It Landed

The ingest itself prints the written counts when it completes. Then read the rows it produced:

SH
dots rows list code-symbols --limit 5 --level scan

--limit bounds how many rows come back and --level bounds how much of each, so at scan this check is five ids and titles rather than five whole symbol records.

A repository whose row records your checkout's commit, with symbol rows to show for it, is ready to query. Query the Code Graph is the next step; Repo Graph explains what the model underneath is doing; dots mcp and repo is the full command reference.

Ingest A Repository · This page in the graph

Connected Records12

Documented by
Mentions
DOT
References
12 connections.

Where To Go Next

Reading this as an agent?For Agents
Something wrong on this page?Dots On GitHub