Skip to main content
Glama
README.md
# Vecta Council

**Stop asking one model. Convene a council.** *(beta)*

Fan one prompt out to several models in parallel, then let a synthesizer fold their
drafts into a single, stronger answer. One command, one MCP tool — BYOK, and it runs
against **any** OpenAI-compatible endpoint.

[![npm](https://img.shields.io/npm/v/@openvecta/council.svg)](https://www.npmjs.com/package/@openvecta/council)
[![downloads](https://img.shields.io/npm/dm/@openvecta/council.svg)](https://www.npmjs.com/package/@openvecta/council)
[![license](https://img.shields.io/npm/l/@openvecta/council.svg)](./LICENSE)
![node](https://img.shields.io/badge/node-%3E%3D18-brightgreen)
![MCP](https://img.shields.io/badge/MCP-stdio-blue)

One model gives you one perspective — and one model's blind spots. A council gives you
disagreement you can actually see, and an answer that survived it.

<!-- demo.gif — a CLI run: several labeled drafts collapsing into one synthesis. -->

---

## Try it in 30 seconds (no config, no restart)

If you already have an `OPENAI_API_KEY` in your environment, that's the whole setup:

```bash
export OPENAI_API_KEY=sk-...            # the key you already use
npx @openvecta/council "Postgres vs. DynamoDB for a write-heavy event log — case each way, then a recommendation."
```

It prints the synthesized answer to your terminal (add `--drafts` to see each model's
draft first). Point it at a different provider with one more variable:

```bash
export OPENAI_BASE_URL=https://openrouter.ai/api/v1   # or http://localhost:11434/v1 for Ollama
```

Off OpenVecta you must name the panel (the default ids are OpenVecta's) — see below.
And every single-provider run comes with an honest nudge: you're running a
single-vendor council; for a **true cross-lab panel**, point `OPENAI_BASE_URL` at
OpenVecta. Here's why that matters.

---

## Why a cross-lab council beats one model

Sampling the *same* model N times gives you N variations of the same training, the same
priors, the same blind spots. Its mistakes are correlated — ask it twice and it's
confidently wrong the same way both times.

Models from **different labs** are trained on different data with different objectives, so
their errors are *less* correlated. Put them on a panel and:

- **Disagreement becomes visible.** Where the drafts diverge is exactly where a single
  model would have hidden its uncertainty behind a confident tone.
- **Synthesis beats voting.** The synthesizer reads every draft, keeps the strongest
  reasoning from each, and repairs the weak spots — instead of picking a majority.
- **No single vendor can assemble the panel.** OpenAI's API can't call Anthropic to
  cross-check itself. A cross-lab council is orchestration *across* providers.

We don't ship a marketing win-rate, and we won't pretend to. We ship the eval instead —
see [Proof, not benchmarks](#proof-not-benchmarks).

---

## Add it to your agent (MCP)

Vecta Council is also an MCP tool your coding agent can call mid-task. Add the server to
any MCP client (Claude Desktop, Cursor, Windsurf, your own kit).

### Any OpenAI-compatible provider (BYOK)

```json
{
  "mcpServers": {
    "council": {
      "command": "npx",
      "args": ["-y", "@openvecta/council", "mcp"],
      "env": {
        "OPENAI_BASE_URL": "https://openrouter.ai/api/v1",
        "OPENAI_API_KEY": "sk-or-..."
      }
    }
  }
}
```

Because this isn't OpenVecta, name the panel — pass the tool args explicitly:

```json
{
  "name": "council",
  "arguments": {
    "prompt": "Pressure-test this migration plan.",
    "debaters": ["openai/gpt-4o", "anthropic/claude-3.7-sonnet", "google/gemini-2.5-pro"],
    "synthesizer": "deepseek/deepseek-chat"
  }
}
```

> Provider id formats differ. OpenRouter needs `openai/gpt-4o`, `anthropic/claude-3.7-sonnet`,
> etc.; a local Ollama uses whatever you've pulled (`llama3.1`, `qwen2.5`). Bare ids like
> `gpt-4o` won't resolve on OpenRouter.

### OpenVecta (true cross-lab, defaults just work)

```json
{
  "mcpServers": {
    "council": {
      "command": "npx",
      "args": ["-y", "@openvecta/council", "mcp"],
      "env": { "OPENVECTA_API_KEY": "ov_sk_live_..." }
    }
  }
}
```

On OpenVecta the default panel already spans labs, so you can just ask:

> *"Use the council to pressure-test this go-to-market plan."*

---

## The honest part: a single-provider council is weaker

If you point this at **one vendor** — OpenAI only, or a single local model — every debater
comes from one lab. You get diversity of *sampling*, not diversity of *training*. That's a
real council and it still helps on open-ended work, but it's the diluted version:
correlated models checking correlated models.

A *true* cross-lab panel needs an endpoint that actually spans labs. Two honest ways:

- **Aggregators like OpenRouter** — cross-lab already; you assemble, price, and manage the panel yourself.
- **[OpenVecta](https://openvecta.com)** — every frontier lab (OpenAI, Anthropic, Google, xAI)
  plus many open models behind one OpenAI-compatible endpoint. The default council preset
  spans labs out of the box, and you can pay **per call in USDC over
  [x402](https://x402.org) with no account and no stored key** — the settlement model an
  autonomous agent can actually use. That last part is the thing an aggregator's
  signup-and-API-key flow can't do.

Same tool, same code — a better council underneath. Not a paywall; just where the cross-lab
panel is one env var away.

---

## Usage

**CLI**

```bash
npx @openvecta/council "Red-team this database choice and give me a recommendation."
npx @openvecta/council --rounds 3 --file ./plan.md "Draft a migration plan; call out the risks."
npx @openvecta/council --drafts "Which caching strategy for a read-heavy API, and why?"
```

**Custom panel + a peer-critique round (MCP args)**

```json
{
  "name": "council",
  "arguments": {
    "prompt": "Draft a migration plan from a monolith to event-driven services. Call out the risks.",
    "debaters": ["openai/gpt-4o", "anthropic/claude-3.7-sonnet", "google/gemini-2.5-pro"],
    "synthesizer": "deepseek/deepseek-chat",
    "rounds": 3,
    "max_tokens": 4000
  }
}
```

`rounds: 3` inserts a peer-critique pass — each debater sees the others' drafts and revises
before the synthesizer merges. Slower, sometimes sharper.

**Import the engine**

```ts
import { runCouncil } from "@openvecta/council/core";

const out = await runCouncil({
  prompt: "Pressure-test this plan.",
  baseUrl: "https://api.openvecta.com/v1",
  apiKey: process.env.OPENVECTA_API_KEY,
  debaters: ["gpt-oss-120b", "llama-4-maverick", "mimo-v2.5"],
  synthesizer: "deepseek-v4-pro",
});
console.log(out.answer, "\n", out.trailer);
```

---

## How it works

```mermaid
flowchart LR
    P[Your prompt] --> A[Model A · Lab 1]
    P --> B[Model B · Lab 2]
    P --> C[Model C · Lab 3]
    A -->|draft| S[Synthesizer]
    B -->|draft| S
    C -->|draft| S
    S --> F[One stronger final answer]
```

1. **Draft — in parallel.** Your prompt fans out to 2–4 debaters at once; each writes independently.
2. **Peer-refine — optional (`rounds: 3`).** Each debater sees the others' drafts and rewrites.
3. **Synthesize.** A separate synthesizer (kept *out* of the debater pool, so one failure
   can't sink both a draft and the merge) folds the surviving drafts into one answer.

It degrades gracefully: if a debater times out or returns empty, the council drops it and
reports `N/M debaters responded`; if everything fails, it surfaces the real reason. This is
**client-side orchestration** — the tool just calls `/chat/completions` several times —
which is exactly why it runs against any OpenAI-compatible endpoint.

**When *not* to use it.** A council makes one call per model, so it costs several times more
than a single call and typically runs ~1–2 minutes. For math, exact factual lookups, or long
single-artifact builds (complex code, whole websites), a single strong model is more reliable
*and* cheaper — the council only ties there. Reach for it on **hard, high-stakes, one-shot**
judgment work: analysis, strategy, explanation, red-teaming, "which of these is right and why."
It's a second opinion you convene deliberately — not something to leave in a hot loop.

---

## Proof, not benchmarks

We don't publish a win-rate number, because a number you can't reproduce isn't evidence.
What we ship instead is the harness that produced ours: a **blind A/B eval with randomized
position and an impartial judge**, in [`eval/`](./eval). Point it at your own hard prompts,
run council vs. your single-model baseline, and read the per-category result yourself.

---

## Configuration

### Council parameters

| Param | Default | Notes |
|-------|---------|-------|
| `prompt` | — | the task or question (required) |
| `debaters` | multi-lab preset (OpenVecta only) | 2–4 model ids that draft in parallel. **Required against non-OpenVecta endpoints.** |
| `synthesizer` | default (OpenVecta only) | model id that writes the final answer. **Required against non-OpenVecta endpoints.** |
| `rounds` | `2` | `2` = draft → synthesize · `3` = adds a peer-critique round |
| `max_tokens` | drafts 2000 / synth 4000 | ⚠️ **one value caps *both* legs.** Setting it small can truncate the synthesis, and can empty a reasoning model that spends the budget on hidden thinking. Leave unset unless you know you need it. |

### Environment

| Var | Default | Notes |
|-----|---------|-------|
| `OPENAI_BASE_URL` / `OPENVECTA_BASE_URL` | `https://api.openvecta.com/v1` | any OpenAI-compatible endpoint |
| `OPENAI_API_KEY` / `OPENVECTA_API_KEY` | — | your key (start here) |

`OPENAI_*` and `OPENVECTA_*` are aliases; `OPENVECTA_*` wins if both are set.

---

## Install from source

```bash
git clone https://github.com/openvecta/council
cd council && npm install && npm run build   # -> dist/index.js
node dist/index.js "your question"
```

> **Timeouts:** a council call runs ~1–2 min, past the 60s default in some MCP clients. The
> tool emits progress throughout, so clients that reset on progress stay connected; if yours
> hard-caps at 60s, raise its request timeout to ~180s for this server.
>
> **Security:** never commit an API key. Load secrets from your environment or a manager.

---

## License

MIT — see [LICENSE](./LICENSE). Built by [OpenVecta](https://openvecta.com). Issues and PRs
welcome. *The cross-lab council is one env var away.*