Extending
The rule manifest
A custom rule is two files sharing a basename:
.garboard/rules/
instance_size.json # manifest — identity, severity, the docs line
instance_size.wasm # module — the check itself
The manifest
{
"id": "instance_size",
"severity": "warn",
"title": "Oversized instance class",
"docs": "https://acme.dev/rules/instance-size",
"description": "Finance signed off on sizes up to db.m5.4xlarge."
}
| Field | Required | Rules |
|---|---|---|
id |
yes | [a-z0-9_.-], 3–64 characters, must not start with custom. — the prefix is added for you |
severity |
yes | critical, warn or info — the gate’s existing tiers, no new ones |
title |
yes | Fallback title when a finding omits one |
docs |
yes | An http(s) URL — the line a reader follows from the pull request comment |
description |
no | Free text for the settings UI |
Unknown fields are an error. A typo’d "severty" that silently defaulted would be a rule running at the wrong tier, and finding that out from a production pull request is the wrong time.
The manifest owns identity, not the module
Severity and rule id are read from the manifest and stamped onto every finding the module returns.
Two consequences, both deliberate:
- A module cannot escalate its own severity between uploads. The tier is a property of the rule as configured, reviewable in a diff, not something the code decides at run time.
- A module cannot report under a built-in’s id. Findings always appear as
custom.<id>— for the manifest above,custom.instance_size.
This is why docs is required rather than optional. A custom finding appears in someone’s pull request alongside built-in ones, and the reader deserves somewhere to go that explains your rule. A rule that cannot explain itself is noise with your name on it.
Where the files live
Committed to .garboard/rules/ in the repository they apply to. garboard gate picks them up automatically — --rules defaults to <path>/.garboard/rules and is skipped when that directory is absent, so a repository without custom rules needs no flag.
Committing them is what keeps CI offline: the rule travels with the code it checks.
