Cordy
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.From its SKILL.md
npx -y skills add ellyseum/claude-cordyceps --skill cordyAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
16.8 KB, as published. Nobody here has run it
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:
# File review — host as chair
cordy council review <path> \
--panel codex,gemini,claude:sonnet,claude:opus \
--no-chair \
--timeout 600 --json
# Diff review — host as chair
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>'
# Spawn — note bare driver names + --model=<x> for Claude variants
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
# Parallel send
for n in codex gemini opus; do
( cordy send "$PFX-$n" "$PROMPT" --timeout 600 > "/tmp/$PFX-$n.txt" 2>&1 ) &
done
wait
# Read each, dedupe, synthesize, present.
# Cleanup
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
# Read both, synthesize trade-offs.
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
# Cluster + dedupe + present
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
# If confident → done. Otherwise:
cordy spawn codex --name fc-codex --mode=exec
cordy send fc-codex "<claim>" --timeout 180
# Compare; surface disagreement to the user.
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
# ... in subsequent turns, as the user iterates ...
cordy send sidecar "<follow-up question>" --timeout 300
cordy interrupt sidecar # cancel current work if stuck
# ... at end of session ...
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-chairand synthesize yourself — you're the chair. Only override (with--chair codexorclaude: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=execfor one-shot work (default for council);--mode=server-httpfor Ollama;--mode=ptyonly when you need TUI control flow. --jsononcordy 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'srun_in_backgroundparameter 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
Monitortool 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 -ccalls — it stays empty until the slowest reviewer returns, then becomes the full result. Polling burns context for nothing. - Use
sleeploops 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 (incordy 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
cordyor 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 diffexists, use it instead of writing a manual diff-review loop. - Don't pass
claude:opus/claude:sonnetas the driver argument tocordy spawn— that's council-panel shorthand only and will fail. Use bareclaude+--model=opus.