avodado
avodado docs
Authoring

Validation

The full diagnostic taxonomy — stable codes, what each means, the first thing to check, and the CLI's exit codes.

Run avo check after creating or editing any doc and fix everything it reports — a change is not done until avo check passes. It validates every block's schema, doc#id cross-references, and duplicate ids, and names the file, line, and offending value for each problem.

avo check                       # validate all docs (default: docs/**/*.md)
avo check docs/orders-api.md    # validate one file or glob
avo check --json                # machine-readable diagnostics (CI)

Diagnostic taxonomy

Stable codes that the CLI can sort, filter, and format. Uniform shape: { file, line?, level, code, message, value? }.

CodeLevelWhen
E_PARSE_YAMLerrorYAML body failed to parse
E_SCHEMAerrorZod validation issue
E_DUP_IDerrorSame id used twice
E_DANGLING_REFerrorRef target not found
E_BAD_REF_FORMATerrorRef doesn't match doc#id or #id
E_UNKNOWN_BLOCKerrorDefensive (splitter should prevent)
W_EMPTY_BLOCKwarnTyped block with empty body
W_SUSPECT_BLOCKwarnFence tag looks like a typo of a real block type (rendered as plain text; carries a did-you-mean suggestion)
W_DUP_HEADINGwarnMarkdown heading nearly duplicated by the following block's title (renders as two stacked headings)

Error-code recipes

Every diagnostic carries a stable code so you can mechanically apply a fix:

CodeWhat it meansFirst thing to check
E_PARSE_YAMLYAML body failed to parse. Almost always a quoting issue.Re-read YAML pitfalls. Unquoted ,/:/# in a desc is the usual culprit.
E_SCHEMAA field is missing, the wrong type, or an unknown name. The message contains the path (e.g. sequence: messages.2.kind: …).Compare your YAML against the field contract and the block's family page. The schema is strict — don't add undocumented fields.
E_DANGLING_REFA ref points at an id that doesn't exist anywhere in the repo. value is the bad ref.Either fix the ref string, or add the missing id: to the target block. Bare #id is current-doc; doc#id is path-under-docs-root + #id.
E_DUP_IDThe same id: was used in two blocks. The message names both files + lines.Ids are repo-global. Rename one.
E_BAD_REF_FORMATA ref: string isn't doc#id or #id shape.Match the format exactly. The id slug is [\w-]+.
E_UNKNOWN_BLOCKA segment claims a block type the registry doesn't know. Defensive — you should rarely see it.Make the fence info-string exactly one of the 76 documented types.
W_EMPTY_BLOCKA typed block had an empty body.Add fields or remove the block.
W_SUSPECT_BLOCKA fence tag isn't a documented block type but is within typo distance of one (e.g. ```sequnce) — the block silently rendered as plain text.Rename the fence to the suggested type in the "did you mean" hint.
W_DUP_HEADINGA ## heading is nearly duplicated by the next block's title.Keep one: drop the block title or reword the heading.

Common schema errors

SymptomCauseFix
Expected string, received number on tech: 16YAML parsed 16 as a number.Quote: tech: "16".
Invalid enum value on tone: xyz / kind: xyzUsed a value not in the enum.Stick to the documented enum (tone: note|tip|warn|danger, etc.).
Unrecognized key(s) in object: 'foo'You added a field that isn't in the schema.Schemas are strict. Remove the field, or use a documented one.
Schemas on the meta block failYou put a meta block somewhere other than first.Move it to the top of the file.
Unrecognized key(s) in object: 'persists' and similarUnquoted comma in a flow-style mapping turned a phrase into multiple keys.Quote the value containing the comma.

Exit codes

CodeMeaning
0Clean (or non-error warnings only)
1One or more error-level diagnostics
2CLI usage error (missing required flag, etc.)

Under the hood, the libraries return diagnostics as values — they don't throw for expected conditions. The CLI is the only layer that maps diagnostics to console output and exit codes (see Architecture).