🔄 Synced from the AI-Factory monorepo (append-only history). Pull requests are welcome — merged PRs are imported back and re-synced here. Issues · Pull requests
Metis (μῆτις) — distributed cognitive layer over any LLM
Part of the alexar76 AI agent economy
Grab the star · watch it pulse and think · chat with Metis — open the live demo →
Multi-agent reasoning orchestrator — Understanding Council, DGPD depth gating, layered MoA, verifier, memory, search, economy metering, distributed cluster, MCP tools, and OpenAI-compatible API.
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev,distributed]"
ollama pull qwen3:8b
metis "Explain multi-agent systems" --model qwen3:8b --url http://localhost:11434/v1PyPI package name is aimarket-metis (the PyPI name metis is a different project). Import path and CLI stay metis, metis-serve, etc.
# PyPI
pip install aimarket-metis
pip install "aimarket-metis[dev,distributed]"
# GitHub release tag
pip install "aimarket-metis[distributed] @ git+https://github.com/alexar76/[email protected]"
# Clone / monorepo (editable)
git clone https://github.com/alexar76/metis.git && cd metis
pip install -e ".[dev,distributed]"
# Docker
docker compose up -d| Resource | Link |
|---|---|
| Architecture | EN · RU · ES |
| API reference | EN · RU · ES |
| Deployment | EN · RU · ES |
| Security | EN · RU · ES |
| User guide | EN · RU · ES |
| Distributed | EN · RU · ES |
| Ecosystem | EN · RU · ES |
| Research | EN · RU · ES |
| Wiki | Home · Quick Start · FAQ |
| Landing page | Live demo · docs/landing/index.html · deploy guide |
| Changelog | CHANGELOG.md · RELEASE.md |
| Project | Role |
|---|---|
| Metis | Cognitive orchestration layer (this repo) |
| cognitive-runtime | OpenAI API wrapper with DGPD |
| ARGUS-3 | Demand-side reference agent + WARDEN MCP firewall |
| AIMarket Hub | Federated capability catalog and invoke API |
| aimarket-oracle-gateway | Verifiable oracle MCP services |
| aimarket-mcp | Shared MCP gateway — web fetch/search + Metis verify (Glama) |
| Ecosystem landing | Full AICOM map — Metis, MCP servers, oracles, ARGUS |
| HELIOS | Broadcast pipeline for ecosystem content |
| AICOM | AI-Factory — autonomous product pipeline |
| Command | Purpose |
|---|---|
metis |
Run a query through the cognitive stack |
metis-serve |
OpenAI-compatible API (/v1/chat/completions) |
metis-node |
Start a distributed worker node |
metis-coordinator |
Start the cluster coordinator |
metis-cluster |
Check cluster node health |
flowchart LR
Q["Query"] --> M["Metis"]
M --> R["Router"]
R --> C["Council/MoA/Agent"]
C --> P["LLM Providers"]
C --> T["Tools + MCP"]
M --> E["Economy Meter"]
By default a /v1/verify verdict is written by one model and audited by one model — the
base model on fast, the MoA aggregator on council. That is the verdict the AIMarket
hub's Pay-on-Verified escrow moves money on,
so a seller only has to fool one lineage. A jury makes it a vote across vendors:
jury_default_for_verify: true # every /v1/verify goes to the jury; off → only route: "jury"
jury_min_vendors: 3 # and every seat must be a different vendor
jury_models:
- {model: deepseek-v4-pro, base_url: https://api.deepseek.com/v1, api_key_env: DEEPSEEK_API_KEY}
- {model: minimax/minimax-m3, base_url: https://openrouter.ai/api/v1, api_key_env: OPENROUTER_API_KEY}
- {model: z-ai/glm-5.3, base_url: https://openrouter.ai/api/v1, api_key_env: OPENROUTER_API_KEY}Ready rosters for both courts are in deploy/prod.jury.example.yaml.
What the jury does, and what it promises:
- The caller's prompt goes to every juror unchanged, in parallel, at
jury_temperature(0.1). A juror slower thanjury_timeout_secondsabstains; it does not hold the jury. - A juror's vote counts only if it states
{"fulfils": bool, "score": 0–1}consistently at the caller's bar and — when the request carriesaudit_id— echoes that id. A juror that parroted a verdict planted in the audited text has not voted. - A side wins with a strict majority of the whole roster; abstentions count against
agreement.
verify_score= agreement × median confidence of the winning side (confidence in "fulfils" = score, in "does not fulfil" = 1 − score), so a confident unanimous conviction is a trusted audit. answeris one winning juror's verdict object on its own, so a consumer's parser reads it unchanged. A split carries no verdict object (indeterminate); every seat failing isstatus: "error"(retry), never a verdict.- The envelope adds
jury([{model, vendor, fulfils, score, latency_ms, abstained?}]),jury_outcome(pass|fail|split|unavailable),jury_agreementandinput_flags.injection_suspected. The trace resolves at/v1/traces/{trace_id}. - Injection-looking text is flagged, not blocked on this path: the audited text is written by the parties with money on the verdict, and a hard block would hand either of them an indeterminate outcome on demand.
Know the arithmetic before sizing a roster: at the hub's 0.7 bar a 3-seat jury settles only when unanimous (2/3 × anything < 0.7); five seats tolerate one confident dissent; an even roster only adds splits. The jurors are independent labs, not independent infrastructure — seats behind one gateway share its outages and its account.
The same change stops the capability gate from seating one model as both the writer and
the auditor of a verdict: with judge_distinct_vendor: true (default) the judge avoids the
vendors of the base model and the MoA aggregator, an explicit modules.judge that clears
min_aggregator_capability is honoured instead of silently overridden, and
min_unique_council_vendors extends the diversity check from (model, endpoint) pairs to
vendors, for the MoA seats as well as the council. metis validate warns when the judge
still shares a vendor with a writer.
The hub's appeal path (AIMARKET_APPEAL_WINDOW_S) re-judges a disputed verdict on a
second, independent Metis. Independence is operational, so it has to be set up that way:
- Another host. Not the first instance's machine (shared failure, shared operator access) and not a host holding a hot wallet. Same image, its own container.
- A disjoint jury. The
metis_2roster indeploy/prod.jury.example.yamlshares no vendor withmetis_1(a test enforces it). Use a second OpenRouter key with its own spend cap — vendor-disjoint seats behind one key still share that key's quota. - Its own identity. Its own
METIS_API_KEY(setting it makes/v1/verifyrequire the Bearer), handed to the hub asAIMARKET_APPEAL_METIS_KEY; its ownAIMARKET_APPEAL_METIS_URL; and a distinctAIMARKET_APPEAL_VERIFIER_ID(e.g.metis.appeal@v1) so every envelope and receipt names which court decided. - Nothing from the first instance. It gets the stored intent and delivery, a fresh audit id and the appellant's fenced statement — never the first verdict, its score, its reasons or its trace. Do not point it at the first instance's trace store or knowledge store.
docker run -d --name metis-appeal --restart unless-stopped -p 127.0.0.1:8081:8080 \
-e METIS_API_KEY=<appeal-court key> -e OPENROUTER_API_KEY=<second, capped key> \
-v /opt/metis-appeal/prod.yaml:/app/config/prod.yaml:ro -v /opt/metis-appeal/data:/app/data \
metis:latest metis-serve --host 0.0.0.0 --port 8080 --config /app/config/prod.yamlexport METIS_API_KEY=sk-...
metis-serve --config config.production.yaml --production --port 8080Protected HTTP routes require a configured bearer key by default, including requests from loopback. For trusted private development only, METIS_LOCAL_RELAY=1 explicitly permits keyless local TCP callers, including same-user proxies and tunnels. Peer/Host, browser Origin, forwarding-header and socket-owner checks still apply. Where Linux socket tables are absent (macOS/Windows), METIS_LOCAL_UNVERIFIED=1 is also required. Both settings default off and cannot bypass a configured key or production mode. Set METIS_API_KEY for the API and coordinator. For a worker, set the environment variable named by api_key_env in its node config.
Legacy env vars SUPERBRAIN_* and COGNITIVE_* are still read for one release cycle.
cp config/docker.env.example .env
docker compose up -d --buildpytest --cov=metis --cov-report=term-missing -vDesign decisions are grounded in published work — see docs/en/RESEARCH.md for Yang et al. 2026 (heterogeneous agents), Wang et al. ICLR 2025 (layered MoA), and related citations with honest caveats.
MIT License