Documentation
¶
Overview ¶
Package config loads the cascading YAML config that drives local-review.
Cascade (lowest precedence first):
- Built-in defaults (compiled in)
- Org config (optional URL, fetched + cached) -- not yet wired; the Org.ConfigURL field is parsed but unused. Planned for v0.18.0 (see ROADMAP).
- ~/.local-review.yml (per-user)
- .local-review.yml (project root) (per-repo)
- CLI flags (per-invocation)
Each layer is a partial YAML; later layers shallow-merge over earlier ones.
Index ¶
Constants ¶
This section is empty.
Variables ¶
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 ¶
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
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`).
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
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+).