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 whoamishould 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
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:
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 :
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
.gitignoreis respected without any configuration on your part. A directory that is not a git checkout falls back to a glob with built-in exclusions fornode_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:
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:
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:
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
- mentionstoDots
- mentionstoEdge
- mentionstoDotabase
- mentionstoDIIICE: Context
- mentionstoDOT
- referencestoDOTs And The Knowledge Graph
- referencestodots mcp, dots repo, and dots graph
- referencestoQuery The Code Graph
- referencestoRepo Graph Overview
- documented byfromLocal Repo Ingest into the Code Knowledge Graph
- referencesfromRepo Graph Overview
- referencesfromQuery The Code Graph