| name | cordy |
| description | Drive `cordy` (the @ellyseum/cordyceps CLI) to consult peer LLMs from
different model families — Codex (OpenAI), Gemini (Google), Ollama
(local), and additional Claude variants — for ANY task where
cross-model input improves the answer: code reviews, plan critiques,
red-teaming, brainstorming, decision exploration, claim
cross-checking, meta-reviews of reviews. Capability skill — Claude
picks the right shape (single peer query, silo'd panel + chair,
adversarial pair, divergent panel, tiered escalation, persistent
sidecar, meta-review) for the user's ask.
ACTIVATE on explicit cross-model phrases: "consult peers", "spawn
council", "convene council", "ask the panel", "code review with
peers", "plan critique with peers", "brainstorm with peers" /
"brainstorm with multiple LLMs", "what would <name-of-model> think
about this", "ask Codex/Gemini/Ollama".
TIGHT, NOT BROAD: phrases like "second opinion", "peer review",
"plan review", "red team this" are AMBIGUOUS — they can mean "Claude
take another pass" rather than "spawn external models". Activate on
those ONLY when accompanied by a target artifact (file, plan, claim)
AND a peers/panel/multi-model signal. Otherwise ask a one-line
clarifying question first.
SKIP on trivial / time-sensitive tasks. Cross-model consultation
costs latency and tokens; only invoke when the task rewards
multiple perspectives.
|
Cordy — cross-model consultation
This skill teaches you how to drive cordy for cross-model
consultation. It's a capability skill, not a recipe — pick the
shape that fits the user's ask.
The thesis
Models from different training lineages have uncorrelated blind spots.
A bug Claude misses is often a bug Codex catches. A claim Gemini gets
wrong is often one a local Ollama model nails. On any task that
rewards multiple perspectives, a panel from different families lifts
quality measurably.
Note: cross-model consultation is adversarial sanity-checking, not
grounded fact verification. Consensus among LLMs is not truth — it's
"these models all agree". For sourced verification you need tools
(web search, file reads, etc.) inside the peer's own session, not
this skill.
Pre-flight: check cordy + drivers (do this first, every time)
Before any cordy invocation, read the preflight cache. The plugin's
SessionStart hook writes the cache to multiple locations — pick the
first one that exists:
${CLAUDE_PLUGIN_DATA}/preflight.json — canonical, only set inside
the Claude Code harness; may not be exported to Bash subshells,
so the env-var probe can return empty even when the file exists.
${XDG_CACHE_HOME}/claude-cordyceps/preflight.json — XDG override.
~/.cache/claude-cordyceps/preflight.json — always written as a
shell-accessible mirror; this is the fallback that always works
from a Bash subshell on POSIX.
for p in \
"${CLAUDE_PLUGIN_DATA:+$CLAUDE_PLUGIN_DATA/preflight.json}" \
"${XDG_CACHE_HOME:+$XDG_CACHE_HOME/claude-cordyceps/preflight.json}" \
"$HOME/.cache/claude-cordyceps/preflight.json"; do
[ -n "$p" ] && [ -f "$p" ] && cat "$p" && break
done
If no cache file exists at any of those paths, probe inline:
cordy --ephemeral drivers --json. (This means the SessionStart hook
either hasn't run yet or failed silently — surface the inline-probe
result and proceed.)
Preflight status schema
{
"schemaVersion": 1,
"ts": "...",
"testedRange": "^0.5.2",
"cordy": { "installed": true|false, "version": "x.y.z", "execError"?: "..." },
"drivers": [{ "id": "...", "available": true|false, "compat": "...", "warnings": [...] }],
"driverProbeError"?: "...",
"preflightError"?: "..."
}
Decision tree — check fields in this order (first match wins):
| State | Tell the user |
|---|
preflightError set | Preflight itself crashed (<preflightError>). The cordy.installed field is unreliable in this state — surface the message and ask the user to file an issue, then probe inline with cordy --ephemeral drivers --json to recover. |
cordy.execError set | Cordy is installed but couldn't be executed (<execError>). Likely a permissions or shell-policy issue; do NOT suggest reinstall. |
cordy.installed === false | Cordy not on PATH. Install: npm i -g @ellyseum/cordyceps. Ask permission before running it. |
driverProbeError set | Cordy ran but the driver probe failed (<driverProbeError>). Try cordy doctor for a clearer error. |
drivers all available: false | No peer drivers reachable. List the README's per-driver setup steps. |
| Some drivers available | Proceed; build the panel from available: true drivers. |
What cordy gives you
cordy is a local daemon plus CLI. Two surfaces:
- High-level subcommands (use these whenever they fit):
cordy council review <path> — silo'd file review with chair
synthesis. Built-in chunking for files > 30KB.
cordy council diff [base] [--staged] [--scope <path>] — same,
for git diffs.
- Low-level primitives for everything else:
cordy spawn <driver> --name <id> --mode=<mode> [--key=val ...]
cordy send <id> "<prompt>" --timeout <s>
cordy list / cordy state <id>
cordy interrupt <id> (cancel current work)
cordy kill <id>
Driver naming — two distinct surfaces
This is easy to get wrong. Different commands accept different driver syntaxes.
| Command | Driver argument shape |
|---|
cordy spawn | bare driver id or alias: claude, claude-code, codex, cx, gemini, gm, ollama, ol. To pick a Claude model, pass --model=opus or --model=sonnet. |
cordy council --panel / --chair | comma-separated list of driver or driver:model shorthand: codex,gemini,claude:sonnet,claude:opus. |
Don't use claude:opus as the first arg to cordy spawn — that's
council-only shorthand and will fail (cordy emits a generic
"Internal error" without surfacing the parse failure, so the wrong-
syntax cause isn't obvious from the message alone). Use
cordy spawn claude --mode=exec --model=opus instead.
cordy spawn flag form is --key=value (with =), per its
[--key=val ...] parser. --mode=exec works; --mode exec does not.
Use --mode=exec whenever possible — much cleaner output than PTY,
no TUI parsing surprises, faster.
Common shapes (ingredients, not recipes)
Pick what fits the user's ask; combine; deviate as needed.
Shape 1 — Single peer query
One spawn, one send, one kill. For "ask Codex/Gemini what they think
about X" with no synthesis needed.
cordy spawn codex --name ask-codex --mode=exec
cordy send ask-codex "<question>" --timeout 300
cordy kill ask-codex
For Claude variants:
cordy spawn claude --name ask-claude --mode=exec --model=opus
cordy send ask-claude "<question>" --timeout 300
cordy kill ask-claude
Shape 2 — Silo'd panel + host-as-chair synthesis
The default for code review, plan critique, design review. Each peer
reviews independently (no peer sees another's output); you (the
host Claude session) synthesize their findings.
The host has the user's full conversation context, framing, and the
panel's outputs all in one place — that's exactly the chair's job. No
reason to spawn a separate chair LLM and pay the extra round-trip;
read the per-reviewer findings and synthesize them yourself.
For files and git diffs, cordy ships this with --no-chair:
cordy council review <path> \
--panel codex,gemini,claude:sonnet,claude:opus \
--no-chair \
--timeout 600 --json
cordy council diff [base] [--staged] [--scope <path>] \
--panel codex,gemini,claude:opus \
--no-chair \
--timeout 600 --json
--no-chair (cordy ≥ 0.5.2) skips the chair-spawn entirely; the
result's synthesis field is empty. Read reviews[] and produce
the synthesis yourself, then present it to the user.
On cordy < 0.5.2 (no --no-chair): pass --chair codex (or any
cheap chair), use --json, IGNORE synthesis/chairError, and
synthesize from reviews[] yourself. The wasted chair spawn is
unavoidable on older cordy.
When TO let cordy chair (rare): long-running automated runs where
the host isn't around to consume per-reviewer JSON, or "give me a
single verdict" workflows where the user explicitly wants one model
producing the synthesis without your interpretation. Pass
--chair codex (or claude:opus) explicitly in those cases.
Note: --panel and --chair accept the driver:model shorthand
(claude:opus); cordy spawn does NOT.
For non-file targets (a plan in chat, a design proposal, a decision),
do the orchestration manually with the primitives:
PFX=council-$$
PROMPT='Review the following plan. For each finding: severity, what is wrong, what to do about it. Output JSON findings array on the LAST line.
PLAN:
<the user plan>'
cordy spawn codex --name "$PFX-codex" --mode=exec
cordy spawn gemini --name "$PFX-gemini" --mode=exec
cordy spawn claude --name "$PFX-opus" --mode=exec --model=opus
for n in codex gemini opus; do
( cordy send "$PFX-$n" "$PROMPT" --timeout 600 > "/tmp/$PFX-$n.txt" 2>&1 ) &
done
wait
for n in codex gemini opus; do cordy kill "$PFX-$n"; done
Shape 3 — Adversarial pair (for / against)
When the user wants a decision explored from both sides.
cordy spawn codex --name advocate --mode=exec
cordy spawn gemini --name critic --mode=exec
( cordy send advocate "Argue FOR <X>. Strongest case." --timeout 300 > /tmp/advocate.txt ) &
( cordy send critic "Argue AGAINST <X>. Strongest case." --timeout 300 > /tmp/critic.txt ) &
wait
cordy kill advocate
cordy kill critic
Shape 4 — Divergent brainstorm panel
Same prompt to N peers, no chair — present all responses or cluster
them.
PFX=brain-$$
cordy spawn codex --name "$PFX-codex" --mode=exec
cordy spawn gemini --name "$PFX-gemini" --mode=exec
cordy spawn claude --name "$PFX-opus" --mode=exec --model=opus
cordy spawn claude --name "$PFX-sonnet" --mode=exec --model=sonnet
for n in codex gemini opus sonnet; do
( cordy send "$PFX-$n" "Brainstorm: <prompt>. Give 5 distinct ideas." --timeout 300 > "/tmp/$PFX-$n.txt" ) &
done
wait
for n in codex gemini opus sonnet; do cordy kill "$PFX-$n"; done
Shape 5 — Tiered escalation (cheap-first)
For high-volume claim cross-checks. Start cheap (local Ollama);
escalate only when uncertain or contested.
cordy spawn ollama --name fc --mode=server-http
cordy send fc "<claim>" --timeout 60
cordy spawn codex --name fc-codex --mode=exec
cordy send fc-codex "<claim>" --timeout 180
cordy kill fc
cordy kill fc-codex
Shape 6 — Persistent sidecar
Spawn once, send multiple times during an iterative session, kill at
the end. For "keep a challenger around while I refactor" workflows.
cordy spawn codex --name sidecar --mode=exec
cordy send sidecar "<follow-up question>" --timeout 300
cordy interrupt sidecar
cordy kill sidecar
Shape 7 — Meta-review (review-of-review)
Feed one peer's verdict to another peer for evaluation. Highest-signal
shape — second-peer critique often surfaces what both you AND the
first reviewer missed.
cordy spawn gemini --name meta --mode=exec
cordy send meta "Another LLM reviewed <X> and produced these findings: \
<first peer's verdict>
The <X> being reviewed: <content or path>
Evaluate the first reviewer. For each finding: do you agree, disagree,
partially agree? What did they miss?" --timeout 600
cordy kill meta
Building the invocation
Whichever shape you pick, build flags from the preflight context:
- Panel: pick from drivers where
available: true. Aim for
cross-family diversity (one of: codex, gemini, ollama; plus one or
two Claude variants). Two Claude models is fine when stakes are
high — they catch different things despite shared lineage.
- Chair: default to
--no-chair and synthesize yourself —
you're the chair. Only override (with --chair codex or
claude:opus) for the rare "give me one model's verdict without
your interpretation" workflow. Avoid Ollama as chair if you do
override — synthesis is where local models tend to drop quality.
- Timeout: ~300s for a single peer; 600s for a multi-peer
council on a real file or diff; 900s for large content with
chunking.
- Mode:
--mode=exec for one-shot work (default for council);
--mode=server-http for Ollama; --mode=pty only when you need
TUI control flow.
--json on cordy council: structured per-peer output for
consumption. Omit to print the chair's verdict directly.
Spawning concurrent peers safely (low-level primitives)
When the high-level subcommands don't fit:
- Unique agent names per task. Prefix with a session-scoped id
(
PFX=task-$$ or a random hex string) so concurrent invocations
don't collide.
- Send in parallel via background subshells +
wait (or the Bash
tool's run_in_background parameter for proper tracking).
- Always kill spawned agents when done, even on error paths —
use a trap or explicit cleanup loop.
Long-running councils — don't poll, don't monitor
Council reviews on real files take 5–15 minutes (per-reviewer model
calls run concurrently; total wall-clock = slowest reviewer + chunk
synthesis). Run them with the Bash tool's run_in_background: true
and write JSON output to a tempfile:
cordy council review <path> --panel <drivers> --no-chair \
--timeout 600 --json > /tmp/council-$$.json 2>&1
When the background command finishes, the runtime fires a
<task-notification> automatically. Do not:
- Set up a
Monitor tool stream — there are no intermediate events
during a council run; cordy buffers per-reviewer output until all
reviewers finish, then writes one JSON blob in one shot.
- Poll the output file with repeated
tail / wc -c calls — it
stays empty until the slowest reviewer returns, then becomes the
full result. Polling burns context for nothing.
- Use
sleep loops to "check back" — the auto-notification is the
signal.
The right pattern: fire-and-forget background run, do other work or
respond to the user, surface findings when the notification lands.
If the run hasn't notified in ≳1.5× the panel's max --timeout,
something is genuinely stuck — at that point investigate.
Council reviewer modes — Claude defaults to exec (cordy 0.5.3+)
Claude reviewers in council default to exec mode (claude --print)
not pty. PTY output parsing was unreliable for headless review use
— TUI escape codes and multi-line JSON arrays caused silent reviewer
parse-failures, degrading 4-driver panels to 2 drivers in the wild.
If you absolutely need PTY for a Claude reviewer (rare — interactive
back-and-forth doesn't fit the council shape), pass an explicit
profile via the JSON-RPC method (council.review with
{ panel: [{ driver: "claude", profile: { mode: "pty" } }] }).
The CLI --panel shorthand always uses the default mode.
Failure modes
- Driver auth failure. Cordy emits a clear error; surface it.
Tell the user what env var or login command the failing driver
needs.
- Timeout. Bump
--timeout, shrink the prompt, or use cordy's
built-in chunking (in cordy council review).
- Peers disagree. Don't collapse to majority — the minority
opinion is often where the real insight is. Surface the
disagreement.
- All available drivers same family. Diversity benefit is
reduced. Tell the user; offer to proceed or pause to install
another driver.
Anti-patterns
- Don't activate on chitchat. "Sounds good" / "that works" are not
consult requests.
- Don't activate on ambiguous "second opinion" / "peer review" /
"plan review" without a clear cross-model signal AND a target
artifact. When in doubt, ask one clarifying question.
- Don't auto-install
cordy or any driver CLI without permission.
- Don't write to
~/.cordyceps/ — that's cordy's own state dir.
Use ${CLAUDE_PLUGIN_DATA} or ~/.cache/claude-cordyceps/.
- Don't fabricate peer responses. If a peer errored or timed out,
say so plainly.
- Don't burn an Ollama call when a faster cloud peer is available
unless the user specifically asked for cheap / local.
- Don't re-implement what cordy ships. If
cordy council diff
exists, use it instead of writing a manual diff-review loop.
- Don't pass
claude:opus / claude:sonnet as the driver argument
to cordy spawn — that's council-panel shorthand only and will
fail. Use bare claude + --model=opus.