Skip to content

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

HTTPS

API

FastAPI · verifies & records

enqueue

Redis

Celery broker

consume

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

The worker drives the sandbox and the LLM, and posts results back to GitHub.

Lifecycle of a review

  1. Webhook. GitHub sends a pull_request event to /webhooks/github. The API checks the HMAC-SHA256 signature and ignores actions other than opened, reopened, and synchronize.
  2. Enrollment check. The repository must be enabled in the dashboard. Events for other repositories are acknowledged and dropped.
  3. Record and enqueue. A Review row is committed in the PENDING state with the PR's metadata. Then two Celery tasks are queued, one for the review and one for the summary, and the API responds 202 Accepted.
  4. 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.
  5. 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.
  6. Finish. The agent calls finish_review with a summary and a verdict (APPROVE, REQUEST_CHANGES, or COMMENT). The worker submits the review, marks it COMPLETED, 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:

  1. sends the conversation so far and the agent's tool schemas to the LLM;
  2. runs every tool call the model asked for, concurrently, inside the sandbox;
  3. 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.

AgentTriggered byTools
ReviewerPR webhookread_file, list_files, search_files, git_status, git_branches, run_tests, run_linter, run_command, post_inline_finding, post_file_finding, finish_review
SummaryPR webhookread_file, list_files, search_files, git_status, finish_summary
CoderLaunched from an issue in the dashboardread_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

TableHolds
usersGitHub users who signed in, with their encrypted OAuth token.
installationsOne row per enrolled repository: the GitHub installation ID, owner, active flag, and review settings.
reviewsOne row per reviewed commit: status, PR metadata, summary, verdict, and run metrics.
review_commentsEach finding: file, line, severity, category, title, body, and GitHub comment ID.
agent_runsIssue → 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

PathContents
backend/app/api/HTTP routes: webhooks, auth, installations, issues, agents, analytics
backend/app/services/webhook.pySignature 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)