Skip to content

Write a check

This guide shows you how to create a custom check that validates a standard across your repositories.

Create the check file

Checks are YAML files stored in data/checks/. The filename becomes the check's slug (identifier).

Create data/checks/has-readme.yaml:

name: Has README
description: Ensures every tracked repo has a README.md

targets:
  regex: ".*"   # all repos

script: |
  test -f README.md

That's it — Grimoire picks up new check files automatically on the next refresh cycle.

Understand the structure

Every check definition has these fields:

Field Required Description
name Yes Display name on the dashboard
description Yes What the check validates
targets Yes Which repos to run against (see targeting)
script Yes Bash script to execute
schedule No Cron expression; defaults to refresh_schedule
enabled No true (default) or false
severity No "error" (default) or "warning" — controls how failures appear on the dashboard

Exit codes

A check script communicates its result via exit code:

Exit code Result
0 ✅ Pass
Any non-zero ❌ Fail (reported as error or warning based on severity)

Script environment

Scripts execute inside the cloned repository directory for the target branch. Available environment variables:

Variable Description
REPO_OWNER Repository owner
REPO_NAME Repository name
REPO_FULL_NAME owner/name
BRANCH Branch being checked

Scripts have a 5-minute timeout and output is capped at 64 KB.

Targeting

The targets field determines which repos a check runs against. You must specify exactly one strategy:

All repos (regex match-all)

targets:
  regex: ".*"

Specific repos (explicit list)

targets:
  list:
    - "owner/repo-a"
    - "owner/repo-b"

Pattern match (regex)

targets:
  regex: "myorg/.*-service"

Dynamic (script)

Run a script in each repo — include the repo if it exits 0:

targets:
  script: |
    test -f pyproject.toml

Set severity

By default, check failures are reported as errors. For advisory checks, set severity to warning:

severity: warning

Warnings appear with a yellow indicator on the dashboard instead of red, and carry a lower weight in the backlog.

Set a custom schedule

By default, checks run on the global refresh_schedule. Override with a cron expression:

schedule: "0 * * * *"   # hourly

Trigger manually

# Run against all targeted repos
curl -X POST http://localhost:8000/api/checks/has-readme/run

# Run against a specific repo
curl -X POST "http://localhost:8000/api/checks/has-readme/run?repo=owner/repo"

Disable a check

Toggle from the API:

curl -X POST http://localhost:8000/api/checks/has-readme/toggle

Or set enabled: false in the YAML file.

Example: Lint check with severity

# data/checks/no-fixme-comments.yaml
name: No FIXME comments
description: Warns when FIXME comments are found in source code
severity: warning

targets:
  regex: ".*"

schedule: "0 6 * * *"   # daily at 6am

script: |
  ! grep -r "FIXME" --include="*.py" .