Skip to main content

Ask one question to multiple local AI coding CLIs in parallel and collect their answers.

Project description

moa - mixture of agents

CI

MOA - Mixture of Agents

Ask one question to multiple local AI coding CLIs in parallel and collect their answers. MOA detects which agent CLIs you have installed (Claude Code, Codex, agy, opencode), fans your prompt out to them, and streams each answer back the moment that agent finishes. Optionally, it can synthesize the answers into a single unified response.

It's a drop-in, batteries-included replacement for hand-rolling parallel claude -p / codex exec / opencode run calls (or a "peer review" agent skill): one command, clean attributed output, made to be called by a human or by another agent.

The package is named moa-cli but installs the command moa.

uv tool install moa-cli
moa ask "Is Postgres or SQLite better for a desktop app?"

Or run it once without installing:

uvx --from moa-cli moa ask "Review this plan."

Why

A single model gives you one perspective. Asking three frontier models the same question - and seeing where they agree, diverge, or contradict - is a fast, cheap way to pressure-test an answer. MOA makes that a one-liner using the CLIs you already pay for, with no API keys of its own.

Usage

moa doctor                                  # show which agent CLIs are installed
moa ask "Should this feature use SQLite?"   # ask the top 3 installed agents
moa ask -n 2 "..."                          # ask only the top 2 (priority order)
moa ask -p claude -p agy "..."              # pin specific agents
moa ask -x claude "..."                     # drop an agent (e.g. exclude the caller's own model)
moa ask -m claude=sonnet "..."              # override which model a tool uses
moa ask --synth "..."                       # also merge the answers into one
moa ask --json "..."                        # machine-readable JSONL (for agents/pipes)
git diff | moa ask -f - "Review this diff." # read the prompt from stdin

How agents are selected

-n/--num (default 3) picks the first N installed agents from a popularity-ordered priority list:

claude  ->  codex  ->  agy  ->  opencode

So moa ask -n 3 on a machine with all four installed asks Claude, Codex, and agy. Use -p/--provider (repeatable) to pin an exact set and ignore -n.

Use -x/--exclude (repeatable) to drop one or more agents from the run. Exclusion is applied before -n takes the first N, and it also drops excluded names from an explicit -p set. It is off by default. The motivating case: an agent (e.g. Claude Code) calls moa for other opinions; moa ask -x claude makes sure one "peer" isn't just the caller's own model. So moa ask -n 3 -x claude asks Codex, agy, and opencode.

Choosing models

Each tool ships with a reasonable default model, but you can override which model any tool uses with -m/--model PROVIDER=MODEL (repeatable). Only the providers you name change; the rest keep their defaults.

moa ask -m claude=sonnet -m agy="Gemini 3.1 Pro (Low)" "..."

The model-string format differs per tool and is passed through verbatim (the tool's own CLI validates it):

Provider Default -m format
claude opus short id, e.g. claude=sonnet
codex gpt-5.5 model id, e.g. codex=gpt-5.5
agy Gemini 3.1 Pro (High) exact display name, e.g. agy="Gemini 3.1 Pro (Low)"
opencode (tool's authed default) provider/model slug, e.g. opencode=anthropic/claude-sonnet-4

opencode has no built-in default; without an override it omits -m and lets opencode pick. Pass -m opencode=provider/model to pin one.

Output

  • stdout carries only content: each agent's answer as a Markdown block (## claude (opus) - OK - 3.5s), flushed the instant that agent finishes, then the synthesis block if --synth is set.
  • stderr carries progress and selection notes (Asking claude, codex ...), so piping stdout stays clean.
  • --json emits one JSON object per line (JSONL): a {"type": "response", ...} record per agent as it completes, then a {"type": "synthesis", ...} record. Ideal when another agent calls MOA and parses the result.

Synthesis

--synth runs one more pass that merges the collected answers into a single, unified answer. The synthesizer is chosen with --synthesizer:

  • auto (default) - the highest-priority agent that ran (deterministic)
  • random - pick one of the agents that ran, at random
  • a provider name (claude, codex, agy, opencode)

Attribution policy

The human (or agent) reading MOA's output always gets correct attribution: every response block shows the real provider name. There is no human-facing anonymization toggle.

The synthesizer is a different story. To stop it picking favourites by brand, it always receives the proposer answers anonymized as "Response A / B / C" and order-shuffled. This is always-on internal behaviour, not a flag. The synthesized answer itself is brand-agnostic prose, and the A/B/C labels never leak into stdout, stderr, or the JSON.

Supported agents

Provider CLI Invocation
claude claude claude --model opus -p PROMPT
codex codex codex exec -m gpt-5.5 --skip-git-repo-check PROMPT
agy agy agy --model "Gemini 3.1 Pro (High)" -p PROMPT
opencode opencode opencode run PROMPT

Adding a new agent is a single entry in the PROVIDERS table in src/moa_cli/cli.py (executable, default model, command builder); it then participates in detection, -n selection, and synthesis automatically.

Development

uv sync
uv run pytest
uv run ruff check src tests

MIT licensed.

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

moa_cli-0.1.0.tar.gz (9.9 kB view details)

Uploaded Source

Built Distribution

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

moa_cli-0.1.0-py3-none-any.whl (11.0 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for moa_cli-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c7d7ff5f580ecae9b7eae4e87fa406af2e366e53e8929d0bdf8e1ae80555696a
MD5 5471e6f074e6a2fa9ed225a3528607a4
BLAKE2b-256 326a28e0ea587b8cce4f7fa50f11631dab4d46d833920a7743b29f5654dc9d17

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for moa_cli-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c3f99990698fe6ed274838dd7b23f4b16dd88a40d1a7f8153174364915e8c0af
MD5 3134520a1b10fd29d3d078cb01da17a1
BLAKE2b-256 67ce3c5e292b9b5503b716ecdf0f8332f8f9099a7e3c956de6c67a95eefcf454

See more details on using hashes here.

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