Concepts
Architecture

Metis is an event-driven system. A small API responds to GitHub quickly, and a worker does the slow part: running LLM agents against your code inside isolated sandboxes.
GitHub
PR webhook
API
FastAPI · verifies & records
Redis
Celery broker
Worker
Celery · runs agents
Dashboard
React · talks to the API
PostgreSQL
Shared by API & worker
Daytona
Sandbox per agent run
LLM
Any provider via LiteLLM
Lifecycle of a review
- Webhook. GitHub sends a
pull_requestevent to/webhooks/github. The API checks the HMAC-SHA256 signature and ignores actions other thanopened,reopened, andsynchronize. - Enrollment check. The repository must be enabled in the dashboard. Events for other repositories are acknowledged and dropped.
- Record and enqueue. A
Reviewrow is committed in thePENDINGstate with the PR's metadata. Then two Celery tasks are queued, one for the review and one for the summary, and the API responds202 Accepted. - Sandbox. The worker marks the review
PROCESSING, fetches the diff, gets an installation token for the app, and creates a Daytona sandbox with the PR's head branch cloned. - Agent loop. The review agent explores the code and posts each finding to GitHub as soon as it is confident in it. Every finding is also saved to the database.
- Finish. The agent calls
finish_reviewwith a summary and a verdict (APPROVE,REQUEST_CHANGES, orCOMMENT). The worker submits the review, marks itCOMPLETED, and deletes the sandbox.
The summary task runs in parallel with the same setup. When its agent calls finish_summary, the worker updates the PR title and appends the summary to the description below a --- separator.
The agent loop
All three agents share one small loop. Each iteration:
- sends the conversation so far and the agent's tool schemas to the LLM;
- runs every tool call the model asked for, concurrently, inside the sandbox;
- appends the results to the conversation and goes again.
The loop ends when a completion tool (finish_review, finish_summary, or finish_task) succeeds, or when a limit is hit. Review runs are capped at 50 iterations and 100 tool calls. A run that ends without calling its completion tool is marked failed, so a half-finished review is never posted as if it were complete.
Agents and their tools
Each agent only gets the tools its job needs. The reviewer can run your tests but cannot edit files or push.
| Agent | Triggered by | Tools |
|---|---|---|
| Reviewer | PR webhook | read_file, list_files, search_files, git_status, git_branches, run_tests, run_linter, run_command, post_inline_finding, post_file_finding, finish_review |
| Summary | PR webhook | read_file, list_files, search_files, git_status, finish_summary |
| Coder | Launched from an issue in the dashboard | read_file, list_files, search_files, replace_in_files, create_file, delete_file, git_status, git_branches, git_create_branch, git_checkout_branch, git_add, git_commit, git_push, git_pull, run_code, run_tests, run_linter, run_command, finish_task |
Issue → PR
Launching an agent on an issue creates an AgentRun and queues a task. The worker loads the issue and repository, opens a sandbox on the default branch, configures git with the app's installation token, and runs the coder agent. When the agent calls finish_task, the worker checks that the branch exists on GitHub and opens the pull request. The full conversation and tool trace are saved, so you can replay the run on the dashboard's agent page.
Data model
| Table | Holds |
|---|---|
users | GitHub users who signed in, with their encrypted OAuth token. |
installations | One row per enrolled repository: the GitHub installation ID, owner, active flag, and review settings. |
reviews | One row per reviewed commit: status, PR metadata, summary, verdict, and run metrics. |
review_comments | Each finding: file, line, severity, category, title, body, and GitHub comment ID. |
agent_runs | Issue → PR runs: status, metrics, resulting PR, and the full conversation. |
Security model
- Webhooks are authenticated with HMAC-SHA256 against your webhook secret.
- Agent tools run inside Daytona sandboxes, never on the worker host. Each run gets a fresh sandbox, deleted afterwards.
- GitHub access goes through short-lived installation tokens, limited to the permissions and repositories you granted the app.
- Users' OAuth tokens are encrypted at rest with Fernet. Sessions use HTTP-only cookies.
- Dashboard APIs only return data for repositories the signed-in user enrolled.
Found a vulnerability? Please follow the security policy instead of opening a public issue.
Where to look in the code
| Path | Contents |
|---|---|
backend/app/api/ | HTTP routes: webhooks, auth, installations, issues, agents, analytics |
backend/app/services/webhook.py | Signature check and task dispatch |
backend/app/tasks/ | Celery tasks for reviews, summaries, and Issue → PR |
backend/app/agents/ | Agent loop, agent implementations, prompts, sandbox, tools |
backend/alembic/ | Database migrations |
frontend/src/ | Dashboard (React, TypeScript, Tailwind) |