Providers
The review pass runs against one LLM provider. Providers are config-driven: there are two first-class kinds (anthropic and openai) and any specific vendor (GLM via z.ai, DeepSeek, Moonshot, a self-hosted gateway, any Anthropic- or OpenAI-compatible endpoint) is just a named profile of one of those kinds. New vendors are added by config alone, no rebuild.
Nothing here is persisted; see Credentials.
Layering
Section titled “Layering”Settings resolve in this order, highest wins:
CLI flags > environment > config file > built-in defaultsThe optional config file lives at ~/.config/miu/cr/config.toml (same on macOS and Linux), alongside the SQLite state DB at ~/.config/miu/cr/state.db, matching the miu family convention.
It is entirely optional; miu-cr works with zero config. A fully commented starter is in config.example.toml.
Choosing a provider
Section titled “Choosing a provider”--provider takes a profile name: a built-in (anthropic, openai), any name you defined in the config file, or auto (the default).
With auto, miu-cr picks OpenAI when OPENAI_API_KEY is set and no Anthropic credential is present (--api-key, --auth-token, ANTHROPIC_API_KEY, or ANTHROPIC_AUTH_TOKEN); otherwise it uses default_provider from the config file (Anthropic by default). Anthropic is the default because it backs both the native API and Anthropic-compatible gateways.
Config schema
Section titled “Config schema”default_provider = "anthropic" # profile to use when --provider is omitted
[providers.<name>]kind = "anthropic" # or "openai"; the first-class familybase_url = "https://…" # optional; gateway/endpoint overridemodel = "…" # optional; default model for this profileauth_env = "MY_TOKEN" # RECOMMENDED; NAME of an env var holding the credentialauth_token = "…" # discouraged literal credential; plaintext on diskauth = "oauth" # OpenAI only: pin the credential method ("oauth" | "api_key" | omit for auto)The two built-in profiles anthropic and openai always exist; you only declare a [providers.<name>] block to add a vendor or override a built-in’s model/base_url. A profile’s credential (auth_token or auth_env) is sent as a Bearer token on the Anthropic path and as the API key on the OpenAI path. Standard env vars and CLI flags still override it. auth is OpenAI-only and pins the credential method: "oauth" (use miucr login/the ChatGPT plan, never an API key), "api_key" (always a key, never OAuth), or omitted for intent-ordered auto; an unknown value is a config.invalid error.
Review defaults: [review]
Section titled “Review defaults: [review]”The optional [review] table sets defaults for miucr review flags. An explicit flag always wins; a [review] value only fills a flag you did not pass. A bad enum or timeout is a typed config.invalid error (exit 2).
[review]gate = "high" # default --gate: none|info|low|medium|high|criticalfilter_mode = "diff_context" # default --filter-mode (--pr): added|diff_context|file|nofiltermin_severity = "low" # default --min-severity (--pr inline floor)timeout = "300s" # default review timeout (a Go duration: 300s, 5m, …)suggest = false # default --suggest (GitHub one-click suggestions on --post)
[review.category_urls] # map a finding Category → a docs URL (clickable link + SARIF helpUri)"security" = "https://example.com/docs/security"Only these review attributes can be defaulted from config; there is intentionally no approve_clean config (a write-action defaulting on is a footgun).
Viewing and editing config (config show / set / edit)
Section titled “Viewing and editing config (config show / set / edit)”miucr config show prints the effective configuration with every credential masked (auth_token, the store dsn) by structural redaction, so a token can never reach stdout. By default it shows only your user-set values; --all includes the built-in defaults.
miucr config show # user-set values only (secrets redacted)miucr config show --all # full effective config incl. built-in defaultsmiucr config show -o pretty # TOML view for humansconfig set <key> <value> merges one dotted, non-secret key (e.g. default_provider, review.gate, providers.zai.model) into the existing config without re-running init; secret keys (auth_token, store.dsn) are rejected to avoid a plaintext-secret footgun. config edit opens ~/.config/miu/cr/config.toml in $VISUAL/$EDITOR (it needs an interactive terminal; in CI use config set). You can also edit the file directly.
Anthropic
Section titled “Anthropic”export ANTHROPIC_API_KEY=...miucr review --stagedResolution order (first non-empty wins):
| Setting | Flag | Env | Profile | Default |
|---|---|---|---|---|
| API key (x-api-key) | --api-key | ANTHROPIC_API_KEY | - | required unless an auth token is set |
| Auth token (Bearer) | --auth-token | ANTHROPIC_AUTH_TOKEN | auth_token / auth_env | - |
| Base URL | --base-url | ANTHROPIC_BASE_URL | base_url | SDK default |
| Model | --model | ANTHROPIC_MODEL | model | claude-sonnet-4-5-20250929 |
The API key is sent as x-api-key. An auth token is sent as a Bearer Authorization header instead, what Anthropic-compatible gateways expect.
GLM via z.ai (Anthropic-compatible): example profile
Section titled “GLM via z.ai (Anthropic-compatible): example profile”z.ai exposes an Anthropic-compatible gateway, so it’s an anthropic-kind profile with a base URL + bearer token. There is no z.ai-specific code; it is purely configuration.
[providers.zai]kind = "anthropic"base_url = "https://api.z.ai/api/anthropic"model = "glm-5.2"auth_env = "ZAI_API_KEY" # or: auth_token = "<token>"export ZAI_API_KEY=...miucr review --staged --provider zaiEquivalent without a config file, using the generic Anthropic env vars:
export ANTHROPIC_BASE_URL=https://api.z.ai/api/anthropicexport ANTHROPIC_AUTH_TOKEN=$ZAI_API_KEYmiucr review --staged --model glm-5.2…or entirely via flags:
miucr review --staged \ --base-url https://api.z.ai/api/anthropic \ --auth-token "$ZAI_API_KEY" \ --model glm-5.2OpenAI (and OpenAI-compatible)
Section titled “OpenAI (and OpenAI-compatible)”export OPENAI_API_KEY=...miucr review --staged --provider openaiResolution order:
| Setting | Flag | Env | Profile | Default |
|---|---|---|---|---|
| API key | --api-key | OPENAI_API_KEY | auth_token / auth_env | required |
| Base URL | --base-url | OPENAI_BASE_URL | base_url | https://api.openai.com/v1 |
| Model | --model | OPENAI_MODEL | model | gpt-4o |
Requests send max_tokens (not max_completion_tokens) for the broadest compatibility with OpenAI-compatible gateways. --auth-token is Anthropic-only; passing it with an OpenAI provider is a typed error.
OAuth / your ChatGPT plan
Section titled “OAuth / your ChatGPT plan”The OpenAI provider can also authenticate without an API key by reviewing on your ChatGPT plan. miucr login caches an OAuth token and subsequent OpenAI reviews talk to the codex backend (the ChatGPT-plan Responses protocol). On that path the model defaults to gpt-5.5; precedence is --model > MIUCR_CODEX_MODEL > an explicit model in your [providers.openai] profile > gpt-5.5. miucr init writes model = "gpt-5.5" for you on the OAuth path so the codex model is visible and editable. The pinned gpt-4o/OPENAI_MODEL default never applies here: the codex backend rejects api.openai.com models, so a config model = "gpt-4o" is ignored and falls through to gpt-5.5.
When auth is unset, the OpenAI credential resolves intent-ordered so an ambient OPENAI_API_KEY (often set for other tools) never silently overrides a deliberate choice:
- a profile-configured key (
auth_env/auth_token) or--api-key; - a cached
miucr login(OAuth → codex / ChatGPT-plan backend); - an ambient
OPENAI_API_KEYenv var.
Pin the method with auth = "oauth" or auth = "api_key" to skip the auto order. See Credentials → Using your ChatGPT plan.
Generic OpenAI-compatible gateway: example profile
Section titled “Generic OpenAI-compatible gateway: example profile”[providers.my-gateway]kind = "openai"base_url = "https://gateway.example.com/v1"model = "your-model-id"auth_env = "MY_GATEWAY_TOKEN" # or: auth_token = "<token>"export MY_GATEWAY_TOKEN=...miucr review --staged --provider my-gatewayMissing credentials
Section titled “Missing credentials”If no credential is found for the resolved provider, the review fails with a typed error (exit 1) and a hint, e.g.:
no Anthropic credentials: set ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN, configure a provider in <config path>, or pass --api-key / --auth-token