> For the complete documentation index, see [llms.txt](https://ascribed-dev.com/docs/llms.txt). This documentation describes Ascribe 0.4.4. Anything marked in main, not yet released isn't in that release yet.

# JSON report contract

> Reference · The JSON Schemas of what the ascribe commands write with --format json.

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/`](https://github.com/ascribed-dev/ascribe/tree/main/schemas/) folder. The [command reference](https://ascribed-dev.com/docs/command.md) says what each command does, with an example of its document.

Every document follows these rules:

- `schema_version` changes 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 `severity` or `next`, may gain a value without a new version. A reader treats a value it doesn't know as the field says: an unknown `severity` as 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 `null` is always written.
- Keys are snake_case.

The pages are grouped as the [`ascribe.toml` reference](https://ascribed-dev.com/docs/content-model.md#contents) is, by what the commands are for:

- What pages are: [`ascribe init` and `ascribe model`](https://ascribed-dev.com/docs/contracts/json-reports/model.md), and [`ascribe templates`](https://ascribed-dev.com/docs/contracts/json-reports/templates.md)
- How content varies: [`ascribe versions`](https://ascribed-dev.com/docs/contracts/json-reports/versions.md)
- Where pages are published: [`ascribe permalinks` and `ascribe addresses`](https://ascribed-dev.com/docs/contracts/json-reports/addresses.md)
- What pages draw from: [`ascribe sources` and `ascribe observe`](https://ascribed-dev.com/docs/contracts/json-reports/sources.md)
- Checks: `ascribe check`, `ascribe build`, `ascribe fmt`, `ascribe baseline`, and `ascribe vale eject`, on this page, [`ascribe report`](https://ascribed-dev.com/docs/contracts/json-reports/report.md), and [`ascribe diff` and `ascribe drift`](https://ascribed-dev.com/docs/contracts/json-reports/diff.md)
- Questions: [`ascribe explain`, `outline`, `link`, `refs`, `resolve`, and `search`](https://ascribed-dev.com/docs/contracts/json-reports/questions.md)
- Agents: [`ascribe agents index`, `sync`, and `prompt`](https://ascribed-dev.com/docs/contracts/json-reports/agents.md)

## `ascribe check` and `ascribe build`

[`schemas/check.schema.json`](https://github.com/ascribed-dev/ascribe/blob/main/schemas/check.schema.json):

```json
{
  "$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`

[`schemas/fmt.schema.json`](https://github.com/ascribed-dev/ascribe/blob/main/schemas/fmt.schema.json):

```json
{
  "$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`](https://github.com/ascribed-dev/ascribe/blob/main/schemas/baseline-write.schema.json):

```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`](https://github.com/ascribed-dev/ascribe/blob/main/schemas/baseline-prune.schema.json):

```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`

Available: Ascribe (in main, not yet released, 0.4.5)

[`schemas/vale-eject.schema.json`](https://github.com/ascribed-dev/ascribe/blob/main/schemas/vale-eject.schema.json):

```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"
}
```
