- Rust 99.8%
- Dockerfile 0.2%
|
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
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. |
||
|---|---|---|
| docs | ||
| src | ||
| .env.example | ||
| .gitignore | ||
| .woodpecker.yml | ||
| Cargo.lock | ||
| Cargo.toml | ||
| compose.yaml | ||
| Dockerfile | ||
| LICENSE | ||
| README.md | ||
| ROADMAP.md | ||
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
/mimirtrigger 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
mctloperator 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-demandPOST /v1/reviewer-assignmentendpoint plusmctl assign-reviewerclient.
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 runin 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 toinfo,tower_http=infowhen unset. - Every response carries an
x-request-idheader. 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/completionsadditionally logs the requestedmodel, message count, and the upstream LiteLLM response status, and logs a warning on non-success upstream responses or transport failures.