JSON reports: ascribe permalinks and ascribe addresses

The JSON Schemas of what ascribe permalinks and ascribe addresses write with --format json.

For AI agents: the documentation index is at llms.txt, and this page is available as Markdown.

Part of the JSON report contract, whose rules every document here follows.

schemas/permalinks-sync.schema.json:

{
  "$defs": {
    "MovedEntry": {
      "description": "A permalink whose place changed.",
      "properties": {
        "from": {
          "description": "Where the list had it.",
          "type": "string"
        },
        "name": {
          "description": "Its name.",
          "type": "string"
        },
        "to": {
          "description": "Where it's declared now.",
          "type": "string"
        }
      },
      "required": [
        "name",
        "from",
        "to"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe permalinks sync` does to the list.",
  "properties": {
    "added": {
      "description": "The names added, by name.",
      "items": {
        "type": "string"
      },
      "type": "array"
    },
    "aliased": {
      "description": "The names moved to another permalink recorded, new or leading\nsomewhere new, by name.",
      "items": {
        "type": "string"
      },
      "type": "array"
    },
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "changed": {
      "description": "Whether the list's file changes: it's new, or its text differs.",
      "type": "boolean"
    },
    "created": {
      "description": "Whether the project had no list, so this makes one.",
      "type": "boolean"
    },
    "forwarded": {
      "description": "The names moved to a page recorded, new or leading somewhere new, by\nname.",
      "items": {
        "type": "string"
      },
      "type": "array"
    },
    "moved": {
      "description": "The names whose place changed, by name.",
      "items": {
        "$ref": "#/$defs/MovedEntry"
      },
      "type": "array"
    },
    "removed": {
      "description": "The names the list keeps that the project no longer has, by name.\n`ascribe check` warns about each.",
      "items": {
        "type": "string"
      },
      "type": "array"
    },
    "retired": {
      "description": "The retired permalinks recorded, new or with a new reason, by name.",
      "items": {
        "type": "string"
      },
      "type": "array"
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "minimum": 0,
      "type": "integer"
    },
    "written": {
      "description": "Whether the list's file was written: it changes, and nothing said to\nwrite nothing (`--check`, `--dry-run`).",
      "type": "boolean"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "changed",
    "written",
    "created",
    "added",
    "moved",
    "aliased",
    "forwarded",
    "retired",
    "removed"
  ],
  "title": "PermalinksSyncReport",
  "type": "object"
}

schemas/permalinks-list.schema.json:

{
  "$defs": {
    "AliasEntry": {
      "description": "A name `ascribe.addresses` moves to another permalink: an alias.",
      "properties": {
        "name": {
          "description": "Its name.",
          "type": "string"
        },
        "state": {
          "$ref": "#/$defs/ListState",
          "description": "Whether the list has it, leading there: `listed`, or `not_listed`."
        },
        "target": {
          "description": "The name it was moved to.",
          "type": "string"
        }
      },
      "required": [
        "name",
        "target",
        "state"
      ],
      "type": "object"
    },
    "DeclaredEntry": {
      "description": "A permalink the content declares.",
      "properties": {
        "file": {
          "description": "The file it's declared in, from the project root, as `ascribe check`\nreports it.",
          "type": "string"
        },
        "line": {
          "description": "The line of its `@id` or its frontmatter `permalink`, from 1.",
          "minimum": 0,
          "type": "integer"
        },
        "listed_at": {
          "description": "The place the list has for it, when that's somewhere else.",
          "type": [
            "string",
            "null"
          ]
        },
        "name": {
          "description": "Its name.",
          "type": "string"
        },
        "place": {
          "description": "Where it's declared, as the list writes it: the file's path from the\ncontent root, and `#` and the id for a heading.",
          "type": "string"
        },
        "state": {
          "$ref": "#/$defs/ListState",
          "description": "Whether the list has it: `listed` at one of the places its name is\ndeclared, `moved` when the list has it somewhere else, or\n`not_listed`."
        }
      },
      "required": [
        "name",
        "place",
        "file",
        "line",
        "state",
        "listed_at"
      ],
      "type": "object"
    },
    "ListState": {
      "description": "Whether the list has a permalink where it's declared.",
      "oneOf": [
        {
          "const": "listed",
          "description": "At one of the places its name is declared.",
          "type": "string"
        },
        {
          "const": "moved",
          "description": "At a place that doesn't declare it any more.",
          "type": "string"
        },
        {
          "const": "not_listed",
          "description": "Not at all.",
          "type": "string"
        }
      ]
    },
    "ListedAs": {
      "description": "Which of the list's tables has a name.",
      "oneOf": [
        {
          "const": "permalink",
          "description": "`[permalinks]`: a permalink the content declared.",
          "type": "string"
        },
        {
          "const": "alias",
          "description": "`[aliases]`: a name moved to another permalink.",
          "type": "string"
        },
        {
          "const": "moved",
          "description": "`[moved]`: a name moved to a page.",
          "type": "string"
        },
        {
          "const": "retired",
          "description": "`[retired]`: a retired permalink.",
          "type": "string"
        }
      ]
    },
    "MovedName": {
      "description": "A name `ascribe.addresses` moves to a page.",
      "properties": {
        "name": {
          "description": "Its name.",
          "type": "string"
        },
        "state": {
          "$ref": "#/$defs/ListState",
          "description": "Whether the list has it, leading there: `listed`, or `not_listed`."
        },
        "to": {
          "description": "Where its address leads now, as written: a page, and `#` and a\nheading's id.",
          "type": "string"
        }
      },
      "required": [
        "name",
        "to",
        "state"
      ],
      "type": "object"
    },
    "RemovedEntry": {
      "description": "A name the list has that the project doesn't.",
      "properties": {
        "name": {
          "description": "Its name.",
          "type": "string"
        },
        "place": {
          "description": "Where the list says a permalink was declared; for an alias, the name\nit led to; for a moved one, where; for a retired one, its reason.",
          "type": "string"
        },
        "was": {
          "$ref": "#/$defs/ListedAs",
          "description": "What the list has it as."
        }
      },
      "required": [
        "name",
        "was",
        "place"
      ],
      "type": "object"
    },
    "RetiredEntry": {
      "description": "A name `ascribe.addresses` retires.",
      "properties": {
        "name": {
          "description": "Its name.",
          "type": "string"
        },
        "reason": {
          "description": "Why it was retired.",
          "type": "string"
        },
        "state": {
          "$ref": "#/$defs/ListState",
          "description": "Whether the list has it as retired, with this reason: `listed`, or\n`not_listed`."
        }
      },
      "required": [
        "name",
        "reason",
        "state"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe permalinks list` answers.",
  "properties": {
    "aliases": {
      "description": "The names `ascribe.addresses` moves to another permalink, by name.",
      "items": {
        "$ref": "#/$defs/AliasEntry"
      },
      "type": "array"
    },
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "has_list": {
      "description": "Whether the project has `ascribe.permalinks`. Without it, every\npermalink is `not_listed`, and nothing is `removed`.",
      "type": "boolean"
    },
    "moved": {
      "description": "The names `ascribe.addresses` moves to a page, by name.",
      "items": {
        "$ref": "#/$defs/MovedName"
      },
      "type": "array"
    },
    "permalinks": {
      "description": "Every permalink the content declares, in path order and then in\ndocument order, a page's own first. A name declared in several\nplaces is here once for each.",
      "items": {
        "$ref": "#/$defs/DeclaredEntry"
      },
      "type": "array"
    },
    "removed": {
      "description": "The names the list has that the project no longer has, by name.",
      "items": {
        "$ref": "#/$defs/RemovedEntry"
      },
      "type": "array"
    },
    "retired": {
      "description": "The names `ascribe.addresses` retires, or moves to one that's\nretired, by name.",
      "items": {
        "$ref": "#/$defs/RetiredEntry"
      },
      "type": "array"
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "minimum": 0,
      "type": "integer"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "has_list",
    "permalinks",
    "aliases",
    "moved",
    "retired",
    "removed"
  ],
  "title": "PermalinksListReport",
  "type": "object"
}

schemas/permalinks-verify.schema.json:

{
  "$defs": {
    "RetiredName": {
      "description": "A name the list has as retired.",
      "properties": {
        "name": {
          "description": "The name.",
          "type": "string"
        },
        "reason": {
          "description": "Why it was retired, as the docs' authors wrote it.",
          "type": "string"
        }
      },
      "required": [
        "name",
        "reason"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe permalinks verify` answers.",
  "properties": {
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "found": {
      "description": "The names the list has, as permalinks, or moved to another permalink\nor a page, in the order given, each once.",
      "items": {
        "type": "string"
      },
      "type": "array"
    },
    "list": {
      "description": "The list checked against, as given.",
      "type": "string"
    },
    "missing": {
      "description": "The names it doesn't have at all, in the order given, each once.",
      "items": {
        "type": "string"
      },
      "type": "array"
    },
    "retired": {
      "description": "The names the list has as retired, in the order given, each once.",
      "items": {
        "$ref": "#/$defs/RetiredName"
      },
      "type": "array"
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "minimum": 0,
      "type": "integer"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "list",
    "found",
    "retired",
    "missing"
  ],
  "title": "PermalinksVerifyReport",
  "type": "object"
}

schemas/permalinks-retire.schema.json:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe permalinks retire` did.",
  "properties": {
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "created": {
      "description": "Whether `ascribe.addresses` was made, since the project had none.",
      "type": "boolean"
    },
    "list_changed": {
      "description": "Whether `ascribe.permalinks` was changed to record them. Only a name\nthe content no longer declares is recorded as retired.",
      "type": "boolean"
    },
    "reason": {
      "description": "The reason each was given; none when each leads to `to`.",
      "type": [
        "string",
        "null"
      ]
    },
    "retired": {
      "description": "The names retired, each written in `ascribe.addresses` as\n`go:<name>`: in `[retired]`, or, with `to`, in `[moved]`, in order.",
      "items": {
        "type": "string"
      },
      "type": "array"
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "minimum": 0,
      "type": "integer"
    },
    "to": {
      "description": "Where each address leads now, as written in `ascribe.addresses`;\nnone when it shows the reason.",
      "type": [
        "string",
        "null"
      ]
    },
    "written": {
      "description": "Whether the files were written: false with `--dry-run`, which says\nwhat would change.",
      "type": "boolean"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "retired",
    "reason",
    "to",
    "created",
    "list_changed",
    "written"
  ],
  "title": "PermalinksRetireReport",
  "type": "object"
}

ascribe addresses init

schemas/addresses-init.schema.json:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe addresses init --format json` writes.",
  "properties": {
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "created": {
      "description": "Whether the project had no file, so this made one. A file already\nthere is left as it is, but for what's moved into it.",
      "type": "boolean"
    },
    "file": {
      "description": "The file, from the project's folder: `ascribe.addresses`.",
      "type": "string"
    },
    "moved": {
      "description": "The keys moved into the file from `ascribe.toml`'s `[permalinks]`,\neach `go:<name>`, in the order written there; empty when it has\nnone.",
      "items": {
        "type": "string"
      },
      "type": "array"
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "minimum": 0,
      "type": "integer"
    },
    "written": {
      "description": "Whether a file was written: one made, or moved into, without\n`--dry-run`.",
      "type": "boolean"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "file",
    "created",
    "moved",
    "written"
  ],
  "title": "AddressesInitReport",
  "type": "object"
}

ascribe addresses move and retire

schemas/addresses-record.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"
    },
    "Pos": {
      "description": "A position in a file.",
      "properties": {
        "column": {
          "description": "The column, from 1, in Unicode characters (not bytes or UTF-16\nunits).",
          "minimum": 0,
          "type": "integer"
        },
        "line": {
          "description": "The line, from 1.",
          "minimum": 0,
          "type": "integer"
        },
        "offset": {
          "description": "The byte offset from the start of the file.",
          "minimum": 0,
          "type": "integer"
        }
      },
      "required": [
        "line",
        "column",
        "offset"
      ],
      "type": "object"
    },
    "Range": {
      "description": "A span of a file. `end` is just past its last character; an empty range\n(an insertion) has equal positions.",
      "properties": {
        "end": {
          "$ref": "#/$defs/Pos",
          "description": "Just past its last character."
        },
        "start": {
          "$ref": "#/$defs/Pos",
          "description": "Its first character."
        }
      },
      "required": [
        "start",
        "end"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe addresses move` and `retire` write with `--format json`.",
  "properties": {
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "changed": {
      "description": "Whether the file changed: an entry already the same changes nothing.",
      "type": "boolean"
    },
    "edits": {
      "description": "The edits that make the change, each replacing the text of its\nrange in the file as it was; none when nothing changed.",
      "items": {
        "$ref": "#/$defs/Edit"
      },
      "type": "array"
    },
    "file": {
      "description": "The file, from the project's folder: `ascribe.addresses`.",
      "type": "string"
    },
    "key": {
      "description": "The entry's key: a page's path from the content root, a file's path\nwith `#` and an id, an address starting with `/`, or a permalink,\n`go:<name>`.",
      "type": "string"
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "minimum": 0,
      "type": "integer"
    },
    "table": {
      "description": "The table the entry is in: `moved` or `retired`.",
      "type": "string"
    },
    "value": {
      "description": "The entry's value: where it moved, or why it was retired.",
      "type": "string"
    },
    "written": {
      "description": "Whether the change was written: the MCP server's tools write\nnothing, and give the edits to apply.",
      "type": "boolean"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "file",
    "table",
    "key",
    "value",
    "changed",
    "written",
    "edits"
  ],
  "title": "AddressesRecordReport",
  "type": "object"
}

ascribe addresses move --from-git

schemas/addresses-from-git.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"
    },
    "MoveJson": {
      "description": "A move `--from-git` records.",
      "properties": {
        "key": {
          "description": "The entry's key: where the page was.",
          "type": "string"
        },
        "value": {
          "description": "The entry's value: where it is now.",
          "type": "string"
        }
      },
      "required": [
        "key",
        "value"
      ],
      "type": "object"
    },
    "Pos": {
      "description": "A position in a file.",
      "properties": {
        "column": {
          "description": "The column, from 1, in Unicode characters (not bytes or UTF-16\nunits).",
          "minimum": 0,
          "type": "integer"
        },
        "line": {
          "description": "The line, from 1.",
          "minimum": 0,
          "type": "integer"
        },
        "offset": {
          "description": "The byte offset from the start of the file.",
          "minimum": 0,
          "type": "integer"
        }
      },
      "required": [
        "line",
        "column",
        "offset"
      ],
      "type": "object"
    },
    "Range": {
      "description": "A span of a file. `end` is just past its last character; an empty range\n(an insertion) has equal positions.",
      "properties": {
        "end": {
          "$ref": "#/$defs/Pos",
          "description": "Just past its last character."
        },
        "start": {
          "$ref": "#/$defs/Pos",
          "description": "Its first character."
        }
      },
      "required": [
        "start",
        "end"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe addresses move --from-git --format json` writes.",
  "properties": {
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "base": {
      "description": "The base git's renames are seen from: the revision asked for, or the\ndefault branch, and its commit when that's something else.",
      "type": "string"
    },
    "changed": {
      "description": "Whether the file changed.",
      "type": "boolean"
    },
    "edits": {
      "description": "The edits that make the change, each replacing the text of its\nrange in the file as it was; none when nothing changed.",
      "items": {
        "$ref": "#/$defs/Edit"
      },
      "type": "array"
    },
    "file": {
      "description": "The file, from the project's folder: `ascribe.addresses`.",
      "type": "string"
    },
    "moves": {
      "description": "Each move recorded, in path order: the page's old path, from the\ncontent root, and its new one.",
      "items": {
        "$ref": "#/$defs/MoveJson"
      },
      "type": "array"
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "minimum": 0,
      "type": "integer"
    },
    "written": {
      "description": "Whether the change was written: the MCP server's tools write\nnothing, and give the edits to apply.",
      "type": "boolean"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "file",
    "base",
    "moves",
    "changed",
    "written",
    "edits"
  ],
  "title": "AddressesFromGitReport",
  "type": "object"
}

ascribe addresses list

schemas/addresses-list.schema.json:

{
  "$defs": {
    "Gone": {
      "description": "An address retired on purpose.",
      "properties": {
        "entry": {
          "description": "The `ascribe.addresses` key it comes from.",
          "type": "string"
        },
        "page": {
          "description": "Where the page saying so is, from the host's root: the base path,\n`GONE_FOLDER`, and the key's address from the base path, its page's\nfor a Markdown version.",
          "type": "string"
        },
        "path": {
          "description": "The address, from the host's root.",
          "type": "string"
        },
        "reason": {
          "description": "Why it was retired.",
          "type": "string"
        }
      },
      "required": [
        "path",
        "reason",
        "entry",
        "page"
      ],
      "type": "object"
    },
    "Redirect": {
      "description": "An address that leads somewhere else now.",
      "properties": {
        "entry": {
          "description": "The `ascribe.addresses` key the pair comes from; or, for a pair a\n`[former]` setting makes, `former.` and the setting:\n`former.base-path`, `former.permalink-path`, or `former.agents`.",
          "type": "string"
        },
        "from": {
          "description": "The old address, from the host's root, in the published case and\nslash form.",
          "type": "string"
        },
        "status": {
          "description": "The HTTP status: 301.",
          "maximum": 65535,
          "minimum": 0,
          "type": "integer"
        },
        "to": {
          "description": "Where it leads now, from the host's root.",
          "type": "string"
        }
      },
      "required": [
        "from",
        "to",
        "status",
        "entry"
      ],
      "type": "object"
    },
    "Redirects": {
      "description": "Where the addresses a build used to publish lead now, and which were\nretired: `_ascribe/redirects.json`.",
      "properties": {
        "build": {
          "description": "The build's name.",
          "type": "string"
        },
        "gone": {
          "description": "Each retired address, sorted by `path`.",
          "items": {
            "$ref": "#/$defs/Gone"
          },
          "type": "array"
        },
        "redirects": {
          "description": "Each pair, sorted by `from`.",
          "items": {
            "$ref": "#/$defs/Redirect"
          },
          "type": "array"
        },
        "version": {
          "description": "The format's version.",
          "minimum": 0,
          "type": "integer"
        }
      },
      "required": [
        "version",
        "build",
        "redirects",
        "gone"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "What `ascribe addresses list --format json` writes.",
  "properties": {
    "ascribe_version": {
      "description": "The version of Ascribe that wrote it.",
      "type": "string"
    },
    "builds": {
      "description": "Each build's redirects and retired addresses, as its\n`_ascribe/redirects.json` has them, in the content model's order.",
      "items": {
        "$ref": "#/$defs/Redirects"
      },
      "type": "array"
    },
    "has_file": {
      "description": "Whether the project has `ascribe.addresses`. Without it, every\nbuild's lists are empty.",
      "type": "boolean"
    },
    "schema_version": {
      "description": "The version of this schema. It changes only when a field is removed\nor changes meaning.",
      "minimum": 0,
      "type": "integer"
    }
  },
  "required": [
    "schema_version",
    "ascribe_version",
    "has_file",
    "builds"
  ],
  "title": "AddressesListReport",
  "type": "object"
}