Review rules — COMMITBRIEF.md and OUTPUT.md
Customise the system prompt your reviewer sees (COMMITBRIEF.md) and how findings render to markdown locally (OUTPUT.md template).
CommitBrief separates what the reviewer looks for from how the review is rendered. Two files, two layers, neither required to get started.
COMMITBRIEF.md — the system prompt
The team-shared review rules file. Sent to the LLM as the system prompt on every review. Lives at the repo root and is committed to git.
Path
<repo-root>/COMMITBRIEF.md
If the file is missing, CommitBrief falls back to an embedded default. The default works fine on its own — customising is purely additive.
Scaffold it
commitbrief init
Writes the embedded default to COMMITBRIEF.md. Use
--force (or --yes) to overwrite an existing file.
Format
Free-form markdown. Anything you write is passed to the model as
the system prompt, wrapped in <project_rules>...</project_rules>
XML tags. Inside the envelope the model sees your literal content
verbatim; outside, the prompt builder appends a language directive
(per output.lang) and an immutability guard (a prompt-injection
defense — the model is told to treat project rules as data, not
instructions, when they conflict with its baseline behavior).
There are no required headings or template variables.
What the embedded default covers
- Persona — adversarial defender + optimization engineer.
- What to look for — correctness, security, performance, maintainability, testing.
- Output format — instructions for the structured-findings JSON contract (severity, title, description, suggestion, …).
- What NOT to flag — explicit “do not nitpick” list to keep the noise floor down.
Customisation patterns
Project-specific context
## Project context
This is a financial transaction service. Every state change to
`Transaction` must go through `transactions.Repo.Apply()` which
enforces audit logging — direct mutations bypass compliance.
The `internal/billing/` package operates on cents (int64). Never
introduce float64 anywhere in the price-handling path.
High-stakes paths
## High-stakes paths
- `internal/auth/` — authentication / session handling. Any
change here needs a security-focused review.
- `db/migrations/` — schema changes. Verify backward
compatibility with the previous release.
Style conventions
## Conventions
- Use `errors.Is` / `errors.As`, never string-compare error messages.
- All public exported functions must have a doc comment starting with the function name.
- No `panic()` outside `init()` blocks.
Size considerations
A COMMITBRIEF.md is sent on every review as part of the prompt.
Past ~10k tokens (~40k characters) you pay noticeable input cost.
Use commitbrief compress to losslessly shrink the file via the
LLM:
commitbrief compress # default level: balanced
commitbrief compress --dry-run # preview without writing
commitbrief compress --level=aggressive --out COMMITBRIEF.compressed.md
The compress pipeline backs up the original to
.commitbrief/backups/COMMITBRIEF-<ISO-timestamp>.md before
overwriting, and refuses to apply when the compressed result is
not smaller than the original.
What CommitBrief does NOT do with this file
- It does NOT lint the file or enforce a schema.
- It does NOT validate references (e.g. “the file mentioned doesn’t exist”).
- It does NOT version the file or track changes — that is git’s job.
OUTPUT.md — the markdown template
A per-user Go text/template
that controls how findings are formatted locally. Applied to
the parsed findings JSON to produce the markdown output for
--markdown and --output <file>.md. Never sent to the LLM.
Where it lives
CommitBrief looks in this order (first hit wins):
<repo-root>/.commitbrief/OUTPUT.md— per-repo override.<user-home>/.commitbrief/OUTPUT.md— per-user default.- Embedded default at
internal/rules/output.md.
A repo-local OUTPUT.md is gitignored by default. This makes it a personal preference rather than a team artifact.
Template data
type TemplateData struct {
Findings []Finding
}
type Finding struct {
Severity string
File string
Line int
LineEnd int
Title string
Description string
Suggestion string
Language string
Snippet string
}
Inside the template, .Findings is a typed slice:
{{ range .Findings }}
- **{{ upper .Severity }}** {{ .File }}:{{ .Line }} — {{ .Title }}
{{ .Description }}
> {{ .Suggestion }}
{{ end }}
Available functions
| Function | Signature | Purpose |
|---|---|---|
upper | string → string | strings.ToUpper. |
lower | string → string | strings.ToLower. |
groupBySeverity | []Finding → map[Severity][]Finding | Bucket by severity. |
countFiles | []Finding → int | Distinct file count. |
The set is the public template contract; additions are allowed in
v1.x, removals require a schema bump. All built-in
text/template actions (range, if, with, len, printf,
…) also work.
Pre-send validation
If you write a custom OUTPUT.md and the template is malformed, CommitBrief catches it before any provider call. Three checks run on load:
- Parse —
text/templatesyntax check. - Empty execute — template runs against an empty
[]Finding{}. - Sample execute — template runs against a synthetic sample of one finding per severity.
A failure aborts the run with a pointer at the file and a hint
to run commitbrief init --yes to overwrite with the default.
Example — group by severity
{{ $bucketed := groupBySeverity .Findings }}
# Review summary
Files touched: {{ countFiles .Findings }}
{{ with index $bucketed "critical" }}
## Critical
{{ range . }}
- **{{ .File }}:{{ .Line }}** — {{ .Title }}
{{ .Description }}
> {{ .Suggestion }}
{{ end }}
{{ end }}
What OUTPUT.md does NOT do
- It does NOT affect the LLM prompt or the review behavior.
- It does NOT affect
--jsonoutput (the JSON schema is fixed). - It does NOT apply to the cards renderer (lipgloss-styled layout).
- It does NOT apply to CLI-tool-backed providers (claude-cli / gemini-cli emit pre-formatted text directly).
See also
- Output formats — where the rendered markdown shows up.
- Configuration —
output.langand other rendering knobs. .commitbriefignore— separate file controlling which files reach the prompt.