codex-claude-council
Get one cross-checked answer from ChatGPT (Codex) and Claude discussing until they agree, or ask either model alone.
council_ask— full council: both models answer independently, exchange replies until both say AGREE, then one writes the final answer and the other checks it (minutes; uses both plans' quota).council_debate— same council but returns the whole transcript as JSON: opening answers, every exchange and verdict, final check, and settings.council_ask_codex/council_ask_claude— quick second opinion from a single model (ChatGPT or Claude) only.council_join— the current session takes part itself as one member while the plugin runs the other model; you reply withcouncil_turn.Sessions — continue existing Codex/Claude Code sessions (by id or
/renamename), including ones on another machine viauser@host:sessionover ssh, so the models keep their memory.Project awareness — pass a
workspaceand both models read the project (files, search, read-only commands likegit log/diff) in plan mode/read-only, never changing it.Tunable per call — model and effort overrides per side,
max_rounds(including 0 = until agreement),synthesizer(who writes the final answer),web_searchon/off, andnetworkfor Codex's shell commands.Skills — name installed skills (e.g.
llm-council, caveman) for both models to use at the steps they judge fit.Job handling — long runs return
status: workingwith ajob_id; poll withcouncil_result(waits ~50 s, uses no quota) or stop withcouncil_cancel.
Allows querying OpenAI's ChatGPT through the Codex CLI, including using ChatGPT as one side of a cross-model council, running debates, configuring model/effort, and generating synthesized final answers.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@codex-claude-councilAsk the council: should I use Postgres or MongoDB for a user analytics dashboard?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Quick start
Install in Claude Code and Codex (this checks Node.js and both CLIs first; other ways under Install):
npx -y codex-claude-council installRestart Claude Code and Codex, so they load the plugin.
Ask, in a project: "Ask the council: what does this project do, and what would you improve first?"
Already in a session of one model? Say"discuss with my Codex session 019a…" (in Claude Code) and your session takes part itself, with everything it already knows. See council_join.
Related MCP server: codex-mcp-server
Why two models?
One model answers with confidence, right or wrong. Two models that disagree, and must explain why to each other, catch what either misses alone, the way a second reviewer does.
A real run (low effort): "PostgreSQL or SQLite for a single-server internal tool with about 20 users?"
ChatGPT | Claude | |
Opening answer | SQLite | PostgreSQL |
Exchange 1 | holds: "20 users alone does not establish write contention" | accepts most points and switches to SQLite, but keeps one objection |
Exchanges 2–3 | sharpens when PostgreSQL would be right | withdraws "multiple app instances" as a reason |
Exchange 4 | agrees | agrees |
Final check | rejects the first final text (over the 120-word limit, one unsupported claim); accepts the revision |
The final answer was sharper than either opening answer: SQLite, with the exact conditions under which to move to PostgreSQL. See the whole discussion as a page: open it (source) (make your own with --html, see From the terminal).
Benchmark
24 programs in which several traps interact (the hard set: the event loop across nested promises and timers, class fields, yield from, NULL in joins, …), each asked "what exactly does this print?" and graded against what it really prints. Codex gpt-6.1-sol and Claude Sonnet 5.5, both at low effort, fresh sessions, no web search (October 13, 2026):
Right answers | Median time per question | |
Codex alone | 24 / 24 | 18 s |
Claude alone | 23 / 24 | 11 s |
Council | 24 / 24 | 59 s |
The council caught the one mistake: on
h-py-dunderClaude alone printedV3 V102 V3 …; the council printed the rightV3 V102 V102 …, with both models agreeing.It never made things worse: there is no question the council got wrong that either model got right alone.
What it means: here Codex alone was already perfect, so the council's gain is insurance. You get the better answer without knowing in advance which model will slip, at about 3 to 5 times the time. One miss in 24 is a small sample, not proof.
Every answer is in the result file. Run it yourself with your own models and effort.
How it works
flowchart LR
Q[Your question] --> CA[Codex answers]
Q --> LA[Claude answers]
CA -- to Claude --> L1[Claude replies]
LA -- to Codex --> C1[Codex replies]
L1 -- to Codex --> C2[Codex replies]
C1 -- to Claude --> L2[Claude replies]
C2 & L2 --> V{Both agree?}
V -- no: exchange again --> V
V -- yes --> F[One writes the final answer, the other checks it]Answer: both models answer on their own, without seeing each other.
Exchange: each model gets the other's latest message (first its answer, then its replies) and replies point by point: what it accepts and how its position changes, where it still disagrees and why, then its current answer and a verdict,
AGREEorDISAGREE. The two replies cross over, and the exchange repeats: a crossed zig-zag that narrows round after round.Converge: as soon as both say
AGREEin the same exchange, one model writes the final answer and the other checks that it matches what they agreed (at most 5 exchanges by default;max_rounds: 0for no limit).No agreement: if the limit is reached first, the final answer sets out what they agree on and each point still in dispute, with both positions.
Neither model leads the discussion: in every exchange both reply to each other at the same time, and only after they agree does one of them write the final text. Each model keeps its session between questions, so it remembers the discussion and what it has already read, and each prompt carries only what that model has not seen yet.
Requirements
You need | Install | Sign in |
Node.js 20 or newer: runs the small MCP server (no dependencies) | – | |
Claude Code CLI, with a Claude Pro, Max, Team or Enterprise plan | macOS / Linux / WSL: |
|
Codex CLI, with a ChatGPT plan | any OS: |
|
Git (recommended) | usually already installed | – |
Both CLIs are required. The installer checks for them and stops, with these install steps, if either is missing. Before each council, the CLIs it runs are checked for a sign-in, and nothing is sent until they are signed in.
Git lets both models look at your project's history, changes and blame, and
skill adduses it to download a repository's skills.
Keep both CLIs up to date. The council uses recent options: Claude Code's plan mode and stream-json output, and Codex's exec resume and web search. If a run fails with "unknown option" or "unexpected argument", update the CLI it names: claude update, or npm install -g @openai/codex@latest.
Install
macOS / Linux / WSL
curl -fsSL https://raw.githubusercontent.com/hamza-aziz-ai/codex-claude-council/main/install.sh | bashWindows (PowerShell)
irm https://raw.githubusercontent.com/hamza-aziz-ai/codex-claude-council/main/install.ps1 | iexAny OS with Node.js
npx -y codex-claude-council installThe installer checks Node.js and both CLIs (and whether each is signed in), then adds this repository's marketplace to Claude Code and Codex and installs the plugin in both (for Claude Code, for your user, so it works in every project). If the plugin is already installed, it updates it instead.
Options: --only claude|codex (one app only; both CLIs are still required), --claude-desktop (also register the server with Claude Desktop's Chat tab), --dry-run (show the commands without running them). To pass them:
curl -fsSL https://raw.githubusercontent.com/hamza-aziz-ai/codex-claude-council/main/install.sh | bash -s -- --claude-desktop& ([scriptblock]::Create((irm https://raw.githubusercontent.com/hamza-aziz-ai/codex-claude-council/main/install.ps1))) --claude-desktopAfterwards:
Fully quit and reopen Claude Code and Codex (and Claude Desktop), so they load the plugin.
Check the setup:
npx -y codex-claude-council doctor.Try it in a project: "Ask the council: what does this project do, and what would you improve first?"
Update
npx -y codex-claude-council update # both apps
npx -y codex-claude-council update --only claude # or --only codex
npx -y codex-claude-council update --dry-run # show the commands onlyIt refreshes the marketplace and updates the plugin in Claude Code and Codex; then fully quit and reopen both. Running the installer again does the same. CHANGELOG.md lists what changed. In Claude Desktop, updates arrive through Sync automatically (or Sync under Settings → Plugins); in the ChatGPT desktop app, update the plugin under Settings → Plugins.
Windows: if Codex fails with "failed to back up plugin cache entry: Access is denied. (os error 5)", a running app still has the plugin's folder open (versions up to 0.5.1 did this). Quit every Codex and Claude session, IDE extension and desktop app, then update again.
Or install per app
App | How |
Claude Code |
|
Codex (CLI and IDE extension) |
|
Claude Desktop (Cowork and Code) | Settings → Customize → Plugins → + Add → Add marketplace → Add from a repository, enter |
Claude Desktop, one-click extension | Download |
Claude Desktop, Chat tab |
|
ChatGPT desktop app | Settings → Plugins → Add → + Add a marketplace, enter |
Any other MCP client (Cursor, VS Code, Windsurf, …) | Add a local (stdio) MCP server with command |
Keep the desktop app open while you use it: the council runs on your computer through your local CLIs, so both still need to be installed and signed in.
Use it
Just ask in plain language. The host (the app you are asking in) picks the tool and fills in its inputs:
You say | What runs |
"Ask the council: should I use Postgres or MongoDB for this?" |
|
"Run a council debate on this migration plan." |
|
"Get Codex's second opinion on this function." |
|
"Discuss with my Codex session 019a… whether this refactor is safe." (asked in Claude Code) |
|
"Ask the council, continuing my Claude session 3f2a… and my Codex session "auth refactor": is my plan sound?" |
|
"Council this with ChatGPT on gpt-5.6-sol at xhigh and Claude on opus at max: …" |
|
"Ask the council and keep going until they agree: …" |
|
"Ask the council, and let ChatGPT write the final answer: …" |
|
"Ask the council: is the latest Next.js release safe to upgrade to for our app?" |
|
"Ask the council without internet access: …" |
|
"Ask the council, using the llm-council skill: rewrite the billing service or refactor it?" |
|
"Ask the council, using the llm-council and caveman skills: …" |
|
In a project, the host passes its folder as the workspace, and the models read what they need themselves: point them at files, functions, the failing test or the error rather than pasting whole files. They cannot see the host's conversation (unless the host takes part itself), so the host states the task and any context that is not in the project.
Long runs. A council takes several minutes: two CLI calls for the answers, two per exchange and two for the final answer and its check, all counting against both plans' limits. Some apps end a tool call after about 60 seconds (Claude Desktop does), so every tool returns within about 50 seconds, with the answer or with "still working", the current step and a job_id; the host then calls council_result until the answer is ready, while the council keeps running. council_cancel stops a job.
Examples and best practices
Pick the right tool
flowchart TD
S{What do you want?} -->|a quick second opinion| O[council_ask_codex / council_ask_claude]
S -->|a cross-checked answer| W{Who should take part?}
W -->|two fresh sessions| CA[council_ask]
W -->|my existing Claude Code and Codex sessions| CS[council_ask with claude_session_id and codex_session_id]
W -->|the session I am in, with the other model| CJ[council_join]
S -->|every step, to see where they disagree| D[council_debate]The host picks the tool from your words. Name the tool if you want to be sure:
To get | Say | Not |
| "Discuss with my Codex session 019a… whether …", "take part yourself as Claude, with my Codex session …", or "use council_join …" | "council_ask with my Codex session", which starts a separate Claude session instead |
| "Ask the council, continuing my Claude session … and my Codex session …" | naming the session you are asking from |
| "Run a council debate on …", "show me every step" | – |
Use it from the desktop apps
Claude Cowork with a ChatGPT Work conversation. Conversations in ChatGPT's Work mode are saved as Codex sessions, so the plugin can continue one by its title. In a Cowork conversation, ask:
Discuss with my ChatGPT Work session "Find UAE job platforms": which three job portals should I focus on first, and why?
Cowork is the Claude member, with everything its project gives it: its folders, instructions, connectors and skills.
Codex continues that Work conversation, read-only, in its own folder, and the council's turns appear there when you reopen it. Close it in the ChatGPT app first.
A Cowork conversation can't be continued from outside: Cowork doesn't save its conversations as Claude Code sessions. Start from Cowork to have it take part.
Share the project folder. If both apps' projects use the same folder on your computer, both models read the same files. Instructions stored only inside an app (a Cowork project's instructions, ChatGPT project settings) are not shared: the other model sees the folder's
CLAUDE.md/AGENTS.mdinstead.
Give the members what they can't reach
The members run on your computer, read-only. By default Codex's commands have no network access: it can't call an API, query a database, open a Google Sheet or open a claude.ai link, and its web search runs on OpenAI's side and only reaches public pages. Claude's read-only commands can reach the network. Turn on network to let Codex call APIs too. Either way, data behind a login (SSH, databases, private sheets) is best collected by the host first, into the workspace, with the question pointing to it:
flowchart LR
subgraph Remote[Out of the members' reach]
L[(Server logs)]
DB[(Database)]
G[Google Sheet]
A[claude.ai artifact]
end
H[Host session] -->|ssh, export, download| F["workspace/.council-data/<br/>(in .git/info/exclude)"]
L & DB & G & A -.-> H
F --> C[Claude member]
F --> X[Codex member]Copy only what the question needs, such as the log lines for the calls in question, not whole log folders.
Keep the copies out of git: put them in a folder listed in
.git/info/exclude, which stays on your machine.Keep secrets out of the question. The question is saved in both sessions and sent to both providers. Have the host read a connection string from an environment variable instead.
Write a question that works
The members can't see your conversation with the host: they see only the question (at most 12,000 characters) and the workspace. For a long task, split your prompt in two:
## Part A — instructions for you (the host), not sent to the other model
1. Collect the data into .council-data/ (see above).
2. Start council_join with me "claude", other_session_id "<id>",
workspace "<absolute path>", max_rounds 0.
3. When they agree, show me the result and wait for my OK before changing code.
## Part B — the council question (send verbatim)
Goal: <what you want, and what "done" means>.
Data: <each file or folder, and its format>.
Tasks: 1. Measure … 2. Trace the code path (file:line) … 3. Propose the smallest fix as a diff …
Constraints: every claim cites a log line, a file:line or a measured number.Say what to measure, not what to find. If the question states the answer ("p50 is 2.7 s"), the other model tends to confirm it instead of checking. Give earlier findings as a file to open after its own measurement: "Do not open prior-study.md until you have your own numbers; then compare."
Ask for evidence and for measured results. "Report the saving as measured; do not round it up to a target" keeps a goal like "save 2 s" from turning into a claim.
State the premise as a question, not a fact. "Measure first; do not assume a fast path exists" lets the models correct a wrong assumption.
The members only propose. They are read-only, so the host applies the agreed change afterwards, then tests and commits it.
In Claude Code,
/goalis limited to 4,000 characters. Save a long prompt as a file and give/goala short condition: "/goal Follow every step in /path/task.md in order. Done when: …".
Skills, models and effort
Several skills at once. Name them all (
skill: "llm-council, caveman", or--skill llm-council --skill caveman). Both models get each one's instructions and use each where it fits. Withcouncil_join, have the host invoke the same skills itself.Use heavy skills once. llm-council starts five advisors each time it runs. Ask for it once, on the final plan, not on every turn.
Model and effort: anything you don't set comes from the plugin's config (effort
highby default), then from each CLI's own config. So Codex uses the model in your~/.codex/config.toml, but the plugin'shigheffort replaces the effort set there. Ask forxhighormaxfor one question, or set it in the config.
Sessions
Close a session before the council continues it. Codex refuses a session that is open in the Codex CLI or app ("already has an active writer"). A session Codex hasn't saved yet (no message sent in it) can't be continued either.
Pass the id when it matters which session you get. Names are easy to reuse;
codex resumeand/statusshow ids.
Who takes part
There are three ways to run the two members. The discussion is the same in all of them.
Claude member | Codex member | Use it when | |
New sessions (default) | a new Claude Code session | a new Codex session | you want two fresh, independent opinions |
Your sessions | your Claude Code session, continued | your Codex session, continued | both of your sessions already know the work |
Take part yourself | the session you are asking from (if it is Claude Code) | your Codex session, continued, or a new one | you want the session you are in to discuss with the other model |
New sessions
By default each side runs a new Codex / Claude Code session in the workspace, which lasts as long as your host session: follow-up questions reuse it, so the models remember earlier questions and what they read. When you start a new host session, the council starts new sessions too.
Your sessions
Pass sessions you already have, by id or by name, and the council continues those sessions in place, with everything they have read and discussed. The council's turns are added to them, so you see the discussion when you go back.
Tool | Inputs | Terminal |
|
|
|
|
|
|
Finding a session's id or giving it a name:
Claude Code | Codex | |
Id |
|
|
Name |
|
|
List |
|
|
A name is looked up where each CLI keeps it: Claude Code in the session's own transcript, Codex in
~/.codex/session_index.jsonl. If several sessions have that name, the most recently used one is taken (an exact match before one that differs only in case). A name can contain spaces:--codex-session "auth refactor".Names are easy to reuse by mistake, so pass the id when it matters which session you get.
Each session runs in the folder it was started in, which is also the default
workspace. Pass aworkspaceto have it work in another folder.For the council's turns, both run in plan mode / read-only, whatever mode you used them in.
Close those sessions first, or at least don't type in them while the council runs: two programs writing to one session can mix up its history. Reopen them afterwards (
claude --resume <id>,codex resume <id>) to see the council's turns.Don't pass the id of the session you are asking from; to have that session take part, use
council_join.
Sessions on another machine
A session on another computer takes part too: write it as user@host:session, with the session's id or name as there, for example --claude-session hamza@10.152.15.202:fix-order-dialog-bugs or "continuing my Claude session hamza@10.152.15.202:fix-order-dialog-bugs". That member runs on that machine, through ssh: this plugin's own codex / claude command, with that machine's CLI and its sign-in (any account, not necessarily yours here), in the session's own folder, read-only as here.
Needs: key-based
sshfrom this computer (no password prompt:ssh -o BatchMode=yes user@host truemust work), and Node.js 20+ and the CLI, signed in, on that machine (Linux or macOS). Node.js installed with nvm is found too, even when nvm loads only in~/.bashrc. Nothing is installed there:npxfetches this plugin's version for the call.Its model and effort come from that machine's config, unless you set them for the call.
Skills (
skill): the council asks that machine which of them are installed for its CLI (in the session's folder too), with onesshcall; those it loads by name, the others' instructions are sent. If the check fails, every skill's instructions are sent.It continues the saved session, not the window it is open in: don't type in that session while the council runs, and resume it afterwards to see the council's turns.
Cancelling stops the council here; a turn already running on that machine finishes there.
sshis found on your PATH; set"ssh": { "command": "<path>" }in the config to use another.
Take part yourself: council_join
Say your repository has a Claude Code session abcd and a Codex session efgh, and you are working in abcd. Ask there: "discuss with my Codex session efgh whether we should split the auth module".
abcditself is the Claude member. No second Claude session is started.council_joinhandsabcdeach of Claude's turns (the same prompts a Claude member gets);abcdwrites them in its own conversation, with everything it already knows, and sends each back withcouncil_turn.Codex continues
efghin place, read-only. Without a session id, Codex starts a new session.The steps are the same as
council_ask:abcdand Codex exchange replies until both agree, and the agreed answer lands inabcd.abcdwrites the final answer and Codex checks it, unless you name another synthesizer.
It works the other way round too: from a Codex session, council_join makes that session the Codex member, and Claude continues the Claude Code session you name (or a new one).
The host is asked, not forced, to leave files alone. The other model is read-only as usual, but the session you are asking from keeps its own permissions.
Only the other model's CLI must be signed in.
Each of the host's turns may take up to
skill_timeout_seconds(default 1800); after that the council stops.council_cancelstops it at any time.It needs a host that takes turns (Claude Code, Codex, the desktop apps), so it is not a terminal command.
What the members can use
Claude member ( | Codex member ( | The host, with | |
Mode | plan mode | read-only sandbox (Codex's command line has no plan mode) | its own, unchanged |
Your setup | settings, skills, plugins, MCP servers, |
| everything it already has |
Can | read, search, run read-only commands ( | read, search, run commands that change nothing, use skills and sub-agents, search the web; with | anything it normally can; asked not to change files |
Cannot | edit, write or run other commands; ask you questions; use this plugin | write anywhere; reach the network from its commands (unless | – |
Skills that a step would use to change something (saving a report, building an index) have those steps skipped. Your MCP servers' tools run in their own processes: plan mode refuses Claude's tools that change things, while Codex follows each server's own approval settings. See Security and privacy.
Options
Agreement: max_rounds and synthesizer
| What happens |
omitted | the configured default: at most 5 exchanges, stopping as soon as both agree |
| at most N exchanges, stopping as soon as both agree |
| no limit: they exchange until both agree (can take long and use a lot of both plans) |
Each exchange is one reply from each model, sent at the same time, each to the other's latest message. They have agreed when both end the same exchange with AGREE. Then the synthesizer writes the final answer and the other model checks that it matches what they agreed; if it does not, the writer revises it once.
Claude writes the final answer by default; pass synthesizer: "codex" (or change it in your config) to swap. With council_join, the host writes it by default, whichever model it is, since it has the whole context; pass synthesizer to have the other model write it instead. The writer only turns an agreement into text: the discussion itself is symmetric.
If the limit is reached without agreement, the synthesizer writes a final answer that sets out what they agree on and each point still in dispute, with both positions; it is marked as not agreed. If a call fails partway (for example a usage limit), you get what was reached and the reason.
Web search: web_search
Both models can search the web and read pages (on by default): Codex with its live web search, Claude with WebSearch and WebFetch. They prefer primary sources such as official docs and release notes, say where a fact came from, and check each other's claims against them. With a workspace they combine the two: "Is our use of the Stripe API in src/billing still correct for the current API version?"
Turn it off with web_search: false for one question ("ask the council without internet access"), --no-web in the terminal, or "web_search": false in your config. See Security and privacy before using it with a sensitive project.
Network for Codex's commands: network
By default Codex's commands have no network access (its web search still works). Turn on network to let them reach the network, for example to call an API or fetch live data, while the disk stays read-only: "ask the council, with network access for Codex: is our API returning the new field yet?", --network in the terminal, or "network": true in your config. Claude's read-only commands can already reach the network in plan mode.
Limit where it can connect with
"network_domains": ["api.github.com", "*.example.com"]in your config. With a list, Codex's network proxy blocks every other domain; with an empty list (the default), any domain is allowed.How: Codex runs with a permission profile instead of its read-only sandbox: the whole disk read-only, the network on. Permission profiles are a beta feature of Codex and may change; checked with Codex CLI 0.160.
Windows: HTTPS from
curl.exe,Invoke-WebRequestandgitfails inside Codex's sandbox (Windows' own TLS has no credentials for the sandbox account), while Python and Node work; Codex is told so. The sandbox also can't read~/.ssh, so SSH logins don't work from Codex there.Off by default, for a reason: a model that can read your files and reach the network could also send them out, for example if a log or web page it reads tries to instruct it (a prompt injection). Use a domain list, and keep
networkoff for sensitive projects.
Skills: skill
Skills are SKILL.md folders with a method or style the models can follow. Install a repository's skills once:
npx -y codex-claude-council skill add https://github.com/aiwithremy/claude-skills-llm-council
npx -y codex-claude-council skill add https://github.com/JuliusBrussee/caveman.git
npx -y codex-claude-council skill add https://github.com/DietrichGebert/ponytail.git
npx -y codex-claude-council skill add https://github.com/Graphify-Labs/graphify.git
npx -y codex-claude-council skill list
npx -y codex-claude-council skill remove caveman-statsskill addclones the repository and installs every skill in it, each with its files (references, scripts): caveman brings 20 (caveman,caveman-review,caveman-compress, …), ponytail 6 (ponytail,ponytail-review, …), graphify and llm-council one each. It also takes one folder of a repository (…/tree/<branch>/<folder>), a local folder or aSKILL.mdfile. Without git, it installs a repository's top-levelSKILL.mdonly.Skills are saved in
~/.codex-claude-council/skills/<name>/. Skills installed natively for Claude Code (~/.claude/skills) or Codex (~/.codex/skills,~/.agents/skills), and those of their enabled plugins, can be named too. Restart the apps afterwards so the tools list new skills (plugin skills are not listed, but work by name).A skill a member already has is named, not sent. If the member's own CLI has the skill (in its skills folder, the project's
.claude/skillsor.agents/skills, or an enabled plugin), the member is told to load it by name, as it loads any of its skills. Only the skills it lacks have their instructions sent. For llm-council and graphify, both installed for both CLIs here, that cuts the first prompt from about 61,000 characters to about 1,100. The host of acouncil_joinalways gets the full instructions, since a desktop app may not load the CLI's skills.Nothing third-party ships with the plugin: check a skill's license and contents before you install it (llm-council, for example, has no license file).
A skill is used only when you ask for it: "ask the council, using the llm-council skill: …", or --skill llm-council in the terminal. For several, name them all: "using the llm-council and caveman skills", skill: "llm-council, caveman", or --skill llm-council --skill caveman. Both models (and the host, with council_join) get its instructions with the question and decide for themselves at which steps it is needed, following the skill's own guidance: a method like llm-council for a real decision or disagreement, a style like caveman (terse replies) or ponytail (the simplest solution that works) on every reply. When a model uses a skill, it follows it fully, including sub-agents, which are read-only too. The discussion's rules come first, and each answer comes back in the format its step asks for.
graphify builds its knowledge graph by running a Python tool that writes graphify-out/, which the members cannot do. Build it yourself first (pip install graphifyy, then graphify . in the project); the members then read graphify-out/GRAPH_REPORT.md and graph.json, and Codex can run graphify query.
A step that uses a skill with sub-agents can take several minutes and uses much more of both plans; such a call may take up to skill_timeout_seconds (default 1800).
Tool reference
Tool | Does | Optional inputs (besides |
| the full council; returns the agreed answer |
|
| the same; returns JSON with every step and the settings | as |
| one model only |
|
| the host takes part as one member |
|
| sends the host's turn ( | – |
| waits for a running job's answer (or, with |
|
| stops a running job |
|
Every tool also returns its result as structuredContent (declared in its outputSchema): status (done, working, your_turn or stopped), the text, and the job_id or council_id to use next. The tool names before 0.11.7 (debate, ask_codex, ask_claude) still work.
workspace: the absolute path of the project folder both models work in. In Claude Code and Codex, the plugin's skill tells the host to pass the folder you are working in.Codex effort:
none,minimal,low,medium,high,xhigh. Claude effort:low,medium,high,xhigh,max.Claude models: an alias (
opus,sonnet,fable) or a full model name. Codex models: any name your Codex CLI accepts.Anything you leave out comes from your config.
From the terminal
npx -y codex-claude-council ask "Which is faster for 10M rows, A or B?"
npx -y codex-claude-council debate "..." --codex-effort xhigh --claude-model opus
npx -y codex-claude-council ask "..." --max-rounds 0 # until both agree
npx -y codex-claude-council ask "..." --synthesizer codex # ChatGPT writes the final answer
npx -y codex-claude-council codex "..." --effort low # Codex only
npx -y codex-claude-council claude "..." --model sonnet # Claude only
npx -y codex-claude-council ask "..." --workspace ~/code/app # this project
npx -y codex-claude-council ask "..." --no-workspace # no project folder
npx -y codex-claude-council ask "..." --no-web # no web search
npx -y codex-claude-council ask "..." --network # Codex's commands may reach the network
npx -y codex-claude-council ask "..." --skill llm-council # with an installed skill
npx -y codex-claude-council ask "..." --skill llm-council,caveman # with several
npx -y codex-claude-council ask "..." --html council.html # also save the discussion as a page to share
npx -y codex-claude-council ask "..." --claude-session <uuid> --codex-session <id> # your sessions
npx -y codex-claude-council codex "..." --session <id> # your Codex sessionIn the terminal, both models work in the git repository you run the command from (if any), unless you pass --workspace, --no-workspace or a session id. Each command is a new pair of sessions for that run, unless you pass session ids. Questions can also be piped on stdin. For a shorter command, install it globally (npm install -g codex-claude-council) and use codex-claude-council ask "...".
Configure
npx -y codex-claude-council config --initThis creates ~/.codex-claude-council/config.json. It is re-read on every call, so edits apply immediately:
{
"timeout_seconds": 600,
"skill_timeout_seconds": 1800,
"tool_wait_seconds": 50,
"synthesizer": "claude",
"max_rounds": 5,
"web_search": true,
"network": false,
"network_domains": [],
"allow_api_key_auth": false,
"codex": { "command": null, "model": null, "effort": "high" },
"claude": { "command": null, "model": null, "effort": "high" }
}Setting | Meaning |
| limit for each CLI call |
| limit for each CLI call when a skill is in use, and for each of the host's turns with |
| how long one tool call waits before returning "still working" and a |
| which model drafts the final answer: |
| exchanges until both agree: |
| whether the models may search the web and read pages: |
| whether Codex's commands may reach the network, read-only on disk: |
| with |
| default model; |
| default effort |
| full path to a CLI if it isn't found automatically |
|
|
Set COUNCIL_CONFIG to use a different config file. The installer shows the plugin's icon in terminals that draw sixel images, which it asks the terminal (so it works over ssh too); set COUNCIL_BANNER=image to always show it, or COUNCIL_BANNER=text never to.
Security and privacy
Everything runs on your computer. Your question goes to OpenAI and Anthropic through their official CLIs, under your own accounts.
The members cannot change your files.
Codex runs
codex execin its read-only sandbox, enforced by the operating system, withapproval_policy="never". Both are set on the command line, which overrides yourconfig.toml, so even a config that grants full access stays read-only.Claude Code runs in plan mode: it reads, searches and runs commands it knows to be read-only, and every edit, write or other command is refused, since nobody is there to approve it. Plan mode is Claude Code's own permission guard, not an operating-system sandbox; the only file it may write is its plan file under
~/.claude/plans/.With
council_join, the host is your own session and keeps its own permissions; it is only asked not to change files.
Your own setup applies. The members run with your skills, plugins, MCP servers, hooks,
CLAUDE.md/AGENTS.mdand permission rules. This plugin is switched off inside them, so a member can't start another council. MCP tools run in their own processes: plan mode refuses Claude's tools that change things, while Codex follows each server's own approval settings, so keep that in mind for MCP servers that can change things.What they read is sent to the model providers. Whatever either model chooses to read goes to OpenAI or Anthropic, as when you paste it. Both can read files outside the project too, as in your normal sessions: Codex's read-only sandbox allows reading the whole disk, and plan mode allows read-only commands anywhere. Without a
workspace, they start in an empty folder and are told to work from the question.Web access. Codex's web search runs on OpenAI's side (its sandbox has no network for commands unless you turn on
network); Claude can search and fetch pages, and its read-only commands can reach the network. With aworkspaceas well, text in the project that tries to instruct the model (a prompt injection) could in principle get it to send project content to a website, for example in a URL it fetches. For sensitive projects, turn web access off.Sessions. The members' sessions are saved by the CLIs like any other, so they appear in
claude --resumeandcodex resumefor that folder. A session you pass by id is continued in place: the council's turns are added to it.Subscriptions, not API keys. API-key environment variables are removed before the CLIs start. Codex must be signed in with ChatGPT and Claude Code with a Claude subscription, unless you set
allow_api_key_auth.Privacy policy: PRIVACY.md. The plugin has no servers and no telemetry; what goes to OpenAI and Anthropic goes through their CLIs, under your accounts.
The plugin itself runs with your user permissions: about 1,700 lines of dependency-free JavaScript in
src/. Read it before installing if you like.
Troubleshooting
Run the doctor. It checks Node.js, both CLIs, their sign-ins and your effective config:
npx -y codex-claude-council doctor"The council needs … signed in": nothing was sent. The message names each CLI with a problem and the fix:
codex login(choose Sign in with ChatGPT) and/orclaude auth login."usage limit": your ChatGPT or Claude plan hit its limit. Wait for the reset or lower the effort.
"timed out": raise
timeout_seconds(orskill_timeout_secondswith a skill), or lower the effort.The tool call ended after about 60 seconds: update to 0.6.2 or later, where every tool returns within about 50 seconds and the host polls
council_result. If your app has no such limit,"tool_wait_seconds": 0waits in one call."no … session named …": no session has that name. Check it with
claude --resume/codex resume --all, rename the session with/rename, or pass its id from/status."Waiting for the … session": another council or question is using that session; each session takes one at a time, and this one starts when it is free. If the message names a
council_joinjob waiting for your reply, that job holds the session until the host answers it (up toskill_timeout_seconds, 30 minutes by default): send the reply withcouncil_turn, or stop that job withcouncil_cancel."… is not waiting for your reply now" (
council_join): the other model is still working; the host should callcouncil_resultwith the id to get its next turn.skill "…" is not installed: install it withskill add, then restart the app so the tools list it.Tools don't appear: fully quit and reopen the app after installing. In the desktop apps, check the plugin is installed and enabled under Settings → Plugins.
nodenot found by a desktop app on macOS: GUI apps don't read your shell profile, so Node installed with nvm may be invisible to them. Install Node from nodejs.org or Homebrew.CLI not found: set
codex.command/claude.commandto the full path."unknown option" / "unexpected argument": a CLI is too old. Update it:
claude update, ornpm install -g @openai/codex@latest.Windows: "Access is denied (os error 5)" when installing or updating: see Update.
Uninstall
npx -y codex-claude-council uninstallThis removes the plugin from Claude Code and Codex and the Claude Desktop chat entry, and keeps your config file and installed skills. In the desktop apps, uninstall it under Settings → Plugins.
Development
git clone https://github.com/hamza-aziz-ai/codex-claude-council.git
cd codex-claude-council
npm testThe tests use fake codex / claude executables, so they make no model calls. CI runs them on Windows, macOS and Linux. To try a local checkout, use its path as the marketplace: claude plugin marketplace add ./codex-claude-council or codex plugin marketplace add ./codex-claude-council.
Disclaimer
Not affiliated with, or endorsed by, OpenAI or Anthropic. Codex, ChatGPT, Claude and Claude Code are trademarks of their owners. The OpenAI and Claude logos in the plugin's icon and on shared discussion pages (from @lobehub/icons) only identify the two CLIs the plugin runs; the installer draws the icon with chafa. Your use of each CLI is subject to its provider's terms and your plan's limits.
License
MIT © Hamza Aziz
Available Tools
8 toolscouncil_askAsk the Codex–Claude councilARead-only
Get one cross-checked answer from Codex (ChatGPT) and Claude: each answers on its own, then they reply to each other until both agree, and one writes the final answer that the other checks. Use it for decisions, reviews and questions where a second model's check is worth minutes of waiting; for a quick single opinion use council_ask_codex or council_ask_claude, and for the whole discussion use council_debate. It runs the user's local Codex and Claude Code CLIs on their own subscriptions, so it uses both plans' quota, and takes minutes; a call still running after about 50 s returns a job_id for council_result. With workspace, both models read the project but never change it. Each model keeps its session between calls, so it remembers earlier questions.
| Name | Required | Description | Default |
|---|---|---|---|
| skill | No | Optional: the name of an installed skill both models may use for this question, at the steps where they judge it is needed, including any sub-agents it calls for; for several skills, their names separated by commas ("llm-council, caveman"). Pass only skills the user asks to use (by name, or by a phrase the skill says triggers it). Skills of Claude Code's and Codex's enabled plugins can be named too. Installed: none (install with `codex-claude-council skill add <GitHub URL>`). A step that uses it takes much longer and uses much more of both plans. | |
| network | No | Optional: whether Codex's shell commands may reach the network (for example to call an API or fetch live data), still read-only on disk. Omit to use the configured default (off unless the user changed it). Pass true only when the user asks for it. | |
| question | Yes | The question, with any context the models need. | |
| workspace | No | Absolute path of the project folder you are working in. Both models then work in it in plan mode: they read it (files, search, read-only commands such as git log and diff) but never change it. Pass it whenever the question is about the code, a change, a fix, an error or logs in this project. Omit only for questions unrelated to any project (or when passing a session id: the session's own folder is used). | |
| max_rounds | No | Optional limit on the exchange. After the two independent answers, each model replies to the other's latest message, round after round, until both agree; then the synthesizer writes the final answer and the other checks it. N (1 or more): at most N exchanges. 0: no limit (can take a long time and use a lot of both plans' usage). Omit to use the configured default (5 unless the user changed it). Set only when the user asks for a number of rounds or for agreement without a limit. | |
| web_search | No | Optional: whether the models may search the web and read web pages. Omit to use the configured default (on unless the user changed it). Pass false only when the user asks for no internet access. | |
| codex_model | No | Optional Codex (ChatGPT) model override, e.g. gpt-5.6-sol. Omit to use the configured default; set only when the user asks for a specific one. | |
| synthesizer | No | Optional: which model writes the final answer ("codex" is ChatGPT); the other checks it. Omit to use the configured default (Claude unless the user changed it). | |
| claude_model | No | Optional Claude model override: an alias such as opus, sonnet or fable, or a full model name. Omit to use the configured default; set only when the user asks for a specific one. | |
| codex_effort | No | Optional Codex reasoning effort override. Omit to use the configured default; set only when the user asks for a specific one. | |
| claude_effort | No | Optional Claude effort level override. Omit to use the configured default; set only when the user asks for a specific one. | |
| codex_session_id | No | Optional: a Codex session the user already has: its id (as shown by `/status`) or the name they gave it with `/rename`; on another machine, user@host:<id or name> (runs there through ssh), to continue in place instead of a new session, so the model keeps that session's memory. Pass it exactly as the user gives it, only when they give one. The council's turns are added to that session, in plan mode (nothing is changed). | |
| claude_session_id | No | Optional: a Claude Code session the user already has: its UUID (as shown by `/status`) or the name they gave it with `/rename`; on another machine, user@host:<id or name> (runs there through ssh), to continue in place instead of a new session, so the model keeps that session's memory. Pass it exactly as the user gives it, only when they give one. The council's turns are added to that session, in plan mode (nothing is changed). |
Output Schema
| Name | Required | Description |
|---|---|---|
| text | Yes | The answer (council_debate: its JSON), or the message to act on; the same as the text content. |
| job_id | No | With working or stopped: the job to wait for, or the one stopped. |
| status | Yes | done: text is the answer. working: still running; call council_result with job_id. your_turn (council_join): text is the council's message; reply with council_turn and council_id. stopped: council_cancel stopped job_id. |
| council_id | No | With your_turn: the council to reply to with council_turn. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare read-only/open-world/non-idempotent; the description adds the material operational facts: it consumes both subscriptions' quota, takes minutes, can hand back a job_id for council_result, runs models in plan mode so the project is read but never modified, and that each model retains session memory across calls. It is consistent with readOnlyHint=true and openWorldHint=true (network is opt-in via the network parameter).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The most important facts - what it is, when to use it, cost, and the job_id fallback - are front-loaded, and every sentence carries information. It is long and dense with several compound clauses, but for a 13-parameter orchestration tool the length is largely earned rather than padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, the presence of an output schema, and annotations covering the safety profile, the description covers the remaining agent-facing gaps: cost/quota, latency, the async job_id handoff to council_result, read-only plan-mode workspace behavior, and session persistence. Nothing needed to invoke it correctly appears to be missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so all 13 parameters are already documented in the schema, which sets the baseline at 3. The description reinforces a few semantics ('With workspace, both models read the project but never change it', session memory across calls) but adds no format, default or usage detail beyond what the schema fields already state, so it does not clear the bar for a 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence names a specific verb and resource ('Get one cross-checked answer from Codex (ChatGPT) and Claude') and immediately explains the mechanism: independent answers, mutual reply, synthesis, verification. It also explicitly contrasts itself with council_ask_codex, council_ask_claude and council_debate, so an agent can place it correctly without opening sibling schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states the positive case ('decisions, reviews and questions where a second model's check is worth minutes of waiting') and names the alternatives with the condition that selects each: quick single opinion -> council_ask_codex/council_ask_claude, whole discussion -> council_debate. It also gives an operational switchover rule: still running after ~50 s, use council_result.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
council_ask_claudeAsk Claude onlyARead-only
Ask Claude alone, through the user's Claude Code CLI signed in with a Claude subscription, and return its answer. Use it for a quick second opinion from Claude, for example from Codex or ChatGPT; use council_ask when the answer should also be cross-checked by Codex, or council_ask_codex for Codex alone. It uses the user's Claude plan and usually answers within a minute (longer at high effort, when it returns a job_id for council_result). With workspace it reads the project in plan mode and never changes it; its session carries over between calls.
| Name | Required | Description | Default |
|---|---|---|---|
| model | No | Optional Claude model override: an alias such as opus, sonnet or fable, or a full model name. Omit to use the configured default; set only when the user asks for a specific one. | |
| skill | No | Optional: the name of an installed skill both models may use for this question, at the steps where they judge it is needed, including any sub-agents it calls for; for several skills, their names separated by commas ("llm-council, caveman"). Pass only skills the user asks to use (by name, or by a phrase the skill says triggers it). Skills of Claude Code's and Codex's enabled plugins can be named too. Installed: none (install with `codex-claude-council skill add <GitHub URL>`). A step that uses it takes much longer and uses much more of both plans. | |
| effort | No | Optional Claude effort level override. Omit to use the configured default; set only when the user asks for a specific one. | |
| question | Yes | The question, with any context the models need. | |
| workspace | No | Absolute path of the project folder you are working in. Both models then work in it in plan mode: they read it (files, search, read-only commands such as git log and diff) but never change it. Pass it whenever the question is about the code, a change, a fix, an error or logs in this project. Omit only for questions unrelated to any project (or when passing a session id: the session's own folder is used). | |
| session_id | No | Optional: a Claude Code session the user already has: its UUID (as shown by `/status`) or the name they gave it with `/rename`; on another machine, user@host:<id or name> (runs there through ssh), to continue in place instead of a new session, so the model keeps that session's memory. Pass it exactly as the user gives it, only when they give one. The council's turns are added to that session, in plan mode (nothing is changed). | |
| web_search | No | Optional: whether the models may search the web and read web pages. Omit to use the configured default (on unless the user changed it). Pass false only when the user asks for no internet access. |
Output Schema
| Name | Required | Description |
|---|---|---|
| text | Yes | The answer (council_debate: its JSON), or the message to act on; the same as the text content. |
| job_id | No | With working or stopped: the job to wait for, or the one stopped. |
| status | Yes | done: text is the answer. working: still running; call council_result with job_id. your_turn (council_join): text is the council's message; reply with council_turn and council_id. stopped: council_cancel stopped job_id. |
| council_id | No | With your_turn: the council to reply to with council_turn. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover safety (readOnly, non-destructive, open world), and the description still adds materially: it runs through the user's Claude subscription plan, usually answers within a minute, may return a job_id for council_result at high effort, workspace is plan-mode read-only and 'never changes it', and sessions carry over between calls. These are exactly the operational traits an agent needs before invoking.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then alternatives, then timing and workspace semantics; no filler sentences. The prose is dense and slightly long for a single paragraph, but each clause carries routing or behavioral information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description needn't document return values, yet it explains the async job_id path and the session/plan-mode behavior anyway. Combined with annotations and full schema coverage, an agent has everything required to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the schema text is verbose and self-sufficient (each parameter documents its own omission/default rules). The description's parameter remarks, such as workspace/session_id interaction, largely restate the schema, so the baseline 3 applies rather than a higher value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Ask Claude alone ... and return its answer') and immediately names the two sibling alternatives it is distinct from (council_ask for cross-checking, council_ask_codex for Codex alone). An agent can route between the three council ask tools without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use ('quick second opinion from Claude, for example from Codex or ChatGPT') and explicit alternatives with selection conditions. It further scopes sub-cases: pass workspace whenever the question concerns code/logs in the project, omit it otherwise, and omit it when a session id is supplied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
council_ask_codexAsk Codex (ChatGPT) onlyARead-only
Ask Codex (ChatGPT) alone, through the user's Codex CLI signed in with ChatGPT, and return its answer. Use it for a quick second opinion from ChatGPT; use council_ask when the answer should also be cross-checked by Claude, or council_ask_claude for Claude alone. It uses the user's ChatGPT plan and usually answers within a minute (longer at high effort, when it returns a job_id for council_result). With workspace it reads the project but never changes it; its session carries over between calls.
| Name | Required | Description | Default |
|---|---|---|---|
| model | No | Optional Codex (ChatGPT) model override, e.g. gpt-5.6-sol. Omit to use the configured default; set only when the user asks for a specific one. | |
| skill | No | Optional: the name of an installed skill both models may use for this question, at the steps where they judge it is needed, including any sub-agents it calls for; for several skills, their names separated by commas ("llm-council, caveman"). Pass only skills the user asks to use (by name, or by a phrase the skill says triggers it). Skills of Claude Code's and Codex's enabled plugins can be named too. Installed: none (install with `codex-claude-council skill add <GitHub URL>`). A step that uses it takes much longer and uses much more of both plans. | |
| effort | No | Optional Codex reasoning effort override. Omit to use the configured default; set only when the user asks for a specific one. | |
| network | No | Optional: whether Codex's shell commands may reach the network (for example to call an API or fetch live data), still read-only on disk. Omit to use the configured default (off unless the user changed it). Pass true only when the user asks for it. | |
| question | Yes | The question, with any context the models need. | |
| workspace | No | Absolute path of the project folder you are working in. Both models then work in it in plan mode: they read it (files, search, read-only commands such as git log and diff) but never change it. Pass it whenever the question is about the code, a change, a fix, an error or logs in this project. Omit only for questions unrelated to any project (or when passing a session id: the session's own folder is used). | |
| session_id | No | Optional: a Codex session the user already has: its id (as shown by `/status`) or the name they gave it with `/rename`; on another machine, user@host:<id or name> (runs there through ssh), to continue in place instead of a new session, so the model keeps that session's memory. Pass it exactly as the user gives it, only when they give one. The council's turns are added to that session, in plan mode (nothing is changed). | |
| web_search | No | Optional: whether the models may search the web and read web pages. Omit to use the configured default (on unless the user changed it). Pass false only when the user asks for no internet access. |
Output Schema
| Name | Required | Description |
|---|---|---|
| text | Yes | The answer (council_debate: its JSON), or the message to act on; the same as the text content. |
| job_id | No | With working or stopped: the job to wait for, or the one stopped. |
| status | Yes | done: text is the answer. working: still running; call council_result with job_id. your_turn (council_join): text is the council's message; reply with council_turn and council_id. stopped: council_cancel stopped job_id. |
| council_id | No | With your_turn: the council to reply to with council_turn. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover safety (readOnlyHint, destructiveHint=false, openWorldHint), and the description adds behavior they cannot express: it bills against the user's ChatGPT plan, typically answers within a minute but goes longer at high effort and then returns a job_id for council_result, workspace access is plan-mode read-only, and session memory carries over between calls. The async job_id path is operationally important and not derivable from the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then siblings, then behavioral facts; no filler sentences. The third sentence is a dense semicolon chain, but every clause (plan usage, latency, job_id, read-only workspace, session carryover) carries distinct information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be explained, and the async job_id note is a bonus. Annotations and the 100%-covered 8-parameter schema handle the rest; the only mild gap is that rate/plan-limit behavior beyond 'uses the user's plan' is left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the 3 baseline applies and the detailed schema already carries model/effort/network/skill semantics. The description goes slightly beyond by tying workspace to 'questions about the code, a change, a fix, an error or logs' and noting read-only plan mode plus session carryover, adding usage context rather than repeating field docs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (ask) and resource (Codex/ChatGPT via the user's Codex CLI) and immediately distinguishes the tool from its siblings by naming council_ask and council_ask_claude and the condition that selects each. An agent can route between the three without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use ('quick second opinion from ChatGPT') plus explicit alternatives and their selection criteria (council_ask when cross-checking with Claude is wanted, council_ask_claude for Claude alone). This is the strongest form of routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
council_cancelStop a running councilADestructive
Stop a running job (a council_ask, council_debate, council_ask_codex, council_ask_claude or council_join): its Codex and Claude CLI processes are ended and its progress is discarded, so its answer can no longer be retrieved. Use it when the user asks to stop, or a council is no longer needed; to check on a job instead, use council_result.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | No | The job_id a council tool returned while still working. Omit to use the most recent job. |
Output Schema
| Name | Required | Description |
|---|---|---|
| text | Yes | The answer (council_debate: its JSON), or the message to act on; the same as the text content. |
| job_id | No | With working or stopped: the job to wait for, or the one stopped. |
| status | Yes | done: text is the answer. working: still running; call council_result with job_id. your_turn (council_join): text is the council's message; reply with council_turn and council_id. stopped: council_cancel stopped job_id. |
| council_id | No | With your_turn: the council to reply to with council_turn. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, but the description goes further by specifying what is destroyed: the Codex and Claude CLI processes are ended and progress is discarded. It also states the practical consequence the annotations cannot convey — the answer is no longer retrievable — which is exactly the irreversibility an agent needs before calling a destructive tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, zero filler. The destructive effect is front-loaded in the first sentence and the routing alternative closes the second, so an agent reading only the first clause still gets the critical warning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and the single optional parameter is fully covered by the schema. The description supplies the safety profile, scope, and sibling routing — everything an agent needs to invoke this destructive tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for the single job_id parameter, and the schema already documents the 'omit to use the most recent job' default behavior. The description adds no additional syntax, format, or edge-case meaning beyond what the schema provides, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Stop a running job') and enumerates the exact job-producing siblings it applies to (council_ask, council_debate, council_ask_codex, council_ask_claude, council_join). It also names the contrasting sibling council_result, so an agent can distinguish it without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly gives the triggering condition ('when the user asks to stop, or a council is no longer needed') and names the alternative for the opposite intent ('to check on a job instead, use council_result'). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
council_debateCodex–Claude debate transcriptARead-only
Run the same council as council_ask but return the whole discussion as JSON: both opening answers, every exchange with each model's reply and verdict, the check of the final answer, and the settings used. Use it when the user wants to see where the models disagreed or how they converged; use council_ask when only the answer matters, since the transcript is long. Same cost and timing as council_ask: both plans' quota, minutes, and a job_id for council_result if it is still running after about 50 s.
| Name | Required | Description | Default |
|---|---|---|---|
| skill | No | Optional: the name of an installed skill both models may use for this question, at the steps where they judge it is needed, including any sub-agents it calls for; for several skills, their names separated by commas ("llm-council, caveman"). Pass only skills the user asks to use (by name, or by a phrase the skill says triggers it). Skills of Claude Code's and Codex's enabled plugins can be named too. Installed: none (install with `codex-claude-council skill add <GitHub URL>`). A step that uses it takes much longer and uses much more of both plans. | |
| network | No | Optional: whether Codex's shell commands may reach the network (for example to call an API or fetch live data), still read-only on disk. Omit to use the configured default (off unless the user changed it). Pass true only when the user asks for it. | |
| question | Yes | The question, with any context the models need. | |
| workspace | No | Absolute path of the project folder you are working in. Both models then work in it in plan mode: they read it (files, search, read-only commands such as git log and diff) but never change it. Pass it whenever the question is about the code, a change, a fix, an error or logs in this project. Omit only for questions unrelated to any project (or when passing a session id: the session's own folder is used). | |
| max_rounds | No | Optional limit on the exchange. After the two independent answers, each model replies to the other's latest message, round after round, until both agree; then the synthesizer writes the final answer and the other checks it. N (1 or more): at most N exchanges. 0: no limit (can take a long time and use a lot of both plans' usage). Omit to use the configured default (5 unless the user changed it). Set only when the user asks for a number of rounds or for agreement without a limit. | |
| web_search | No | Optional: whether the models may search the web and read web pages. Omit to use the configured default (on unless the user changed it). Pass false only when the user asks for no internet access. | |
| codex_model | No | Optional Codex (ChatGPT) model override, e.g. gpt-5.6-sol. Omit to use the configured default; set only when the user asks for a specific one. | |
| synthesizer | No | Optional: which model writes the final answer ("codex" is ChatGPT); the other checks it. Omit to use the configured default (Claude unless the user changed it). | |
| claude_model | No | Optional Claude model override: an alias such as opus, sonnet or fable, or a full model name. Omit to use the configured default; set only when the user asks for a specific one. | |
| codex_effort | No | Optional Codex reasoning effort override. Omit to use the configured default; set only when the user asks for a specific one. | |
| claude_effort | No | Optional Claude effort level override. Omit to use the configured default; set only when the user asks for a specific one. | |
| codex_session_id | No | Optional: a Codex session the user already has: its id (as shown by `/status`) or the name they gave it with `/rename`; on another machine, user@host:<id or name> (runs there through ssh), to continue in place instead of a new session, so the model keeps that session's memory. Pass it exactly as the user gives it, only when they give one. The council's turns are added to that session, in plan mode (nothing is changed). | |
| claude_session_id | No | Optional: a Claude Code session the user already has: its UUID (as shown by `/status`) or the name they gave it with `/rename`; on another machine, user@host:<id or name> (runs there through ssh), to continue in place instead of a new session, so the model keeps that session's memory. Pass it exactly as the user gives it, only when they give one. The council's turns are added to that session, in plan mode (nothing is changed). |
Output Schema
| Name | Required | Description |
|---|---|---|
| text | Yes | The answer (council_debate: its JSON), or the message to act on; the same as the text content. |
| job_id | No | With working or stopped: the job to wait for, or the one stopped. |
| status | Yes | done: text is the answer. working: still running; call council_result with job_id. your_turn (council_join): text is the council's message; reply with council_turn and council_id. stopped: council_cancel stopped job_id. |
| council_id | No | With your_turn: the council to reply to with council_turn. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnly/openWorld/non-idempotent), it discloses the async execution model ('a job_id for council_result if it is still running after about 50 s') and the cost profile ('both plans' quota, minutes'), plus the practical warning that the transcript is long. These are the traits an agent cannot derive from the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three front-loaded sentences with no filler; the return shape, selection rule, and cost/timing come in that order. Slightly dense but every clause adds information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 13-parameter, asynchronous, non-idempotent tool, the description covers selection, cost, polling via job_id, and transcript scope; the return values are further specifiable via the output schema, so nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter is already documented in the schema, and the description only alludes to 'the settings used' being returned. The baseline of 3 applies when the schema carries the parameter burden.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb plus resource ('Run the same council as council_ask but return the whole discussion as JSON') and then enumerates the returned contents (opening answers, exchanges with replies and verdicts, final check, settings). An agent can distinguish it from council_ask purely from the description.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes: 'Use it when the user wants to see where the models disagreed or how they converged; use council_ask when only the answer matters, since the transcript is long.' Names the alternative sibling and the condition that selects each — no inference required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
council_joinDiscuss with the other model yourselfARead-only
Take part in the council yourself, in this conversation, with everything you already know, instead of a separate session of your model: you are one member and the plugin runs the other model (Codex if you are Claude, Claude if you are Codex), optionally continuing the user's own session of it. The steps are the same as council_ask (answer independently, then reply to each other's latest message until both agree, then write and check the final answer). Whenever it is your turn, this tool (or council_turn / council_result) returns the council's message to you: write your reply yourself and send it with council_turn. Use this when the user wants you to discuss with the other model, or gives the id of their session of the other model; use council_ask instead when the user wants a council of two separate sessions. Only the other model runs a CLI session; your turns are written here, in this conversation.
| Name | Required | Description | Default |
|---|---|---|---|
| me | No | Which model you are: "claude" if you are Claude (Claude Code, Claude Desktop), "codex" if you are Codex or ChatGPT. The other model is the one the plugin runs. | |
| skill | No | Optional: the name of an installed skill both models may use for this question, at the steps where they judge it is needed, including any sub-agents it calls for; for several skills, their names separated by commas ("llm-council, caveman"). Pass only skills the user asks to use (by name, or by a phrase the skill says triggers it). Skills of Claude Code's and Codex's enabled plugins can be named too. Installed: none (install with `codex-claude-council skill add <GitHub URL>`). A step that uses it takes much longer and uses much more of both plans. | |
| network | No | Optional: whether Codex's shell commands may reach the network (for example to call an API or fetch live data), still read-only on disk. Omit to use the configured default (off unless the user changed it). Pass true only when the user asks for it. | |
| question | Yes | The question, with any context the models need. | |
| workspace | No | Absolute path of the project folder you are working in. Both models then work in it in plan mode: they read it (files, search, read-only commands such as git log and diff) but never change it. Pass it whenever the question is about the code, a change, a fix, an error or logs in this project. Omit only for questions unrelated to any project (or when passing a session id: the session's own folder is used). | |
| max_rounds | No | Optional limit on the exchange. After the two independent answers, each model replies to the other's latest message, round after round, until both agree; then the synthesizer writes the final answer and the other checks it. N (1 or more): at most N exchanges. 0: no limit (can take a long time and use a lot of both plans' usage). Omit to use the configured default (5 unless the user changed it). Set only when the user asks for a number of rounds or for agreement without a limit. | |
| web_search | No | Optional: whether the models may search the web and read web pages. Omit to use the configured default (on unless the user changed it). Pass false only when the user asks for no internet access. | |
| other_model | No | Optional model override for the other model. Omit to use the configured default; set only when the user asks for a specific one. | |
| synthesizer | No | Optional: which model writes the final answer, "claude" or "codex" (you or the other model); the other checks it. Omit to write it yourself (the host); pass it only when the user names who should write it. | |
| other_effort | No | Optional effort override for the other model (Codex: none, minimal, low, medium, high, xhigh; Claude: low, medium, high, xhigh, max). Omit to use the configured default; set only when the user asks for a specific one. | |
| other_session_id | No | Optional: the id or /rename name of the user's own session of the other model (a Codex session if you are Claude, a Claude Code session if you are Codex), or user@host:<id or name> for one on another machine (it runs there through ssh), to continue in place with its memory. Pass it exactly as the user gives it, only when they give one; never your own session. |
Output Schema
| Name | Required | Description |
|---|---|---|
| text | Yes | The answer (council_debate: its JSON), or the message to act on; the same as the text content. |
| job_id | No | With working or stopped: the job to wait for, or the one stopped. |
| status | Yes | done: text is the answer. working: still running; call council_result with job_id. your_turn (council_join): text is the council's message; reply with council_turn and council_id. stopped: council_cancel stopped job_id. |
| council_id | No | With your_turn: the council to reply to with council_turn. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnlyHint, destructiveHint=false, openWorldHint), so the bar is lower. The description still adds real mechanics: only the other model runs a CLI session, your turns are written in this conversation, and the exchange continues (answers, mutual replies, synthesis and check) via council_turn/council_result. It stops short of describing the response payload itself, but that is largely covered by the output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The key differentiator (you participate here rather than in a separate session) is front-loaded, and the workflow and routing follow in a logical order. It is dense and slightly repetitive around the turn-taking mechanism, but for a multi-turn tool of this complexity little of it is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex, multi-turn, 11-parameter tool with an output schema and full annotation coverage, the description supplies the missing pieces: the interaction model, who runs which session, how turns are exchanged, and when to choose the sibling. An agent has enough to call and orchestrate it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% across 11 parameters, so the schema already documents each one thoroughly. The description only touches parameter semantics lightly (the other model's session id, and the fact that a session id selects this tool over council_ask); it adds little syntax or default detail beyond the schema. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('take part in the council yourself, in this conversation') and immediately contrasts it with the sibling it is not ('instead of a separate session of your model'). An agent can distinguish it from council_ask and council_debate without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit routing: 'Use this when the user wants you to discuss with the other model, or gives the id of their session of the other model; use council_ask instead when the user wants a council of two separate sessions.' It also states the follow-up path (write your reply and send it with council_turn). Both the trigger and the alternative are named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
council_resultGet a running council's answerARead-only
Wait for a job that returned status working with a job_id (from council_ask, council_debate, council_ask_codex, council_ask_claude or council_join), and return its answer, or with council_join your next turn. Waits up to about 50 s and returns as soon as something is ready; if the job is still working, call it again. Use it instead of asking the same question again, which would start a second job and use the plans twice. Waiting uses no model quota.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | No | The job_id a council tool returned while still working. Omit to use the most recent job. |
Output Schema
| Name | Required | Description |
|---|---|---|
| text | Yes | The answer (council_debate: its JSON), or the message to act on; the same as the text content. |
| job_id | No | With working or stopped: the job to wait for, or the one stopped. |
| status | Yes | done: text is the answer. working: still running; call council_result with job_id. your_turn (council_join): text is the council's message; reply with council_turn and council_id. stopped: council_cancel stopped job_id. |
| council_id | No | With your_turn: the council to reply to with council_turn. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnlyHint=true, destructiveHint=false) but not the polling semantics, which the description supplies: a ~50 s wait that returns as soon as something is ready, the need to re-call while still working, and the notable fact that waiting consumes no model quota while re-asking burns the plan twice. This explains the otherwise puzzling idempotentHint=false for a read-only tool (council_join advances the turn) and adds real operational context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is a single dense paragraph, but it is front-loaded with the trigger and retry rule, and every clause earns its place (sibling list, wait duration, retry, anti-pattern, quota note). Slightly run-on rather than wasteful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and the description still covers the polling loop, the retry rule, the sibling routing, and the quota trade-off. Nothing an agent needs to invoke this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents job_id's origin and the omit-to-use-most-recent behavior. The description reinforces the source tools but adds no syntax or format detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action (wait for a job that returned status 'working' with a job_id) and the result (its answer, or with council_join the next turn). It explicitly names the sibling tools that produce such job_ids (council_ask, council_debate, council_ask_codex, council_ask_claude, council_join), so an agent can distinguish it from the start-a-job siblings without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use ('Wait for a job that returned status working with a job_id'), the alternative it replaces ('Use it instead of asking the same question again, which would start a second job and use the plans twice'), and the retry condition ('if the job is still working, call it again'). Both the positive trigger and the anti-pattern are spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
council_turnSend your turn to the councilA
Send your reply to the council's latest message, after council_join, council_turn or council_result returned your turn, and wait for the next step. Only for councils started with council_join; the text is passed to the other model as written, so write the complete reply yourself. If the council is not waiting for you, it says so and you call council_result instead; if the next step takes longer than about 50 s, call council_result with the council_id.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | Your complete reply to that message, written by you. | |
| council_id | Yes | The council_id from the message you are replying to. |
Output Schema
| Name | Required | Description |
|---|---|---|
| text | Yes | The answer (council_debate: its JSON), or the message to act on; the same as the text content. |
| job_id | No | With working or stopped: the job to wait for, or the one stopped. |
| status | Yes | done: text is the answer. working: still running; call council_result with job_id. your_turn (council_join): text is the council's message; reply with council_turn and council_id. stopped: council_cancel stopped job_id. |
| council_id | No | With your_turn: the council to reply to with council_turn. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare a non-read-only, open-world, non-idempotent, non-destructive write, and the description adds behavioral context beyond that: the call blocks waiting for the next step, it can exceed ~50 s and must then be abandoned for council_result, and the text is forwarded verbatim to the other model. It also discloses the 'not waiting for you' response path rather than hiding it.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and consequence, and every clause carries information (prerequisite, verbatim passing, error path, timeout path). The final sentence chains three conditional clauses, making it denser than ideal, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, and the description still covers the prerequisites, the blocking/timeout behavior, and the not-waiting error path. Nothing an agent needs to invoke this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning about `text`: it is passed to the other model as written, so the caller must compose the complete reply rather than a fragment. `council_id` is also implicitly sourced from the message being replied to, matching the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (send your reply to the council's latest message) and scopes it to councils started with council_join, which separates it from council_ask/council_debate siblings. An agent can identify the tool and its role in the turn cycle without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to call it (after council_join, council_turn or council_result returned your turn) and when not to (only for councils started with council_join). It also names the fallback: if the council is not waiting, call council_result, and repeats that routing when the wait exceeds ~50 s.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
8 tool updates
v0.13.4- First observed
council_ask - First observed
council_ask_claude - First observed
council_ask_codex - First observed
council_cancel - First observed
council_debate - First observed
council_join - First observed
council_result - First observed
council_turn
TDQS
Scored across 8 tools
The tools have largely distinct purposes and the descriptions actively cross-reference each other (single-model asks vs. cross-check vs. transcript vs. self-participation vs. async polling vs. cancel). The main subtlety is council_ask vs council_debate, which run the same council but return the answer versus the full transcript—an agent could occasionally pick the wrong one, though descriptions clarify the tradeoff.
All tools share a consistent council_ namespace prefix in snake_case, and follow an action-focused pattern (council_ask, council_join, council_turn, council_result, council_cancel). Minor irregularity: council_ask_codex / council_ask_claude use a model suffix while the combined council_ask does not, but the scheme is still readable and predictable.
Eight tools is well within the ideal range for this domain. Each earns its place: the three ask variants for single/cross-checked answers, debate for transcripts, join/turn for self-participation, and result/cancel for the async job lifecycle.
The surface covers the full lifecycle: starting single- and dual-model jobs, participating as a model yourself, polling long-running jobs, and cancelling them. The only minor gap is no way to enumerate or list previously started jobs/sessions, but result and cancel let agents recover and manage state adequately.
Maintenance
Related MCP Connectors
Multi-model AI debates: GPT-4o, Claude, Gemini & 200+ models discuss, then synthesize insight.
Source-checked CLI guides and model-aware planning for Claude Code, Codex, and Grok Build.
Ask GPT, Claude, Gemini and Grok at once: one consensus answer plus where they agree and split.
Share context and questions between Claude instances — VS Code, claude.ai web, and mobile.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceConnects Claude Code with multiple AI models (Gemini, Grok-3, ChatGPT, DeepSeek) simultaneously, allowing users to get diverse AI perspectives, conduct AI debates, and leverage each model's unique strengths.155MIT
- AlicenseAqualityDmaintenanceBridges Claude and OpenAI's Codex CLI for AI-powered code analysis, generation, and review, with support for session management, web search, and structured output.6687 npm645ISC
- AlicenseNot gradedqualityDmaintenanceLets Claude Code query multiple AI models (Gemini, Grok, ChatGPT, DeepSeek) for diverse perspectives, code reviews, debates, and more.MIT
- AlicenseBqualityDmaintenanceAn open-source MCP server that connects your IDE or AI assistant to the Codex CLI, enabling non-interactive automation with codex exec, safe sandboxed edits with approvals, and large-scale code analysis via @ file references.86 npmMIT