Dispatch prompts to external AI models from your coding session as separate
reviewer processes. Their repository exploration and tool traces stay out of
your primary agent's context; Rival returns the final review. The default
/rival-review runs Sol and DeepSeek V4 Pro in parallel and merges their
findings with a consilium judge. Use -m/--model to run an exact subset or add
Kimi K3 as an opt-in reviewer.
Rival is an orchestration layer for independent AI review, not another model. One coding agent tends to preserve its own assumptions when reviewing its work; Rival asks different models, with complementary roles, to inspect the actual repository and then turns their overlap and disagreements into one verdict.
- Catch different blind spots: correctness, architecture/security, and code quality reviewers explore the codebase instead of seeing only a pasted diff.
- Get one usable answer: a consilium pass merges duplicates, attributes agreement, filters weak findings, and reports skipped or failed reviewers.
- Keep long work out of the way: reviews run detached with queue and timeout controls, while terminal and web dashboards retain progress and bounded logs.
- Use only the providers you have: select one model or an exact subset; the review can continue when another selected provider is unavailable.
brew install 1F47E/tap/rival
rival installcd rival && make install
rival installNote: run
make installfrom the repository'srival/subdirectory. It writes toGOBINor$(go env GOPATH)/bin; make sure that directory appears before any older Rival installation inPATH. Remotego install github.com/1F47E/rival@latestis not supported because the Go module lives in a repository subdirectory.
rival install copies the slash-command skills (embedded in the binary) into ~/.claude/skills/. After that, /rival-review, /rival-sol, /rival-plan, /rival-plan-sol, /rival-plan-fable, /rival-fable, and /rival-k3 are available. Install also removes superseded skill names.
Use rival install --force to overwrite without prompting.
For a Homebrew installation, this upgrades the binary and then refreshes the embedded skills:
rival update
# equivalent: brew upgrade 1F47E/tap/rival && rival install --forceSource installs update with git pull, make install from rival/, and
rival install --force. Rival performs a cached GitHub release check at
startup; set RIVAL_NO_UPDATE_CHECK=1 to disable it.
- Codex CLI, authenticated with ChatGPT (recommended) or an OpenAI API key, provides Sol.
- OpenCode plus an
OpenCode Zen key in
RIVAL_OPENCODE_API_KEYprovides DeepSeek V4 Pro. - OpenCode plus a
Kimi API key in
MOONSHOT_API_KEYprovides opt-in Kimi K3. - Opus/Fable runtime: install + authenticate (or use Docker — see below), then use
/rival-plan,/rival-plan-fable, or/rival-fable
You only need the runtimes for the models you use. The default review uses two
curated models — any unavailable selection is skipped, and the run proceeds
when at least one succeeds. Put RIVAL_OPENCODE_API_KEY in the environment file
loaded by non-interactive shells (for example ~/.zshenv for zsh).
Rival is installed into Claude Code as slash-command skills, but those skills delegate to local model CLIs. This is the shortest clean setup.
-
Install Rival and its skills:
brew install 1F47E/tap/rival rival install
-
Install Codex for Sol:
npm install -g @openai/codex codex login codex login status
Browser-based ChatGPT login is preferred: it uses your eligible ChatGPT plan and does not put an API key in the project or Rival config. If you intentionally prefer usage-based API billing, create a key in the OpenAI dashboard, then let Codex store that authentication:
export OPENAI_API_KEY='your-key' printenv OPENAI_API_KEY | codex login --with-api-key unset OPENAI_API_KEY codex login status
Rival supports both Codex login methods. Do not put the OpenAI key in the reviewed repository; Rival only needs the resulting Codex login.
-
Install OpenCode for DeepSeek and K3:
curl -fsSL https://opencode.ai/install | bash # macOS alternative: brew install anomalyco/tap/opencode
-
For the default DeepSeek reviewer, create a key at OpenCode Zen and expose it to non-interactive shells:
# ~/.zshenv (zsh example) export RIVAL_OPENCODE_API_KEY='your-zen-key'
-
For Kimi K3, create a key in the Kimi API console. Put it in the project
.envso Rival can find it when Claude Code runs from any subdirectory:MOONSHOT_API_KEY=your-kimi-api-key
Add
.envto.gitignoreand never commit it. ExportingMOONSHOT_API_KEYfrom your shell is also supported. Rival injects the key into OpenCode's built-inmoonshotai/kimi-k3provider at runtime, so no custom OpenCode provider config is required.
Run rival install --force after every Rival upgrade, then restart or reload
Claude Code so it discovers the refreshed skills.
Default review (runs Sol + DeepSeek V4 Pro):
/rival-review — both default models; auto-detect changed files
/rival-review -m sol src/api/ — Sol only
/rival-review -m deepseek src/api/ — DeepSeek V4 Pro only
/rival-review -m k3 src/api/ — Kimi K3 only (requires MOONSHOT_API_KEY)
/rival-review -m deepseek,k3 src/api/ — exactly those two models
/rival-review -re ultra src/api/ — override compatible model defaults
Single-model skills (use only when you want one specific model):
/rival-sol explain the auth flow in this project
/rival-sol -re ultra find bugs in src/main.go
/rival-sol review — review (auto-detects changed files via git)
/rival-sol review src/api/ — review specific scope
Code review via Fable (built-in medium default, configurable):
/rival-fable — review changed files with Fable (auto-detects via git)
/rival-fable src/api/ — review a specific scope
Kimi K3 (thinking-only model, always max reasoning, via opencode's Moonshot provider):
/rival-k3 explain the auth flow in this project
/rival-k3 review — review changed files with Kimi K3 (auto-detects via git)
/rival-k3 review src/api/ — review a specific scope
reviewruns under the same mechanical read-only sandbox as the megareview reviewers. Raw prompts run full auto — the agent can edit files and run commands in the workdir (native file tools are denied outside it); rival strips known credential env vars (OPENAI_API_KEY,ANTHROPIC_API_KEY, the wholeAWS_*family, tokens, …) from that child as blast-radius reduction. Not containment: bash runs as you.
Plan/spec review (single path to a markdown plan, rated 1-10):
/rival-plan path/to/plan.md — review with Sol + Fable at ultra effort
/rival-plan-sol path/to/plan.md — rate the plan 1-10 with Sol at ultra effort
/rival-plan-fable path/to/plan.md — same, with Fable (low fallback unless configured)
Each model rates the plan 1-10 and returns numbered findings. /rival-plan runs
Sol and Fable in parallel at ultra and shows both results.
/rival-plan-sol also always uses ultra. /rival-plan-fable uses the
configured Fable effort when present, otherwise its low fallback. The native
binary accepts an explicit override, for example
rival command plan --model sol --effort ultra.
Model selection (-m, --model): sol, deepseek, and k3 (Kimi K3,
needs MOONSHOT_API_KEY); comma-separated or repeated. An explicit list
replaces the complete roster. Reasoning effort (-re): low, medium,
high, or ultra. When omitted, each model uses its own configured default.
Set defaults by stable model label in ~/.rival/config.yaml:
efforts:
sol: high
deepseek-v4-pro: high
kimi-k3: max
opus: xhigh
fable: mediumAn explicit --effort or -re wins for every compatible selected model.
Otherwise Rival uses the configured model value, then that command's built-in
fallback. Kimi K3 is fixed at max, the only reasoning level its provider
supports. The paired plan skills deliberately request ultra; an explicit
skill choice therefore still wins over this file. When a grouped run uses
different per-model efforts, the dashboard summary shows mixed and each
member detail shows its actual effort.
Invalid model names or effort values fail before Rival creates sessions or touches the queue, with the config path and accepted values in the error.
The curated /rival-review reviewers and /rival-k3 review mode get
mechanically read-only access to your project. They don't just see a diff:
they run as separate agents inside your workdir with safe exploration tools
enabled, so they can:
- Read any file in the project
- Follow imports and trace dependencies
- Explore the full codebase to understand context
- Search, list, and inspect project files without modifying them; Sol can also run read-only inspection commands
Smart scope detection. Running /rival-review with no arguments auto-detects what to review via git:
- Dirty files (staged + unstaged + untracked new files) → reviews those files
- Last commit (if working tree is clean) → reviews files from HEAD
- Full project → only if not a git repo or no changes found
The scope is a focus hint, not a restriction. review src/api/ tells the reviewer to focus on src/api/, but it can (and will) read other files to understand the code in context. Explicit scope bypasses git detection entirely.
This means you can use natural language for the scope:
/rival-sol review the files changed in the last commit
/rival-sol review the authentication middleware
/rival-review -m deepseek -re ultra the new payment flow in src/billing/
The reviewer will figure out what to look at, explore the relevant code, and give you a review with full project understanding.
Megareview assigns specialized roles to each reviewer:
- Sol → Bug Hunter — an independent correctness pass and the first default consilium-judge candidate.
- DeepSeek V4 Pro → Bug Hunter — the primary correctness reviewer for concrete code-level defects, broken state transitions, races, and missing edge cases.
- Kimi K3 → Bug Hunter (opt-in) — adds a Moonshot-backed correctness pass
when selected with
-m k3; it is not part of the default two-model roster.
DeepSeek V4 Pro uses the OpenCode Zen credential and quota. Kimi K3 uses the
separate MOONSHOT_API_KEY credential and Moonshot quota. Rival skips failed
reviewers and proceeds when at least one remains.
All reviewers emit structured JSON with file, line, severity, category, confidence (1-10), and fix suggestions.
If a reviewer hits a provider quota/rate limit, Rival detects it from the captured log and reports that concrete model as skipped with a reason, rather than silently counting it as a clean empty review.
Role prompts can be customized via ~/.rival/config.yaml:
roles:
bug_hunter: |
Your custom bug hunter instructions...
code_quality: |
Your custom code quality instructions...A separate consilium pass runs with the highest-priority selected model that successfully reviewed (default priority: Sol → DeepSeek V4 Pro), then:
- Merges duplicate findings (same file + line + problem → single finding with all reporters in
found_by) - Applies consensus bonus (+2 confidence for findings reported by 2+ reviewers)
- Filters by confidence threshold (default: ≥6)
- Sorts by severity (critical first), then confidence
- Produces a unified verdict:
approve,request_changes, orcomment
═══ RIVAL REVIEW ═══
Summary: ...
[CRITICAL] file.go:42 — Title
Description...
Fix: ...
Found by: sol, deepseek-v4-pro
[HIGH] file.go:100 — Title
...
Recommendation: request_changes — ...
Reviewed by: sol (bug_hunter), deepseek-v4-pro (bug_hunter)
Judge: sol (consilium)
Findings: 5 (threshold: 6)
For an explicit multi-model selection, requested order controls judge priority. A single-model review uses that same model for the review and consilium phases. If a reviewer fails to produce structured JSON, the consilium receives a stub with a 2KB debug tail instead of the full raw output (prevents prompt overflow).
# Run Sol with a prompt from stdin
echo 'explain the auth flow' | rival run sol --prompt-stdin --workdir .
echo 'explain the auth flow' | rival run k3 --prompt-stdin --workdir . # needs MOONSHOT_API_KEY
# Review via the default two-model roster
rival review src/api/
# Exact one-model reviews
rival review --model sol src/api/
rival review --model deepseek src/api/
rival run k3 --review src/api/ --workdir .
# Rate a plan/spec doc 1-10 (Sol + Fable by default, high effort)
echo 'docs/plan.md' | rival command plan --workdir .
echo 'docs/plan.md' | rival command plan --model sol --effort ultra --workdir .
echo 'docs/plan.md' | rival command plan --model fable --effort low --workdir .Monitor running and past sessions in a full-screen terminal UI:
rival tuiList view shows all sessions with status, concrete model, effort, elapsed time, workdir, and prompt preview. Multi-session runs are grouped into one row: the megareview glyph repeats per selected reviewer (❯ mega through ❯❯❯❯ mega). Plan reviews (/rival-plan, /rival-plan-sol, /rival-plan-fable) show ▤ plan.
Detail view shows full metadata, prompt, and live-streaming log output.
Group titles and metadata are derived from the sessions: a default megareview
lists sol+deepseek-v4-pro, while an explicit subset shows only its selected
models. A dual plan group lists sol+fable. All member logs and model-specific
failures are shown; o opens one combined public log for a grouped run.
| Key | List View | Detail View |
|---|---|---|
j/k or ↑/↓ |
Navigate sessions | — |
Enter |
Open detail view | — |
Esc |
— | Back to list |
g / G |
Jump to top / bottom | — |
p |
— | Toggle full prompt |
o |
— | Open log (all logs for a group) |
x |
— | Kill running or queued session |
q |
Quit | Quit |
rival server --port 3333The server binds to 127.0.0.1 only. If the requested port is occupied, Rival
tries the next ten ports and prints the selected local URL.
The self-contained browser dashboard uses the same stable grouping and requested model order as the TUI. The newest 100 grouped runs load first, with pagination for older history. A fixed detail drawer shows prompt metadata, per-member status, queue position, duration, exit code, errors, and a bounded live log tail. Details remain usable for queued, running, completed, failed, grouped, empty-log, and missing-log sessions, including direct links to older runs. Each member log response is limited to the newest 256 KiB.
rival sessions # all sessions as a text table
rival sessions --recent 20 # newest 20
rival sessions --active # running sessions only
rival version # show versionMultiple coding-agent sessions (or terminals) invoke rival as independent
processes. Without coordination they launch their provider CLIs at once and hit
rate limits. rival coordinates them through a cross-process FIFO queue — by
default two reviews run at a time; the rest wait their turn. Set
RIVAL_MAX_CONCURRENT=1 for strict serialization on quota-constrained accounts.
- Each waiting review prints its position to stderr while it waits:
rival queue: position 2/3 (1 running), waiting 1m12s. Skills relay this to you. - Queued sessions show up in the TUI and web dashboard with a
◌ queued #Nrow and a growing wait time, alongside a queued counter. - No daemon: coordination is via ticket files in
~/.rival/queue/guarded by a file lock (flock). A crashed holder is reaped automatically (its slot frees when both the rival process and any surviving provider CLI child are gone).
rival queue # list tickets (position, state, mode, wait, workdir)
rival queue clear # remove dead tickets
rival queue clear --force # remove ALL tickets (live waiters re-queue at the tail)Config (env vars):
| Var | Default | Effect |
|---|---|---|
RIVAL_MAX_CONCURRENT |
2 |
How many reviews may run at once |
RIVAL_QUEUE_TIMEOUT |
30m |
Max wait for a slot before the review fails |
RIVAL_RUN_TIMEOUT |
30m |
Max run time once a slot is held; kills a hung provider CLI (0 disables) |
RIVAL_NO_QUEUE |
unset | Set to bypass the queue entirely |
RIVAL_RUN_TIMEOUT is a per-provider-phase baseline. A megareview receives
twice that budget for its two sequential phases (parallel reviewers, then the
consilium judge); a plan or standalone run receives one baseline.
Provider-invoking review, run, and command subcommands also accept
--no-queue to skip the queue for that invocation.
--detach — rival command … re-execs itself into its own process session
(setsid), prints rival: detached pid=N to stderr, and the parent exits
immediately. The launching shell returns at once and the run survives the
caller's teardown (the host may kill a skill's shells with a process-group kill
when it ends, which used to SIGTERM a running or queued review).
rival wait — blocks until a run reaches a terminal state. Skills arm it as
a background watcher; it's also usable from scripts/CI:
rival wait --log <stderr-file> # parse detached pid + session IDs, wait, summarize
rival wait <session-id>... # terminal-status-only mode
# exit: 0 completed · 2 failed · 3 rival crashed · 4 timed outBounded by default: a run is bounded by RIVAL_RUN_TIMEOUT; rival wait
detects a crashed rival (process dead, sessions unfinalized) and has its own
--timeout. The skills launch detached, watch in the background, and do not
block your session. Setting RIVAL_RUN_TIMEOUT=0 intentionally disables the run
bound.
NFS note: the queue relies on
flock, which is unreliable over NFS-mounted home directories. On such hosts setRIVAL_NO_QUEUE=1.
Host coding session
│
│ /rival-review
▼
Slash-command skill (async — does not block the session)
│ 1. prompt tempfile → rival command megareview --detach --workdir $(pwd)
│ (parent prints "rival: detached pid=N" and exits in seconds)
│ 2. arm background watcher: rival wait --log <err>
│ 3. hand back to the session and END the turn
▼
rival binary (own process session — survives the skill/fork teardown)
├─ parses model selection (-m), effort (-re), and review scope
├─ builds review prompt with scope injection
├─ waits for a queue slot, then bounds the run by RIVAL_RUN_TIMEOUT
├─ spawns the selected models in separate subprocesses
├─ pipes prompt to stdin, tees stdout to log file
└─ writes session JSON + live log to ~/.rival/sessions/
│
▼ (rival exits → background `rival wait` exits → harness wakes session)
The host reads the output file and presents the review verbatim
Megareview (roles + consilium):
rival binary
├─ generates shared GroupID (UUID)
├─ assigns the bug_hunter role to Sol, DeepSeek, and opt-in Kimi K3
├─ spawns the exact selected roster concurrently with role-specific prompts
├─ skips any reviewer that hits a provider quota/rate limit (429)
├─ parses structured JSON output from each reviewer
├─ runs the highest-priority successful selected model as consilium judge
│ ├─ merges duplicates, applies consensus bonus
│ ├─ filters by confidence threshold (≥6)
│ └─ produces unified verdict with found_by attribution
├─ prints formatted review to stdout
└─ TUI and web dashboards group all sessions by GroupID
Second terminal:
rival tui
├─ watches ~/.rival/sessions/ via fsnotify (.json + .log)
├─ groups sessions by GroupID for megareview display
├─ live-refreshes every second while sessions are running
└─ x key sends SIGTERM to kill stuck sessions
- Full project access: reviewers run as AI CLI tools with tool use — they explore your codebase, not just diffs
- Async, non-blocking: skills launch rival detached and watch it in the background — your session is never blocked for the run, and a hung run can never hang the session (
RIVAL_RUN_TIMEOUT+rival waitcrash/timeout detection) - Safe stdin piping: skills create input files with the host Write tool (never echo/printf/heredoc), then redirect them to Rival's stdin
- Env filtering: child processes get a sanitized environment (blocks proxy/preload vars from .env)
- Fault tolerant: megareview continues if one CLI fails, reports the error inline
- Consilium overflow protection: reviewer outputs that fail JSON parsing are replaced with a stub + 2KB debug tail, preventing oversized judge prompts
The Opus/Fable runtime auto-detects its execution mode:
- Native (default): uses the authenticated host runtime. No extra config needed.
- Docker: otherwise runs inside a container with a separate subscription.
Native Opus/Fable runs bill your CLI subscription login (Pro/Max)
by default. An ANTHROPIC_API_KEY exported in your shell is stripped from
the child environment — without this, the claude CLI silently prefers the env
key and bills API credits even though you're logged in with a subscription.
RIVAL_CLAUDE_AUTH |
Behavior |
|---|---|
unset / subscription / sub |
Use the CLI's /login auth; ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN are stripped from the subprocess env |
api |
Bill the API key; requires ANTHROPIC_API_KEY to be set, hard error if empty |
| anything else | Hard error — auth is never guessed |
The active mode is logged per run (auth=subscription) and shown in the TUI
detail view (Account field). If a run fails on auth/billing, rival appends an
actionable hint: not logged in → run claude and /login; api mode → check
the key and its credit balance.
See the full Opus/Fable Docker setup for architecture and troubleshooting details.
-
Build the image (auto-builds on first run, or manually):
docker build -t rival-opus-fable -f - . <<'EOF' FROM node:22-slim RUN npm install -g @anthropic-ai/claude-code && \ useradd -m -s /bin/bash claude USER claude WORKDIR /workspace ENTRYPOINT ["claude"] EOF
-
Authenticate via interactive login in a temp container:
docker run -d --name rival-opus-fable-login --user claude --entrypoint sh rival-opus-fable -c 'sleep 3600' docker exec -it rival-opus-fable-login claude login # Opens auth URL → authorize in browser → paste localhost redirect back docker exec rival-opus-fable-login cat /home/claude/.claude/.credentials.json # Copy the accessToken value (starts with sk-ant-oat01-...) docker rm -f rival-opus-fable-login
-
Export the token:
export RIVAL_CLAUDE_TOKEN=sk-ant-oat01-YOUR-TOKEN-HERE -
Optionally set subscription type in
~/.rival/config.yaml:claude: subscription: team # or "personal" — shown in TUI
- OAuth tokens expire — re-run the login flow if you get 401 errors
- The Docker image runs as non-root user
claude(required by the runtime) - Your workdir is mounted as
/workspaceinside the container - To rebuild:
docker rmi rival-opus-fable, next run rebuilds automatically - TUI shows
⬡ opus/dkfor Docker sessions and⬡ opusfor native
| Model | Default Effort | Used by |
|---|---|---|
| Sol | high; ultra is explicit in plan skills | /rival-review, /rival-sol, /rival-plan, /rival-plan-sol |
deepseek-v4-pro |
high; ultra maps to max |
/rival-review |
| Opus | xhigh | standalone binary command |
| Fable | medium for code review; plan commands have surface-specific fallbacks | /rival-fable, /rival-plan, /rival-plan-fable |
kimi-k3 |
max (only level the model supports) | /rival-k3, /rival-review -m k3 |
These are built-in fallbacks. The efforts map in ~/.rival/config.yaml
overrides any omitted model effort; an explicit command or skill effort wins.
rm -rf ~/.claude/skills/rival-*
brew uninstall rival # if installed via brew
# source install:
RIVAL_BIN_DIR="$(go env GOBIN)"
[ -n "$RIVAL_BIN_DIR" ] || RIVAL_BIN_DIR="$(go env GOPATH)/bin"
rm "$RIVAL_BIN_DIR/rival"MIT
