config

package
v0.17.5 Latest Latest
Warning

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

Go to latest
Published: Jul 29, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package config loads the cascading YAML config that drives local-review.

Cascade (lowest precedence first):

  1. Built-in defaults (compiled in)
  2. Org config (optional URL, fetched + cached) -- not yet wired; the Org.ConfigURL field is parsed but unused. Planned for v0.18.0 (see ROADMAP).
  3. ~/.local-review.yml (per-user)
  4. .local-review.yml (project root) (per-repo)
  5. CLI flags (per-invocation)

Each layer is a partial YAML; later layers shallow-merge over earlier ones.

Index

Constants

This section is empty.

Variables

View Source
var ErrAllLLMsDisabled = errors.New("all LLMs are explicitly disabled; at least one must be enabled for multi-LLM mode")

Validate checks the configuration for common errors. Returns an error if the config is invalid. Note: This should be called explicitly by commands that need validation (e.g., multi), not automatically in Load(), to avoid breaking v0-only users. ErrAllLLMsDisabled is returned by Validate when every configured LLM has an explicit `enabled: false`. The runner tolerates this specifically when `--only` is set: `--only` is an explicit allow-list that overrides config-level enable/disable for agent SELECTION, so an all-disabled config is fine in that case (the user opted into the named agents). Without the sentinel the runner couldn't tell this benign case apart from a genuinely misconfigured default run.

Functions

func FindRepoConfig

func FindRepoConfig(start string) string

FindRepoConfig walks up from start looking for a .local-review.yml. Returns "" when none is found (not an error).

func SanitizeBaseURLForDisplay added in v0.14.1

func SanitizeBaseURLForDisplay(raw string) string

SanitizeBaseURLForDisplay strips potentially-sensitive parts of a configured base_url before echoing it back into any user-facing surface (`local-review config` dump, CI logs, terminal history). Basic-auth userinfo (`https://user:pass@host`) and the query / fragment (`?api_key=…`) get dropped; scheme + host + path survive because that's the part the user actually needs. A URL that fails to parse is replaced with a literal placeholder rather than leaked verbatim — fail-closed (CLAUDE.md rule 4) and beats printing garbage into a YAML stanza we're showing the user.

Introduced in v0.14 for the (since-removed) deprecation warning; the `local-review config` printer still uses it for every `llms.<name>.base_url` value.

Types

type Config

type Config struct {
	Review Review `yaml:"review"`
	Org    Org    `yaml:"org"`

	// v0.1: multi-LLM support
	LLMs    map[string]LLMConfig `yaml:"llms"`
	Merge   MergeConfig          `yaml:"merge"`
	Storage StorageConfig        `yaml:"storage"`

	// v0.8: prompt-pack customization (issue #55). Lets teams ship
	// their own house rules without forking the binary.
	Prompts PromptsConfig `yaml:"prompts"`
}

Config is the resolved (post-cascade) configuration.

The v0.13-and-earlier top-level `provider:` block was removed in v0.15 (deprecated in v0.14). Loading a YAML file that still contains a `provider:` key surfaces a migration error from mergeFrom — see detectRemovedProviderBlock below — rather than silently dropping the fields. Provider endpoints now live under `llms.<name>:` with the same field shape (`base_url`, `model`, `api_key_env`, `timeout_seconds`).

func Defaults

func Defaults() Config

Defaults returns the built-in starting point.

func Load

func Load(repoConfigPath string) (Config, error)

Load resolves the cascade.

repoConfigPath is the path to the project-level .local-review.yml (typically found by walking up from cwd). Either path may be empty / missing.

func (*Config) Validate

func (c *Config) Validate() error

type LLMConfig

type LLMConfig struct {
	Enabled *bool  `yaml:"enabled"`
	CLIPath string `yaml:"cli_path"` // path to CLI binary (auto-detect if empty)
	// BaseURL turns an entry into a PROVIDER agent (HTTP / OpenAI-
	// compatible: Ollama, vLLM, OpenAI, Together, Groq, OpenRouter,
	// Anthropic-compat, …). When set, the runtime treats this entry
	// as a provider, not a CLI subprocess. cli_path is then ignored.
	// User-chosen entry name is the agent's identifier (free-form;
	// "qwen", "local-fast", "air-gapped"). Added in v0.14 as part of
	// the unified agent model — providers can now run side-by-side
	// with the CLI agents in the same `local-review review` fan-out.
	BaseURL    string `yaml:"base_url"`
	Model      string `yaml:"model"`           // model name passed to the agent CLI OR provider
	APIKeyEnv  string `yaml:"api_key_env"`     // env var name for API key
	APIKey     string `yaml:"api_key"`         // DEPRECATED: use environment variable instead
	TimeoutSec int    `yaml:"timeout_seconds"` // per-call timeout

	// ForceAfterSunset overrides the auto-disable behaviour applied
	// to manufacturer-sunset CLIs (today: gemini, sunset 2026-06-18).
	// Default behaviour is to drop a sunset CLI from the fan-out as
	// soon as the cutoff passes — keeping it active without an
	// override risks confusing 401s / "model unavailable" errors
	// against an unreachable endpoint. A user who wants to retry
	// past the cutoff (in case Google extends, or in case their
	// network sees a different rollout) can set
	// `llms.gemini.force_after_sunset: true` to opt back in.
	//
	// Pointer (*bool) so "field absent in YAML" is distinguishable
	// from "field explicitly false". Today only meaningful on the
	// gemini entry; ignored everywhere else.
	ForceAfterSunset *bool `yaml:"force_after_sunset"`
}

LLMConfig holds configuration for a single LLM (v0.1+).

Note: a `mode: cli|api` field shipped in v0.1's example config but was never wired through to the orchestrator (multi-LLM always invokes via CLI). It was removed in v0.5.x. Existing YAML configs with a `mode:` line still load — yaml.v3 silently ignores unknown fields. The "API fallback when CLI auth fails" idea is parked in do-not-merge/v06-fully-local-ollama-preset.md.

type MergeConfig

type MergeConfig struct {
	PreferredLLM       string `yaml:"preferred_llm"`       // "auto" or specific LLM name
	Deduplicate        *bool  `yaml:"deduplicate"`         // remove duplicate findings
	ConsensusThreshold int    `yaml:"consensus_threshold"` // N LLMs agreeing = "Confirmed by N"
}

MergeConfig controls how multi-LLM reviews are merged (v0.1+).

type Org

type Org struct {
	ConfigURL string `yaml:"config_url"`
}

Org is reserved for org-wide config delivery (v1: stub).

type PromptsConfig added in v0.8.0

type PromptsConfig struct {
	PackDir string `yaml:"pack_dir"` // directory of override <language>.md files
	Prepend string `yaml:"prepend"`  // text spliced BEFORE the pack body
	Append  string `yaml:"append"`   // text spliced AFTER the pack body
}

PromptsConfig customises the language prompt packs the binary ships with. Issue #55: teams want to tune review tone, severity bar, or add house rules without forking. Three knobs, all optional, all composable:

  • PackDir: directory of override files keyed by language id. A `go.md` in this directory replaces the embedded `go.md`. Files not present fall through to the embedded pack of the same name.
  • Prepend / Append: free-form text spliced before/after whatever pack content was loaded. Survives an upstream pack update — the prepend/append text is yours, the pack body keeps tracking upstream improvements.

All three apply to BOTH the single-LLM fallback path AND the per-LLM CLI invocations (claude/gemini/codex), so a team's house rules reach every reviewer.

type Review

type Review struct {
	MinSeverity  string   `yaml:"min_severity"` // "nit"|"info"|"warning"|"major"|"critical"
	MaxFindings  int      `yaml:"max_findings"` // hard cap to avoid noise
	IncludeGlobs []string `yaml:"include"`      // file globs to consider
	ExcludeGlobs []string `yaml:"exclude"`      // file globs to drop
	PromptPack   string   `yaml:"prompt_pack"`  // override auto-detection
}

Review holds tuning knobs for what gets surfaced.

type Source added in v0.17.4

type Source struct {
	Role    SourceRole
	Path    string // "" when the layer can't be resolved (no home dir / no repo file found)
	Found   bool   // the file exists on disk
	Merges  bool   // Load will call mergeFrom on it (mergeFrom no-ops when !Found)
	Trusted bool   // merged without sanitizeUntrustedLayer
	// SameAsHome is set on the repo layer when the walk-up found the
	// user's own home config (project lives under $HOME with no
	// project-local file) — Load skips the redundant untrusted pass.
	SameAsHome bool
}

Source describes one file-backed layer of the config cascade — which path a layer resolves to, whether the file exists, whether Load will merge it, and under what trust. Load itself iterates this description, and the `config` command prints it, so the two cannot disagree.

func DescribeSources added in v0.17.4

func DescribeSources(repoConfigPath string) []Source

DescribeSources resolves the file-backed cascade layers for a given repo-config path (as found by FindRepoConfig; may be empty). The home layer is always trusted. The repo layer is untrusted unless LOCAL_REVIEW_TRUST_REPO_CONFIG=1, and is skipped entirely when it IS the home config file.

type SourceRole added in v0.17.4

type SourceRole string

SourceRole labels a config cascade layer in Source.

const (
	SourceRoleHome SourceRole = "home"
	SourceRoleRepo SourceRole = "repo"
)

type StorageConfig

type StorageConfig struct {
	BasePath string `yaml:"base_path"` // base directory for reviews
}

StorageConfig controls where reviews are saved (v0.1+).

Jump to

Keyboard shortcuts

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