Grounding Guide

What a repository sync reads, in priority order, and what it never touches

By the engineer who builds Datadef, from client work on data platforms · Reviewed August 21, 2026

A generated diagram is only as trustworthy as the reading behind it, and most tools are vague about that on purpose. This is the specific version: which classes of file are read, in what order, under what caps, what is skipped outright, and the consequence that follows from all of it.

6 min readFor anyone reviewing a generated diagram and asking where did that come from

See it as a diagram

Everything below, as a diagram you can edit. Describe yours and see it in seconds.

145/20003 credits left
Try:

No account needed · Editable canvas, not a picture

The priority ladder

Architecture concentrates in a small number of files, and they are not the ones with the most lines. The sync walks the tree once, classifies each file, and then takes files in priority order until the budget runs out. The order is deliberate: declarations of what exists come before descriptions of what someone thought existed.

Infrastructure as code first, because a .tf file, a serverless.yml, or a CloudFormation template names real resources. Containers and orchestration second: Dockerfiles, compose files, Kubernetes and Helm YAML. Data third: a dbt project with its models, SQL definitions, a Prisma schema, sampled migrations. APIs fourth: OpenAPI and Swagger specs, proto files, GraphQL schemas. CI fifth, since a workflow file names the environments and the deploy steps. Dependency manifests sixth. Prose last, meaning READMEs and docs directories, which are read for naming and intent rather than believed as fact.

That last ordering choice is the one that matters most. Prose is where drift lives. Putting it below the declarations means a README paragraph describing a service that was deleted two quarters ago does not outrank the compose file that no longer contains it.

Two rules in that table surprise people, so they are worth saying out loud. Deployment YAML is recognized by the directory it sits in, not by its content, so a kustomization.yaml at the repository root is not classified while the same file under k8s/base is. And the docs class matches on the filename: docs/adr/architecture-decisions.md is read, docs/architecture/overview.md is not, because the name that has to start with architecture is the file name.

                                                                    cap
1  infrastructure as code    *.tf, serverless.yml, cdk.json, Pulumi     12
2  containers                Dockerfile*, docker-compose*                6 + 6
                             YAML under k8s|kube|kubernetes|            12
                             manifests|charts|helm
3  data                      dbt_project.yml                             2
                             *.sql under models/                        12
                             other *.sql                                10
                             prisma/schema.prisma                        2
                             */migrations/*.{sql,py,js,ts}               6
4  APIs                      openapi.*, swagger.*, *.proto, *.graphql   10
5  CI                        .github/workflows/*, .gitlab-ci.yml,        8
                             azure-pipelines*.yml
6  manifests                 package.json, pyproject.toml, go.mod,       8
                             pom.xml, Cargo.toml, composer.json
7  prose                     readme* at any depth                        5
                             docs/**/architecture*                       4

The caps, and why they are fixed

Up to 40 files, 250KB in total, 30KB per file. A file longer than that is cut and marked in place with the line "[... truncated at 30KB by Datadef repo sync ...]", so a reader of the corpus can tell a short file from a shortened one. Anything over 400KB is skipped before it is fetched wherever the provider reports sizes, and re-checked after the fetch where it does not.

Each class also carries its own ceiling, the right-hand column above, which is what stops a repository with two hundred dbt models from spending the whole budget on models and never reaching the file that says how the thing deploys. Those ceilings shift when a diagram is set to the architecture or content focus, but they are fixed for a given focus rather than adaptive: the same repository at the same commit produces the same corpus, and a diagram that changed is a diagram whose source changed.

Migrations are the one class not read from the top. The budget is split between the two ends of the sorted list, half from the earliest files and half from the latest, because the first migrations describe the schema the project started with and the last describe what is changing now, while the hundreds in between describe the path from one to the other.

Alongside the files, a summary of the directory tree is included: every directory in the top three levels with its file count, up to eighty lines, plus the count of files at the root. It is cheap and it prevents a specific kind of wrong answer, where a sampled corpus gets mistaken for the entire system.

What is never read, and what is never touched

Vendored and generated directories are skipped by name, anywhere in the path: node_modules, vendor, dist, build, out, .next, target, .terraform, coverage, __pycache__, .venv, and venv. Lockfiles go by exact name, package-lock.json through pnpm-lock.yaml, poetry.lock, uv.lock, Cargo.lock, composer.lock, Gemfile.lock, bun.lockb, .terraform.lock.hcl and go.sum, since a resolved dependency tree says nothing about architecture. Binaries, images, archives, and notebooks go by extension, .ipynb and .parquet included.

Nothing is executed. There is no build, no install, no terraform init, no plan, no state file access, and no cloud credential anywhere in the flow. Terraform repositories are parsed straight from their .tf and .tfvars source, which is what makes it safe to point at a production repository with read-only access and nothing else.

And nothing is written back. Every provider call is a read: list refs, list tree, read file. There is no path that commits, opens a pull request, or posts a status check.

The consequence, stated plainly

Architecture that lives in no file cannot be drawn from files. The generated doc is instructed to say a section is unanswered rather than fill it in, so the gap shows up as a gap. More on that boundary in what an agent can infer from code.

How to review what came back

Read the diagram node by node and ask which file put this here. A generated component that no file explains is the thing to catch, and it is catchable in a few minutes because the candidate files are a short list rather than the whole repository.

Then read the architecture.md next to it. It carries an overview, a component inventory, the data flow, the deployment path, and short notes per notable directory, all grounded in the same read. A section that says the files do not show this is doing its job, not failing.

Then look for what is missing. The manual step nobody automated, the legacy database still receiving writes, the queue that exists only in production: those come from people, and adding them as annotations on the canvas is how the generated base layer becomes a diagram worth trusting. Keeping an AI-generated diagram trustworthy goes through the review in more depth.

FAQ

Which files are used to generate an architecture diagram from a repository?

Files are taken in priority order: infrastructure as code first, then containers and orchestration, then data definitions, then API specs, then CI pipelines, then dependency manifests, then prose such as READMEs. Declarations of what exists outrank descriptions of what someone believed existed.

How much of the repository is actually read?

Up to 40 files and 250KB in total, with 30KB per file and anything longer truncated behind a visible marker, plus a hard skip on anything over 400KB. Each class of file also has its own ceiling, twelve infrastructure files, ten API definitions, eight CI pipelines and so on. A directory summary three levels deep, up to eighty lines, rides along so the scale of what was not read stays visible.

Why is the README read last?

Because prose is where documentation drift accumulates. A README describing a service that was removed two quarters ago should not outrank the compose file that no longer contains it, so prose is used for naming and intent rather than treated as a statement of fact.

Is anything executed during a sync?

No. There is no build, no dependency install, no terraform init or plan, no state file access, and no cloud credential in the flow. Terraform repositories are parsed directly from their source files, and every provider call is a read.

What if part of our architecture is not in any file?

It will not be drawn. That is the trade for a diagram that cannot invent components. The generated document is instructed to state that a section is unanswered rather than guess, and the missing pieces are usually best added by hand as annotations on the canvas.