Automated multi-agent code review tool for GitHub PRs
Project description
MARX - Multi-Agentic Review eXperience
An interactive CLI tool for automated multi-model AI code review of GitHub Pull Requests. Marx fetches open PRs and runs parallel code reviews inside Docker using three AI models (Claude, Codex, and Gemini) without modifying your local repository.
TL;DR: Install, Configure, Run
# 1) Install (no checkout needed)
uv tool install marx-ai
# 2) Configure credentials
# Create a GitHub token at https://github.com/settings/tokens with 'repo' scope
cat > ~/.marx <<'EOF'
GITHUB_TOKEN=ghp_your_token_here
ANTHROPIC_API_KEY=your_claude_key
OPENAI_API_KEY=your_openai_key
GEMINI_API_KEY=your_gemini_key
# Optional: override repo detection
# MARX_REPO=owner/repo
EOF
# 3) Run on a repo with all agents
cd /path/to/your/git/repo
marx --pr 123 --agents claude,codex,gemini
Features
- Multi-Model AI Review: Runs Claude, Codex, and Gemini in parallel for comprehensive code analysis
- Containerized Checkout: Clones the PR branch inside Docker so your local repo stays untouched
- Intelligent PR Filtering: Automatically filters PRs where you're not the author or reviewer
- Docker Isolation: All AI models run in containers with proper permissions
- Structured Review Files: Line-based, machine-parseable review outputs from each agent
- Robust Error Handling: Graceful fallbacks and comprehensive validation
- Collision-free Containers: Each agent run uses a unique Docker container name to avoid clashes
- Preflight PR Context: Captures PR details, diff, changed files, and review comments up front to keep agents aligned on the exact PR state
- User-Friendly Interface: Colored output with clear progress indicators
Prerequisites
The following tools must be installed:
git- Version controlgh- GitHub CLI (must be authenticated)docker- Container runtime
Installation
Option 1: Install the published package from PyPI
If you simply want to use Marx and do not need the repository checked out locally, install the published package directly from PyPI using uv:
# Install globally
uv tool install marx-ai
# Or run without installing
uvx marx-ai
After installation the marx CLI will be on your PATH and you can run marx --help to verify
everything is set up correctly.
Option 2: Using Nix (Recommended for development)
If you have Nix with flakes enabled:
# Clone the repository
git clone https://github.com/forketyfork/marx.git
cd marx
# Install globally to your profile
nix profile install .
# Or run without installing
nix run .
# Or enter development environment
nix develop
Option 3: From source with uv
For standard Python environments when working from a clone of the repository:
# Clone the repository
git clone https://github.com/forketyfork/marx.git
cd marx
# Install globally
uv pip install .
# Or install in editable mode for development
uv pip install -e ".[dev]"
Note: If you're using Nix, uv pip install will fail because Nix's Python environment is read-only. Use the Nix installation methods above instead.
Running Marx
After installation, run:
marx
Structured JSON output
Use --json-output to print the merged review in a machine-readable format instead of the
default rich terminal view:
marx --pr 123 --json-output
The output includes PR context, issue counts, all issues, and pointers to the saved artifacts:
{
"pr": {"number": 123, "title": "Add new feature"},
"descriptions": [{"agent": "claude", "description": "Short summary"}],
"counts": {"total": 5, "p0": 1, "p1": 3, "p2": 1},
"issues": [
{
"agent": "claude",
"priority": "P1",
"file": "src/app.py",
"line": 42,
"commit_id": "abcd1234",
"category": "bug",
"description": "Potential issue",
"proposed_fix": "Suggested change"
}
],
"artifacts": {
"claude_review": "runs/pr-123-main/claude-review.txt",
"codex_review": "runs/pr-123-main/codex-review.txt",
"gemini_review": "runs/pr-123-main/gemini-review.txt",
"dedup_review": null,
"merged_review": "runs/pr-123-main/merged-review.txt"
},
"run_directory": "runs/pr-123-main"
}
Authentication notes
Marx uses the GitHub CLI (gh) under the hood. If you haven't run gh auth login, Marx will try to authenticate gh by supplying a token from your environment/config:
- If
GH_TOKENis already set, it will be used as-is - Else, Marx will look for
MARX_GITHUB_TOKENorGITHUB_TOKEN(env or~/.marx) and pass it toghasGH_TOKEN
Recommended options:
- Either run
gh auth loginonce and rely on yourghkeychain, or - Put
GITHUB_TOKEN=...(orMARX_GITHUB_TOKEN=...) into~/.marxas shown above, or export it in your shell environment. - Use a classic personal access token with
repo(orpublic_repofor public-only) andread:orgscopes. Fine-grained tokens are not supported.
If you see an error like:
Repository 'owner/repo' not found or not accessible
ensure that your token has at least the repo scope and that the repository exists and your account has access to it. For GitHub Enterprise, also verify your gh host configuration.
Quick Start with Nix (Recommended for Development)
If you have Nix with flakes enabled:
# Clone the repository
git clone https://github.com/forketyfork/marx.git
cd marx
# Enter the development environment
nix develop
# Or use direnv for automatic environment loading
direnv allow
The Nix flake provides:
- Python 3.12 with all dependencies
- System tools (git, gh, docker)
- Development tools (pytest, black, ruff, mypy)
- Just command runner for common tasks
Using Just Commands
# See all available commands
just
# Run linters
just lint
# Run tests
just test
# Run marx
just run
# Cut a release (updates versions, commits, tags, pushes)
just release v0.1.1 # creates and pushes branch release-0.1.1 and tag v0.1.1
# Install package in editable mode
just install
# Run all checks (CI equivalent)
just check
Environment Variables
Setting up Environment Variables
Copy the example environment file and fill in your credentials:
cp .env.example .env
# Edit .env with your API keys and tokens
If using direnv (recommended), the .env file will be automatically loaded.
Required
GITHUB_TOKEN- GitHub API token (required for container access to GitHub API)- Create at https://github.com/settings/tokens
- Use a classic PAT (fine-grained tokens are not supported)
- Required scopes:
repo(full control of private repositories) andread:org - For public repositories only,
public_repo+read:orgis sufficient - The token is used to fetch PR metadata, read diffs, and post reviews
API Keys (at least one required)
The following API keys enable the respective AI models to function. You can provide one or more:
ANTHROPIC_API_KEY- Anthropic API key for ClaudeOPENAI_API_KEY- OpenAI API key for CodexGOOGLE_API_KEYorGEMINI_API_KEY- Google API key for Gemini
Without API keys, the AI models will fall back to using local configuration from ~/.claude, ~/.codex, or ~/.gemini directories if available.
Optional
MARX_REPO- Optional owner/name override (e.g.,owner/repo) when auto-detection fails
Configuration
Marx supports two authentication methods for AI models:
Method 1: API Keys (Recommended for CI/CD)
Set environment variables with your API keys:
export ANTHROPIC_API_KEY="your-key-here"
export OPENAI_API_KEY="your-key-here"
export GOOGLE_API_KEY="your-key-here"
Method 2: Local Configuration Directories
Marx can use AI model configuration directories from your home directory:
~/.claude- Claude CLI configuration~/.codex- Codex CLI configuration~/.gemini- Gemini CLI configuration
These directories are mounted read-only into the Docker container during execution. This method is useful for development when you've already authenticated via the respective CLI tools.
Global Config File (~/.marx)
Marx also looks for a configuration file at ~/.marx. Any values defined here act as defaults and are only applied when the corresponding environment variable is unset. The file uses a simple KEY=value format (an optional leading export is allowed, e.g., export GITHUB_TOKEN=...) and supports comments starting with # on their own line.
Example:
# Default repository for GitHub operations
MARX_REPO=acmecorp/my-app
# API keys (omit or override with environment variables as needed)
GITHUB_TOKEN=ghp_example
OPENAI_API_KEY="sk-123"
This file is loaded automatically when the CLI starts. Environment variables still take precedence, allowing you to override individual values for a single run.
Customizing the review prompt
The default review instructions provided to each agent are stored in the package at
marx/prompts/review_prompt.md. You can supply your own prompt template by either setting the
MARX_REVIEW_PROMPT_PATH environment variable or adding REVIEW_PROMPT_PATH=/path/to/prompt.md
to your ~/.marx configuration file. The template supports the placeholders {pr_number}, {repo},
{commit_sha}, {agent}, and {container_workspace_dir}, which are replaced at runtime.
Deduplication prompt
When more than one agent is selected, Marx automatically invokes an agent for a follow-up
deduplication pass. By default, the first agent in the --agents list is used, but you can
override this with the --dedupe-with option. This step reads the individual review outputs,
asks the agent to merge duplicate issues, and writes the consolidated results to
runs/<pr>/dedup-review.txt, ensuring the agent field lists all reporting agents as a
comma-separated value. You can customize the deduplication instructions by providing a
template at MARX_DEDUP_PROMPT_PATH or DEDUP_PROMPT_PATH (in ~/.marx). The bundled
template lives at marx/prompts/dedup_prompt.md. The Docker runner copies this file from
.marx/dedup-review.txt in the workspace back to the run directory, so keep custom output
names aligned with that location. The template is rendered with Python string formatting, so
escape any literal braces as {{ and }} when editing to avoid malformed prompts.
Usage
marx [OPTIONS]
Use marx --help for a quick reminder of prerequisites, environment variables, and example commands.
Options
--help- Show help message and exit--version- Show version and exit--pr <number>- Specify PR number directly (skip interactive selection)--agents <agents>- Comma- or space-separated list of agents to run (claude, codex, gemini). Append:<model>to override the model used by that agent.- Default: all agents
- Claude accepts aliases like
opus,sonnet, andhaiku, or full release identifiers such asclaude-sonnet-4-5-20250929. See the Claude models documentation for available models. - Codex works with OpenAI models including
gpt-5andgpt-5-codex, plus any custom providers configured in~/.codex/config.toml. - Gemini supports model IDs such as
gemini-2.5-flash-lite,gemini-2.5-flash, andgemini-2.5-pro. See the Gemini models documentation for the complete list of available models.
--repo <owner/repo>- Repository in the format owner/repo (e.g., acmecorp/my-app)- Overrides automatic repository detection
--resume- Reuse artifacts from the previous run and skip AI execution--dedupe-with <agent>- Agent to use for deduplication (claude, codex, gemini). Append:<model>to override the model.- Default: first agent from
--agents
- Default: first agent from
Examples
# Interactive mode with all agents (default)
marx
# Review PR #123 with all agents
marx --pr 123
# Review PR #123 with Claude only
marx --pr 123 --agents claude
# Interactive mode with Codex and Gemini
marx --agents codex,gemini
# Run Claude Opus with Codex defaults
marx --agents "claude:opus,codex"
# Review with Gemini 2.5 Pro only
marx --agents "gemini:gemini-2.5-pro"
# Review PRs in specific repository
marx --repo acmecorp/my-app
# Review specific PR in specific repository
marx --pr 123 --repo acmecorp/my-app
# Review specific PR with custom Claude + Gemini models
marx --pr 456 --agents "claude:sonnet,gemini:gemini-1.5-pro"
# Resume from previous run without rerunning agents
marx --resume --pr 123
# Use Claude Opus for deduplication while running all agents
marx --pr 123 --dedupe-with claude:opus
# Run Codex and Gemini, use Claude for deduplication
marx --agents codex,gemini --dedupe-with claude
How It Works
1. Setup & Validation
- Checks for required dependencies (git, gh, docker)
- Pulls the configured Docker image (default:
ghcr.io/forketyfork/marx:latest) if not present - Validates
GITHUB_TOKENenvironment variable - Confirms current directory is a git repository
2. Repository Detection
Determines repository slug (owner/name) using three methods in order:
MARX_REPOenvironment variablegh repo viewcommand- Git remote URL parsing (fallback)
3. PR Discovery
- Gets current GitHub user via GitHub API
- Fetches open PRs with metadata (title, author, reviewers, line changes)
- Filters PRs where:
- You are NOT the author
- You are NOT a reviewer
- Has at least one reviewer assigned
- Handles both flat array and nested
nodes[]API response formats
4. PR Selection & Checkout
- If
--pris specified: validates PR exists and gets branch name - Otherwise: displays formatted PR list with colors and statistics and prompts for selection
- Fetches the PR and gets commit SHA
- Clones the repository inside the Docker container and checks out the PR head (or specific commit SHA)
5. Parallel AI Code Review
- If
--agentsis specified: runs only the selected agents - Otherwise: runs all three agents (claude, codex, gemini)
Each AI model receives a detailed prompt instructing it to:
- Gather PR context using
ghcommands - Review code for bugs, security issues, performance problems, etc.
- Output findings in a structured text format
Selected models run simultaneously in isolated Docker containers with:
- Repository clone inside the container
- Run artifacts directory mounted from the host
- Config directories from home
- GitHub token for API access
6. Results Merging & Display
- Validates all structured review outputs
- Merges reviews from all three models
- Sorts issues by priority (P0 → P1 → P2)
- Displays formatted output with:
- PR summary and title
- Description from each AI model
- Issue counts by priority
- Detailed issue breakdown
Output Format
Review Text Structure
Each AI model produces a structured text file with this format:
PR_NUMBER: 123
PR_TITLE: PR Title
PR_DESCRIPTION:
Brief description of changes
--- ISSUE ---
agent: claude|codex|gemini
priority: P0|P1|P2
path: path/to/file.js
line: 42
commit_id: abcd1234
category: bug|security|performance|quality|style
description:
Detailed description of the issue
proposed_fix:
Concrete suggestion on how to fix it
Priority Definitions
- P0 (Critical): Must be fixed - security vulnerabilities, bugs causing crashes/data loss
- P1 (Important): Should be fixed - logic bugs, performance problems, poor error handling
- P2 (Nice-to-have): Suggestions - code style, minor optimizations
Output Files
All files are saved in the run artifacts directory (runs/pr-{number}-{branch}/):
claude-review.txt- Claude's reviewcodex-review.txt- Codex's reviewgemini-review.txt- Gemini's reviewdedup-review.txt- Deduplicated issues when multiple agents runmerged-review.txt- Combined review from all models
Example Workflow
# Run marx
marx
# The tool will:
# 1. Detect your repository
# 2. Show available PRs
# 3. Prompt you to select one
# 4. Clone the PR inside Docker and run AI reviews in parallel
# 5. Display merged results and write artifacts to runs/pr-<number>-<branch>/
# If you want a local checkout to apply fixes:
gh pr checkout 123
# Review artifacts are available at:
ls runs/pr-123-<branch>/
Docker Image
Marx uses a Docker image containing:
- AI CLI Tools: Claude, Codex, Gemini
- GitHub Tools:
gh(GitHub CLI) - Search & Navigation:
rg(ripgrep),fd,tree - Code Refactoring:
fastmod,ast-grep(withsgalias) - Development Tools: git and other utilities
The default image is ghcr.io/forketyfork/marx:latest. It is published to GHCR and
pulled automatically on first run.
Customizing the Docker image
You can run Marx with a different Docker image by setting the MARX_DOCKER_IMAGE
environment variable or by adding DOCKER_IMAGE=your/image:tag to your ~/.marx
configuration file. The environment variable takes precedence over the config file,
and both fall back to the bundled ghcr.io/forketyfork/marx:latest image when unspecified.
When supplying a custom image make sure it satisfies the baseline requirements expected by the runner script:
- A Linux base with
/bin/bash, core utilities, and the ability to create users viauseradd gitandgh(GitHub CLI)- Search and navigation tools:
rg,fd,tree - Code editing helpers:
fastmod,ast-grep(available assg) - The CLI tools for any agents you intend to run (
claude,codex,gemini)
Images missing these tools will fail at runtime, so verify your custom build before invoking Marx.
If you prefer a local build, build the image yourself (for example,
docker build -t marx:latest .) and set MARX_DOCKER_IMAGE=marx:latest so Marx
uses your local tag.
Error Handling
Marx includes robust error handling:
- Non-compliant review outputs from AI models are handled gracefully with empty reviews
- Failed API calls are caught and reported with detailed error messages
- Docker errors and container stderr are both captured and displayed
- Invalid review formats are replaced with valid fallback structures
- All temporary files are cleaned up automatically
- Helpful hints are provided when authentication or configuration issues occur
Security Considerations
- AI models run in isolated Docker containers
- Config directories are mounted read-only
- GitHub token is passed as an environment variable
- No destructive git operations are performed
- User input is validated before use
Troubleshooting
"GITHUB_TOKEN environment variable is not set"
Set your GitHub token: export GITHUB_TOKEN=ghp_your_token_here
"Unable to determine repository automatically"
Set the repository manually: export MARX_REPO=owner/repo
"Missing required dependencies"
Install the missing tools listed in the error message.
AI model fails or returns invalid review output
Marx will automatically handle this by creating an empty review. Error details are displayed in the terminal output, including:
- Docker errors (if Docker command failed)
- Container stderr output (errors from the AI CLI tool)
- Helpful hints for common issues (missing/invalid credentials)
Common causes:
- Missing authentication: Set API key environment variables (e.g.,
ANTHROPIC_API_KEY) or run the CLI auth command (e.g.,claude authfor Claude) - Invalid API keys or credentials in
~/.claude/,~/.codex/, or~/.gemini/ - Network connectivity issues
- API quota/rate limiting
Tip: For CI/CD environments, using API key environment variables is more reliable than local configuration directories.
Development & Testing
Nix Development Workflow (Recommended)
The project includes a Nix flake for reproducible development environments:
# Enter development shell
nix develop
# Or use direnv for automatic loading (recommended)
echo "use flake" > .envrc
direnv allow
# Use just for common tasks
just # List all commands
just check # Run all checks (lint + type-check + test)
just lint # Run linters
just test # Run tests
just run --pr 123 # Run marx
Setting up direnv
- Install direnv:
nix-env -iA nixpkgs.direnvor see direnv installation - Add hook to your shell (e.g.,
eval "$(direnv hook bash)"for bash) - Allow the directory:
direnv allow
Now the environment will automatically load when you cd into the project!
Just Command Reference
just install # Install package in editable mode
just lint # Run all linters (black, ruff, mypy)
just format # Format code with black
just fix # Auto-fix linting issues
just test # Run all tests
just test-cov # Run tests with coverage
just test-file FILE # Run specific test file
just clean # Clean build artifacts
just docker-build # Build Docker image
just info # Show environment info
Python Version
The Python codebase includes a comprehensive test suite. To run tests manually:
# Install development dependencies (includes pytest-cov for coverage)
uv pip install -e ".[dev]"
# or
pip install -r requirements-dev.txt
# Run tests with coverage
pytest
# Run tests with verbose output
pytest -v
# Run specific test file
pytest tests/test_github.py
# Type checking with mypy
mypy marx
# Code formatting with black
black marx tests
# Linting with ruff
ruff check marx tests
Project Structure
marx/
├── marx/ # Main package
│ ├── __init__.py
│ ├── cli.py # CLI entry point and orchestration
│ ├── config.py # Configuration and constants
│ ├── docker_runner.py # Docker container orchestration
│ ├── exceptions.py # Custom exceptions
│ ├── github.py # GitHub API client
│ ├── review.py # Review processing and merging
│ └── ui.py # Terminal UI and formatting
├── tests/ # Test suite
│ ├── conftest.py # Pytest fixtures
│ ├── test_github.py # GitHub client tests
│ └── test_review.py # Review processing tests
├── pyproject.toml # Project configuration
├── requirements.txt # Dependencies
└── README.md # This file
Publishing
Marx ships with an automated publication pipeline defined in .github/workflows/publish.yml.
The workflow builds source and wheel distributions and uploads them as a workflow artifact on every run. Because uploading
artifacts requires elevated GitHub token capabilities, the workflow explicitly grants the actions: write permission at the
workflow level. When a GitHub release is published, the same workflow also pushes the distributions to PyPI using the
PYPI_API_TOKEN repository secret.
Preparing a release
- Update the version number in
pyproject.toml. - Run
just buildlocally to confirm the package can be built. - Commit and push the release changes, then create a Git tag (for example
v1.2.3). - Draft a GitHub release for the tag and click Publish to trigger the PyPI deployment.
Configuring credentials
- Create a PyPI API token.
- Add the token to the repository secrets as
PYPI_API_TOKEN(set the username to__token__). - Ensure the token has permission to upload to the
marx-aiproject on PyPI.
Manual runs of the workflow via Run workflow in the Actions tab will build and attach the distributions without publishing them, making it easy to validate the packaging process before performing a release.
Contributing
Contributions are welcome! Please ensure:
- Code passes
mypytype checking - Code passes
rufflinting - Code is formatted with
black - Tests pass with
pytest - New features include tests
- Follow Python best practices and PEP 8
License
See LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file marx_ai-0.3.0.tar.gz.
File metadata
- Download URL: marx_ai-0.3.0.tar.gz
- Upload date:
- Size: 48.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a870f5b33319aad2ff35af4080cab6402a8b687e8756ce069dcce3a011b463a9
|
|
| MD5 |
a5aa1a0cf2599d3c4c4c10f09b4b264d
|
|
| BLAKE2b-256 |
fbdec4025802270cb610b080c296c7e5fec2a9efe0862494b3cc02ee446c65ac
|
File details
Details for the file marx_ai-0.3.0-py3-none-any.whl.
File metadata
- Download URL: marx_ai-0.3.0-py3-none-any.whl
- Upload date:
- Size: 38.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c0397c29d7efabc2893a1c43538febbd0fae188804145868b88b0661dbe5065f
|
|
| MD5 |
4f9327abe516c23fe9662a827fdc4dc3
|
|
| BLAKE2b-256 |
04425ce238f40ad019e00b820ced0ab691bc44d27e6554330076b3bceebaa813
|