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 field is for, with an example of each 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.

ascribe check and ascribe build

schemas/check.schema.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.",
          "format": "uint",
          "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.",
          "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.",
          "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.",
          "format": "uint",
          "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.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "errors": {
          "description": "How many errors.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "file": {
          "description": "The file, as a diagnostic's `file` is.",
          "type": "string"
        },
        "warnings": {
          "description": "How many warnings.",
          "format": "uint",
          "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"
    },
    "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).",
          "format": "uint32",
          "minimum": 0,
          "type": "integer"
        },
        "line": {
          "description": "The line, from 1.",
          "format": "uint32",
          "minimum": 0,
          "type": "integer"
        },
        "offset": {
          "description": "The byte offset from the start of the file.",
          "format": "uint",
          "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.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "advice": {
          "description": "How many advice.",
          "format": "uint",
          "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.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "warnings": {
          "description": "How many warnings.",
          "format": "uint",
          "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.",
      "format": "uint",
      "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.",
      "format": "uint",
      "minimum": 0,
      "type": "integer"
    },
    "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.",
      "format": "uint32",
      "minimum": 0,
      "type": "integer"
    },
    "shown": {
      "description": "How many diagnostics `diagnostics` lists.",
      "format": "uint",
      "minimum": 0,
      "type": "integer"
    },
    "summary": {
      "$ref": "#/$defs/Summary",
      "description": "How many errors, warnings, and advice."
    },
    "total": {
      "description": "How many diagnostics there are.",
      "format": "uint",
      "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 diff

Ascribe (GA, 0.2.0+)

schemas/diff.schema.json:

{
  "$defs": {
    "Anchor": {
      "description": "Where a block's text is written: the README's anchor grammar, the same\nstring the rendered page carries in `data-ascribe-source` and\n`data-ascribe-via`.",
      "properties": {
        "source": {
          "description": "`<path>:<first>-<last>`: the file's content path, percent-encoded by\nsegment, and the block's first and last lines, from 1.",
          "type": "string"
        },
        "via": {
          "description": "The includes the block came through, outermost first, each\n`<path>:<line>`. Empty for a block written in the page itself.",
          "items": {
            "type": "string"
          },
          "type": "array"
        }
      },
      "required": [
        "source",
        "via"
      ],
      "type": "object"
    },
    "BaseInfo": {
      "description": "The base of a comparison, in the report.",
      "properties": {
        "commit": {
          "description": "The commit it names.",
          "type": "string"
        },
        "merge_base": {
          "description": "The merge base of that commit and `HEAD`, which the comparison reads;\n`null` with `--base-exact`, which reads `commit`.",
          "type": [
            "string",
            "null"
          ]
        },
        "requested": {
          "description": "The revision asked for, or the default branch used.",
          "type": "string"
        }
      },
      "required": [
        "requested",
        "commit",
        "merge_base"
      ],
      "type": "object"
    },
    "BuildDiff": {
      "description": "What changed in one build.",
      "properties": {
        "build": {
          "description": "The build's name.",
          "type": "string"
        },
        "pages": {
          "description": "The pages that changed, in path order.",
          "items": {
            "$ref": "#/$defs/PageDiff"
          },
          "type": "array"
        }
      },
      "required": [
        "build",
        "pages"
      ],
      "type": "object"
    },
    "Change": {
      "description": "One block's change.",
      "properties": {
        "after": {
          "anyOf": [
            {
              "$ref": "#/$defs/Anchor"
            },
            {
              "type": "null"
            }
          ],
          "description": "For a removed block, and a moved block's old place: the block of the\nnew version it came after, among its siblings. Absent when it was\nfirst."
        },
        "kind": {
          "$ref": "#/$defs/ChangeKind",
          "description": "What happened to it."
        },
        "now": {
          "anyOf": [
            {
              "$ref": "#/$defs/Anchor"
            },
            {
              "type": "null"
            }
          ],
          "description": "Where it's written now: every kind but `removed`."
        },
        "parent": {
          "anyOf": [
            {
              "$ref": "#/$defs/Anchor"
            },
            {
              "type": "null"
            }
          ],
          "description": "For a removed block, and a moved block's old place: the block of the\nnew version it was inside. Absent at the top of the page."
        },
        "text": {
          "description": "For a removed block, its text, whitespace collapsed, so it can be\nshown where it was.",
          "type": [
            "string",
            "null"
          ]
        },
        "was": {
          "anyOf": [
            {
              "$ref": "#/$defs/Anchor"
            },
            {
              "type": "null"
            }
          ],
          "description": "Where it was written: every kind but `added`."
        },
        "words": {
          "anyOf": [
            {
              "$ref": "#/$defs/Words"
            },
            {
              "type": "null"
            }
          ],
          "description": "For changed prose, the words that differ."
        }
      },
      "required": [
        "kind"
      ],
      "type": "object"
    },
    "ChangeKind": {
      "description": "The kinds of block change.",
      "oneOf": [
        {
          "const": "changed",
          "description": "The block's content changed.",
          "type": "string"
        },
        {
          "const": "added",
          "description": "The block is new.",
          "type": "string"
        },
        {
          "const": "removed",
          "description": "The block is gone.",
          "type": "string"
        },
        {
          "const": "moved",
          "description": "The same block is somewhere else.",
          "type": "string"
        }
      ]
    },
    "Counts": {
      "description": "How many changes of each kind a page has.",
      "properties": {
        "added": {
          "description": "Blocks only in the new version.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "changed": {
          "description": "Blocks whose content changed.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "moved": {
          "description": "Blocks in both, somewhere else.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "removed": {
          "description": "Blocks only in the old version.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        }
      },
      "required": [
        "changed",
        "added",
        "removed",
        "moved"
      ],
      "type": "object"
    },
    "PageDiff": {
      "description": "What changed on one page of a build.",
      "properties": {
        "because": {
          "description": "The other changed files the page's change can come from: fragments it\nincludes and pages its links take a title or a heading from, in path\norder; then the snippets whose code changed, by address\n(`code:app.py#main`); and `ascribe.toml` (last) when the content model\nis a cause.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "changes": {
          "description": "The block-level changes, in the page's order, a removed block where\nit was. Empty for an added or removed page, and for every page when\nthe report's `blocks_omitted` is `true`.",
          "items": {
            "$ref": "#/$defs/Change"
          },
          "type": "array"
        },
        "counts": {
          "$ref": "#/$defs/Counts",
          "description": "How many changes of each kind."
        },
        "own_file_changed": {
          "description": "Whether the page's own file changed (or exists on one side only).",
          "type": "boolean"
        },
        "page_changed": {
          "description": "What changed about the page itself besides its blocks, in this\norder: `title`, `frontmatter`, `availability` (the page-level one),\nand `route`. Empty for an added or removed page.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "path": {
          "description": "The page's content path.",
          "type": "string"
        },
        "route": {
          "description": "Its route: the new one, or for a removed page the old one.",
          "type": "string"
        },
        "status": {
          "$ref": "#/$defs/PageStatus",
          "description": "Whether the build publishes it only now, only before, or in both\nwith a difference."
        }
      },
      "required": [
        "path",
        "route",
        "status",
        "own_file_changed",
        "because",
        "page_changed",
        "counts",
        "changes"
      ],
      "type": "object"
    },
    "PageStatus": {
      "description": "Whether a page is new, gone, or different.",
      "oneOf": [
        {
          "const": "added",
          "description": "The build publishes it now, and didn't before.",
          "type": "string"
        },
        {
          "const": "removed",
          "description": "The build published it before, and doesn't now.",
          "type": "string"
        },
        {
          "const": "changed",
          "description": "The build publishes it in both, and it differs.",
          "type": "string"
        }
      ]
    },
    "RepositoryInfo": {
      "description": "The repository, in the report.",
      "properties": {
        "project_prefix": {
          "description": "The project's folder inside it, with a trailing `/`, or empty when\nthe project is at the repository's root.",
          "type": "string"
        },
        "root": {
          "description": "The repository's top-level directory, as git prints it.",
          "type": "string"
        }
      },
      "required": [
        "root",
        "project_prefix"
      ],
      "type": "object"
    },
    "Words": {
      "description": "The words that differ inside a changed block of prose. Ranges are\n`[start, end)` in characters (Unicode scalar values) of each side's\n`text`, which is the block's text with whitespace collapsed.",
      "properties": {
        "now": {
          "description": "Ranges in `now_text`: words added or replacing others.",
          "items": {
            "items": {
              "format": "uint",
              "minimum": 0,
              "type": "integer"
            },
            "maxItems": 2,
            "minItems": 2,
            "type": "array"
          },
          "type": "array"
        },
        "now_text": {
          "description": "The block's text now.",
          "type": "string"
        },
        "was": {
          "description": "Ranges in `was_text`: words removed or replaced.",
          "items": {
            "items": {
              "format": "uint",
              "minimum": 0,
              "type": "integer"
            },
            "maxItems": 2,
            "minItems": 2,
            "type": "array"
          },
          "type": "array"
        },
        "was_text": {
          "description": "The block's text before.",
          "type": "string"
        }
      },
      "required": [
        "now",
        "was",
        "now_text",
        "was_text"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "The whole report, as `ascribe diff --format json` writes it.",
  "properties": {
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "base": {
      "$ref": "#/$defs/BaseInfo",
      "description": "What was compared with."
    },
    "blocks_omitted": {
      "description": "Whether every page's `changes` was left empty, as `ascribe diff\n--pages-only` leaves them: its `counts` still count them. Only there\nwhen it's `true`.",
      "type": "boolean"
    },
    "builds": {
      "description": "What changed, per build, in the order asked for.",
      "items": {
        "$ref": "#/$defs/BuildDiff"
      },
      "type": "array"
    },
    "repository": {
      "$ref": "#/$defs/RepositoryInfo",
      "description": "Where the project is."
    },
    "schema_version": {
      "description": "`SCHEMA_VERSION`.",
      "format": "uint32",
      "minimum": 0,
      "type": "integer"
    },
    "working_tree_errors": {
      "description": "How many errors `ascribe check` finds in the working tree, for the\nbuilds compared. The comparison runs regardless, but a page with an\nerror may not render as it will once it's fixed, so a reviewer should\nknow. `diff_project` sets it; `Report::new` leaves it zero.",
      "format": "uint",
      "minimum": 0,
      "type": "integer"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "base",
    "repository",
    "working_tree_errors",
    "builds"
  ],
  "title": "DiffReport",
  "type": "object"
}

ascribe drift

Ascribe (GA, 0.2.0+)

schemas/drift.schema.json:

{
  "$defs": {
    "BaseInfo": {
      "description": "The base of a comparison, in the report.",
      "properties": {
        "commit": {
          "description": "The commit it names.",
          "type": "string"
        },
        "merge_base": {
          "description": "The merge base of that commit and `HEAD`, which the comparison reads;\n`null` with `--base-exact`, which reads `commit`.",
          "type": [
            "string",
            "null"
          ]
        },
        "requested": {
          "description": "The revision asked for, or the default branch used.",
          "type": "string"
        }
      },
      "required": [
        "requested",
        "commit",
        "merge_base"
      ],
      "type": "object"
    },
    "BrokenExample": {
      "description": "A snippet that resolved at the base and doesn't in the working tree: its\nregion, file, or source is gone.",
      "properties": {
        "address": {
          "description": "Its address, as the page writes it.",
          "type": "string"
        },
        "problem": {
          "description": "The slug of the diagnostic `ascribe check` reports for it\n(`snippet-region-missing`).",
          "type": "string"
        },
        "reason": {
          "description": "Why it doesn't resolve, in a few words.",
          "type": "string"
        },
        "source": {
          "description": "The source the address names.",
          "type": "string"
        }
      },
      "required": [
        "address",
        "source",
        "problem",
        "reason"
      ],
      "type": "object"
    },
    "ChangedExample": {
      "description": "A snippet whose code changed.",
      "properties": {
        "added": {
          "description": "Lines only in the code now.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "address": {
          "description": "Its address, as the page writes it.",
          "type": "string"
        },
        "file": {
          "description": "The code file now, from the repository's root.",
          "type": "string"
        },
        "removed": {
          "description": "Lines only in the code at the base.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "source": {
          "description": "The source the address names.",
          "type": "string"
        },
        "was_file": {
          "description": "The code file at the base, when it was renamed since.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "address",
        "source",
        "file",
        "was_file",
        "added",
        "removed"
      ],
      "type": "object"
    },
    "DriftPage": {
      "description": "A page with an example that changed or broke.",
      "properties": {
        "broken": {
          "description": "The examples that resolved at the base and don't now, by address.",
          "items": {
            "$ref": "#/$defs/BrokenExample"
          },
          "type": "array"
        },
        "builds": {
          "description": "The builds that show it with a changed example, in the order asked\nfor.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "examples": {
          "description": "The examples that changed, by address. Empty when only `broken`\nisn't.",
          "items": {
            "$ref": "#/$defs/ChangedExample"
          },
          "type": "array"
        },
        "page_changed": {
          "description": "Whether the page changed apart from its examples: its own file, or\nits resolved content through anything else it uses (a fragment, the\ncontent model), in any of those builds. When it didn't, the example\nchanged and the words around it didn't.",
          "type": "boolean"
        },
        "path": {
          "description": "The page's content path.",
          "type": "string"
        },
        "route": {
          "description": "Its route, in the first of the builds it's in.",
          "type": "string"
        }
      },
      "required": [
        "path",
        "route",
        "builds",
        "page_changed",
        "examples",
        "broken"
      ],
      "type": "object"
    },
    "RepositoryInfo": {
      "description": "The repository, in the report.",
      "properties": {
        "project_prefix": {
          "description": "The project's folder inside it, with a trailing `/`, or empty when\nthe project is at the repository's root.",
          "type": "string"
        },
        "root": {
          "description": "The repository's top-level directory, as git prints it.",
          "type": "string"
        }
      },
      "required": [
        "root",
        "project_prefix"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "The report, as `ascribe drift --format json` writes it.",
  "properties": {
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "base": {
      "$ref": "#/$defs/BaseInfo",
      "description": "What was compared with."
    },
    "pages": {
      "description": "Every page with an example that changed or broke, in path order.",
      "items": {
        "$ref": "#/$defs/DriftPage"
      },
      "type": "array"
    },
    "repository": {
      "$ref": "#/$defs/RepositoryInfo",
      "description": "Where the project is."
    },
    "schema_version": {
      "description": "`DRIFT_SCHEMA_VERSION`.",
      "format": "uint32",
      "minimum": 0,
      "type": "integer"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "base",
    "repository",
    "pages"
  ],
  "title": "DriftReport",
  "type": "object"
}

ascribe report

Ascribe (GA, 0.2.0+)

schemas/report.schema.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"
    },
    "AgentsJson": {
      "description": "`agents`: the delivery spec's checks on a built site.",
      "properties": {
        "diagnostics": {
          "$ref": "#/$defs/Capped_Entry",
          "description": "A diagnostic for each check that failed or warned that the hosting\nor Ascribe owns. One a page owns is `ascribe check`'s, and isn't\nrepeated."
        },
        "not_run": {
          "anyOf": [
            {
              "$ref": "#/$defs/NotRunJson"
            },
            {
              "type": "null"
            }
          ],
          "description": "Why it couldn't run, or `null` when it ran. When it isn't `null`,\nthe rest is empty."
        },
        "results": {
          "description": "Each check's result, in the checker's order.",
          "items": {
            "$ref": "#/$defs/CheckResultJson"
          },
          "type": "array"
        },
        "site": {
          "description": "The site checked, as `--site` gives it; empty when none was given.",
          "type": "string"
        }
      },
      "required": [
        "not_run",
        "site",
        "results",
        "diagnostics"
      ],
      "type": "object"
    },
    "BuildJson": {
      "description": "What one build leaves out that another build keeps.",
      "properties": {
        "build": {
          "description": "The build.",
          "type": "string"
        },
        "content": {
          "$ref": "#/$defs/Capped_LeftContentJson",
          "description": "The content it takes out of the pages it publishes, in file and\nsource order."
        },
        "pages": {
          "$ref": "#/$defs/Capped_LeftPageJson",
          "description": "The pages it doesn't publish, in path order."
        }
      },
      "required": [
        "build",
        "pages",
        "content"
      ],
      "type": "object"
    },
    "Capped_AcknowledgedEntry": {
      "description": "A list of at most `--limit` items.",
      "properties": {
        "items": {
          "description": "The items, at most `--limit` of them.",
          "items": {
            "$ref": "#/$defs/AcknowledgedEntry"
          },
          "type": "array"
        },
        "shown": {
          "description": "How many are listed.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "total": {
          "description": "How many there are.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "truncated": {
          "description": "Whether some are left out: `shown` is less than `total`. The\nreport's `next_command` lists them all.",
          "type": "boolean"
        }
      },
      "required": [
        "items",
        "shown",
        "total",
        "truncated"
      ],
      "type": "object"
    },
    "Capped_CheckCount": {
      "description": "A list of at most `--limit` items.",
      "properties": {
        "items": {
          "description": "The items, at most `--limit` of them.",
          "items": {
            "$ref": "#/$defs/CheckCount"
          },
          "type": "array"
        },
        "shown": {
          "description": "How many are listed.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "total": {
          "description": "How many there are.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "truncated": {
          "description": "Whether some are left out: `shown` is less than `total`. The\nreport's `next_command` lists them all.",
          "type": "boolean"
        }
      },
      "required": [
        "items",
        "shown",
        "total",
        "truncated"
      ],
      "type": "object"
    },
    "Capped_Entry": {
      "description": "A list of at most `--limit` items.",
      "properties": {
        "items": {
          "description": "The items, at most `--limit` of them.",
          "items": {
            "$ref": "#/$defs/Entry"
          },
          "type": "array"
        },
        "shown": {
          "description": "How many are listed.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "total": {
          "description": "How many there are.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "truncated": {
          "description": "Whether some are left out: `shown` is less than `total`. The\nreport's `next_command` lists them all.",
          "type": "boolean"
        }
      },
      "required": [
        "items",
        "shown",
        "total",
        "truncated"
      ],
      "type": "object"
    },
    "Capped_FileCount": {
      "description": "A list of at most `--limit` items.",
      "properties": {
        "items": {
          "description": "The items, at most `--limit` of them.",
          "items": {
            "$ref": "#/$defs/FileCount"
          },
          "type": "array"
        },
        "shown": {
          "description": "How many are listed.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "total": {
          "description": "How many there are.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "truncated": {
          "description": "Whether some are left out: `shown` is less than `total`. The\nreport's `next_command` lists them all.",
          "type": "boolean"
        }
      },
      "required": [
        "items",
        "shown",
        "total",
        "truncated"
      ],
      "type": "object"
    },
    "Capped_LeftContentJson": {
      "description": "A list of at most `--limit` items.",
      "properties": {
        "items": {
          "description": "The items, at most `--limit` of them.",
          "items": {
            "$ref": "#/$defs/LeftContentJson"
          },
          "type": "array"
        },
        "shown": {
          "description": "How many are listed.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "total": {
          "description": "How many there are.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "truncated": {
          "description": "Whether some are left out: `shown` is less than `total`. The\nreport's `next_command` lists them all.",
          "type": "boolean"
        }
      },
      "required": [
        "items",
        "shown",
        "total",
        "truncated"
      ],
      "type": "object"
    },
    "Capped_LeftPageJson": {
      "description": "A list of at most `--limit` items.",
      "properties": {
        "items": {
          "description": "The items, at most `--limit` of them.",
          "items": {
            "$ref": "#/$defs/LeftPageJson"
          },
          "type": "array"
        },
        "shown": {
          "description": "How many are listed.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "total": {
          "description": "How many there are.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "truncated": {
          "description": "Whether some are left out: `shown` is less than `total`. The\nreport's `next_command` lists them all.",
          "type": "boolean"
        }
      },
      "required": [
        "items",
        "shown",
        "total",
        "truncated"
      ],
      "type": "object"
    },
    "CheckCount": {
      "description": "How many diagnostics one check reports.",
      "properties": {
        "code": {
          "description": "The code, such as `ASC036`.",
          "type": "string"
        },
        "count": {
          "description": "How many.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "next": {
          "description": "Its kind of next step, as a diagnostic's `next` is.",
          "type": "string"
        },
        "severity": {
          "description": "`error`, `warning`, or `advice`.",
          "type": "string"
        },
        "slug": {
          "description": "The check's name, such as `link-target-missing`.",
          "type": "string"
        }
      },
      "required": [
        "code",
        "slug",
        "severity",
        "next",
        "count"
      ],
      "type": "object"
    },
    "CheckResultJson": {
      "description": "One check of the delivery spec.",
      "properties": {
        "category": {
          "description": "Its category in the spec.",
          "type": "string"
        },
        "id": {
          "description": "The check's id, such as `llms-txt-exists`.",
          "type": "string"
        },
        "message": {
          "description": "What the checker said.",
          "type": "string"
        },
        "owner": {
          "description": "Who changes what it checks: `ascribe` (what Ascribe writes),\n`hosting` (where the site is hosted), or `pages` (the pages, which\n`ascribe check` reports on).",
          "type": "string"
        },
        "status": {
          "description": "`pass`, `warn`, `fail`, `skip`, or `error`.",
          "type": "string"
        }
      },
      "required": [
        "id",
        "category",
        "status",
        "message",
        "owner"
      ],
      "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.",
          "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.",
          "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.",
          "format": "uint",
          "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 one file has.",
      "properties": {
        "advice": {
          "description": "How many advice.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "errors": {
          "description": "How many errors.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "file": {
          "description": "The file, relative to the project root, as a diagnostic's `file` is.",
          "type": "string"
        },
        "warnings": {
          "description": "How many warnings.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        }
      },
      "required": [
        "file",
        "errors",
        "warnings",
        "advice"
      ],
      "type": "object"
    },
    "Findings": {
      "description": "How many findings of each severity, and of each kind of next step.",
      "properties": {
        "advice": {
          "description": "How many advice.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "by_next": {
          "description": "How many of each kind of next step, in the order `fix`, `choose`,\n`write`, `review`, `outside`; a kind with none is left out.",
          "items": {
            "$ref": "#/$defs/NextCount"
          },
          "type": "array"
        },
        "errors": {
          "description": "How many errors.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "warnings": {
          "description": "How many warnings.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        }
      },
      "required": [
        "errors",
        "warnings",
        "advice",
        "by_next"
      ],
      "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"
    },
    "InventoryJson": {
      "description": "`inventory`: what the project holds.",
      "properties": {
        "by_owner": {
          "description": "How many pages each owner has, most first: the value of the\nfrontmatter field the page's type marks `role = \"owner\"`.",
          "items": {
            "$ref": "#/$defs/OwnerCount"
          },
          "type": "array"
        },
        "by_type": {
          "description": "How many pages of each content type, most first.",
          "items": {
            "$ref": "#/$defs/TypeCount"
          },
          "type": "array"
        },
        "orphans": {
          "$ref": "#/$defs/Capped_Entry",
          "description": "The pages nothing links to (`page-orphan`)."
        },
        "overdue": {
          "$ref": "#/$defs/Capped_Entry",
          "description": "The pages whose review date has passed (`review-overdue`)."
        },
        "pages": {
          "description": "How many pages.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "unused": {
          "$ref": "#/$defs/Capped_Entry",
          "description": "The fragments, phrases, features, glossary terms, and images nothing\nuses."
        }
      },
      "required": [
        "pages",
        "by_type",
        "by_owner",
        "overdue",
        "orphans",
        "unused"
      ],
      "type": "object"
    },
    "LeftContentJson": {
      "description": "Content a build takes out of a page it publishes.",
      "properties": {
        "file": {
          "description": "The file it's written in: the page, or a fragment it includes.",
          "type": "string"
        },
        "kept_by": {
          "description": "The builds that keep it.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "kind": {
          "description": "`variant` for a variant arm, or `availability` for content a\nfeature's availability takes out.",
          "type": "string"
        },
        "page": {
          "description": "The page it's taken out of, as `file` is.",
          "type": "string"
        },
        "range": {
          "$ref": "#/$defs/Range",
          "description": "Where in the file."
        },
        "why": {
          "description": "Why, with the content model's labels: `Shows only os=linux`.",
          "type": "string"
        }
      },
      "required": [
        "file",
        "range",
        "page",
        "kind",
        "why",
        "kept_by"
      ],
      "type": "object"
    },
    "LeftPageJson": {
      "description": "A page a build doesn't publish.",
      "properties": {
        "file": {
          "description": "The page, relative to the project root, as a diagnostic's `file` is.",
          "type": "string"
        },
        "kept_by": {
          "description": "The builds that publish it.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "why": {
          "description": "Why, as the end of a sentence: `its variant frontmatter names …`.",
          "type": "string"
        }
      },
      "required": [
        "file",
        "why",
        "kept_by"
      ],
      "type": "object"
    },
    "LinksJson": {
      "description": "`links`: what the link checker said about the external links.",
      "properties": {
        "acknowledged": {
          "$ref": "#/$defs/Capped_AcknowledgedEntry",
          "description": "The broken links acknowledged as intended."
        },
        "checked": {
          "description": "How many different addresses were checked.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "diagnostics": {
          "$ref": "#/$defs/Capped_Entry",
          "description": "A diagnostic for each link that moved or is broken, at its place,\nand for each acknowledgement of a broken link that covers nothing."
        },
        "ignored": {
          "description": "How many `[checks.links] ignore` left out.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "not_run": {
          "anyOf": [
            {
              "$ref": "#/$defs/NotRunJson"
            },
            {
              "type": "null"
            }
          ],
          "description": "Why it couldn't run, or `null` when it ran. When it isn't `null`,\nthe rest is empty."
        }
      },
      "required": [
        "not_run",
        "checked",
        "ignored",
        "diagnostics",
        "acknowledged"
      ],
      "type": "object"
    },
    "NextCount": {
      "description": "How many findings have one kind of next step.",
      "properties": {
        "count": {
          "description": "How many.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "next": {
          "description": "`fix`, `choose`, `write`, `review`, or `outside`, as a diagnostic's\n`next` is.",
          "type": "string"
        }
      },
      "required": [
        "next",
        "count"
      ],
      "type": "object"
    },
    "NotRunJson": {
      "description": "Why a section couldn't run, and what would let it.",
      "properties": {
        "how": {
          "description": "What to do so that it runs, as a sentence.",
          "type": "string"
        },
        "reason": {
          "description": "Why, as a sentence.",
          "type": "string"
        }
      },
      "required": [
        "reason",
        "how"
      ],
      "type": "object"
    },
    "OwnerCount": {
      "description": "How many pages one owner has.",
      "properties": {
        "owner": {
          "description": "The owner, as the frontmatter gives it; `null` for the pages without\none.",
          "type": [
            "string",
            "null"
          ]
        },
        "pages": {
          "description": "How many pages.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        }
      },
      "required": [
        "owner",
        "pages"
      ],
      "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).",
          "format": "uint32",
          "minimum": 0,
          "type": "integer"
        },
        "line": {
          "description": "The line, from 1.",
          "format": "uint32",
          "minimum": 0,
          "type": "integer"
        },
        "offset": {
          "description": "The byte offset from the start of the file.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        }
      },
      "required": [
        "line",
        "column",
        "offset"
      ],
      "type": "object"
    },
    "ProblemsJson": {
      "description": "`problems`: what `ascribe check` reports, counted.",
      "properties": {
        "acknowledged": {
          "$ref": "#/$defs/Capped_AcknowledgedEntry",
          "description": "The problems acknowledged as intended, with their reasons, in file\norder."
        },
        "by_check": {
          "$ref": "#/$defs/Capped_CheckCount",
          "description": "How many diagnostics each check reports, most first."
        },
        "by_file": {
          "$ref": "#/$defs/Capped_FileCount",
          "description": "How many diagnostics each file has, most first."
        },
        "findings": {
          "$ref": "#/$defs/Findings",
          "description": "How many errors, warnings, and advice, and of each kind of next\nstep."
        },
        "list_command": {
          "description": "The command that lists each problem: `ascribe check`, as JSON.",
          "type": "string"
        }
      },
      "required": [
        "findings",
        "by_check",
        "by_file",
        "acknowledged",
        "list_command"
      ],
      "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"
    },
    "TypeCount": {
      "description": "How many pages one content type has.",
      "properties": {
        "pages": {
          "description": "How many pages.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "type": {
          "description": "The type's name; `null` for the pages no one type applies to.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "type",
        "pages"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe report --format json` writes: one document, whatever the\noutcome. A reader ignores fields it doesn't know.",
  "properties": {
    "agents": {
      "anyOf": [
        {
          "$ref": "#/$defs/AgentsJson"
        },
        {
          "type": "null"
        }
      ],
      "description": "`agents`, when asked for."
    },
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "builds": {
      "description": "`builds`, when asked for: one for each build checked.",
      "items": {
        "$ref": "#/$defs/BuildJson"
      },
      "type": [
        "array",
        "null"
      ]
    },
    "builds_checked": {
      "description": "The builds `problems` checked and `builds` reports on, in\n`ascribe.toml`'s order.",
      "items": {
        "type": "string"
      },
      "type": "array"
    },
    "error": {
      "description": "Why the report couldn't be made (exit code 2), or `null`. When it\nisn't `null`, no section is there.",
      "type": [
        "string",
        "null"
      ]
    },
    "findings": {
      "$ref": "#/$defs/Findings",
      "description": "How many findings of each severity the sections that ran have, and\nof each kind of next step: the diagnostics of `problems`, `links`,\nand `agents`."
    },
    "inventory": {
      "anyOf": [
        {
          "$ref": "#/$defs/InventoryJson"
        },
        {
          "type": "null"
        }
      ],
      "description": "`inventory`, when asked for."
    },
    "links": {
      "anyOf": [
        {
          "$ref": "#/$defs/LinksJson"
        },
        {
          "type": "null"
        }
      ],
      "description": "`links`, when asked for."
    },
    "next_command": {
      "description": "The command that lists everything a list here leaves out, when one\ndoes; `null` otherwise.",
      "type": [
        "string",
        "null"
      ]
    },
    "not_run": {
      "description": "The sections asked for that couldn't run. Each says why in its own\n`not_run`. With `--exit-code`, any is exit code 2.",
      "items": {
        "type": "string"
      },
      "type": "array"
    },
    "problems": {
      "anyOf": [
        {
          "$ref": "#/$defs/ProblemsJson"
        },
        {
          "type": "null"
        }
      ],
      "description": "`problems`, when asked for."
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "format": "uint32",
      "minimum": 0,
      "type": "integer"
    },
    "sections": {
      "description": "The sections asked for, in the order the report has them:\n`problems`, `inventory`, `builds`, `links`, `agents`.",
      "items": {
        "type": "string"
      },
      "type": "array"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "error",
    "sections",
    "builds_checked",
    "not_run",
    "findings",
    "next_command"
  ],
  "title": "ReportReport",
  "type": "object"
}

ascribe sources status

Ascribe (GA, 0.2.0+)

schemas/sources-status.schema.json:

{
  "$defs": {
    "CopyState": {
      "description": "The state of a copy.",
      "oneOf": [
        {
          "const": "current",
          "description": "It's the file the lock pins, and a snippet uses it.",
          "type": "string"
        },
        {
          "const": "changed",
          "description": "It isn't the file the lock pins.",
          "type": "string"
        },
        {
          "const": "missing",
          "description": "The lock lists it, and it isn't there.",
          "type": "string"
        },
        {
          "const": "unlocked",
          "description": "It's there, and the lock doesn't list it.",
          "type": "string"
        },
        {
          "const": "unused",
          "description": "No snippet names it.",
          "type": "string"
        },
        {
          "const": "not_copied",
          "description": "A snippet names it, and it hasn't been copied.",
          "type": "string"
        },
        {
          "const": "not_at_pin",
          "description": "A snippet names it, and it isn't in the repository at the pin.",
          "type": "string"
        }
      ]
    },
    "CopyStatus": {
      "description": "A file of a source's copies.",
      "properties": {
        "path": {
          "description": "Its path in the source.",
          "type": "string"
        },
        "state": {
          "$ref": "#/$defs/CopyState",
          "description": "Its state."
        }
      },
      "required": [
        "path",
        "state"
      ],
      "type": "object"
    },
    "SourceStatus": {
      "description": "One source's pin and copies.",
      "properties": {
        "branch": {
          "description": "The branch an update follows; `None` for the repository's default.",
          "type": [
            "string",
            "null"
          ]
        },
        "commit": {
          "description": "Its pin, when it has one to this repository.",
          "type": [
            "string",
            "null"
          ]
        },
        "files": {
          "description": "Each copy, and each file snippets name with none, by path.",
          "items": {
            "$ref": "#/$defs/CopyStatus"
          },
          "type": "array"
        },
        "git": {
          "description": "Its repository.",
          "type": "string"
        },
        "name": {
          "description": "The source.",
          "type": "string"
        }
      },
      "required": [
        "name",
        "git",
        "branch",
        "commit",
        "files"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe sources status --format json` writes: each source's pin and\nthe state of its copies, read from the files alone.",
  "properties": {
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "format": "uint32",
      "minimum": 0,
      "type": "integer"
    },
    "sources": {
      "description": "Each source in another repository, in declaration order.",
      "items": {
        "$ref": "#/$defs/SourceStatus"
      },
      "type": "array"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "sources"
  ],
  "title": "SourcesStatusReport",
  "type": "object"
}

ascribe sources update

Ascribe (GA, 0.2.0+)

schemas/sources-update.schema.json:

{
  "$defs": {
    "BrokenExample": {
      "description": "A snippet that resolved at the base and doesn't in the working tree: its\nregion, file, or source is gone.",
      "properties": {
        "address": {
          "description": "Its address, as the page writes it.",
          "type": "string"
        },
        "problem": {
          "description": "The slug of the diagnostic `ascribe check` reports for it\n(`snippet-region-missing`).",
          "type": "string"
        },
        "reason": {
          "description": "Why it doesn't resolve, in a few words.",
          "type": "string"
        },
        "source": {
          "description": "The source the address names.",
          "type": "string"
        }
      },
      "required": [
        "address",
        "source",
        "problem",
        "reason"
      ],
      "type": "object"
    },
    "ChangedExample": {
      "description": "A snippet whose code changed.",
      "properties": {
        "added": {
          "description": "Lines only in the code now.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "address": {
          "description": "Its address, as the page writes it.",
          "type": "string"
        },
        "file": {
          "description": "The code file now, from the repository's root.",
          "type": "string"
        },
        "removed": {
          "description": "Lines only in the code at the base.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "source": {
          "description": "The source the address names.",
          "type": "string"
        },
        "was_file": {
          "description": "The code file at the base, when it was renamed since.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "address",
        "source",
        "file",
        "was_file",
        "added",
        "removed"
      ],
      "type": "object"
    },
    "CommitLine": {
      "description": "A commit, by its hash and the first line of its message.",
      "properties": {
        "commit": {
          "description": "Its full hash.",
          "type": "string"
        },
        "subject": {
          "description": "The first line of its message.",
          "type": "string"
        }
      },
      "required": [
        "commit",
        "subject"
      ],
      "type": "object"
    },
    "Commits": {
      "description": "The commits between two pins.",
      "properties": {
        "count": {
          "description": "How many.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "newest": {
          "description": "The newest, newest first, at most 20.",
          "items": {
            "$ref": "#/$defs/CommitLine"
          },
          "type": "array"
        }
      },
      "required": [
        "count",
        "newest"
      ],
      "type": "object"
    },
    "DriftPage": {
      "description": "A page with an example that changed or broke.",
      "properties": {
        "broken": {
          "description": "The examples that resolved at the base and don't now, by address.",
          "items": {
            "$ref": "#/$defs/BrokenExample"
          },
          "type": "array"
        },
        "builds": {
          "description": "The builds that show it with a changed example, in the order asked\nfor.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "examples": {
          "description": "The examples that changed, by address. Empty when only `broken`\nisn't.",
          "items": {
            "$ref": "#/$defs/ChangedExample"
          },
          "type": "array"
        },
        "page_changed": {
          "description": "Whether the page changed apart from its examples: its own file, or\nits resolved content through anything else it uses (a fragment, the\ncontent model), in any of those builds. When it didn't, the example\nchanged and the words around it didn't.",
          "type": "boolean"
        },
        "path": {
          "description": "The page's content path.",
          "type": "string"
        },
        "route": {
          "description": "Its route, in the first of the builds it's in.",
          "type": "string"
        }
      },
      "required": [
        "path",
        "route",
        "builds",
        "page_changed",
        "examples",
        "broken"
      ],
      "type": "object"
    },
    "Failure": {
      "description": "A file a snippet names that couldn't be copied.",
      "properties": {
        "path": {
          "description": "Its path in the source.",
          "type": "string"
        },
        "reason": {
          "description": "Why.",
          "type": "string"
        }
      },
      "required": [
        "path",
        "reason"
      ],
      "type": "object"
    },
    "FileChange": {
      "description": "What happened to a copy.",
      "oneOf": [
        {
          "const": "added",
          "description": "It's new.",
          "type": "string"
        },
        {
          "const": "changed",
          "description": "Its contents changed.",
          "type": "string"
        },
        {
          "const": "removed",
          "description": "It's gone.",
          "type": "string"
        }
      ]
    },
    "FileUpdate": {
      "description": "How a copy changed.",
      "properties": {
        "change": {
          "$ref": "#/$defs/FileChange",
          "description": "What happened to it."
        },
        "path": {
          "description": "Its path in the source.",
          "type": "string"
        }
      },
      "required": [
        "path",
        "change"
      ],
      "type": "object"
    },
    "SourceUpdate": {
      "description": "What `update` did for one source.",
      "properties": {
        "back": {
          "description": "Whether the new pin isn't after the old one: it moved back, or to\nanother line of history. No commits are counted then.",
          "type": "boolean"
        },
        "commits": {
          "anyOf": [
            {
              "$ref": "#/$defs/Commits"
            },
            {
              "type": "null"
            }
          ],
          "description": "The commits after the old pin up to the new one, when it moved\nforward from one and the repository could say."
        },
        "failed": {
          "description": "The files snippets name that couldn't be copied.",
          "items": {
            "$ref": "#/$defs/Failure"
          },
          "type": "array"
        },
        "files": {
          "description": "The copies that changed.",
          "items": {
            "$ref": "#/$defs/FileUpdate"
          },
          "type": "array"
        },
        "first_copy": {
          "description": "Whether these are the first files copied from the source.",
          "type": "boolean"
        },
        "followed": {
          "description": "The revision followed: `--to`'s, the branch, or `HEAD`.",
          "type": "string"
        },
        "from": {
          "description": "The pin before, if it had one.",
          "type": [
            "string",
            "null"
          ]
        },
        "git": {
          "description": "Its repository.",
          "type": "string"
        },
        "moved": {
          "description": "Whether the pin moved.",
          "type": "boolean"
        },
        "name": {
          "description": "The source.",
          "type": "string"
        },
        "to": {
          "description": "The pin now.",
          "type": "string"
        }
      },
      "required": [
        "name",
        "git",
        "followed",
        "from",
        "to",
        "moved",
        "back",
        "commits",
        "files",
        "failed",
        "first_copy"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe sources update --format json` writes: how each source's pin\nmoved, and the pages whose examples the new copies change.",
  "properties": {
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "changed": {
      "description": "Whether any file changed: a copy, or the lock.",
      "type": "boolean"
    },
    "pages": {
      "description": "The pages whose examples the new copies change, as `ascribe drift\n--format json` lists them; `null` when nothing changed, or when that\ncan't be told.",
      "items": {
        "$ref": "#/$defs/DriftPage"
      },
      "type": [
        "array",
        "null"
      ]
    },
    "pages_unavailable": {
      "description": "Why there are no `pages`, when there aren't.",
      "type": [
        "string",
        "null"
      ]
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "format": "uint32",
      "minimum": 0,
      "type": "integer"
    },
    "sources": {
      "description": "What the update did for each source, in declaration order.",
      "items": {
        "$ref": "#/$defs/SourceUpdate"
      },
      "type": "array"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "changed",
    "sources",
    "pages",
    "pages_unavailable"
  ],
  "title": "SourcesUpdateReport",
  "type": "object"
}

ascribe fmt

Ascribe (GA, 0.2.0+)

schemas/fmt.schema.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).",
          "format": "uint32",
          "minimum": 0,
          "type": "integer"
        },
        "line": {
          "description": "The line, from 1.",
          "format": "uint32",
          "minimum": 0,
          "type": "integer"
        },
        "offset": {
          "description": "The byte offset from the start of the file.",
          "format": "uint",
          "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` 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.",
      "format": "uint32",
      "minimum": 0,
      "type": "integer"
    },
    "written": {
      "description": "Whether the files were rewritten: `false` with `--check`, which\nwrites nothing.",
      "type": "boolean"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "written",
    "files",
    "refused"
  ],
  "title": "FmtReport",
  "type": "object"
}

ascribe explain

Ascribe (GA, 0.2.0+)

schemas/explain.schema.json:

{
  "$defs": {
    "ExampleFile": {
      "description": "A file an example assumes besides its page.",
      "properties": {
        "path": {
          "description": "Its content path.",
          "type": "string"
        },
        "text": {
          "description": "Its text.",
          "type": "string"
        }
      },
      "required": [
        "path",
        "text"
      ],
      "type": "object"
    },
    "ExampleText": {
      "description": "A diagnostic's example.",
      "properties": {
        "files": {
          "description": "The project's other files the example assumes, in path order.",
          "items": {
            "$ref": "#/$defs/ExampleFile"
          },
          "type": "array"
        },
        "model": {
          "description": "The content model the example assumes, when the problem depends on\none: the example's own fragment, or else the explain model. `null`\nwhen it's a problem under any content model.",
          "type": [
            "string",
            "null"
          ]
        },
        "right": {
          "description": "The same page, fixed.",
          "type": "string"
        },
        "wrong": {
          "description": "The page, `page.md`, with the problem.",
          "type": "string"
        }
      },
      "required": [
        "wrong",
        "right",
        "model",
        "files"
      ],
      "type": "object"
    },
    "MessageVariant": {
      "description": "Another wording of a diagnostic's message.",
      "properties": {
        "message": {
          "description": "The message, with its placeholders as written.",
          "type": "string"
        },
        "name": {
          "description": "The case it's for.",
          "type": "string"
        }
      },
      "required": [
        "name",
        "message"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe explain <CODE>` answers: one diagnostic.",
  "properties": {
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "code": {
      "description": "The code, such as `ASC036`.",
      "type": "string"
    },
    "docs": {
      "description": "The address of its entry in the diagnostics reference.",
      "type": "string"
    },
    "example": {
      "anyOf": [
        {
          "$ref": "#/$defs/ExampleText"
        },
        {
          "type": "null"
        }
      ],
      "description": "A page that has the problem and the same page fixed; `null` when the\ndiagnostic has no example."
    },
    "fix": {
      "description": "How to fix it, in general. `null` for a diagnostic that's no longer\nreported.",
      "type": [
        "string",
        "null"
      ]
    },
    "level": {
      "description": "`file` for a problem found in each file on its own; `page` for one\nfound in each page as a build resolves it.",
      "type": "string"
    },
    "message": {
      "description": "The message, with its placeholders (`{path}`) as written.",
      "type": "string"
    },
    "next": {
      "description": "The kind of next step: `fix`, `choose`, `write`, `outside`, or\n`review`. `null` for a diagnostic that's no longer reported.",
      "type": [
        "string",
        "null"
      ]
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "format": "uint32",
      "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"
    },
    "variants": {
      "description": "The other ways the message is worded, by the case they're for, in\nname order.",
      "items": {
        "$ref": "#/$defs/MessageVariant"
      },
      "type": "array"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "code",
    "slug",
    "severity",
    "next",
    "level",
    "message",
    "variants",
    "fix",
    "docs",
    "example"
  ],
  "title": "ExplainReport",
  "type": "object"
}

With --list:

schemas/explain-list.schema.json:

{
  "$defs": {
    "ListedDiagnostic": {
      "description": "A diagnostic in the list.",
      "properties": {
        "code": {
          "description": "The code.",
          "type": "string"
        },
        "severity": {
          "description": "`error`, `warning`, or `advice`.",
          "type": "string"
        },
        "slug": {
          "description": "The slug.",
          "type": "string"
        }
      },
      "required": [
        "code",
        "slug",
        "severity"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe explain --list` answers: every diagnostic.",
  "properties": {
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "diagnostics": {
      "description": "Every diagnostic, in code order.",
      "items": {
        "$ref": "#/$defs/ListedDiagnostic"
      },
      "type": "array"
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "format": "uint32",
      "minimum": 0,
      "type": "integer"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "diagnostics"
  ],
  "title": "ExplainListReport",
  "type": "object"
}

ascribe model

Ascribe (GA, 0.2.0+)

schemas/model.schema.json:

{
  "$defs": {
    "ModelAttribute": {
      "description": "An attribute a widget accepts.",
      "properties": {
        "default": {
          "description": "The value used when it's left out, as written (a set's members joined\nby `|`).",
          "type": [
            "string",
            "null"
          ]
        },
        "description": {
          "description": "What it's for.",
          "type": [
            "string",
            "null"
          ]
        },
        "key": {
          "description": "The key.",
          "type": "string"
        },
        "required": {
          "description": "Whether every use must give it.",
          "type": "boolean"
        },
        "type": {
          "description": "The value's type: `string`, `number`, `boolean`, `enum`, `set`, or\n`note-type`.",
          "type": "string"
        },
        "values": {
          "description": "The values it allows, for `enum` and a `set` of named values; empty\notherwise.",
          "items": {
            "type": "string"
          },
          "type": "array"
        }
      },
      "required": [
        "key",
        "type",
        "values",
        "required",
        "default",
        "description"
      ],
      "type": "object"
    },
    "ModelBuild": {
      "description": "A build.",
      "properties": {
        "availability": {
          "description": "How it treats availability: `badge`, or the target it filters for,\nsuch as `filter self-managed 3.3`.",
          "type": "string"
        },
        "editor": {
          "description": "Whether it's the build the editor checks (`[editor] build`).",
          "type": "boolean"
        },
        "name": {
          "description": "Its name.",
          "type": "string"
        },
        "variants": {
          "description": "Which variant arms it keeps: `switch` for all of them, or the\nselection, such as `deployment=cloud`.",
          "type": "string"
        }
      },
      "required": [
        "name",
        "variants",
        "availability",
        "editor"
      ],
      "type": "object"
    },
    "ModelDimension": {
      "description": "A dimension.",
      "properties": {
        "label": {
          "description": "Its label.",
          "type": "string"
        },
        "name": {
          "description": "Its name.",
          "type": "string"
        },
        "values": {
          "description": "Its values, in display order.",
          "items": {
            "$ref": "#/$defs/ModelDimensionValue"
          },
          "type": "array"
        }
      },
      "required": [
        "name",
        "label",
        "values"
      ],
      "type": "object"
    },
    "ModelDimensionValue": {
      "description": "A value of a dimension.",
      "properties": {
        "label": {
          "description": "Its label.",
          "type": "string"
        },
        "value": {
          "description": "The value.",
          "type": "string"
        },
        "versionless": {
          "description": "Whether it has no versions, so an availability spec gives it a state\nbut no version.",
          "type": "boolean"
        }
      },
      "required": [
        "value",
        "label",
        "versionless"
      ],
      "type": "object"
    },
    "ModelFeature": {
      "description": "A feature.",
      "properties": {
        "availability": {
          "description": "Its availability spec, as written.",
          "type": "string"
        },
        "key": {
          "description": "Its key, which an availability spec can name.",
          "type": "string"
        },
        "name": {
          "description": "Its name.",
          "type": "string"
        }
      },
      "required": [
        "key",
        "name",
        "availability"
      ],
      "type": "object"
    },
    "ModelField": {
      "description": "A frontmatter field.",
      "properties": {
        "description": {
          "description": "What it's for, as the content model describes it.",
          "type": [
            "string",
            "null"
          ]
        },
        "fields": {
          "description": "An object's fields; empty for any other type.",
          "items": {
            "$ref": "#/$defs/ModelField"
          },
          "type": "array"
        },
        "name": {
          "description": "Its name.",
          "type": "string"
        },
        "required": {
          "description": "Whether every page of the type must give it.",
          "type": "boolean"
        },
        "type": {
          "description": "Its type in short form: `string`, `list(string)`, `enum(a, b)`.",
          "type": "string"
        },
        "values": {
          "description": "The values it allows, for an enumeration or a list of one; empty\notherwise.",
          "items": {
            "type": "string"
          },
          "type": "array"
        }
      },
      "required": [
        "name",
        "type",
        "required",
        "values",
        "description",
        "fields"
      ],
      "type": "object"
    },
    "ModelPhrase": {
      "description": "A phrase.",
      "properties": {
        "key": {
          "description": "Its key, written `{key}` in a page.",
          "type": "string"
        },
        "value": {
          "description": "Its value.",
          "type": "string"
        }
      },
      "required": [
        "key",
        "value"
      ],
      "type": "object"
    },
    "ModelTerm": {
      "description": "A glossary term.",
      "properties": {
        "aliases": {
          "description": "Other ways it's written.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "definition": {
          "description": "Its definition.",
          "type": "string"
        },
        "id": {
          "description": "Its id.",
          "type": "string"
        },
        "match": {
          "description": "Which occurrences are linked: `first` on each page, `every` one, or\nonly those an author links (`marked`).",
          "type": "string"
        },
        "term": {
          "description": "The term.",
          "type": "string"
        }
      },
      "required": [
        "id",
        "term",
        "aliases",
        "definition",
        "match"
      ],
      "type": "object"
    },
    "ModelType": {
      "description": "A page type.",
      "properties": {
        "default": {
          "description": "Whether it applies to pages no type's `files` match.",
          "type": "boolean"
        },
        "fields": {
          "description": "Its frontmatter fields, in declaration order.",
          "items": {
            "$ref": "#/$defs/ModelField"
          },
          "type": "array"
        },
        "files": {
          "description": "The patterns of the pages it applies to, relative to the content root.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "name": {
          "description": "Its name.",
          "type": "string"
        }
      },
      "required": [
        "name",
        "files",
        "default",
        "fields"
      ],
      "type": "object"
    },
    "ModelWidget": {
      "description": "A project widget.",
      "properties": {
        "attributes": {
          "description": "Its attributes, in canonical order.",
          "items": {
            "$ref": "#/$defs/ModelAttribute"
          },
          "type": "array"
        },
        "container": {
          "description": "Whether it may be a container, closed by `@end`.",
          "type": "boolean"
        },
        "description": {
          "description": "What it's for, as the content model describes it.",
          "type": [
            "string",
            "null"
          ]
        },
        "line": {
          "description": "Whether it may be one line.",
          "type": "boolean"
        },
        "name": {
          "description": "Its name, written `@name`.",
          "type": "string"
        }
      },
      "required": [
        "name",
        "description",
        "line",
        "container",
        "attributes"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe model --format json` answers: the content model's sections,\nor the one asked for.",
  "properties": {
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "builds": {
      "description": "Builds, in declaration order.",
      "items": {
        "$ref": "#/$defs/ModelBuild"
      },
      "type": [
        "array",
        "null"
      ]
    },
    "dimensions": {
      "description": "Dimensions, in declaration order.",
      "items": {
        "$ref": "#/$defs/ModelDimension"
      },
      "type": [
        "array",
        "null"
      ]
    },
    "features": {
      "description": "Features, in declaration order.",
      "items": {
        "$ref": "#/$defs/ModelFeature"
      },
      "type": [
        "array",
        "null"
      ]
    },
    "glossary": {
      "description": "Glossary terms, in declaration order.",
      "items": {
        "$ref": "#/$defs/ModelTerm"
      },
      "type": [
        "array",
        "null"
      ]
    },
    "phrases": {
      "description": "Phrases, in declaration order.",
      "items": {
        "$ref": "#/$defs/ModelPhrase"
      },
      "type": [
        "array",
        "null"
      ]
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "format": "uint32",
      "minimum": 0,
      "type": "integer"
    },
    "types": {
      "description": "Page types, in declaration order: the implicit `page` type when none\nis declared.",
      "items": {
        "$ref": "#/$defs/ModelType"
      },
      "type": [
        "array",
        "null"
      ]
    },
    "widgets": {
      "description": "Project widgets, in declaration order.",
      "items": {
        "$ref": "#/$defs/ModelWidget"
      },
      "type": [
        "array",
        "null"
      ]
    }
  },
  "required": [
    "schema_version",
    "ascribe_version"
  ],
  "title": "ModelReport",
  "type": "object"
}

ascribe outline

Ascribe (GA, 0.2.0+)

schemas/outline.schema.json:

{
  "$defs": {
    "OutlineHeading": {
      "description": "A heading a link can name.",
      "properties": {
        "explicit_id": {
          "description": "Whether the id is the heading's `@id`, which stays when its text\nchanges.",
          "type": "boolean"
        },
        "file": {
          "description": "The file it's written in, from the project root.",
          "type": "string"
        },
        "fragment": {
          "description": "The fragment it comes from, as a path from the content root; `null`\nfor the page's own.",
          "type": [
            "string",
            "null"
          ]
        },
        "id": {
          "description": "Its id: what a link writes after `#`.",
          "type": "string"
        },
        "level": {
          "description": "1 to 6.",
          "format": "uint8",
          "maximum": 255,
          "minimum": 0,
          "type": "integer"
        },
        "line": {
          "description": "Its line in that file, from 1.",
          "format": "uint32",
          "minimum": 0,
          "type": "integer"
        },
        "text": {
          "description": "Its text, phrases replaced by their values.",
          "type": "string"
        }
      },
      "required": [
        "level",
        "text",
        "id",
        "explicit_id",
        "file",
        "line",
        "fragment"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe outline <PAGE>` answers.",
  "properties": {
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "build": {
      "description": "The build the headings are limited to, with `--build`.",
      "type": [
        "string",
        "null"
      ]
    },
    "file": {
      "description": "The page's file from the project root, as `ascribe check` reports it.",
      "type": "string"
    },
    "fragment": {
      "description": "Whether it's a fragment, which pages include rather than link to.",
      "type": "boolean"
    },
    "headings": {
      "description": "The headings a link to the page can name, in document order, each id\nonce.",
      "items": {
        "$ref": "#/$defs/OutlineHeading"
      },
      "type": "array"
    },
    "not_published": {
      "description": "Why that build doesn't publish the page, when it doesn't; there are\nno headings then.",
      "type": [
        "string",
        "null"
      ]
    },
    "page": {
      "description": "The page's path from the content root, as links write it.",
      "type": "string"
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "format": "uint32",
      "minimum": 0,
      "type": "integer"
    },
    "title": {
      "description": "Its title (frontmatter `title`).",
      "type": [
        "string",
        "null"
      ]
    },
    "type": {
      "description": "Its content type; `null` for a fragment, or when no one type applies.",
      "type": [
        "string",
        "null"
      ]
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "page",
    "file",
    "fragment",
    "title",
    "type",
    "build",
    "not_published",
    "headings"
  ],
  "title": "OutlineReport",
  "type": "object"
}
Ascribe (GA, 0.2.0+)

schemas/link.schema.json:

{
  "$defs": {
    "LinkKind": {
      "description": "What a link target is.",
      "oneOf": [
        {
          "const": "page",
          "description": "A page.",
          "type": "string"
        },
        {
          "const": "heading",
          "description": "A heading on a page.",
          "type": "string"
        },
        {
          "const": "fragment",
          "description": "A fragment, which pages include and links can't name.",
          "type": "string"
        },
        {
          "const": "file",
          "description": "A file that isn't a page, which a build copies: an image or a\ndownload.",
          "type": "string"
        },
        {
          "const": "external",
          "description": "A URL with a scheme.",
          "type": "string"
        },
        {
          "const": "missing",
          "description": "Nothing: no file has that path.",
          "type": "string"
        }
      ]
    },
    "LinkSuggestion": {
      "description": "A target a link could name instead.",
      "properties": {
        "href": {
          "description": "The destination to write.",
          "type": "string"
        },
        "id": {
          "description": "The heading id, if it's a heading.",
          "type": [
            "string",
            "null"
          ]
        },
        "path": {
          "description": "The page, as a path from the content root.",
          "type": "string"
        },
        "title": {
          "description": "The page's title, or the heading's text.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "href",
        "path",
        "id",
        "title"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe link <TARGET> --from <PAGE>` answers.",
  "properties": {
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "closest": {
      "description": "The closest targets that exist, best first, when it doesn't.",
      "items": {
        "$ref": "#/$defs/LinkSuggestion"
      },
      "type": "array"
    },
    "exists": {
      "description": "Whether a link from that page to the target works. An external URL\ncounts as existing; it isn't checked.",
      "type": "boolean"
    },
    "from": {
      "description": "The page the link is written on, as a path from the content root.",
      "type": "string"
    },
    "href": {
      "description": "The destination to write on that page, when the target exists.",
      "type": [
        "string",
        "null"
      ]
    },
    "id": {
      "description": "The heading id after `#`, if any.",
      "type": [
        "string",
        "null"
      ]
    },
    "kind": {
      "$ref": "#/$defs/LinkKind",
      "description": "What the target is."
    },
    "path": {
      "description": "The file it names, as a path from the content root; `null` for an\nexternal URL, or a file that doesn't exist.",
      "type": [
        "string",
        "null"
      ]
    },
    "problem": {
      "description": "Why it doesn't work, when it doesn't.",
      "type": [
        "string",
        "null"
      ]
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "format": "uint32",
      "minimum": 0,
      "type": "integer"
    },
    "target": {
      "description": "The target, as given.",
      "type": "string"
    },
    "title": {
      "description": "The page's title, or the heading's text: what a link with no text\nshows.",
      "type": [
        "string",
        "null"
      ]
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "from",
    "target",
    "exists",
    "kind",
    "path",
    "id",
    "title",
    "href",
    "problem",
    "closest"
  ],
  "title": "LinkReport",
  "type": "object"
}

ascribe refs

Ascribe (GA, 0.2.0+)

schemas/refs.schema.json:

{
  "$defs": {
    "Place": {
      "description": "A place a target is used.",
      "properties": {
        "column": {
          "description": "The column, from 1, in Unicode characters.",
          "format": "uint32",
          "minimum": 0,
          "type": "integer"
        },
        "file": {
          "description": "The file, from the project root, as `ascribe check` reports it.",
          "type": "string"
        },
        "line": {
          "description": "The line, from 1.",
          "format": "uint32",
          "minimum": 0,
          "type": "integer"
        },
        "use": {
          "description": "How it uses the target: `link`, `include`, `phrase`, `availability`,\n`term`, `variant`, `note`, or `widget`.",
          "type": "string"
        }
      },
      "required": [
        "file",
        "line",
        "column",
        "use"
      ],
      "type": "object"
    },
    "TargetKind": {
      "description": "What a target is.",
      "oneOf": [
        {
          "const": "page",
          "description": "A page.",
          "type": "string"
        },
        {
          "const": "fragment",
          "description": "A fragment.",
          "type": "string"
        },
        {
          "const": "heading",
          "description": "A heading, by its page and id.",
          "type": "string"
        },
        {
          "const": "phrase",
          "description": "A phrase, `phrase:<key>`.",
          "type": "string"
        },
        {
          "const": "feature",
          "description": "A feature, `feature:<key>`.",
          "type": "string"
        },
        {
          "const": "term",
          "description": "A glossary term, `term:<id>`.",
          "type": "string"
        },
        {
          "const": "dimension",
          "description": "A dimension, `dimension:<name>`.",
          "type": "string"
        },
        {
          "const": "note",
          "description": "A note type, `note:<type>`.",
          "type": "string"
        },
        {
          "const": "widget",
          "description": "A project widget, `widget:<name>`.",
          "type": "string"
        }
      ]
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe refs <TARGET>` answers.",
  "properties": {
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "exists": {
      "description": "Whether the target exists. When it doesn't, there are no places.",
      "type": "boolean"
    },
    "kind": {
      "$ref": "#/$defs/TargetKind",
      "description": "What the target is."
    },
    "next_command": {
      "description": "The command that lists them all, when the list was cut.",
      "type": [
        "string",
        "null"
      ]
    },
    "places": {
      "description": "The places that use it, file by file in path order and in document\norder within a file; at most `shown` of them.",
      "items": {
        "$ref": "#/$defs/Place"
      },
      "type": "array"
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "format": "uint32",
      "minimum": 0,
      "type": "integer"
    },
    "shown": {
      "description": "How many are listed.",
      "format": "uint",
      "minimum": 0,
      "type": "integer"
    },
    "target": {
      "description": "The target, as given.",
      "type": "string"
    },
    "total": {
      "description": "How many places use it.",
      "format": "uint",
      "minimum": 0,
      "type": "integer"
    },
    "truncated": {
      "description": "Whether the list was cut: `shown` is less than `total`.",
      "type": "boolean"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "target",
    "kind",
    "exists",
    "places",
    "total",
    "shown",
    "truncated",
    "next_command"
  ],
  "title": "RefsReport",
  "type": "object"
}

ascribe render

Ascribe (GA, 0.2.0+)

schemas/render.schema.json:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe render <PAGE> --format json` answers.",
  "properties": {
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "build": {
      "description": "The build.",
      "type": "string"
    },
    "not_published": {
      "description": "Why the build doesn't publish the page, when it doesn't; `text` is\nempty then.",
      "type": [
        "string",
        "null"
      ]
    },
    "page": {
      "description": "The page, as a path from the content root.",
      "type": "string"
    },
    "route": {
      "description": "The page's route in the build's site.",
      "type": [
        "string",
        "null"
      ]
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "format": "uint32",
      "minimum": 0,
      "type": "integer"
    },
    "text": {
      "description": "The page as plain Markdown, as the build's `plain` output writes it:\nwith its frontmatter first when asked for.",
      "type": "string"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "page",
    "build",
    "not_published",
    "route",
    "text"
  ],
  "title": "RenderReport",
  "type": "object"
}