manni stewardship vocabulary
Built-in id: manni:stewardship:1.0.0
Published at https://hawkeyexl.github.io/manni/schemas/stewardship/1.0.0.json.
A $schema that names this URL resolves to the bundled copy, with no network
call.
The question it answers: is this page cared for? Every field is a fact a person asserts about the document, though version control approximates some of them. That covers who wrote the page, who owns it, and who to consult. It also covers when the page was written, when it last changed, when it was last verified, and against what. Adopt it when a docs set has owners and a review habit, and you want both recorded where a check can see them.
Use it
Section titled “Use it”Stewardship is in the
default set, so a
run checks it on every page with no config line. A config’s own schemas add
to the default set. An override replaces the set, so an entry that should keep
stewardship sets defaults: true:
meta: overrides: - collection: guides defaults: true schemas: - ./schemas/guide.jsonFields
Section titled “Fields”| Field | Type | Location | Notes |
|---|---|---|---|
authors | string, object, or list of them | external | Who wrote the page. owner is who answers for it now |
owner | string or list | external | Who answers for the page, as a name, handle, chat channel, or team slug. Ownership systems such as Backstage make this field mandatory |
stakeholders | string or list | external | Who has a stake in this page being right, such as the feature’s engineer, the product owner, or the support lead |
reviewed-by | string or list | external | Who did the last review. The spelling avoids reviewers, which MyST uses for scholarly metadata |
created | W3CDTF date | external | When the document was written. The document’s date, not the date its path appeared in this repo |
last-updated | W3CDTF date | page | When the content last changed in a way a reader notices. Not every commit that touched the file |
last-reviewed | W3CDTF date | external | When the last review happened. Freshness tooling reads this field |
review-interval | ISO 8601 duration | external | How often review is due, such as P90D or P1Y. Machines can compare these, unlike 90d |
verified-against | string, object, or list of them | external | The product version or spec the content was checked against, such as operator 1.4.2 or {name: operator, version: 1.4.2} |
source-of-truth | string, object, or list of them | external | Where the facts live, as a repo path or an API spec. A drift check compares the page against it |
No field is required. Every list field takes one string or a non-empty list
without duplicates. Three fields also take objects. authors accepts the
person objects that MyST and Docusaurus define. verified-against and
source-of-truth accept an object with any keys, so an anchor can be
structured for a checker instead of written for a reader. Every form still
refuses to be empty.
The Location column is the x-manni-location mark each field carries. page
means the value belongs in the document’s own metadata and reaches delivered
output. external means it belongs in the collection’s external-metadata
manifest. A field is page when an agent fetching the page acts on it.
last-updated is the one stewardship field an agent uses, to judge whether a
page is fresh enough to trust. The rest name people and review cadence. See
field location for how the marks are
used.
Additional properties
Section titled “Additional properties”Allowed. The root is open, so a generator’s keys and the other vocabularies’ keys pass beside stewardship’s. Stewardship checks only the ten keys it claims.
Example
Section titled “Example”---title: Install the operator on Kubernetesdescription: Deploy the operator with Helm and verify the rollout.authors: - Jane Doe - name: Sam Reviewer # MyST/Docusaurus person objects are legalowner: platform-docsstakeholders: [jane.doe, pm-alex]reviewed-by: [sam.reviewer]created: 2025-11-04last-updated: 2026-08-20last-reviewed: 2026-08-20review-interval: P90Dverified-against: operator 1.4.2source-of-truth: https://github.com/example/operator/tree/main/helm---An anchor can also be structured, or carry more than one entry.
---title: Roll out the admission webhookdescription: Enable the operator's admission webhook and confirm it is serving.verified-against: - name: operator version: 1.4.2 - kubernetes 1.31source-of-truth: path: charts/operator/values.yaml kind: helm-values---A common mistake
Section titled “A common mistake”A page template that leaves authors: [] as a placeholder fails, because no
form of a stewardship field may be empty.
---title: Install the operator on Kubernetesdescription: Deploy the operator with Helm and verify the rollout.authors: []last-updated: 2026-08-20---$ manni meta validate page.md --no-config -s manni:core:1.0.0 -s manni:stewardship:1.0.0✗ page.md /authors must NOT have fewer than 1 items (line 4) [manni:stewardship:1.0.0] /authors warning "authors" is stored in the page; manni:stewardship:1.0.0 prefers external metadata, and --no-config leaves it no manifest. (line 4) [location:external]
1 file checked, 0 passed, 1 failed, 1 error, 1 warningThe exit code is 1. The warning is the location mark at work, because
--no-config gives an external field no manifest to live in. Drop the key
until someone is named. An empty "" or {} fails too.
Design decisions
Section titled “Design decisions”authorsrecords who wrote the page, andownerrecords who answers for it now. The two part company the moment an author moves on, which is why both exist. Who wrote a page belongs with the question of whether it is cared for, not with core’s question of what it is. It is not a derivable fact either. Git records who committed a change, not who wrote the prose.authorskeeps its own shape.owner,stakeholders, andreviewed-byare a plain name or a list of names.authorsmust also accept every documented MyST and Docusaurus person form, so it cannot share their definition. The cost is that stewardship is not uniform in shape. Normalizingauthorsbreaks the family’s compatibility rule against two schemas that define the field. It still refuses"",[],{}, and bare numbers.- The document’s own dates are asserted, not derived.
createdandlast-updatedlive here because git answers a neighbouring question.git logreports the history of a path in this repo. A page migrated from a CMS, or split out of a longer one, has a path younger than its content. A last commit date also moves for a typo fix, a link sweep, or a bulk frontmatter migration. None of those change what the page says. A published page carries no repo, so a stamped date travels with the document where a derived one cannot. - The cost of stamping a date is real. A hand-typed
last-updatedgoes stale quietly, and no JSON Schema can catch that.manni meta derivestamps managed fields from evidence, andvalidatereports a stamp that has gone stale. A repository chooses which fields it manages. last-updatedis notlast-reviewed. An update changes the content. A review confirms it is still true. A page can have either without the other, which is why both dates exist. Both carry thelast-prefix because both name the most recent instance of a repeating event.createdneeds no prefix, because a document is written once.- The names avoid every neighbour’s spelling. Seven built-ins claim
date, and the family’s compatibility rule holds that key at their loosest definition, which does not require a date at all. Nothing claims a barecreatedorlast-updated. DITA spells the neighbourscritdates.createdandcritdates.revised. Hugo useslastmodand Docusauruslast_update. Starlight and VitePress uselastUpdated, and Open Grapharticle:modified_time. - An anchor can be written for a reader or for a checker.
verified-againstandsource-of-truthtake a string, an object, or a list of either.operator 1.4.2is the short spelling.{name: operator, version: 1.4.2}is the one a drift check compares without parsing prose.verified-againstcan be derived from a command that reads the product’s own version, and a stamp that disagrees is a finding. The list form exists because a page is usually anchored to more than one thing. Object keys are open, so{name, version}and{path, kind}are recommendations. The strict overlay makes them contracts. - The review dates are records only. JSON Schema cannot compare a date to
today, so a
last-reviewedfrom 1998 validates. Computing the due date fromlast-reviewedplusreview-interval, and judging it, belongs to tooling that can read a clock. Any freshness grader can consume these fields. - There is no stored due-date field. It duplicates a value the two existing fields already give, and a hand-maintained copy of a derived value goes stale.
- All three dates use W3CDTF with a field-range check. Reduced precision
is legal, so
2026and2026-08pass. A timestamp requires its timezone, because the W3CDTF profile mandates one. An impossible date such as2026-13-45fails here. Without that check it reaches downstream tooling asInvalid Date, and the page never comes due. The check is not calendar-exact, so February 31 passes. No date is compared to another either, so alast-updatedolder than itscreatedvalidates. - The field is
stakeholdersrather thansme. It is broader than a subject-matter expert on purpose. The product owner and the support lead have a stake in the page being right, without being its technical authority. Project-wide stakeholder lists stay in project docs. This field is for the people who differ from page to page.
Strict overlay
Section titled “Strict overlay”Strict overlay id: manni:stewardship-strict:1.0.0
Published at https://hawkeyexl.github.io/manni/schemas/stewardship-strict/1.0.0.json.
The overlay holds only what strict adds. It narrows the form of a value that is
present and requires no key, so a page with no stewardship fields still passes
it.
| Field | Strict adds |
|---|---|
authors | A list only, with unique entries. A string entry is one line with no leading or trailing whitespace. A person object carries name, and its email and url are well formed |
owner | Each value is a handle a GitHub or GitLab CODEOWNERS file accepts. That means @user, @org/team, a GitLab nested group, @@role, or an email address |
stakeholders, reviewed-by | Each value is one line with no leading or trailing whitespace |
created, last-updated, last-reviewed | An RFC 3339 full date, or a date-time with seconds and an offset. A year or month alone fails |
verified-against | An object entry carries name and version, alone or in a list. The version’s format stays free, and a string entry is unchanged |
source-of-truth | An object entry carries path or url, alone or in a list. A string entry is one id, path or URL on one line with no surrounding space |
review-interval is the same in both, because its ISO 8601 pattern is already
strict.
strict: true stacks it right after the vocabulary, with every other
default’s overlay beside its own base:
meta: strict: trueTo adopt this overlay alone, list its id. The default set already carries the vocabulary:
meta: schemas: - manni:stewardship-strict:1.0.0Each schema is checked on its own, and a finding names the one that produced it. A strict-only failure reads as one, beside the location warning a run without a manifest prints.
---title: Install the operator on Kubernetesdescription: Deploy the operator with Helm and verify the rollout.authors: Jane Doeverified-against: name: operatorlast-updated: 2026-08-20---$ manni meta validate page.md --no-config -s manni:stewardship:1.0.0 -s manni:stewardship-strict:1.0.0✗ page.md /authors must be array (line 4) [manni:stewardship-strict:1.0.0] /verified-against must have required property 'version' (line 5) [manni:stewardship-strict:1.0.0] /authors warning "authors" is stored in the page; manni:stewardship:1.0.0 prefers external metadata, and --no-config leaves it no manifest. (line 4) [location:external] /verified-against warning "verified-against" is stored in the page; manni:stewardship:1.0.0 prefers external metadata, and --no-config leaves it no manifest. (line 5) [location:external]
1 file checked, 0 passed, 1 failed, 2 errors, 2 warningsThe open vocabulary accepts both values, so the overlay alone fails the page.