// docs · v1.0

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

  1. Persona — adversarial defender + optimization engineer.
  2. What to look for — correctness, security, performance, maintainability, testing.
  3. Output format — instructions for the structured-findings JSON contract (severity, title, description, suggestion, …).
  4. 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):

  1. <repo-root>/.commitbrief/OUTPUT.md — per-repo override.
  2. <user-home>/.commitbrief/OUTPUT.md — per-user default.
  3. 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

FunctionSignaturePurpose
upperstring → stringstrings.ToUpper.
lowerstring → stringstrings.ToLower.
groupBySeverity[]Finding → map[Severity][]FindingBucket by severity.
countFiles[]Finding → intDistinct 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:

  1. Parsetext/template syntax check.
  2. Empty execute — template runs against an empty []Finding{}.
  3. 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 --json output (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