Skip to content

Credentials

miu-cr is bring-your-own-key. You supply an LLM API key via an environment variable or a flag; it lives in memory only for the duration of the call. It is never written to disk, the SQLite history, or anywhere else.

The one exception is the opt-in OAuth flow below: miucr login deliberately caches a subscription token at ~/.config/miu/cr/oauth.json (0600, gitignored) so you can review on your ChatGPT plan. API keys are still never persisted.

Terminal window
export ANTHROPIC_API_KEY=... # Anthropic
export ANTHROPIC_BASE_URL=https://api.z.ai/api/anthropic \
ANTHROPIC_AUTH_TOKEN=$ZAI_API_KEY # GLM via z.ai (Anthropic-compatible)
export OPENAI_API_KEY=... # OpenAI-compatible

Or pass per-run flags (which override the matching env var):

Terminal window
miucr review --staged --api-key "$MY_KEY"
miucr review --staged --auth-token "$ZAI_API_KEY" --base-url https://api.z.ai/api/anthropic

You can also name a provider profile in the optional config file and have it reference an env var by name (auth_env) instead of putting the token inline; the token still resolves from the environment at run time and is never written back. See Providers for the config schema, named-profile examples (z.ai/GLM, a generic OpenAI-compatible gateway), and the full resolution matrix.

Using OpenAI / your ChatGPT plan (miucr login)

Section titled “Using OpenAI / your ChatGPT plan (miucr login)”

Instead of a billed platform API key, you can review on your ChatGPT plan. miucr login runs a standard OpenAI PKCE loopback OAuth flow in your browser and caches the token at ~/.config/miu/cr/oauth.json (dir 0700, file 0600). A subsequent OpenAI review authed by that token talks to the codex backend (chatgpt.com/backend-api/codex, the Responses protocol the codex CLI uses) so it draws on your subscription, not a per-call API bill.

Terminal window
miucr login --provider openai # opens the browser, completes PKCE, caches the token
miucr review --staged # now runs on your ChatGPT plan

provider is an explicit flag backed by a small registry; openai is the only entry today (--provider anthropic/unknown is rejected: third-party Anthropic OAuth is ToS-prohibited). The flow binds a loopback callback on one of the OpenAI-allow-listed ports (1455, then 1457). On a headless/SSH box use:

Terminal window
miucr login --no-browser # prints the authorize URL to open elsewhere

The login.result envelope is secret-free: it emits only {provider, oauth_path, expires_at, account_id, has_api_key}; no tokens.

Inspect and clear the cached login (whoami / logout)

Section titled “Inspect and clear the cached login (whoami / logout)”
Terminal window
miucr whoami # who am I authed as? {logged_in, provider, account_id, expires_at, expired}
miucr logout # delete oauth.json; idempotent ({removed: bool})

whoami reports only the non-secret fields from the cached record (provider, account id, expiry); the access/refresh/id token and api key are never read into the envelope, so no token can leak via whoami (in either json or pretty output). With no cached record it returns {logged_in: false} (a clean result, not an error). logout deletes oauth.json; running it again on an already-cleared record is a no-op ({removed: false}), so it is safe to repeat.

Precedence: the cached login credential sits below an explicit key. An explicit --api-key / OPENAI_API_KEY (and any Anthropic path) still wins, so a real key always overrides a stale token. OAuth is consulted only when no OpenAI key is present.

CI / GitHub Actions: use an API key, not OAuth

Section titled “CI / GitHub Actions: use an API key, not OAuth”

OAuth is interactive (it needs a browser) so it is not used in CI. For GitHub Actions, generate a key at platform.openai.com, add it as the repo secret OPENAI_API_KEY, and run miucr review --provider openai with that key on the step environment. The bundled composite action wires Anthropic env vars, so for the OpenAI path invoke the CLI directly:

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
permissions:
pull-requests: write
contents: read
jobs:
review:
runs-on: ubuntu-latest
if: ${{ github.event.pull_request.head.repo.fork != true }} # never run on fork PR code
steps:
- run: curl -fsSL https://raw.githubusercontent.com/vanducng/miu-cr/main/install.sh | sh
- name: Review PR on OpenAI
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} # step-level secret export
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
miucr review --pr "${GITHUB_REPOSITORY}#${{ github.event.pull_request.number }}" \
--provider openai --post --gate high --timeout 300s
  • The token lives only in oauth.json (0600, dir 0700, atomic write), is gitignored, and is never logged, never put in the CLI envelope, and redacted from any error string.
  • miucr logout deletes oauth.json to revoke locally; miucr whoami shows the cached identity without ever exposing the token.
  • Anthropic OAuth is unsupported by design (Anthropic ToS). Use an API key or an Anthropic-compatible gateway for Anthropic providers.
  • API keys and auth tokens (--api-key, --auth-token, ANTHROPIC_API_KEY, OPENAI_API_KEY, ZAI_API_KEY, …).
  • Base URLs supplied via --base-url.

The SQLite history stores review records only: anchored findings and run stats. Credentials are not part of that record.

The CLI envelope success output is run through a credential scrubber before it leaves the process:

  • Credential-named JSON fields (anything matching password, secret, token, api_key, auth_token, …) are replaced with ***.
  • Credential-bearing URLs and key=value assignments are redacted.
  • Finding prose is exempt: rationale and suggested_patch may legitimately quote token-like example text, so they survive the scrub intact.

On the MCP path the redaction is narrower: tool error messages are redacted, but the structured success output (the engine’s findings + stats) is returned directly, without the *** field scrubber. That output carries no token-bearing fields by construction, so no credentials flow through it. Errors on both paths are always redacted.

The SQLite review history is a local file at ~/.config/miu/cr/state.db (same on macOS and Linux), alongside config.toml. The project .gitignore excludes *.db and state.db so review state (and the code it references) is never committed. Treat the history database as local-only.

The state DB moved here from the older miucr directory. If you have an existing state.db under the old location, move it to ~/.config/miu/cr/state.db to keep your history; otherwise miu-cr re-creates an empty one on first run.