# 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

- Skill: `ellyseum/cordy` (Agent Skill)
- Install (CLI): `npx skillmds@latest add ellyseum/cordy`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ellyseum/cordy/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: ellyseum (https://skillmd.com/u/ellyseum)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ellyseum/cordy

---


# 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:

1. `${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.
2. `${XDG_CACHE_HOME}/claude-cordyceps/preflight.json` — XDG override.
3. `~/.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.

```bash
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

```json
{
  "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.

```bash
cordy spawn codex --name ask-codex --mode=exec
cordy send ask-codex "<question>" --timeout 300
cordy kill ask-codex
```

For Claude variants:

```bash
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`:

```bash
# 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:

```bash
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.

```bash
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.

```bash
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.

```bash
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.

```bash
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.

```bash
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:

```bash
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`.

