Engineering discipline for AI code generation — smart routing, 97% token reduction, unbreakable code by default
Project description
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.
Install • Quick Start • How It Works • Examples • Integrations • Full 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
↑ 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
📈 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 |
| 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 config —
pip install arbiterx-gate && arbiterx initand 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.
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 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
06fbcbe99420e282993939548bf973b090d3b2036880d7cbbad33b0c7e3d32cb
|
|
| MD5 |
eb62089af107295b21c99fbc5569f41f
|
|
| BLAKE2b-256 |
3539883b220068b7b25610e187404b4438a764ef87471fdf16b22c5c632862b1
|
Provenance
The following attestation bundles were made for arbiterx_gate-0.1.0.tar.gz:
Publisher:
publish.yml on NeelPrime/arbiterx
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
arbiterx_gate-0.1.0.tar.gz -
Subject digest:
06fbcbe99420e282993939548bf973b090d3b2036880d7cbbad33b0c7e3d32cb - Sigstore transparency entry: 2073179470
- Sigstore integration time:
-
Permalink:
NeelPrime/arbiterx@519174777ec57c6378d39a61d99b52c0a3417c11 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/NeelPrime
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@519174777ec57c6378d39a61d99b52c0a3417c11 -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d11dfa1c5521637fc21fa36bc87fd199bd0847a5bde1eb5fa6d7bd0a4a42ad16
|
|
| MD5 |
2d43213dd6e138aa4d9423c8eb0bcc9c
|
|
| BLAKE2b-256 |
278bda1456d26592333f25d78cbba98711b9e03176bc31fca6094ac505f1a84a
|
Provenance
The following attestation bundles were made for arbiterx_gate-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on NeelPrime/arbiterx
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
arbiterx_gate-0.1.0-py3-none-any.whl -
Subject digest:
d11dfa1c5521637fc21fa36bc87fd199bd0847a5bde1eb5fa6d7bd0a4a42ad16 - Sigstore transparency entry: 2073179492
- Sigstore integration time:
-
Permalink:
NeelPrime/arbiterx@519174777ec57c6378d39a61d99b52c0a3417c11 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/NeelPrime
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@519174777ec57c6378d39a61d99b52c0a3417c11 -
Trigger Event:
release
-
Statement type: