Skip to main content

Engineering discipline for AI code generation — smart routing, 97% token reduction, unbreakable code by default

Project description

ArbiterX Logo

ArbiterX

Your AI writes code. ArbiterX decides if it's good enough.

The intelligent middleware that makes AI coding assistants write like senior engineers — minimal, robust, unbreakable.

License PyPI Python Tests Token Savings Integrations

InstallQuick StartHow It WorksExamplesIntegrationsFull Guide



💀 The Problem

Your AI assistant just wrote this:

def get_user(id):
    try:
        conn = psycopg2.connect("postgresql://admin:password123@localhost/db")
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM users WHERE id = " + str(id))
        return cursor.fetchone()
    except:
        return None

5 security vulnerabilities. 3 resource leaks. 0 type hints. Your code review just got longer.


✅ The Fix

With ArbiterX active, the AI writes this instead:

from typing import Optional
from dataclasses import dataclass

@dataclass(frozen=True)
class User:
    id: int
    name: str
    email: str

def get_user(user_id: int, conn: Connection) -> Optional[User]:
    """Fetch a user by ID. Returns None if not found."""
    row = conn.execute(
        "SELECT id, name, email FROM users WHERE id = ?", (user_id,)
    ).fetchone()
    return User(**row._asdict()) if row else None

Typed. Parameterized. No hardcoded secrets. No resource leak. Ships on first review.



🏗️ What ArbiterX Does

┌──────────────────────────────────────────────────────────────────┐
│                        YOUR AI TOOL                                │
│  Claude Code • Codex • Cursor • Copilot • Aider • Windsurf       │
└───────────────────────────────┬──────────────────────────────────┘
                                │
                                ▼
┌──────────────────────────────────────────────────────────────────┐
│                         ARBITERX                                   │
│                                                                   │
│   ┌─────────────┐  ┌─────────────┐  ┌─────────────────────────┐ │
│   │ ① DECIDE    │  │ ② COMPRESS  │  │ ③ ENFORCE               │ │
│   │             │  │             │  │                         │ │
│   │ Route to    │  │ Send 2KB    │  │ Score output 0-100      │ │
│   │ right model │  │ not 200KB   │  │ Reject if below 70      │ │
│   │             │  │             │  │                         │ │
│   │ trivial→    │  │ symbols +   │  │ ✓ security              │ │
│   │   haiku     │  │ signatures  │  │ ✓ robustness            │ │
│   │ hard→opus   │  │ only        │  │ ✓ efficiency            │ │
│   └─────────────┘  └─────────────┘  └─────────────────────────┘ │
└───────────────────────────────────────────────────────────────────┘
                                │
                                ▼
                    Clean, Minimal, Unbreakable Code


📊 Numbers That Matter

97.1%
Token Reduction
0.25s
Map Build Time
0.5ms
Query Latency
109
Tests Passing
10
Engineering Rules
6
Quality Checks
22
Languages
5
LLM Providers

196,247 tokens → 5,639 tokens. That's what your AI actually needs to see.



📦 Install

pip install arbiterx-gate

From source:

git clone https://github.com/neelpatel/arbiterx.git
cd arbiterx
pip install -e .

Verify:

arbiterx --version
# arbiterx 0.1.0

Requirements: Python 3.9+ · No system dependencies · Works offline for local models



🚀 Quick Start

# Install
pip install arbiterx-gate

# Set up (once per project)
arbiterx init
arbiterx map            # Index your codebase (30 seconds)

# Use
arbiterx route "task"   # See how any task gets classified
arbiterx query Symbol   # Find any function instantly
arbiterx gate --file main.py  # Score any file 0-100

That's it. You're running.

Using with an AI tool? After pip install arbiterx-gate:

# Claude Code
/plugin install NeelPrime/arbiterx

# Codex CLI
codex plugin install NeelPrime/arbiterx

ArbiterX terminal demo
pip install arbiterx-gate && arbiterx init && arbiterx map



⚙️ How It Works

1. Codebase Map (the 97% saver)

ArbiterX parses your code with tree-sitter, builds a graph of every function/class/import, ranks them with PageRank, and stores it in SQLite.

When the AI needs context, it queries the map:

  • Without ArbiterX: Read 40 files → 200,000 tokens
  • With ArbiterX: Query relevant signatures → 5,000 tokens

2. Smart Router (the cost saver)

Every task gets classified:

Task Type Model
"rename this variable" TRIVIAL Haiku / GPT-4o-mini
"fix the auth bug" DEBUGGING Sonnet / GPT-4o
"redesign the caching layer" ARCHITECTURE Opus / o1

3. Quality Gate (the code saver)

Every AI output gets scored:

┌─────────────────────────────────────────────┐
│  QUALITY GATE                                │
│                                             │
│  Security ·····  ✓ No hardcoded secrets     │
│  Robustness ···  ✓ Errors handled           │
│  Efficiency ···  ✓ No O(n²) patterns        │
│  Types ········  ✓ All functions typed       │
│  Style ········  ✓ Clean naming             │
│  Complete ·····  ✓ No TODOs left            │
│                                             │
│  Score: 100/100  ✓ PASSED                   │
└─────────────────────────────────────────────┘


🛡️ The 10 Engineering Rules

These run on every piece of generated code. No exceptions.

# Rule What Gets Rejected
1 YAGNI Building features nobody asked for
2 Error Handling open("file") without try/except
3 Type Safety def process(x, y): with no types
4 Resource Cleanup f = open(...) without with
5 No Magic Numbers if retries > 3: → name it
6 No Dead Code Commented-out code, unused imports
7 Single Responsibility 50-line functions that do 3 things
8 Fail Fast Validating inputs on line 47
9 Idempotency Unsafe-to-retry operations
10 Performance Nested loops when unnecessary


🎬 Real-World Examples

Example 1: Using with Claude Code

Install the package and plugin, then start coding. ArbiterX scores all generated code automatically.

> pip install arbiterx-gate
> /plugin install NeelPrime/arbiterx

✓ ArbiterX installed. Engineering mode active.
✓ Quality gate will score all generated code.

> Build a REST endpoint to create users

Claude (with ArbiterX active):
from typing import Annotated
from fastapi import APIRouter, HTTPException, Depends
from pydantic import BaseModel, EmailStr

router = APIRouter()

class CreateUserRequest(BaseModel):
    name: str
    email: EmailStr

class UserResponse(BaseModel):
    id: int
    name: str
    email: str

@router.post("/users", response_model=UserResponse, status_code=201)
async def create_user(
    request: CreateUserRequest,
    db: Annotated[Database, Depends(get_db)],
) -> UserResponse:
    """Create a new user. Returns 409 if email already exists."""
    existing = await db.execute(
        "SELECT id FROM users WHERE email = ?", (request.email,)
    ).fetchone()
    if existing:
        raise HTTPException(status_code=409, detail="Email already registered")

    result = await db.execute(
        "INSERT INTO users (name, email) VALUES (?, ?) RETURNING id",
        (request.name, request.email),
    )
    user_id = result.fetchone()["id"]
    return UserResponse(id=user_id, name=request.name, email=request.email)

What ArbiterX enforced: Typed params ✓ | Parameterized SQL ✓ | Proper HTTP codes ✓ | No magic strings ✓ | Validation via Pydantic ✓ | Error case handled ✓


Example 2: Using with Codex CLI

> pip install arbiterx-gate
> codex plugin install NeelPrime/arbiterx
> codex

You: Write a file downloader with retry logic

Codex (with ArbiterX active):
from pathlib import Path
from typing import Optional
import httpx

MAX_RETRIES = 3
DOWNLOAD_TIMEOUT = 30
CHUNK_SIZE = 8192

class DownloadError(Exception):
    """Raised when a download fails after all retries."""

def download_file(
    url: str,
    destination: Path,
    retries: int = MAX_RETRIES,
) -> Path:
    """Download a file with retry logic. Returns the saved path."""
    if not url.startswith(("http://", "https://")):
        raise ValueError(f"Invalid URL scheme: {url}")

    last_error: Optional[Exception] = None

    for attempt in range(1, retries + 1):
        try:
            with httpx.stream("GET", url, timeout=DOWNLOAD_TIMEOUT) as response:
                response.raise_for_status()
                with open(destination, "wb") as out_file:
                    for chunk in response.iter_bytes(CHUNK_SIZE):
                        out_file.write(chunk)
            return destination
        except httpx.HTTPError as err:
            last_error = err
            if attempt == retries:
                break

    raise DownloadError(
        f"Failed after {retries} attempts: {last_error}"
    ) from last_error

What ArbiterX enforced: Named constants ✓ | Type hints ✓ | Input validation (fail fast) ✓ | Error handling with retries ✓ | Context manager for file ✓ | Custom exception ✓ | No bare except ✓


Example 3: Using with Cursor (Rules File)

Drop .cursor/rules/arbiterx.mdc into your project. Now every Cursor generation follows the rules.

You (in Cursor): Add caching to the database queries

Cursor (with ArbiterX rules):
from functools import lru_cache
from typing import Optional
from dataclasses import dataclass
from time import monotonic

CACHE_TTL_SECONDS = 300
MAX_CACHE_SIZE = 128

@dataclass(frozen=True)
class CacheEntry:
    value: object
    expires_at: float

class QueryCache:
    """Simple TTL cache for database query results."""

    def __init__(self, ttl: int = CACHE_TTL_SECONDS, max_size: int = MAX_CACHE_SIZE) -> None:
        self._store: dict[str, CacheEntry] = {}
        self._ttl = ttl
        self._max_size = max_size

    def get(self, key: str) -> Optional[object]:
        """Get a cached value. Returns None if missing or expired."""
        entry = self._store.get(key)
        if entry is None:
            return None
        if monotonic() > entry.expires_at:
            del self._store[key]
            return None
        return entry.value

    def set(self, key: str, value: object) -> None:
        """Store a value with TTL. Evicts oldest if at capacity."""
        if len(self._store) >= self._max_size:
            oldest_key = next(iter(self._store))
            del self._store[oldest_key]
        self._store[key] = CacheEntry(value=value, expires_at=monotonic() + self._ttl)

What ArbiterX enforced: Frozen dataclass (immutable) ✓ | Named constants ✓ | Typed everything ✓ | Docstrings ✓ | Single responsibility ✓ | No over-engineering (stdlib only) ✓


Example 4: Checking code with the Python API

from arbiterx.gate import QualityGate
from arbiterx.ladder.interrogator import SelfInterrogator

# Check any code snippet
gate = QualityGate()
enforcer = SelfInterrogator()

code = """
def send_email(to, subject, body):
    import smtplib
    server = smtplib.SMTP('smtp.gmail.com', 587)
    server.login('admin@company.com', 'password123')
    server.sendmail('admin@company.com', to, body)
"""

# Quality Gate
result = gate.validate(code, "python")
print(f"Score: {result.score}/100")  # 25/100
print(f"Passed: {result.passed}")    # False

for issue in result.issues:
    print(f"  ❌ [{issue.severity}] {issue.message}")

# Output:
#   ❌ [high] Hardcoded password detected
#   ❌ [medium] No error handling for network operation
#   ❌ [low] Single-letter variable names

The fix (what ArbiterX would guide the AI to write):

import smtplib
import os
from typing import Optional
from dataclasses import dataclass

SMTP_HOST = "smtp.gmail.com"
SMTP_PORT = 587

@dataclass(frozen=True)
class EmailConfig:
    host: str = SMTP_HOST
    port: int = SMTP_PORT
    username: str = ""
    password: str = ""

def send_email(
    recipient: str,
    subject: str,
    body: str,
    config: Optional[EmailConfig] = None,
) -> bool:
    """Send an email. Returns True on success, False on failure."""
    if config is None:
        config = EmailConfig(
            username=os.environ.get("SMTP_USER", ""),
            password=os.environ.get("SMTP_PASS", ""),
        )

    if not config.username or not config.password:
        raise ValueError("SMTP credentials not configured")

    try:
        with smtplib.SMTP(config.host, config.port) as server:
            server.starttls()
            server.login(config.username, config.password)
            server.sendmail(config.username, recipient, body)
        return True
    except smtplib.SMTPException as err:
        raise RuntimeError(f"Failed to send email: {err}") from err

Score: 100/100 ✓ — Secrets from env ✓ | Context manager ✓ | Error handling ✓ | Typed ✓ | Named constants ✓ | Input validation ✓


Example 5: Using the routing decision

$ arbiterx route "rename the getUserName function to getUsername"

  Task           rename the getUserName function to getUsername
  Type           REFACTORING
  Complexity     TRIVIAL
  Context Scope  FILE
  Latency        INTERACTIVE
  Est. Tokens    50
   Model:       haiku (cheapest  this is a trivial rename)

$ arbiterx route "redesign the authentication system to support OAuth2 and SAML"

  Task           redesign the authentication system to support OAuth2 and SAML
  Type           ARCHITECTURE
  Complexity     EXPERT
  Context Scope  REPO
  Latency        BATCH
  Est. Tokens    4000
   Model:       opus (needs deep reasoning across the whole repo)


🔌 Integrations

Plugin Install (recommended)

Tool Install
Claude Code pip install arbiterx-gate then /plugin install NeelPrime/arbiterx
Codex CLI pip install arbiterx-gate then codex plugin install NeelPrime/arbiterx

Why two steps? The plugin injects engineering rules. The pip package provides the quality gate that actively scores and rejects bad code.

Copy a File (prompt-only, no quality gate)

Tool File to Copy
Cursor .cursor/rules/arbiterx.mdc
Windsurf .windsurf/rules/arbiterx.md
GitHub Copilot .github/copilot-instructions.md
Aider AGENTS.md
Kiro .kiro/steering/arbiterx.md
Zed .zed/assistant/rules.md
Any tool AGENTS.md (universal)

As a Git Hook

pip install arbiterx-gate  # required
cp hooks/pre-commit .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
# Now rejects commits scoring below 70/100

📖 Full integration guide →



📈 Benchmarks

Tested on 10 real queries against its own codebase (46 files, 1364 symbols):

Query Naive (full files) ArbiterX (map) Saved
"How does TaskClassifier work?" 9,938 600 94%
"Fix bug in file hasher" 35,581 1,062 97%
"Add new adapter for Mistral" 14,263 643 95%
"How is PageRank used?" 45,300 1,034 97%
Total (10 queries) 196,247 5,639 97.1%


🧰 Supported Languages (22)

Language Status Language Status Language Status
Python TypeScript JavaScript
Go Rust Java
C / C++ C# Ruby
PHP Swift Kotlin
Scala Elixir Haskell
OCaml Lua Zig
Bash JSX TSX


🤝 LLM Providers

Provider Models Local?
Anthropic Claude Opus, Sonnet, Haiku No
OpenAI GPT-4o, o1, o3 No
Google Gemini 2.0 Pro/Flash No
Ollama Any model (Qwen, Llama, Mistral) Yes
OpenRouter All models (unified) No


💬 FAQ

Does it slow down my workflow?

No. Map builds in <1 second. Queries take 0.5ms. The quality gate runs regex — no LLM calls.

Does it work offline?

Yes. The map, router, and quality gate all run locally. Only the LLM adapters need internet (use Ollama for fully offline).

What if my code fails the gate?

You get a score and specific issues with suggested fixes. Fix them or lower the threshold in config.

Is it free?

Yes. Apache-2.0 license. Zero telemetry. Your code never leaves your machine.

How is this different from a linter?

Linters check syntax. ArbiterX enforces engineering decisions — YAGNI, proper abstractions, security patterns, and architectural discipline. It also handles context compression and model routing, which linters don't touch.



⭐ Why Developers Star This

  • Saves money — 97% fewer tokens = 97% lower API bills
  • Saves time — No more reviewing AI slop in PRs
  • Works everywhere — Claude Code, Codex, Cursor, Copilot, Aider + 5 more
  • Zero configpip install arbiterx-gate && arbiterx init and you're done
  • Runs locally — Your code never leaves your machine
  • Actually tested — 109 tests, benchmarked on real code, not vaporware
pip install arbiterx-gate && arbiterx init && arbiterx map

If it saves you from one bad AI-generated commit, ⭐ give it a star.



🔬 Built With

Component Technology Why
AST Parsing tree-sitter Fast, accurate, 22 grammars
Symbol Ranking PageRank (NetworkX) Surfaces what matters
Storage SQLite Zero-config, fast, portable
CLI Typer + Rich Beautiful terminal output
HTTP httpx (async) Modern, streaming-capable
Config TOML Human-readable


📄 License

Apache-2.0 — Use it anywhere. No strings attached.


Stop reviewing AI slop. Let ArbiterX be the gatekeeper.

Install NowRead the GuideIntegrationsArchitecture

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

arbiterx_gate-0.1.0.tar.gz (126.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

arbiterx_gate-0.1.0-py3-none-any.whl (84.8 kB view details)

Uploaded Python 3

File details

Details for the file arbiterx_gate-0.1.0.tar.gz.

File metadata

  • Download URL: arbiterx_gate-0.1.0.tar.gz
  • Upload date:
  • Size: 126.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for arbiterx_gate-0.1.0.tar.gz
Algorithm Hash digest
SHA256 06fbcbe99420e282993939548bf973b090d3b2036880d7cbbad33b0c7e3d32cb
MD5 eb62089af107295b21c99fbc5569f41f
BLAKE2b-256 3539883b220068b7b25610e187404b4438a764ef87471fdf16b22c5c632862b1

See more details on using hashes here.

Provenance

The following attestation bundles were made for arbiterx_gate-0.1.0.tar.gz:

Publisher: publish.yml on NeelPrime/arbiterx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file arbiterx_gate-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: arbiterx_gate-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 84.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for arbiterx_gate-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d11dfa1c5521637fc21fa36bc87fd199bd0847a5bde1eb5fa6d7bd0a4a42ad16
MD5 2d43213dd6e138aa4d9423c8eb0bcc9c
BLAKE2b-256 278bda1456d26592333f25d78cbba98711b9e03176bc31fca6094ac505f1a84a

See more details on using hashes here.

Provenance

The following attestation bundles were made for arbiterx_gate-0.1.0-py3-none-any.whl:

Publisher: publish.yml on NeelPrime/arbiterx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page