an experimental ai review harness
  • Rust 99.8%
  • Dockerfile 0.2%
Find a file
Jesse Garcia 081b741c05
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
tui: hand off reviews to tuicr, seeded with Mimir's draft findings
Adds a tuicr handoff for the inbox (enter/l/t): opens the selected PR in
tuicr for reading and commenting, while a background Mimir draft seeds
findings into the session as soon as it's ready, leaving any comments
already in the session untouched.

Supporting changes:
- tuicr::convert_with lets re-imported findings keep the severity and
  category Mimir originally gave them, instead of flattening to the
  import default.
- review::Comment derives Clone, needed to seed/compare findings.
- Cargo: add the tuicr crate (optional, tui feature) for its library API.
- inbox: page search results at 25 instead of 100 and raise MAX_PAGES to
  20 — GitHub's search gateway was timing out on larger pages against a
  busy org.
- docs/mctl.md: document the tuicr handoff flow and requirements.
2026-10-27 11:32:35 -06:00
docs tui: hand off reviews to tuicr, seeded with Mimir's draft findings 2026-10-27 11:32:35 -06:00
src tui: hand off reviews to tuicr, seeded with Mimir's draft findings 2026-10-27 11:32:35 -06:00
.env.example docs: fix README/env-example inaccuracies about the mimir profile and table count 2026-10-23 09:06:54 -06:00
.gitignore Initial public release 2026-10-13 15:22:37 -06:00
.woodpecker.yml Initial public release 2026-10-13 15:22:37 -06:00
Cargo.lock tui: hand off reviews to tuicr, seeded with Mimir's draft findings 2026-10-27 11:32:35 -06:00
Cargo.toml tui: hand off reviews to tuicr, seeded with Mimir's draft findings 2026-10-27 11:32:35 -06:00
compose.yaml docs: document the durable CLI review flow 2026-10-19 14:51:42 -06:00
Dockerfile feat(mctl): add a terminal UI for triaging the inbox and reviews 2026-10-21 21:16:28 -06:00
LICENSE Initial public release 2026-10-13 15:22:37 -06:00
README.md docs: fix README/env-example inaccuracies about the mimir profile and table count 2026-10-23 09:06:54 -06:00
ROADMAP.md docs: reflow consolidated docs (no content change) 2026-10-23 02:16:22 -06:00

Mimir

Mimir is a self-hostable, open-source pull-request reviewer built in Rust and Axum. It turns signed GitHub webhooks into focused, line-specific feedback and publishes the result as a native GitHub review.

Problem statement

Code review is one of the most important engineering safeguards, but it is also a bottleneck. Reviewers have limited time and context, large or fast-moving pull requests are hard to evaluate, and important correctness or security risks can be buried among style nits. AI reviewers can help, but many require sending code to a hosted black box, lock teams into a model or vendor, lose track of context between pushes, and produce noisy comments that engineers learn to ignore.

Mimir exists to make AI-assisted review a trustworthy capability that teams can own. It keeps code, review state, model choice, guidance, and infrastructure under the team's control, while delivering focused, evidence-based feedback directly in the pull-request workflow engineers already use. It is built for engineers, by engineers.

Problems Mimir aims to solve

  • Review bandwidth: give reviewers an early first pass so human attention can go to design, product intent, and difficult trade-offs.
  • Signal over noise: prioritize concrete correctness, security, data-flow, and access-control risks; drop speculative findings and style/process nits.
  • Missing context: ground reviews in the PR description, commit history, team guidance, selected repository files, and optional repository memory.
  • Large and evolving PRs: handle large diffs with per-commit review, and re-review only new commits instead of repeating already-settled feedback.
  • Token efficiency: cap diff size, bound out-of-diff file fetches, scope re-reviews to only the commits/findings affected by new pushes, and support an optional compression gateway in front of the model provider.
  • Review-thread follow-through: respond to developer replies, track finding status, and resolve issues once they are explained, accepted, or fixed.
  • Vendor lock-in: work with any OpenAI-compatible model gateway and keep optional skills, MCP context, compression, and memory pluggable.
  • Security and governance: keep the workflow self-hosted, verify webhook signatures, constrain model tools, persist an audit trail, and optionally encrypt sensitive review content at rest.
  • Safe adoption: support opt-in reviews and non-publishing observation mode so teams can evaluate Mimir before relying on it.

Mimir is designed as a composable building block rather than a hosted service: you choose the model provider, inference gateway, engineering guidance, memory backend, and deployment environment. It works with any OpenAI-compatible inference endpoint and keeps the review workflow under your control.

The application owns the safety-critical workflow boundary: webhook verification, GitHub fetching and publishing, review deduplication, durable audit state, prompt orchestration, output validation, and token accounting. Optional gateways can provide model routing, context compression, skills, MCP context, or repository memory without coupling the core reviewer to a specific vendor.

Run

The single compose.yaml stack supports two profiles. The local profile starts Mimir, Headroom, LiteLLM, Hindsight, and pgvector-backed Postgres; the mimir profile starts Mimir plus its required Postgres and Hindsight, for when an OpenAI-compatible inference endpoint (LiteLLM/Headroom or otherwise) already runs elsewhere.

cp .env.example .env   # optional; .env.example sets COMPOSE_PROFILES=mimir

# Complete standalone development stack.
COMPOSE_PROFILES=local LITELLM_URL=http://headroom:8787 docker compose --profile local up

# Only Mimir, against the endpoints configured in .env.
docker compose --profile mimir up mimir

OPENAI_API_KEY=sk-... may be passed inline instead of living in .env, and a bare docker compose up starts whichever profile COMPOSE_PROFILES selects.

In the bundled stack, chat traffic flows through Headroom for optional context compression before reaching LiteLLM. In production, point Mimir at the compatible inference services you operate. Mimir is available at http://localhost:3000, Headroom at http://localhost:8787 (dashboard at /dashboard), LiteLLM at http://localhost:4000, and Hindsight at http://localhost:8888.

For a direct local run without Compose:

LITELLM_URL=http://localhost:4000 \
LITELLM_MASTER_KEY=sk-... \
MIMIR_MODEL=my-litellm-model \
cargo run

Endpoints

Method Path Purpose Auth
GET /health Liveness response none
GET /v1/models Advertise the configured MIMIR_MODEL (or mimir) none
POST /v1/chat/completions Forward an OpenAI-compatible chat request to ${LITELLM_URL}/v1/chat/completions and return the upstream response none
POST /webhooks/{platform} Signed webhook receiver (currently github) HMAC signature
GET /preview/review/{owner}/{repo}/{pr_number} Compute a real review against a GitHub PR without publishing or creating an audit record, including token usage none
POST /v1/cli-reviews Compute and durably store a review draft; returns its id, head SHA, and token usage caller's GitHub token
POST /v1/cli-reviews/{id}/published Record that a stored draft was published on GitHub (github_review_id, comment_links, commit_shas) caller's GitHub token
POST /v1/cli-reviews/{id}/discard Retire an unpublished draft caller's GitHub token
POST /v1/reviewer-assignment Pick and request a load-balanced human reviewer for a pull request now caller's token

The chat request preserves additional OpenAI-compatible fields, including tools, tool_choice, and provider-specific fields. Model routing, tools, skills, and other integrations can be provided by a compatible gateway; Mimir intentionally keeps that transport boundary small.

POST /webhooks/{platform} reviews non-draft opened, synchronize, reopened, and ready_for_review events in the background. With MIMIR_REVIEW_OPT_IN enabled they only start a review once the PR has been requested with /mimir; before that they return 200 and wait. Ignored events return 200; malformed payloads return 400; missing or invalid signatures return 401.

POST /v1/cli-reviews requires the caller's GitHub token (github_token), whose read access to the pull request is the authorization check and whose login is recorded as the requester. It returns 409 with the existing review id when that commit already has a published review, unless force is set. A caller may pass their own OpenAI-compatible llm (base_url/api_key/model), honored only for hosts in MIMIR_CLI_LLM_ALLOWED_HOSTS. This is what mctl drafts against. The published and discard endpoints require the same token, and it must belong to the login that created the draft.

Mimir has no authentication of its own yet, so these endpoints rely on the caller's GitHub token rather than a Mimir credential. Run Mimir on a trusted network, or put it behind an authenticating proxy (see V1 hardening).

Reviewing pull requests

A signed webhook is verified and filtered, the PR head commit is claimed in PostgreSQL, and Mimir reviews the diff in focused lenses, reconciles the candidate findings, validates them, and publishes inline comments plus an approve/comment/request-changes review. Large diffs switch to bounded per-commit drafts, developer replies are answered in their review threads, and /mimir re-reviews only the commits that are new since the last one.

See docs/review-pipeline.md for the GitHub App setup, the full pipeline stages, per-commit review, out-of-diff context, review conversations, repository memory, and observation mode.

Reviewing as yourself with mctl

mctl drafts a review with Mimir and publishes it as you, using your own GitHub App user-access token, so GitHub attributes the review, its inline comments, and any approval to your account rather than to Mimir's server credentials:

mctl login                             # optional: mctl also uses `gh auth login`
mctl inbox your-org                    # open PRs ranked by what needs you
mctl tui your-org                      # pick from the inbox, review, publish
mctl review owner/repo#123             # draft, edit in $EDITOR, then publish
mctl draft owner/repo#123 -o review.json && mctl publish review.json
mctl discard <review-id>               # retire a draft you decided not to publish
mctl assign-reviewer owner/repo#123    # pick and request a load-balanced reviewer

mctl login is only needed when mctl has nothing else to go on: if the machine is already logged in with the gh CLI, that token is used instead, and an explicit MCTL_GITHUB_TOKEN always wins over both.

The draft is stored server-side, so it is visible to Mimir; after publishing, mctl reports the GitHub review id and comment ids back, and mctl sync retries a report Mimir could not be reached for. mctl tui is the inbox and the review in one screen, with the diff beside each finding; it is optional and can be built out with --no-default-features. See docs/mctl.md for the workflow, the provenance document, caller-supplied inference, the disclosure footer, and the MCTL_* environment.

Configuration

The tables below cover the Mimir server. mctl uses its own MCTL_* namespace, documented in docs/mctl.md.

Core

Variable Default Description
COMPOSE_PROFILES mimir Profiles to start (mimir or local)
MIMIR_ADDR 0.0.0.0:3000 Listen address
MIMIR_DATABASE_URL postgresql://mimir:mimir-dev@localhost:5432/mimir Dedicated PostgreSQL database for review state
MIMIR_ENCRYPTION_KEY unset 32-byte key (64 hex chars) that encrypts sensitive content at rest

Inference

Variable Default Description
LITELLM_URL http://localhost:4000 Mimir's OpenAI-compatible upstream URL
LITELLM_MASTER_KEY unset LiteLLM proxy key sent by Mimir and Hindsight
MIMIR_MODEL mimir Model shown by /v1/models
MIMIR_REVIEW_MODEL MIMIR_MODEL Model used for PR reviews
MIMIR_REVIEW_SKILL_ID unset Gateway-managed skill containing review guidance
OPENAI_API_BASE https://api.openai.com/v1 Provider API base configured in LiteLLM
OPENAI_API_KEY unset Provider API key passed to LiteLLM
OPENAI_MODEL gpt-4o-mini Provider model routed by LiteLLM
HEADROOM_TARGET_URL http://litellm:4000 Upstream target for Headroom
HEADROOM_UPSTREAM_ALLOWED_HOSTS litellm Hosts Headroom may proxy to
HEADROOM_LOSSLESS_ONLY 1 Disable lossy compression paths
HEADROOM_SAVINGS_PROFILE balanced Headroom compression profile

Review

Variable Default Description
MIMIR_PER_COMMIT_DRAFT_LINE_THRESHOLD 3000 Use per-commit draft + reconcile above this diff size (lines) instead of the default whole-diff lens review
MIMIR_MAX_DIFF_LINES 5000 Reject diffs larger than this
MIMIR_REVIEW_MODE auto_approve Review decision authority: auto_approve, comment_and_reject, or comment_only
MIMIR_REVIEW_OPT_IN false When truthy, PR webhook events only auto-start reviews after the PR has been requested with /mimir
MIMIR_CLI_LLM_ALLOWED_HOSTS unset Comma-separated hosts a mctl caller may point at their own LLM (* for any); unset disables caller inference
MIMIR_MCP_SERVER_LABEL unset LiteLLM-registered MCP server name
MIMIR_MCP_ALLOWED_TOOLS unset Comma-separated read-only MCP tool allowlist

MIMIR_REVIEW_MODE controls how much authority Mimir has over a PR's review decision. auto_approve (default) publishes APPROVE, REQUEST_CHANGES, or COMMENT exactly as the model recommends. comment_and_reject keeps REQUEST_CHANGES and COMMENT but never approves, so Mimir can block a bad PR while a human still signs off. comment_only downgrades every review to COMMENT; Mimir can still open, reply to, and resolve review threads, but it never approves or blocks. The gate is applied at publish time, so previews and observation records still show the model's raw recommendation.

Reviewer assignment

Independent of Mimir's AI review, Mimir can pick a human reviewer for a pull request and request them, spreading review load instead of leaving it to whoever notices first — automatically when a pool is configured, or on demand via mctl assign-reviewer/POST /v1/reviewer-assignment.

Variable Default Description
MIMIR_REVIEWER_POOL_<NAME> unset Comma-separated logins for pool <NAME>; !login marks that person temporarily out of office
MIMIR_REVIEWER_POOL_<NAME>_REPOS unset Comma-separated owner/repo this pool applies to; omit for the fallback pool used by any other repo

See docs/reviewer-assignment.md for how the pick works, the on-demand endpoint/CLI, and platform support.

GitHub

Variable Default Description
GITHUB_API_URL https://api.github.com GitHub REST API base URL
GITHUB_TOKEN unset Static token used to read PRs/publish reviews (single-tenant mode, and fallback for deliveries with no installation)
GITHUB_APP_ID unset GitHub App id; enables per-installation tokens (requires a private key and GITHUB_WEBHOOK_SECRET)
GITHUB_APP_PRIVATE_KEY unset App private key PEM (literal \n allowed); alternative: GITHUB_APP_PRIVATE_KEY_FILE path
GITHUB_WEBHOOK_SECRET unset HMAC secret for webhook signature verification

Repository memory

Variable Default Description
HINDSIGHT_URL unset Optional Hindsight API; the memory bank is the repository name
MIMIR_MEMORY_REPOS unset Comma-separated owner/repo list the background memory flow seeds/syncs

Observation

Variable Default Description
MIMIR_OBSERVATION_ORG unset GitHub organization login that observation-mode events must match
MIMIR_OBSERVATION_REPOS unset Comma-separated backend,ui-host pilot repos for non-publishing comparisons
MIMIR_OBSERVATION_MAX_CONCURRENT 1 Maximum concurrent observation jobs
COMPARISON_REVIEW_GITHUB_LOGINS unset Comma-separated GitHub identities used to locate comparison-review results
COMPARISON_REVIEW_MARKER unset Body substring that also marks a review as a comparison result

Review state

The PostgreSQL database is initialized with eight tables: reviews, review_findings, review_messages, reviewed_commits, review_requests, review_observations, memory_sync_state, and review_assignments (the reviewer-assignment ledger, see docs/reviewer-assignment.md). Reviews store PR title, description, branch, final summary, recommendation, status, and token usage, and record their source (webhook or cli) and, for CLI drafts, the requester. Findings receive stable path:line:category fingerprints so later reviews can mark missing prior findings as fixed. Conversation messages are deduplicated by GitHub comment ID, and the latest twenty messages are supplied to the conversation prompt.

Encrypting Mimir's database content

Set MIMIR_ENCRYPTION_KEY to a dedicated 32-byte random key encoded as 64 hex characters to encrypt PR titles/bodies, review findings and summaries, review conversation messages, observation payloads, and stored error details before they are written to Mimir's PostgreSQL database. Generate one with:

openssl rand -hex 32

Keep this key in a secret manager or a protected .env file, and back it up separately from the database. Losing or rotating the key without re-encrypting the database makes encrypted values unreadable; the key is not recoverable from the ciphertext. Existing plaintext rows remain readable and will be encrypted when those records are updated; this change does not retroactively encrypt untouched rows. Do not enable this feature if database consumers expect these text columns to remain searchable/readable without the application.

This is application-layer encryption at rest, not end-to-end encryption: Mimir decrypts data in memory to review PRs, and external inference services still receive the prompt content. It does not encrypt repository memory in Hindsight; Hindsight needs plaintext to embed and extract memories, so simply proxying ciphertext would break those operations. Database metadata such as repository names, PR identifiers, paths, statuses, and timestamps remains plaintext. Keep encryption disabled until the key is configured and securely stored.

Roadmap

Mimir is evolving from a GitHub PR reviewer into a cross-platform engineering intelligence agent. See ROADMAP.md for the detailed technical phases and current progress.

Open-source project

Mimir is a transparent, self-hosted open-source project: small components, documented interfaces, provider-neutral configuration, and no required connection to a particular SaaS platform. Contributions are welcome in the form of bug reports, tests, documentation, integrations, and review policy improvements. Keep secrets, production credentials, and organization-specific prompts out of commits.

Feature checklist

V1 — GitHub PR review engine

  • Define configurable review lenses and a structured JSON output contract.
  • Ground decisive review calls with configurable engineering guidance through gateway-managed skills.
  • Add GitHub integration for reading repositories and creating PR reviews and comments.
  • Receive and validate signed webhook events for opened, synchronized, and reopened pull requests.
  • Review individual commits and reconcile findings against the full PR diff.
  • Add a dry-run preview endpoint that never publishes or creates audit rows.
  • Provide optional read-only external context through gateway-managed MCP, inferred from configurable branch or PR metadata.
  • Produce and publish structured findings with file, line, severity, category, and explanation fields.
  • Make reviews safe against duplicate delivery with atomic PostgreSQL claims, diff deduplication, and GitHub-side checks.
  • Record review outcomes and actual model token usage in PostgreSQL.
  • Listen for developer replies on inline review threads and respond using stored review context.
  • Store normalized findings, PR context, message history, and finding progression (open → fixed) for future reviews and conversations.
  • Add a manual /mimir trigger or re-review API with optional instructions.
  • Add GitHub App authentication with scoped installation permissions.
  • Publish a review drafted by Mimir, or written by hand, as the person who approved it, through the mctl operator CLI.
  • Add mctl tui, a terminal UI that ranks the inbox, drafts with Mimir, and lets a reviewer accept/edit/publish findings against the diff in one screen.
  • Add end-to-end tests with stub GitHub and model providers.
  • Add richer repository context beyond the PR diff where useful.
  • Add committable code suggestions using GitHub's native suggestion blocks.
  • Capture repository-scoped engineering learnings from developer feedback and inject relevant learnings into future review prompts.
  • Add a PR-level priority and risk signal to help teams triage the review queue and route attention to higher-impact changes.
  • Add least-trailing-load human reviewer assignment (src/assign) with a platform-agnostic core algorithm, a Postgres-backed load ledger, automatic assignment from the webhook route, and an on-demand POST /v1/reviewer-assignment endpoint plus mctl assign-reviewer client.

V1 hardening

  • Add streaming support for OpenAI-compatible responses where required by the review workflow.
  • Add upstream timeouts, cancellation, retry/backoff policy, and clearer propagation of provider errors and rate limits.
  • Add authentication and authorization for Mimir's externally reachable endpoints.
  • Add service health/readiness checks and graceful shutdown handling.
  • Build a production Mimir container instead of running cargo run in the development Compose image.
  • Add CI for formatting, compilation, clippy, unit tests, and integration tests.
  • Add review observability: correlation IDs across GitHub, Mimir, model gateways, and memory services, without logging secrets or repository contents unintentionally.

Later

  • Support multiple review personas and repository-specific instructions.
  • Add configurable review policies, severity thresholds, and path ignores.
  • Add dashboards and operational controls for queued, running, and failed reviews.

Contributions

Contributions should include focused tests or documentation when practical and should preserve provider-neutral behavior in the core service. Keep deployment- specific credentials, prompts, and repository data outside the repository.

Logging & tracing

Mimir uses tracing + tracing-subscriber for structured logs, and tower-http's TraceLayer to emit one http_request span per request with method, path, status, and latency_ms fields.

  • Control verbosity with RUST_LOG (e.g. RUST_LOG=debug,tower_http=debug). Defaults to info,tower_http=info when unset.
  • Every response carries an x-request-id header. If the inbound request already has one it is propagated as-is; otherwise Mimir generates a UUID. The same ID is included in each request's log span.
  • /v1/chat/completions additionally logs the requested model, message count, and the upstream LiteLLM response status, and logs a warning on non-success upstream responses or transport failures.