Skip to main content
That is the whole first answer. It reads both tiers, reports on each, and exits nonzero when something is wrong, which makes it usable in a script as well as by eye.

What healthy looks like

Each tier gets its own line: the graph file’s path, its line count, its size, and confirmation that it ends with a newline. Then an overall verdict. Why the newline check matters. The graph is a line-oriented text format. A file that does not end cleanly is a file something was interrupted while writing, and that is the shape almost every corruption takes. Next rung. base doctor --json gives the same report machine-readable. Pair it with base commands list, base project list and base ast list when you want a full picture: healthy graph, star commands loaded, workspace registered, code maps present.

Repairing

Why it works. It quarantines the lines it cannot parse and atomically rewrites the good set, taking a snapshot before it does. Reads elsewhere in base use a lenient parser on purpose, so one bad line degrades your context rather than blanking it; --repair is what turns that degraded state back into a clean one. The gotcha. Repair is not a substitute for knowing what went wrong. If a graph goes unhealthy repeatedly, something is writing to it that is not base.

Rolling back

Bare --restore lists the snapshots available. Naming one restores it.

Where the backups are

Every repair, restore, compact and purge snapshots the graph first, as a sibling file named graph.nq.bak-<operation>-<timestamp>. The newest ten are kept and older ones are rotated out. Why it works. This is one backup path shared by every mutating operation, rather than each command inventing its own. Verified from source at 4866996, the commit the shipped 0.13.2 binary was built from. The gotcha. Ten is not many on a busy machine. If you want to keep a particular state, copy that snapshot somewhere else; it will rotate out.

Maintenance that runs on its own

Tier graphs auto-compact at session start once they pass a size threshold, and a cooldown stops that from happening repeatedly.
Defaults: on, 12MB, and 24 hours between compactions. The gotcha. Compaction rewrites the graph. It snapshots first and it is atomic, but if you are debugging something that depends on the exact byte layout, turn graph.auto_compact off for the duration rather than being surprised by it.

Manual maintenance

compact deduplicates and canonicalizes. purge --stale removes notes that have gone unread past a threshold, and previews until you pass --apply. The gotcha. The purge clock is recency of reading, not age. A note’s lastRead is stamped every time base recall returns it, so this removes what you have not needed rather than what is old. See Decisions and recall.
Never hand-edit graph.nq. base’s writes are atomic, they snapshot first, and they refuse to run against an already-unhealthy graph. A text editor does none of those things, and an interrupted manual edit is how graphs get corrupted in the first place.

Next

Debugging injection

When the graph is fine and things still are not arriving.

Setup reference

Every base doctor flag.