JSON report contract
The JSON Schemas of what the ascribe commands write with --format json.
For AI agents: the documentation index is at llms.txt, and this page is available as Markdown.
The commands that take --format json each write one JSON document, and this contract gives each document’s schema. The schemas are JSON Schema (draft 2020-12), generated from the code that writes the documents, so the two can’t disagree. They’re in the repository’s schemas/ folder. The command reference says what each command does, with an example of its document.
Every document follows these rules:
schema_versionchanges only when a field is removed or changes meaning. Fields can be added without a new version, so ignore fields you don’t know. The schemas allow fields they don’t list.- A field whose values are a fixed set of names, such as a diagnostic’s
severityornext, may gain a value without a new version. A reader treats a value it doesn’t know as the field says: an unknownseverityas advice, which never fails a check. - A field the schema doesn’t list as required is left out when it has no value. A required field that can be
nullis always written. - Keys are snake_case.
The pages are grouped as the ascribe.toml reference is, by what the commands are for:
- What pages are:
ascribe initandascribe model, andascribe templates - How content varies:
ascribe versions - Where pages are published:
ascribe permalinksandascribe addresses - What pages draw from:
ascribe sourcesandascribe observe - Checks:
ascribe check,ascribe build,ascribe fmt,ascribe baseline, andascribe vale eject, on this page,ascribe report, andascribe diffandascribe drift - Questions:
ascribe explain,outline,link,refs,resolve, andsearch - Agents:
ascribe agents index,sync, andprompt
ascribe check and ascribe build
{
"$defs": {
"AcknowledgedEntry": {
"description": "A problem acknowledged as intended.",
"properties": {
"at": {
"$ref": "#/$defs/Place",
"description": "Where the acknowledgement is written."
},
"builds": {
"description": "The builds it appears in, as a diagnostic's `builds` are.",
"items": {
"type": "string"
},
"type": "array"
},
"code": {
"description": "The code of the check that found it, such as `ASC036`.",
"type": "string"
},
"file": {
"description": "The file, as a diagnostic's `file` is.",
"type": "string"
},
"message": {
"description": "What the check found.",
"type": "string"
},
"range": {
"$ref": "#/$defs/Range",
"description": "Where in the file."
},
"reason": {
"description": "Why it's intended: the acknowledgement's reason.",
"type": "string"
},
"slug": {
"description": "The check's name.",
"type": "string"
}
},
"required": [
"code",
"slug",
"message",
"file",
"range",
"builds",
"reason",
"at"
],
"type": "object"
},
"CodeCount": {
"description": "How many diagnostics have one code.",
"properties": {
"code": {
"description": "The code, such as `ASC036`.",
"type": "string"
},
"count": {
"description": "How many.",
"minimum": 0,
"type": "integer"
},
"severity": {
"description": "`error`, `warning`, or `advice`.",
"type": "string"
},
"slug": {
"description": "The diagnostic's name, such as `link-target-missing`.",
"type": "string"
}
},
"required": [
"code",
"slug",
"severity",
"count"
],
"type": "object"
},
"Edit": {
"description": "One edit of a fix.",
"properties": {
"new_text": {
"description": "The text that replaces it.",
"type": "string"
},
"range": {
"$ref": "#/$defs/Range",
"description": "The text it replaces."
}
},
"required": [
"range",
"new_text"
],
"type": "object"
},
"Entry": {
"description": "A diagnostic.",
"properties": {
"builds": {
"description": "The builds a page-level diagnostic appears in, in `ascribe.toml`'s\norder. Empty for a file-level diagnostic, and for one in content no\nbuild publishes. With `--build`, only that build.",
"items": {
"type": "string"
},
"type": "array"
},
"code": {
"description": "The code, such as `ASC036`.",
"type": "string"
},
"docs": {
"description": "The address of its entry in the diagnostics reference: the docs'\npermalink for its code, such as `https://ascribed-dev.com/go/ASC036/`,\nwhich forwards to the entry wherever it is.",
"type": "string"
},
"file": {
"description": "The file, relative to the project root (the directory of\n`ascribe.toml`), with `/` separators. `ascribe.toml` for a\ncontent-model problem.",
"type": "string"
},
"fixes": {
"description": "Edits that would fix it.",
"items": {
"$ref": "#/$defs/Fix"
},
"type": "array"
},
"help": {
"description": "How to fix it, in general: the diagnostics reference's advice for its\ncode, in Markdown, whose links are the docs' permalinks, such as\n`https://ascribed-dev.com/go/22-checks/`.",
"type": "string"
},
"message": {
"description": "What's wrong, and what to do about it.",
"type": "string"
},
"next": {
"description": "The kind of next step: `fix` when Ascribe can make the edit,\n`choose` when the author picks among things Ascribe can list,\n`write` when it needs writing or judgment, `outside` when nothing in\nthe source can fix it, and `review` when it may be fine as it is.",
"type": "string"
},
"range": {
"$ref": "#/$defs/Range",
"description": "Where in the file."
},
"related": {
"description": "Other places that explain it.",
"items": {
"$ref": "#/$defs/Related"
},
"type": "array"
},
"repeats": {
"description": "For a problem in included content reported because one of its related\nplaces is in a path named: at how many other includes it's reported\ntoo, collapsed into this one. `0` otherwise.",
"minimum": 0,
"type": "integer"
},
"rule": {
"description": "The rule of the program that found it, such as `Ascribe.Repeated`\nfrom Vale, for a `prose` diagnostic. Absent for Ascribe's own.",
"type": [
"string",
"null"
]
},
"severity": {
"description": "`error`, `warning`, or `advice`. Advice never fails the command.\nMore severities may be added; a reader treats one it doesn't know as\nit treats advice.",
"type": "string"
},
"slug": {
"description": "The diagnostic's name, such as `link-target-missing`.",
"type": "string"
},
"unpublished": {
"description": "Whether it's in content that no build publishes.",
"type": "boolean"
}
},
"required": [
"code",
"slug",
"severity",
"next",
"message",
"file",
"range",
"related",
"fixes",
"builds",
"unpublished",
"help",
"docs",
"repeats"
],
"type": "object"
},
"FileCount": {
"description": "How many diagnostics are in one file.",
"properties": {
"advice": {
"description": "How many advice.",
"minimum": 0,
"type": "integer"
},
"errors": {
"description": "How many errors.",
"minimum": 0,
"type": "integer"
},
"file": {
"description": "The file, as a diagnostic's `file` is.",
"type": "string"
},
"warnings": {
"description": "How many warnings.",
"minimum": 0,
"type": "integer"
}
},
"required": [
"file",
"errors",
"warnings",
"advice"
],
"type": "object"
},
"Fix": {
"description": "Edits that would fix a diagnostic.",
"properties": {
"applicability": {
"description": "`safe` when applying the edits as they are can't change what the page\nsays and leaves nothing to decide; `unsafe` otherwise.",
"type": "string"
},
"edits": {
"description": "The edits, each replacing the text of its range.",
"items": {
"$ref": "#/$defs/Edit"
},
"type": "array"
},
"file": {
"description": "The file the edits are in, as a diagnostic's `file` is.",
"type": "string"
},
"title": {
"description": "What the fix does.",
"type": "string"
}
},
"required": [
"title",
"file",
"edits",
"applicability"
],
"type": "object"
},
"FixedEntry": {
"description": "A safe fix `--fix` applied.",
"properties": {
"code": {
"description": "The code of the diagnostic it fixed, such as `ASC036`.",
"type": "string"
},
"file": {
"description": "The file it changed, as a diagnostic's `file` is.",
"type": "string"
},
"slug": {
"description": "The diagnostic's name.",
"type": "string"
},
"title": {
"description": "What the fix did.",
"type": "string"
}
},
"required": [
"code",
"slug",
"title",
"file"
],
"type": "object"
},
"Place": {
"description": "A place in a file.",
"properties": {
"file": {
"description": "The file, as a diagnostic's `file` is.",
"type": "string"
},
"range": {
"$ref": "#/$defs/Range",
"description": "Where in the file."
}
},
"required": [
"file",
"range"
],
"type": "object"
},
"Pos": {
"description": "A position in a file.",
"properties": {
"column": {
"description": "The column, from 1, in Unicode characters (not bytes or UTF-16\nunits).",
"minimum": 0,
"type": "integer"
},
"line": {
"description": "The line, from 1.",
"minimum": 0,
"type": "integer"
},
"offset": {
"description": "The byte offset from the start of the file.",
"minimum": 0,
"type": "integer"
}
},
"required": [
"line",
"column",
"offset"
],
"type": "object"
},
"Range": {
"description": "A span of a file. `end` is just past its last character; an empty range\n(an insertion) has equal positions.",
"properties": {
"end": {
"$ref": "#/$defs/Pos",
"description": "Just past its last character."
},
"start": {
"$ref": "#/$defs/Pos",
"description": "Its first character."
}
},
"required": [
"start",
"end"
],
"type": "object"
},
"Related": {
"description": "Another place that explains a diagnostic.",
"properties": {
"file": {
"description": "The file, as a diagnostic's `file` is.",
"type": "string"
},
"message": {
"description": "What it has to do with the diagnostic.",
"type": "string"
},
"range": {
"$ref": "#/$defs/Range",
"description": "Where in the file."
}
},
"required": [
"file",
"range",
"message"
],
"type": "object"
},
"Summary": {
"description": "How many diagnostics of each severity.",
"properties": {
"acknowledged": {
"description": "How many problems are acknowledged as intended. Left out when there\nare none.",
"minimum": 0,
"type": "integer"
},
"advice": {
"description": "How many advice.",
"minimum": 0,
"type": "integer"
},
"baselined": {
"description": "How many problems `ascribe.baseline` holds back, which `diagnostics`\nleaves out and which are advice. Left out when there are none, and\nwith `--no-baseline`.",
"minimum": 0,
"type": "integer"
},
"by_code": {
"description": "With `--summary`: how many diagnostics have each code, most first.",
"items": {
"$ref": "#/$defs/CodeCount"
},
"type": [
"array",
"null"
]
},
"by_file": {
"description": "With `--summary`: how many diagnostics are in each file, most first.",
"items": {
"$ref": "#/$defs/FileCount"
},
"type": [
"array",
"null"
]
},
"errors": {
"description": "How many errors.",
"minimum": 0,
"type": "integer"
},
"warnings": {
"description": "How many warnings.",
"minimum": 0,
"type": "integer"
}
},
"required": [
"errors",
"warnings",
"advice"
],
"type": "object"
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "What `ascribe check --format json` and `ascribe build --format json`\nwrite: one document, whatever the outcome. Fields can be added without a\nnew `schema_version`, so a reader ignores fields it doesn't know.",
"properties": {
"acknowledged": {
"description": "The problems acknowledged as intended, which `diagnostics` leaves\nout and which don't fail the command, in file order. Left out when\nthere are none, and with `--summary`.",
"items": {
"$ref": "#/$defs/AcknowledgedEntry"
},
"type": "array"
},
"ascribe_version": {
"description": "The version of Ascribe that wrote it.",
"type": "string"
},
"builds_checked": {
"description": "The builds whose page-level checks ran, in `ascribe.toml`'s order:\nevery build, the ones named with `--build`, or the editor's with\n`--editor-build`. Empty when the project couldn't be checked.",
"items": {
"type": "string"
},
"type": "array"
},
"diagnostics": {
"description": "Every diagnostic, in file order, and in source order within a file;\nadvice after the errors and warnings, in the same order.\nWith paths, only those that count for them. With `--summary`, none:\nsee `truncated`.",
"items": {
"$ref": "#/$defs/Entry"
},
"type": "array"
},
"error": {
"description": "Why the project couldn't be checked (exit code 2), or `null`. When it\nisn't `null`, `diagnostics` holds what was found first: the content\nmodel's problems.",
"type": [
"string",
"null"
]
},
"files_checked": {
"description": "How many source files were checked: the project's.",
"minimum": 0,
"type": "integer"
},
"files_reported": {
"description": "How many of them the report covers: the source files in the paths\nnamed, or every one when no path was.",
"minimum": 0,
"type": "integer"
},
"fixed": {
"description": "With `--fix`, the safe fixes it applied, in file order and, within a\nfile, in the order of their diagnostics; the rest of the report is\nthe check after them. With `--dry-run`, the fixes it would apply,\nnone of which was, and the check is of the files as they are. Left\nout when there's none.",
"items": {
"$ref": "#/$defs/FixedEntry"
},
"type": "array"
},
"next_command": {
"description": "The command that lists the ones left out, when `truncated`; `null`\notherwise.",
"type": [
"string",
"null"
]
},
"schema_version": {
"description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
"minimum": 0,
"type": "integer"
},
"shown": {
"description": "How many diagnostics `diagnostics` lists.",
"minimum": 0,
"type": "integer"
},
"summary": {
"$ref": "#/$defs/Summary",
"description": "How many errors, warnings, and advice."
},
"total": {
"description": "How many diagnostics there are.",
"minimum": 0,
"type": "integer"
},
"truncated": {
"description": "Whether `diagnostics` leaves some out. It does with `--summary`,\nwhich lists none.",
"type": "boolean"
}
},
"required": [
"schema_version",
"ascribe_version",
"error",
"files_checked",
"files_reported",
"builds_checked",
"diagnostics",
"truncated",
"shown",
"total",
"next_command",
"summary"
],
"title": "CheckReport",
"type": "object"
}
ascribe fmt
{
"$defs": {
"Edit": {
"description": "One edit of a fix.",
"properties": {
"new_text": {
"description": "The text that replaces it.",
"type": "string"
},
"range": {
"$ref": "#/$defs/Range",
"description": "The text it replaces."
}
},
"required": [
"range",
"new_text"
],
"type": "object"
},
"FmtFile": {
"description": "A file and the edits that format it.",
"properties": {
"edits": {
"description": "The edits, each replacing the text of its range in the file as it\nwas before formatting. They don't overlap, and are in file order.",
"items": {
"$ref": "#/$defs/Edit"
},
"type": "array"
},
"file": {
"description": "The file, relative to the project root (the directory of\n`ascribe.toml`), with `/` separators; a file outside it as it was\nfound.",
"type": "string"
}
},
"required": [
"file",
"edits"
],
"type": "object"
},
"Pos": {
"description": "A position in a file.",
"properties": {
"column": {
"description": "The column, from 1, in Unicode characters (not bytes or UTF-16\nunits).",
"minimum": 0,
"type": "integer"
},
"line": {
"description": "The line, from 1.",
"minimum": 0,
"type": "integer"
},
"offset": {
"description": "The byte offset from the start of the file.",
"minimum": 0,
"type": "integer"
}
},
"required": [
"line",
"column",
"offset"
],
"type": "object"
},
"Range": {
"description": "A span of a file. `end` is just past its last character; an empty range\n(an insertion) has equal positions.",
"properties": {
"end": {
"$ref": "#/$defs/Pos",
"description": "Just past its last character."
},
"start": {
"$ref": "#/$defs/Pos",
"description": "Its first character."
}
},
"required": [
"start",
"end"
],
"type": "object"
},
"RefusedFile": {
"description": "A file left alone.",
"properties": {
"file": {
"description": "The file, as a formatted file's `file` is.",
"type": "string"
},
"reason": {
"description": "Why, as `ascribe check` words it.",
"type": "string"
}
},
"required": [
"file",
"reason"
],
"type": "object"
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "What `ascribe fmt --format json` writes: one document. Fields can be\nadded without a new `schema_version`, so a reader ignores fields it\ndoesn't know.",
"properties": {
"ascribe_version": {
"description": "The version of Ascribe that wrote it.",
"type": "string"
},
"files": {
"description": "Each file that changed, or with `--check` or `--dry-run` would change, in path\norder, with the edits that format it.",
"items": {
"$ref": "#/$defs/FmtFile"
},
"type": "array"
},
"refused": {
"description": "The files left alone because a symbolic link on the way to them\nleads to a file that isn't a source file of the content root.",
"items": {
"$ref": "#/$defs/RefusedFile"
},
"type": "array"
},
"schema_version": {
"description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
"minimum": 0,
"type": "integer"
},
"written": {
"description": "Whether the files were rewritten: `false` with `--check` or\n`--dry-run`, which write nothing.",
"type": "boolean"
}
},
"required": [
"schema_version",
"ascribe_version",
"written",
"files",
"refused"
],
"title": "FmtReport",
"type": "object"
}
ascribe baseline write
schemas/baseline-write.schema.json:
{
"$defs": {
"Skipped": {
"description": "The errors and warnings `ascribe baseline write` left out.",
"properties": {
"errors": {
"description": "How many errors.",
"minimum": 0,
"type": "integer"
},
"warnings": {
"description": "How many warnings.",
"minimum": 0,
"type": "integer"
}
},
"required": [
"errors",
"warnings"
],
"type": "object"
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "What `ascribe baseline write --format json` writes.",
"properties": {
"added": {
"description": "How many of them this added.",
"minimum": 0,
"type": "integer"
},
"ascribe_version": {
"description": "The version of Ascribe that wrote it.",
"type": "string"
},
"changed": {
"description": "Whether the file changed: it's new, or its text differs. With\n`--dry-run`, whether it would.",
"type": "boolean"
},
"created": {
"description": "Whether the project had no baseline, so this made one.",
"type": "boolean"
},
"entries": {
"description": "How many problems the baseline holds, after this.",
"minimum": 0,
"type": "integer"
},
"file": {
"description": "The file written, from the project's folder: `ascribe.baseline`.",
"type": "string"
},
"files": {
"description": "How many files they're in.",
"minimum": 0,
"type": "integer"
},
"schema_version": {
"description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
"minimum": 0,
"type": "integer"
},
"skipped": {
"$ref": "#/$defs/Skipped",
"description": "How many errors and warnings it left out, which a baseline never\nholds."
},
"written": {
"description": "Whether the file was written: it changed, without `--dry-run`.",
"type": "boolean"
}
},
"required": [
"schema_version",
"ascribe_version",
"file",
"created",
"changed",
"written",
"entries",
"files",
"added",
"skipped"
],
"title": "BaselineWriteReport",
"type": "object"
}
ascribe baseline prune
schemas/baseline-prune.schema.json:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "What `ascribe baseline prune --format json` writes.",
"properties": {
"ascribe_version": {
"description": "The version of Ascribe that wrote it.",
"type": "string"
},
"changed": {
"description": "Whether the file changed: some entry was removed. With `--dry-run`,\nwhether it would.",
"type": "boolean"
},
"entries": {
"description": "How many problems the baseline holds, after this.",
"minimum": 0,
"type": "integer"
},
"file": {
"description": "The file pruned, from the project's folder: `ascribe.baseline`.",
"type": "string"
},
"files": {
"description": "How many files they're in.",
"minimum": 0,
"type": "integer"
},
"found": {
"description": "Whether the project has a baseline. Without one, there's nothing to\nprune, and nothing is written.",
"type": "boolean"
},
"removed": {
"description": "How many entries it removed.",
"minimum": 0,
"type": "integer"
},
"schema_version": {
"description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
"minimum": 0,
"type": "integer"
},
"written": {
"description": "Whether the file was written: it changed, without `--dry-run`.",
"type": "boolean"
}
},
"required": [
"schema_version",
"ascribe_version",
"file",
"found",
"changed",
"written",
"entries",
"files",
"removed"
],
"title": "BaselinePruneReport",
"type": "object"
}
ascribe vale eject
schemas/vale-eject.schema.json:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "What `ascribe vale eject --format json` writes: the preset written out,\nand the files written.",
"properties": {
"ascribe_version": {
"description": "The version of Ascribe that wrote it.",
"type": "string"
},
"dry_run": {
"description": "Whether it ran with `--dry-run`, and wrote nothing.",
"type": "boolean"
},
"preset": {
"description": "The preset written out.",
"type": "string"
},
"schema_version": {
"description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
"minimum": 0,
"type": "integer"
},
"written": {
"description": "The files written, from the project's folder, `/`-separated, in the\norder they were written: `ascribe.toml` last. With `--dry-run`, the\nfiles it would write.",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"schema_version",
"ascribe_version",
"preset",
"written",
"dry_run"
],
"title": "ValeEjectReport",
"type": "object"
}