warden

package
v0.10.0 Latest Latest
Warning

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

Go to latest
Published: Mar 23, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package warden implements the code review agent that reviews Smith's changes.

The Warden spawns a separate Claude session with a review-focused prompt, providing the git diff of changes made by the Smith. It returns a structured verdict: approve, reject, or request-changes with feedback.

Index

Constants

View Source
const RulesFileName = ".forge/warden-rules.yaml"

RulesFileName is the per-anvil file storing learned review rules.

Variables

This section is empty.

Functions

func FetchRecentPRNumbers

func FetchRecentPRNumbers(ctx context.Context, repoDir string, limit int) ([]int, error)

FetchRecentPRNumbers returns the most recent merged PR numbers for a repo.

func GroupComments

func GroupComments(comments []PRComment) [][]PRComment

GroupComments groups semantically similar comments using keyword overlap. First, comments with identical normalized text are merged. Then, groups whose keyword sets exceed a Jaccard similarity threshold are merged together so that comments about the same pattern (e.g. "missing error check on Open()" vs "error from ReadFile not handled") land in one group.

func InsertRulesAsPending added in v0.10.0

func InsertRulesAsPending(rules []Rule, anvilName string, insert PendingInserter) error

InsertRulesAsPending serializes each rule to YAML and inserts it into the pending_warden_rules table via the provided inserter function.

func LearnFromCIFix added in v0.4.0

func LearnFromCIFix(ctx context.Context, anvilPath, repoDir string, failingLogs map[string]string, fixDiff string, prNumber int, cfg ...*LearnConfig) error

LearnFromCIFix extracts lint rule patterns from CI failure logs and the subsequent fix diff, then stores them as warden rules so future Smith sessions avoid the anti-patterns before they reach CI.

When cfg is non-nil and cfg.SmelterEnabled is true, new rules are inserted into the pending_warden_rules table instead of being written directly to the rules file. When cfg is nil or SmelterEnabled is false, the existing direct-save behavior is preserved.

It is intentionally non-fatal: callers should log any returned error but not let it block the successful CI fix result from being recorded.

func RulesPath

func RulesPath(anvilPath string) string

RulesPath returns the full path to the warden rules file for an anvil.

func SaveRules

func SaveRules(anvilPath string, rf *RulesFile) error

SaveRules writes the rules file to the anvil path, creating the .forge directory if it does not exist.

Types

type LearnConfig added in v0.10.0

type LearnConfig struct {
	SmelterEnabled bool
	AnvilName      string          // anvil name for pending rule insertion
	InsertPending  PendingInserter // typically state.DB.InsertPendingRule
}

LearnConfig provides optional smelter-aware routing for learned rules. When SmelterEnabled is true and InsertPending is non-nil, new rules are inserted into the pending_warden_rules table instead of being written directly to the rules file.

type PRComment

type PRComment struct {
	Body     string `json:"body"`
	User     string `json:"user"`
	Path     string `json:"path"`
	PRNumber int    `json:"pr_number"`
}

PRComment represents a review comment fetched from GitHub.

func FetchCopilotComments

func FetchCopilotComments(ctx context.Context, repoDir string, prNumber int) ([]PRComment, error)

FetchCopilotComments retrieves review comments on a PR that were authored by copilot[bot], github-actions[bot], or copilot via the gh CLI.

type PendingInserter added in v0.10.0

type PendingInserter func(anvil, ruleYAML, sourcePR string) error

PendingInserter is a function that inserts a rule into the pending_warden_rules table. It matches the signature of state.DB.InsertPendingRule.

type ReviewIssue

type ReviewIssue struct {
	// File is the affected file path.
	File string `json:"file"`
	// Line is the approximate line number (0 if unknown).
	Line int `json:"line"`
	// Severity is "error", "warning", or "suggestion".
	Severity string `json:"severity"`
	// Message describes the issue.
	Message string `json:"message"`
}

ReviewIssue represents a specific issue found during review.

type ReviewResult

type ReviewResult struct {
	// Verdict is the review decision.
	Verdict Verdict
	// UsedProvider records which provider actually completed the review.
	UsedProvider *provider.Provider
	// Summary is a brief summary of the review.
	Summary string
	// Issues is a list of specific issues found.
	Issues []ReviewIssue
	// RawOutput is the full Claude output.
	RawOutput string
	// Duration is how long the review took.
	Duration time.Duration
	// CostUSD is the cost of the review session.
	CostUSD float64
	// NoDiff is true when the rejection was because Smith produced no diff.
	NoDiff bool
}

ReviewResult captures the Warden's review outcome.

func Review

func Review(ctx context.Context, worktreePath, beadID, beadTitle, beadDescription, anvilPath string, db *state.DB, priorFeedback string, providers ...provider.Provider) (*ReviewResult, error)

Review runs a Warden review of the changes in the given worktree. It gets the git diff, spawns a Claude review session, and parses the verdict.

beadTitle and beadDescription are used to check whether the diff actually implements what the bead requested (scope drift detection). db is used to log lifecycle events; db may be nil to skip logging. providers is the ordered list of AI providers to try. When empty, provider.Defaults() is used. Provider fallback applies on rate limit.

type Rule

type Rule struct {
	ID       string     `yaml:"id"       json:"id"`
	Category string     `yaml:"category" json:"category"`
	Pattern  string     `yaml:"pattern"  json:"pattern"`
	Check    string     `yaml:"check"    json:"check"`
	Source   SourceList `yaml:"source"   json:"source"`
	Added    string     `yaml:"added"    json:"added"`
}

Rule represents a single learned review pattern.

func DistillRule

func DistillRule(ctx context.Context, comments []PRComment, repoDir string) (*Rule, error)

DistillRule uses a Claude session to convert a set of similar review comments into a single warden rule. Returns the rule or an error.

func (Rule) MarshalYAML added in v0.8.0

func (r Rule) MarshalYAML() (any, error)

MarshalYAML implements yaml.Marshaler for Rule, applying appropriate YAML styles to string fields:

  • Scalars longer than 80 characters use a folded block scalar (>-) for readability and easier editing.
  • Shorter scalars that contain YAML-special sequences (": ", '"') or a comment-introducing '#' are double-quoted.

It uses a type alias to get automatic field marshaling (so future fields on Rule are included without updating this method), then post-processes the resulting yaml.Node tree.

type RulesFile

type RulesFile struct {
	Rules []Rule `yaml:"rules"`
}

RulesFile is the top-level structure of warden-rules.yaml.

func LoadRules

func LoadRules(anvilPath string) (*RulesFile, error)

LoadRules reads the warden rules file from the anvil path. Returns an empty RulesFile (not an error) if the file does not exist.

func (*RulesFile) AddRule

func (rf *RulesFile) AddRule(r Rule) bool

AddRule appends a rule to the file, skipping duplicates by ID. Returns true if the rule was added (not a duplicate).

func (*RulesFile) FormatChecklist

func (rf *RulesFile) FormatChecklist() string

FormatChecklist returns the rules formatted as a numbered checklist suitable for inclusion in a review prompt.

func (*RulesFile) RemoveRule

func (rf *RulesFile) RemoveRule(id string) bool

RemoveRule removes a rule by ID. Returns true if a rule was removed.

type SourceList added in v0.10.0

type SourceList []string

SourceList is a slice of source references. It YAML-marshals as a plain scalar when there is exactly one element and as a flow sequence when there are multiple, making multi-PR attribution programmatically accessible. It unmarshals from either format for backward compatibility.

func (SourceList) MarshalYAML added in v0.10.0

func (sl SourceList) MarshalYAML() (any, error)

MarshalYAML emits a plain scalar for a single source and a YAML flow sequence for multiple sources.

func (SourceList) String added in v0.10.0

func (sl SourceList) String() string

String returns the sources joined by ", " for display purposes.

func (*SourceList) UnmarshalYAML added in v0.10.0

func (sl *SourceList) UnmarshalYAML(value *yaml.Node) error

UnmarshalYAML reads either a scalar string or a YAML sequence into a SourceList.

type Verdict

type Verdict string

Verdict represents the Warden's review decision.

const (
	VerdictApprove        Verdict = "approve"
	VerdictReject         Verdict = "reject"
	VerdictRequestChanges Verdict = "request_changes"
)

Jump to

Keyboard shortcuts

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