Skip to content

Add manni meta to CI (GitHub Actions)

This page wires manni meta into GitHub Actions. Every push and pull request then validates your document metadata, and fails the job when a file is non-conformant. Each failure is reported as an inline annotation on the pull request diff.

You do not need to install manni meta into your repository. The recipes here run it with npx, which fetches the published manni meta package on demand. The only requirement on the runner is Node.js 24 or newer.

manni meta is built to behave well in CI. Two properties carry the whole integration:

  • Exit codes drive the gate. manni meta exits 0 when every file is valid, and 1 when one or more files fail validation. It exits 2 on an operational or usage error, such as no inputs and no config. GitHub Actions treats any non-zero exit from a step as a failed step, so the metadata gate is enforced for free. There is no separate “if failures, then fail” wiring to maintain.
  • --format github produces inline annotations. Instead of pretty console output, the github format emits one GitHub Actions workflow command per error (::error file=...,line=...,col=...::...). GitHub turns each line into an annotation, pinned to the offending file and line in the pull request. Reviewers then see exactly what failed without opening the job log.

For the full contract, see Exit codes & PR annotations.

Use this when metadata validation is its own job. This is the canonical recipe from examples/manni.yml.

  1. Create the workflow file. Add .github/workflows/manni.yml:

    .github/workflows/manni.yml
    # Validate document metadata on every push and pull request.
    name: Validate metadata
    on:
    push:
    pull_request:
    jobs:
    manni:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v7
    - uses: actions/setup-node@v6
    with:
    node-version: 24
    # Validate all Markdown. `--format github` turns failures into inline
    # PR annotations; the nonzero exit code fails the job.
    - name: Validate frontmatter
    run: npx -y @hawkeyexl/manni meta validate "**/*.md" --format github
  2. Adapt the targets. Replace "**/*.md" with the paths, directories, or globs you want to check, for example "docs/**/*.md". Quote globs so the shell passes them to manni meta intact rather than expanding them itself.

  3. Commit and push. On the next push or pull request, the manni meta job runs. A clean run passes; any validation failure fails the job and annotates the diff.

If your repository has a manni.config.yaml at its root, its top-level collections: list already names the document sets. A run with no positional targets reads those. That lets the workflow step drop the glob entirely:

.github/workflows/manni.yml
- name: Validate frontmatter
# Targets come from collections: in manni.config.yaml at the repo root.
run: npx -y @hawkeyexl/manni meta validate --format github

Keeping the target list in manni.config.yaml means the same command works locally and in CI, and you change what gets validated in one place. Because a collection is declared once for every manni tool rather than per tool, the a11y gate beside this one reads the same list. See Create your manni.config.yaml for both halves of the file.

To gate one part of a docs set rather than all of it, name its collection. --collection <name> is repeatable, one name per occurrence:

.github/workflows/manni.yml
- name: Validate the published guides
run: npx -y @hawkeyexl/manni meta validate --collection guides --format github

A scoped run does skip corpus checks:, with a notice on stderr, because a rule that spans the corpus cannot be answered by part of it. Keep one unscoped job if you gate on those.

You do not need a dedicated workflow. If you already run a docs or lint job, add manni meta as one more step. It needs a checkout and a Node.js 24+ toolchain. If the job already has those, the validation step is a single line.

.github/workflows/docs.yml
jobs:
# ... your existing jobs ...
metadata:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v6
with:
node-version: 24
- name: Validate frontmatter
run: npx -y @hawkeyexl/manni meta validate "docs/**/*.md" --format github

To confirm the gate fires, open a pull request that introduces a metadata error. A Markdown file missing a required type field will do. Then check that:

  • The manni meta job is red.
  • The failing file shows an inline annotation on the changed line.
  • A passing change leaves the job green.

If you want to see the same output locally before pushing, run the command from your shell. Locally, --format github prints the raw ::error lines; drop the flag to get the readable pretty report:

Terminal window
npx -y @hawkeyexl/manni meta validate "docs/**/*.md"