review

package
v1.45.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 22, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package review defines the Reviewer abstraction: what a review needs, what it produces, and how findings are modelled. Backends (the claude CLI today, SDKs later) live in subpackages.

Index

Constants

View Source
const AttributionFooter = "" /* 130-byte string literal not displayed */

AttributionFooter is appended to published comments when publish.attribution is enabled.

View Source
const ChatSystemPrompt = `` /* 958-byte string literal not displayed */

ChatSystemPrompt is the persona for MR conversations: a knowledgeable pair of eyes, not the finding-reporting reviewer contract.

View Source
const DefaultBodyTemplate = "**[{{.severity}} · {{.category}}] {{.title}}**\n\n{{.body}}"

DefaultBodyTemplate is the built-in comment layout (publish.template). Fields available to templates: severity, category, agent, title, body, file.

View Source
const OutputSchema = `` /* 1406-byte string literal not displayed */

OutputSchema is passed to the backend (claude --json-schema) so findings arrive as validated structured output.

View Source
const SystemPrompt = `` /* 1439-byte string literal not displayed */

SystemPrompt is appended to the backend's system prompt: the reviewer persona and the line-reporting contract the position resolver depends on.

Variables

View Source
var AllCategories = []Category{"bug", "security", "performance", "docs", "style", "design"}

Categories the reviewer knows how to look for.

Functions

func BuildChatPrompt added in v1.21.0

func BuildChatPrompt(req ChatRequest) string

BuildChatPrompt renders the opening turn of a conversation: MR metadata, the (bounded) diff under discussion, the focus line if any, then the user's first message. Later turns resume the backend session and send the message alone.

func BuildUserPrompt

func BuildUserPrompt(req Request) string

BuildUserPrompt renders the review request: MR metadata, agent scope, custom instructions, then the bounded diff with annotated line numbers.

func CountBlocking added in v1.29.0

func CountBlocking(findings []Finding, min Severity) int

CountBlocking counts the findings that block a severity gate at min.

func FullSystemPrompt added in v1.16.0

func FullSystemPrompt(req Request) string

FullSystemPrompt is the system prompt for one agent's pass: the shared reviewer contract above, then the agent's own persona/focus text.

func ParseBodyTemplate added in v1.1.0

func ParseBodyTemplate(s string) (*template.Template, error)

ParseBodyTemplate parses a publish.template value; empty means the built-in layout. It trial-executes the template so unknown fields fail here, not at publish time.

Types

type Category

type Category string

Category of a finding.

func (Category) Valid

func (c Category) Valid() bool

Valid reports whether c is a known category.

type ChatFocus added in v1.21.0

type ChatFocus struct {
	File string // new path, repo-relative, as shown in the diff headers
	Line LineRef
}

ChatFocus narrows a chat to one line of the MR diff.

func (ChatFocus) Label added in v1.21.0

func (f ChatFocus) Label() string

Label names the focus for titles and prompts: "path:42" or "path:42(old)".

type ChatReply added in v1.21.0

type ChatReply struct {
	// Text is the model's answer, GitLab-flavoured markdown.
	Text string
	// SessionID identifies the backend conversation; pass it back in the
	// next ChatRequest to continue with full context.
	SessionID string
	CostUSD   float64
}

ChatReply is one completed chat turn.

type ChatRequest added in v1.21.0

type ChatRequest struct {
	// RepoPath is the checkout the chat runs in (the subprocess cwd). It must
	// stay the same across the turns of one conversation: the backend session
	// is resumed from there.
	RepoPath string
	// MR carries metadata shown to the model (title, description, branches).
	MR gitlabx.MRDetail
	// Diffs is the MR's diff set; the prompt builder bounds what is inlined.
	// Only consulted on the first turn.
	Diffs []gitlabx.FileDiff
	// Focus narrows the conversation to one diff line; nil chats about the
	// whole MR.
	Focus *ChatFocus
	// MaxDiffKB bounds the diff inlined into the first turn's prompt; <= 0
	// falls back to a conservative default.
	MaxDiffKB int
	// Message is the user's message for this turn.
	Message string
	// SessionID resumes an earlier conversation; empty starts a new one.
	SessionID string
	// Timeout bounds one turn, not the whole conversation.
	Timeout time.Duration
}

ChatRequest is everything a backend needs to run one chat turn. The first turn of a conversation (empty SessionID) carries the MR context; later turns resume the backend session and carry only the new message.

type Chatter added in v1.21.0

type Chatter interface {
	Chat(ctx context.Context, req ChatRequest, onEvent func(Event)) (*ChatReply, error)
}

Chatter holds a conversation about an MR inside its checkout. onEvent receives progress (tool use, status) while a turn runs; the reply text arrives complete when the turn finishes.

type DiffFile added in v1.15.0

type DiffFile struct {
	Path     string // the changed file
	DiffPath string // the file containing its full diff
}

DiffFile points the reviewer at an on-disk diff for a changed file whose diff was too large to inline in the prompt. Both paths are repo-relative.

type Event

type Event struct {
	Kind EventKind
	Text string
	// Agent is the review agent the event belongs to; empty for run-level
	// events.
	Agent string
}

Event is one progress update for the TUI's review log.

type EventKind

type EventKind int

EventKind classifies progress events streamed during a review.

const (
	EventInit EventKind = iota
	EventStatus
	EventToolUse
	EventText
	EventRetry
)

type Finding

type Finding struct {
	ID       string   `json:"id"`
	File     string   `json:"file,omitempty"`     // new path, repo-relative; empty on MR-level manual comments
	OldFile  string   `json:"old_file,omitempty"` // as reported by the model for renames; advisory only
	Line     LineRef  `json:"line,omitzero"`
	Severity Severity `json:"severity,omitempty"`
	Category Category `json:"category,omitempty"`
	// Agent names the review agent that produced the finding. Stamped by the
	// runner, never reported by the model; empty on records from before
	// agents existed and on manual comments.
	Agent      string       `json:"agent,omitempty"`
	Title      string       `json:"title,omitempty"`
	Body       string       `json:"body"`                 // markdown, user-editable
	Suggestion string       `json:"suggestion,omitempty"` // optional replacement for the flagged line
	State      FindingState `json:"state"`
	// Manual marks a comment written by the reviewer in the TUI rather than
	// produced by the model: it publishes verbatim, without the body
	// template or the attribution footer.
	Manual bool `json:"manual,omitempty"`
}

Finding is one suggested review comment. The json tags define the stored form used by review/resultstore.

func (Finding) Blocking added in v1.29.0

func (f Finding) Blocking(min Severity) bool

Blocking reports whether f counts against a severity gate at min: a model finding at or above the threshold that has not been rejected in curation. Manual comments carry no severity and never block.

func (Finding) RenderBody

func (f Finding) RenderBody(tmpl *template.Template, attribution bool) string

RenderBody formats a finding as the GitLab comment body using tmpl (nil means the built-in layout). Suggestions become GitLab suggestion blocks only when anchored to a new-side line (GitLab applies suggestions to the commented line).

func (Finding) RenderFallbackBody

func (f Finding) RenderFallbackBody(tmpl *template.Template, attribution bool, blobURL string) string

RenderFallbackBody formats a finding for a general MR note when no inline position could be resolved; blobURL may be empty.

type FindingState

type FindingState int

FindingState tracks a finding through the curation flow.

const (
	StatePending FindingState = iota
	StateAccepted
	StateRejected
	StatePublished
	StateFellBack       // published, but as a general note because no position resolved
	StateBelowThreshold // below publish.min_severity: visible in triage, never published
)

func (FindingState) MarshalText added in v1.10.0

func (s FindingState) MarshalText() ([]byte, error)

MarshalText encodes the state as its display word, so persisted findings stay readable and survive reordering of the constants.

func (FindingState) String

func (s FindingState) String() string

func (*FindingState) UnmarshalText added in v1.10.0

func (s *FindingState) UnmarshalText(text []byte) error

UnmarshalText is the inverse of MarshalText.

type LineRef

type LineRef struct {
	OldLine *int `json:"old_line,omitempty"`
	NewLine *int `json:"new_line,omitempty"`
}

LineRef locates a finding in a diff: new-side line for added/context lines, old-side line for removed lines. Nil means not applicable.

type Request

type Request struct {
	// RepoPath is the checkout the review runs in (the subprocess cwd).
	RepoPath string
	// MR carries metadata shown to the model (title, description, branches).
	MR gitlabx.MRDetail
	// Diffs is the bounded, pre-filtered set of file diffs to review.
	Diffs []gitlabx.FileDiff
	// Commits are the MR's commits, shown to the model as context (and for
	// commit-message hygiene checks driven via Instructions).
	Commits []gitlabx.Commit
	// Template is the project's default MR description template, shown to the
	// model so instructions can drive a description-vs-template hygiene
	// check. Empty when the project has no template.
	Template string
	// Excluded lists changed files dropped from review by configuration
	// (exclude globs, generated files); shown to the model as context only.
	Excluded []string
	// DiffFiles lists changed files whose diffs were too large to inline;
	// each full diff was written into the checkout for the model to Read.
	DiffFiles []DiffFile
	// Unavailable lists changed files GitLab returned no diff for; the model
	// can only read their state at the head commit.
	Unavailable []string
	// Instructions is extra prompt text: global then per-project.
	Instructions string
	// Categories the running agent may label findings with.
	Categories []Category
	// AgentName identifies the review agent this request runs as; it is set
	// by the runner when specialising a chunk request per selected agent.
	AgentName string
	// AgentPrompt is the agent's persona/focus text, appended to the shared
	// system prompt by the backend.
	AgentPrompt string
	// Incremental marks a delta review: Diffs holds only the changes pushed
	// since LastReviewedSHA (the previous review's head commit) instead of
	// the whole MR diff.
	Incremental     bool
	LastReviewedSHA string

	Model        string
	Timeout      time.Duration
	MaxBudgetUSD float64

	// AllowedDomains grants WebFetch scoped to these domains only, for this
	// request; empty means WebFetch stays fully denied. Mirrors Model's
	// per-request-with-Backend-fallback shape.
	AllowedDomains []string
	// AllowedCommands grants Bash scoped to these command patterns only,
	// for this request; empty means Bash stays fully denied.
	AllowedCommands []string
}

Request is everything a backend needs to run one review.

type Result

type Result struct {
	Summary   string
	Findings  []Finding
	Warnings  []string // dropped findings, truncation notes
	SessionID string
	CostUSD   float64
	Raw       []byte // raw output for drift debugging; persisted by the caller
	// Agent names the review agent that produced this result, before merging.
	Agent string
}

Result is a completed review.

func MergeResults

func MergeResults(parts []*Result) *Result

MergeResults combines the results of a multi-pass review into one, with finding IDs reassigned to stay unique.

func ParseResult

func ParseResult(data []byte) (*Result, error)

ParseResult decodes and validates a backend's structured output. Findings that fail validation are dropped into Warnings rather than failing the review; a completely undecodable payload is an error.

type Reviewer

type Reviewer interface {
	Name() string
	// CheckAvailable verifies the backend can run (binary present, version
	// supported) and returns a user-actionable error otherwise.
	CheckAvailable(ctx context.Context) error
	Review(ctx context.Context, req Request, onEvent func(Event)) (*Result, error)
}

Reviewer runs reviews. Implementations must be safe to reuse serially; onEvent is called from the reviewing goroutine.

type Severity

type Severity string

Severity of a finding, weakest to strongest.

const (
	SeverityInfo     Severity = "info"
	SeverityMinor    Severity = "minor"
	SeverityMajor    Severity = "major"
	SeverityCritical Severity = "critical"
)

func (Severity) AtLeast

func (s Severity) AtLeast(min Severity) bool

AtLeast reports whether s is min or stronger.

func (Severity) Valid

func (s Severity) Valid() bool

Valid reports whether s is a known severity.

type SkipReason added in v1.15.0

type SkipReason int

SkipReason says why a changed file was left out of the inline diff.

const (
	// SkipExcluded: matched a review.exclude glob or GitLab marked the file
	// as generated. Deliberate filtering, not information loss.
	SkipExcluded SkipReason = iota
	// SkipOverBudget: the file's diff alone exceeds the whole max_diff_kb
	// budget. The diff content is available and can be provided on disk.
	SkipOverBudget
	// SkipUnavailable: GitLab returned no diff content (too_large); only the
	// head state of the file is visible to the reviewer.
	SkipUnavailable
)

type SkippedDiff added in v1.15.0

type SkippedDiff struct {
	Path    string
	OldPath string
	Reason  SkipReason
	Diff    string // populated for SkipOverBudget so the diff can go on disk
}

SkippedDiff is one changed file left out of the inline diff.

func ChunkDiffs

func ChunkDiffs(diffs []gitlabx.FileDiff, exclude []string, maxKB int) (chunks [][]gitlabx.FileDiff, skipped []SkippedDiff)

ChunkDiffs filters the diffs sent to the model and splits them into review passes: excluded and generated files are dropped, and the rest is packed (in original order) into chunks of at most maxKB each so oversized MRs become several passes instead of a truncated one. Files individually larger than the whole budget are returned as SkipOverBudget with their diff content, so the caller can supply them out of band.

Directories

Path Synopsis
Package agents defines the pluggable review agents that a scan can run: the six built-in agents (one per finding category) plus plugin-, user- and project-provided agents loaded from markdown files with YAML frontmatter.
Package agents defines the pluggable review agents that a scan can run: the six built-in agents (one per finding category) plus plugin-, user- and project-provided agents loaded from markdown files with YAML frontmatter.
Package claudecli runs reviews by shelling out to the Claude Code CLI in headless mode (claude -p, stream-json output, structured output schema).
Package claudecli runs reviews by shelling out to the Claude Code CLI in headless mode (claude -p, stream-json output, structured output schema).
Package dedupe collapses review findings that describe the same underlying issue: near-duplicates reported by more than one agent in a single run, and findings that substantially match a comment already posted to the MR.
Package dedupe collapses review findings that describe the same underlying issue: near-duplicates reported by more than one agent in a single run, and findings that substantially match a comment already posted to the MR.
Package delta supports incremental re-review: given the diff between the last reviewed head and the current one, it maps finding anchors from the old head's line numbers to the new head's, so findings on unchanged code carry forward (with their curation state) and findings whose anchor lines were changed or removed are dropped.
Package delta supports incremental re-review: given the diff between the last reviewed head and the current one, it maps finding anchors from the old head's line numbers to the new head's, so findings on unchanged code carry forward (with their curation state) and findings whose anchor lines were changed or removed are dropped.
Package publisher posts curated findings back to a merge request — as live inline discussions, as a draft review published in one action, or as general notes when no diff position resolves — so every frontend (TUI, web GUI) publishes identically.
Package publisher posts curated findings back to a merge request — as live inline discussions, as a draft review published in one action, or as general notes when no diff position resolves — so every frontend (TUI, web GUI) publishes identically.
Package resultstore persists completed review results — the summary and every finding with its curation state — so a review survives navigating away or closing the session, and can be reopened later.
Package resultstore persists completed review results — the summary and every finding with its curation state — so a review survives navigating away or closing the session, and can be reopened later.
Package runlog persists the progress log of each review run — the same timestamped lines streamed to the review screen — so a run can be read back after its screen is gone.
Package runlog persists the progress log of each review run — the same timestamped lines streamed to the review screen — so a run can be read back after its screen is gone.
Package runner orchestrates one review run end to end — checkout, prompt assembly, reviewer passes, result merging, and persistence — so every frontend (TUI, web GUI) drives the same pipeline and stores the same artifacts.
Package runner orchestrates one review run end to end — checkout, prompt assembly, reviewer passes, result merging, and persistence — so every frontend (TUI, web GUI) drives the same pipeline and stores the same artifacts.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL