Skip to content

Checks and findings ​

Every check is deterministic, offline and read-only. Nothing here writes a file, calls a model, or touches the network.

The checks ​

They run in this order, and each prints one line in human output:

CheckCategoryVerifies
manifestmanifestThe manifest exists, parses, and declares a supported schema.
context structurestructure.context/ exists, belongs to Syngraphe, and has the expected files.
internal referencesreferencesLocal paths referenced from context documents resolve.
AGENTS.mdagentsThe AGENTS.md managed block is present, unique and unmodified.
Claude integrationagentsCLAUDE.md points at AGENTS.md, when Claude is used here.
context statestatestate/current.md says something, and has not silently fallen behind.

Checks do not cascade. When .context/ is absent, the structure check reports it once and the others stay quiet rather than adding six symptoms of the same cause.

Integrations that write nothing — Cursor, Codex — contribute no check: there is nothing about them that can be wrong.

Finding codes ​

Codes are stable. They are never renumbered, never reused for a different meaning, and never named after internal implementation details.

Structure — CTX ​

CodeSeverityMessageMeaning
CTX001errorRepository context is not initialized.No .context/. Run syngraphe init.
CTX002errorExpected context file is missing.One of the seven schema files is absent. init restores it.
CTX003error.context/ is not a Syngraphe repository context.The directory exists but belongs to something else.

Manifest — MANIFEST ​

CodeSeverityMeaning
MANIFEST001error.context/manifest.json is missing while the rest of the context exists.
MANIFEST002errorThe manifest is not valid JSON, is not an object, or has no numeric schemaVersion. The parser's message is included as details.
MANIFEST003errorThe manifest declares a schema version this build does not support. Forces exit code 3.
MANIFEST004warningThe manifest declares a layout this build does not know.
MANIFEST005warningThe manifest declares no protocol, so the directory can only be recognised by its shape.

AGENTS.md — AGENT ​

CodeSeverityMeaning
AGENT001errorAGENTS.md has no Syngraphe block. Run syngraphe init.
AGENT002errorThe block was modified manually. Syngraphe will not overwrite it.
AGENT003errorThe file contains more than one Syngraphe block.
AGENT004errorThe markers are unbalanced. The finding carries the line number.
AGENT005errorAGENTS.md cannot be managed safely — it is a directory, a symlink, not valid UTF-8, or declares an unknown block version.
AGENT006warningThe block still holds a body an earlier Syngraphe version wrote. Run syngraphe init to update it.

These are errors rather than warnings because .context/ without a bootstrap is context nothing will read. AGENT006 is the exception: the file says what an older Syngraphe meant it to say, and init updates it without losing anything, so it is work the repository owes rather than a failure. It is a warning, which --strict still fails on.

Claude — CLAUDE ​

CodeSeverityMeaning
CLAUDE001warningClaude is used in this repository (a CLAUDE.md or .claude/ exists) but nothing imports AGENTS.md.
CLAUDE002errorThe CLAUDE.md managed block was modified manually.
CLAUDE003errorCLAUDE.md contains duplicate Syngraphe blocks.
CLAUDE004errorThe markers in CLAUDE.md are unbalanced.
CLAUDE005warningA setup Syngraphe deliberately leaves alone, such as a symlink pointing elsewhere.
CLAUDE006warningThe CLAUDE.md block still holds a body an earlier Syngraphe version wrote. Reserved: this body has had no superseded version yet.

A missing integration is a warning, not an error: an agent nobody uses here needs no file. Nothing at all is reported for a repository that shows no sign of using Claude.

CodeSeverityMeaning
LINK001errorA context document references a local path that does not exist. The finding carries the file and the line.

Markdown links resolve relative to the document and are checked whatever they point at. Destinations may contain balanced parentheses, escaped parentheses or angle brackets, with an optional link title. Every path component must match the entry's letter case, even on a case-insensitive filesystem, so a reference accepted on macOS or Windows does not break on Linux because of its spelling. A reference through a symlink — the file itself or a directory on the way — resolves only when the link's target exists inside the Git repository; a broken link, or one leading outside, is reported. Inline code is prose, so only .md references are checked — `truth/architecture.md` — and they may resolve relative to the document, from the repository root, or from .context/. A directory named in inline code is not treated as a reference. Fenced code blocks, anchors and external URLs are ignored. See context schema for the reasoning.

State — STATE ​

CodeSeverityMeaning
STATE001warningstate/current.md has not changed in N days while the repository has.
STATE002warningstate/current.md contains only headings.

How freshness is judged ​

STATE001 is raised only when both conditions hold:

  1. the last commit touching .context/state/current.md is at least 45 days old, and
  2. the repository has commits newer than that one.

If Git cannot answer — no history, an untracked file, a shallow clone, no git on the PATH — the check stays silent. An unanswerable question produces no finding.

The message states the age and asks for a review:

text
WARN STATE001  .context/state/current.md
.context/state/current.md has not changed in 47 days.
This may be intentional. Review whether it still reflects the current repository state.

What it deliberately does not say is ERROR: context is stale. Age is a signal, not a verdict: a document can be old and perfectly accurate, and a tool that cries wolf about it teaches people to ignore the one time it matters.

Severity and exit codes ​

SeverityDefault run--strict
errorfails (exit 1)fails (exit 1)
warningreported only (exit 0)fails (exit 1)
inforeported onlyreported only

MANIFEST003 is the one special case: it forces exit code 3 regardless, because an unsupported schema makes every other answer unreliable.

Adding a check ​

The registry is a list, and each check is a small object:

ts
interface Check {
  id: string;
  label: string;         // the line printed in human output
  category: CheckCategory;
  run(context: CheckContext): Promise<Finding[]>;
}

CheckContext is a snapshot gathered once per run — the repository, the context inspection, the AGENTS.md state, every agent's state, and the reference instant used by age-based checks. Checks read from it; they never print, never write, and never decide the exit code.

Adding one means: a module in src/checks/, a line in the registry, a new stable code, tests, and a row in this table.

Syngraphe v0.4.1 · context schema v1 · GitHub · Donate