Docs & Code Guide

README architecture section: what to write, and how to keep it true

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

The architecture section of a README has one reader: someone in their first hour with this repository, trying to work out whether the thing they need to change is here at all. Most architecture sections fail that reader in one of two ways. They are three sentences of marketing that explain nothing, or they are two thousand words that duplicate the wiki and were last correct in March. There is a narrow, useful middle, and it fits on one screen.

6 min readFor maintainers writing the section every new joiner reads first

See it as a diagram

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

147/20003 credits left
Try:

No account needed · Editable canvas, not a picture

Five things, in this order

One sentence saying what the system does, phrased for someone who does not already know. Not the tagline, the function: this service accepts uploads, validates them against a schema and writes rows to the warehouse.

The runtime shape. What processes exist, what data stores they talk to, what queues sit between them, and which external systems are involved. This is the diagram, and it is the part people scroll to.

The entry points. Where does a request start, where does a scheduled job start, where does an event consumer start. Name the actual file or package, because the next question is always where do I put a breakpoint.

The map from box to directory. For each component in the diagram, the directory that contains it. This is what turns a picture into something a newcomer can act on, and it is the part almost every README omits.

Where to go next. Links to the deeper documents: the architecture file, the ADR index, the runbooks. The README is the index, not the encyclopedia.

## Architecture

Ingest accepts CSV uploads, validates them against the contract in
`schemas/`, and writes normalised rows to Snowflake.

![Architecture](https://datadef.io/embed/<diagram-id>.png)

| Box in the diagram | Code lives in        |
| ------------------ | -------------------- |
| HTTP API           | `cmd/api`            |
| Validator          | `internal/validate`  |
| Loader worker      | `internal/loader`    |
| Schemas            | `schemas/`           |

Requests enter at `cmd/api/routes.go`. The scheduled reconciliation
job starts at `cmd/reconcile/main.go`.

Deeper: [ARCHITECTURE.md](./ARCHITECTURE.md) - [ADRs](./docs/adr)

What to leave out, and where it goes instead

Sequence diagrams for a single feature. They are useful and they belong next to that feature, not in the front door document that everyone loads. A README with four sequence diagrams is a README nobody scrolls to the end of.

Decision history. Why Postgres instead of DynamoDB is a real question with a real answer, and the answer has a format already: an architecture decision record. Putting it in the README means the reasoning gets edited later by someone who was not there, which is exactly what ADRs exist to prevent. See ADRs versus diagrams.

The full API reference and the full config table. Both should be generated from the source of truth, both are long, and both make the architecture section unfindable. Link to them.

Anything that is true of every service in the company. Company-wide conventions belong in one place, referenced from many, or you will update forty READMEs the next time the convention changes.

Writing it at an altitude that ages well

Prose ages at a rate set by how specific it is. A sentence naming a class that gets renamed is wrong in a month. A sentence naming a directory that gets renamed is wrong in a year, and the rename shows up in the diff so a reviewer can catch it. Write at the directory and component level and the section stays broadly true through several refactors.

The picture ages faster than the prose, because a picture is specific by nature and because updating it is a separate task in a separate tool. That asymmetry is the whole problem with README diagrams: the words survive, the committed PNG does not, and the PNG is the part people look at.

The fix is to stop committing the picture. Point the markdown image at a live embed URL and the README renders whatever the canvas currently holds. Connect the repository through repository sync and the canvas itself is regenerated daily from a branch or a tag, so the image in the README follows the code rather than following whoever last opened the diagramming tool.

The table is the part that breaks, so check it in CI

Every claim in the section is either checkable or it is prose. The box-to-directory table is the checkable part: a path in the right-hand column that no longer exists is a rename nobody carried through, and it is worth fifteen lines of shell to catch on the pull request that caused it rather than on a new joiner in week three.

The check below reads the paths out of the table and fails on the first one that is gone. It is deliberately dumb: no markdown parser, no dependency, nothing to keep up to date when the table grows a column. Run it in the same job as your link checker.

The entry-point lines deserve the same treatment. A grep for each named file in the section, failing when the file is missing, costs another three lines and catches the other rename that silently invalidates the page. Everything else in the section, the one-sentence summary and the links out, ages slowly enough to leave to human review. See docs checks in CI for the rest of the set.

#!/usr/bin/env bash
# Every path in the "Code lives in" column of the README table must exist.
set -uo pipefail
missing=0
while IFS= read -r path; do
  [ -e "$path" ] || { echo "README architecture table: missing $path"; missing=1; }
done < <(sed -n '/^| *Box in the diagram/,/^ *$/p' README.md |
         awk -F'|' 'NR > 2 && NF > 2 { gsub(/[^A-Za-z0-9_.\/-]/, "", $3); if ($3 != "") print $3 }')
exit "$missing"

Check the section the same way you check the code

A directory named in the table that no longer exists is a one-line failure, not a judgement call. Wire it into CI alongside your other docs checks, and leave the prose to human review.

FAQ

What should the architecture section of a README contain?

One sentence on what the system does, a diagram of the runtime shape, the entry points named as real files, a table mapping each box in the diagram to the directory that contains it, and links to deeper documents. It should fit on roughly one screen.

Should the architecture live in the README or in a separate file?

Keep a short section in the README and move the detail into a separate ARCHITECTURE.md once the section grows past a screen. That threshold usually arrives somewhere around ten thousand lines of code, or as soon as the repository holds more than one deployable component.

How do I stop the README diagram from going out of date?

Do not commit a rendered image. Point the markdown image tag at a diagram URL that renders the current canvas, and generate that canvas from the repository itself so it is redrawn on a daily sync rather than by hand. A committed PNG is a second artefact with its own decay rate, and it is the one readers actually look at, so removing it removes the drift rather than managing it.

Why include a table mapping diagram boxes to directories?

Because it is the step that turns a picture into something actionable. A newcomer looking at a box called Validator still has to guess where the code is, and the guess is wrong often enough to cost an afternoon. The table also breaks loudly when a directory is renamed, so a fifteen-line shell check in CI can fail the build on the pull request that caused it.

Should decision rationale go in the README?

No. Rationale belongs in numbered architecture decision records, which are immutable once accepted and superseded rather than edited. Putting it in the README invites later edits by people who were not part of the decision, which destroys the reason for writing it down.