Configuration reference
manni lint reads one file, the shared manni.config.yaml, and one key of it,
lint:. Sibling tools’ keys cost it nothing: it neither reads nor validates
them, and needs no registry of known tools to know that.
The document set is not in lint:. It is declared once for the whole family in
the top-level collections: list, beside
encryptionKey:.
The file
Section titled “The file”# The document set, shared by every tool.collections: - name: guides paths: ["docs/guides/**/*.md"] exclude: ["**/drafts/**"] - name: api paths: ["docs/api/**/*.md"]
# The metadata tool's key, for contrast. manni lint never reads it.meta: schemas: [okf]
# Everything manni lint reads.lint: allowEmpty: false structure: tool: manni templates: - ./templates.yaml template: tgdp:how-to:1.6 types: api-operation: ./templates.yaml#api-operation overrides: - files: "docs/api/**" template: tgdp:reference:1.6
# An outside tool's settings, for the run that starts it. Not under `lint:`,# because a tool is not any one domain's.tools: dita-ot: home: /opt/dita-otEvery key is optional. A repository whose pages all declare a type: a
built-in template serves needs no lint: section at all. An empty one is
the same as none.
Validation is strict, with additionalProperties: false at every level below
lint:. A typo is a loud failure rather than a silent default.
Discovery
Section titled “Discovery”The file is found by walking up from the working directory to the project
boundary, exactly as manni meta finds it. manni.config.yaml and
manni.config.yml are the names, and the nearest one wins; ancestors are never
merged. -c <path> names one explicitly, and the file must then exist or the
run exits 2. --no-config ignores any discovered one.
doc-structure-lint.config.yaml, the standalone tool’s own file, is not
discovered at all. See Coming from
doc-structure-lint for why, and what to do
with one. moose.config.yaml is not discovered either: that is the family
file’s pre-rename name, and discovery walks past it.
In pretty output the run says which file governed it, on stderr:
Using manni.config.yaml (.)That line exists because discovery walks upward. An unexpected ancestor config is the difference between a five-minute diagnosis and an hour of confusion.
Everything a config declares is resolved relative to the config file’s own
directory, not the working directory. So templates: [./templates.yaml]
means the same file whether the command runs from the repository root or from
docs/api/.
The document set
Section titled “The document set”Targets come from three places, in this order:
- Positional
[paths...]on the command line, including-for stdin. - The collections named by
--collection, when no paths were given. - Every declared collection, when neither was given.
No paths, no --collection and no config is an operational error, not a
silently clean run:
manni: No files to check. Pass paths/globs, or declare a collection under `collections:` in manni.config.yaml.A collection carries name, paths, and optionally exclude. Its exclude
decides membership, so a file a collection excludes is not in the set at all
rather than filtered out later. The full contract is on
meta’s configuration page,
because collections: belongs to the family rather than to any one tool.
lint: keys
Section titled “lint: keys”| Key | Type | Default | Required | What it does |
|---|---|---|---|---|
allowEmpty | boolean | false | no | Treat a run that matched zero files as success rather than an operational error. For a shared CI template or a pre-commit hook whose file list may legitimately be empty. The same key, with the same meaning, as cite.allowEmpty. --allow-empty sets it for one run. |
structure | object | absent | no | The structure job. Declaring it with no keys is how a repository says the job applies. |
structure.tool | string, manni or dita-ot | manni | no | Which tool performs the job. manni is this package’s own engine. dita-ot is DITA Open Toolkit, which you install yourself and which settles references across files. Anything else is refused by name. --tool <name> names the same thing for one run. See Choose a structure tool. |
templates | string[] | none | no | Template files to load. Their templates’ types: join the doctype routing table and outrank the built-ins. Adopting a repository’s own how-to shape is one entry here and no flag. Each entry is a template ref. --templates <path> adds more. |
template | string | none | no | Template ref applied to a page that declares no doctype and matches no override. The last rung of the chain, not an override. |
types | object | none | no | Explicit doctype → template ref map, for a doctype no template file claims with its own types:. Keys are the vocabulary your pages’ type: frontmatter is written in, so they are your names rather than the tool’s. |
overrides | array | none | no | Repository policy. Everything under a glob is linted with one template, whatever the pages say they are. First matching entry wins, and an override outranks a page’s own type:. |
overrides[].files | string | n/a | yes | Glob matched against each file’s path, written with forward slashes whatever the platform uses. |
overrides[].template | string | n/a | yes | Template ref applied to the files the entry matches. |
An entry naming no template, or no files, is refused: it is a line that silently does nothing.
tools: keys
Section titled “tools: keys”An outside tool’s settings sit at the top level, beside collections:, not
under lint:. A tool is not any one domain’s. Vale is the case in point, since
manni term lint runs it and so does a docevals grader. Each should read one
description of where a tool lives, not two that can disagree.
Each tool gets a namespace of its own keys rather than a shared shape, because tools do not have the same settings.
| Key | Type | Default | Required | What it does |
|---|---|---|---|---|
tools.dita-ot | object | absent | no | DITA Open Toolkit’s settings, read by the run that starts it. |
tools.dita-ot.home | string | none | no | DITA-OT’s installation directory, relative to this file. Unset means the dita on your PATH. A directory rather than a path to the launcher, because that is the unit DITA-OT ships as. |
A path is kept as you spelled it and resolved when it is used. Whether it
exists is a question for the run that needs it, so manni lint tools reports
an install it cannot find as unavailable rather than refusing to print.
How a template is chosen
Section titled “How a template is chosen”Five rungs, in order. The first that answers wins, and the rest are not consulted:
| # | Rung | Source | Wins when |
|---|---|---|---|
| 1 | cli | -t, --template <ref> | The flag was given. It applies to every file in the run. |
| 2 | frontmatter-template | $template: in the page’s own frontmatter | The page names its template itself. |
| 3 | config-override | lint.overrides[] | A files: glob matches the path. First matching entry wins. |
| 4 | type | The page’s type: frontmatter | A template’s types: claims that doctype, or lint.types maps it. Template files outrank the built-ins. |
| 5 | config-default | lint.template | The page declares no type and nothing above answered. |
A page that falls off the end is skipped, not failed. A page that declares a
type: nothing serves is a manni:lint/structure/unknown-type finding, because
that is an assertion the page made and the tool could not honour.
manni lint structure --explain prints this table per file, marking the rung
that decided. It is the fastest way to answer “why did this page route there?”,
and it always exits 0.
▸ docs/rotate-key.md · cli --template not given · frontmatter-template no $template in frontmatter · config-override no overrides configured → type tgdp:how-to:1.6 type: how-to -> builtin templateWhich types: wins
Section titled “Which types: wins”Doctype routing reads three sources, later ones overwriting earlier:
- The built-in TGDP templates and the doctypes they serve.
- Every file in
lint.templates, in order, then every--templatesfile, in order. A later file’stypes:replaces an earlier one’s for the same doctype. lint.types, the explicit map, which is last and therefore decisive.
So a repository that wants its own how-to shape adds a template file whose
template declares types: [how-to], and nothing else changes. A repository
with a doctype no template file claims writes it in lint.types instead.
Keys that moved
Section titled “Keys that moved”Two keys the imported tool carried are refused by name, so an upgrading repository is told rather than silently linting nothing:
manni: manni.config.yaml: "paths" is no longer a lint key. Document sets are declared once for every tool, under a top-level collections: list. See https://hawkeyexl.github.io/manni/meta/reference/configuration/#collectionsmanni: manni.config.yaml: "exclude" is no longer a lint key. Document sets are declared once for every tool, under a top-level collections: list. See https://hawkeyexl.github.io/manni/meta/reference/configuration/#collectionsBoth exit 2.
Coming from doc-structure-lint
Section titled “Coming from doc-structure-lint”manni lint structure is the doc-structure-lint package, folded into the
manni bin. The engine, the templates and the rules are the same. The surface
around them is the family’s.
Nothing migrates automatically, and nothing is read from the old file. The changes are these:
| Was | Now |
|---|---|
npx doc-structure-lint docs/ | manni lint check docs/, or manni lint structure docs/ for that one job |
doc-structure-lint.config.yaml | The lint: key of manni.config.yaml. The old name is not read at all, not even to warn about it. Its whole document was the lint: section, written in keys the section no longer takes. |
moose.config.yaml | Not discovered. It is the family file’s pre-rename name, not this tool’s. Rename it to manni.config.yaml. |
paths: under the tool’s config | A collection’s paths: under the top-level collections: |
exclude: under the tool’s config | The same collection’s exclude: |
doc-structure-lint lint as a default subcommand | No default subcommand. manni lint alone lists the four verbs and exits 2. |
doc-structure-lint formats | manni lint tools, which lists the formats under the tool that reads them |
heading_pattern_error in output | One manni:lint/structure/heading rule covers every form of heading. The JSON reporter carries the machine name as type, beside the ruleId. |
"error" | "warning" severities of its own | The family scale. Every structural finding is error but one, and that warning never changes the exit code. |
| A template as a map of section rules | A grammar. sections: is an ordered list, required: and additionalSections are gone, and repeat: groups rules rather than taking a boolean. The loader refuses each old key by name and prints the new spelling. |
instructions: in a template | Removed. Structure checking is deterministic; the loader refuses the key and prints the manni docevals eval to move it to. |
The published doc-structure-lint package is unaffected by any of this. It is
archived separately.
Moving one repository
Section titled “Moving one repository”A doc-structure-lint.config.yaml that read:
paths: - "docs/**/*.md"exclude: - "**/drafts/**"templates: - ./templates.yamlbecomes:
collections: - name: guides paths: ["docs/**/*.md"] exclude: ["**/drafts/**"]
lint: templates: - ./templates.yamland npx doc-structure-lint becomes npx @hawkeyexl/manni lint check, with no
arguments, because the collection supplies them.
Related
Section titled “Related”- CLI reference. Every flag, and which config key each mirrors.
- Templates reference. The template file format, the built-in TGDP set, and what a ref may be.
collections:. The family-level document set.- Severity across the family. The one scale every tool speaks.