An adversarial agent that challenges your AI agent session's reasoning.
LLMs take the path of least resistance by design. They optimize for coherence, not correctness. Once an LLM picks a framing early in a conversation — "this is a performance problem", "we need to refactor this module" — it will defend and reinforce that framing for the rest of the session, even when the evidence points elsewhere.
This isn't a bug. It's how autoregressive generation works: each token is conditioned on everything before it. The longer the conversation, the deeper the rut. The agent builds a narrative, and then every new input gets absorbed into that narrative — confirming it, never breaking it.
You won't notice because the agent sounds confident. It gives you structured plans, clean code, reasonable explanations. Everything looks right. But the framing was set in turn 3, and by turn 40 you've built the wrong thing well.
The Challenger breaks the frame. It reads the full conversation history of another session, finds the point where the agent's narrative cracks under a context it cannot contain, and injects one precise challenge — not advice, not a review, but a fact or question that forces the agent to re-examine its assumptions.
┌──────────────────────────┬──────────────────────────────┐
│ Session A │ Session B │
│ Your AI agent │ /challenge │
│ │ │
│ Working on task X... │ "The agent frames this as │
│ │ simple/complex. But the │
│ │ real axis is reversible/ │
│ │ irreversible — and this │
│ │ choice is irreversible." │
│ │ │
│ 📨 Challenge received: │ You: inject it │
│ "Is this reversible?" │ │
└──────────────────────────┴──────────────────────────────┘
- Work with your AI agent normally in Session A
- Open a second session (Session B)
- Type
/challenge - Pick the session you want to challenge from the list
- The Challenger reads the full history and generates a challenge
- You review it, then say "inject" to send it to Session A
- Session A receives the challenge and responds
git clone https://github.com/osbornecox/challenger-agent.git
cd challenger-agent
./install.shThe installer does everything:
- Builds the TypeScript code
- Links the
challengerandchallenger-dumpCLI commands - Installs the
/challengeskill for Claude Code - Sets up claude-peers-mcp for cross-session messaging
Requirements: Node.js 18+, Claude Code CLI, git.
After install: Restart any open Claude Code sessions to pick up the new MCP server.
Open a second Claude Code session and type:
/challenge
That's it. The skill will:
- Show you a list of recent sessions with the last agent message
- You pick one by number
- It reads the full conversation history
- Generates a challenge using the EXTRACT → DISPLACE → CHALLENGE method
- Asks if you want to inject it into the target session
# List sessions
challenger-dump --list
# Dump full session history
challenger-dump <session-id>
# Interactive challenge loop (uses claude -p under the hood)
challengerNote: The standalone CLI cannot inject into running Claude Code sessions. Use the /challenge skill for that.
EXTRACT → What distinctions is the agent using?
"It sees this as performance vs readability"
DISPLACE → What distinctions is it BLIND to?
"It's not seeing correctness vs speed-of-iteration"
CHALLENGE → One stone in the river
"This optimization locks you into a schema that's
impossible to migrate later. Is the 50ms worth it?"
The Challenger doesn't write reviews. It identifies the hidden framing axis the agent is stuck on, finds an alternative axis that reveals a blind spot, and throws one stone.
The /challenge skill uses claude-peers-mcp to send messages between Claude Code sessions:
- Both sessions register as "peers" via the MCP server
- The Challenger calls
list_peersto find the target session - It calls
send_messageto deliver the challenge - The target session receives it instantly
| Agent | Status | Notes |
|---|---|---|
| Claude Code | Supported | Full support: read history, inject via MCP |
| Codex | Planned | Adapter interface ready |
| Gemini CLI | Planned | Adapter interface ready |
| Cursor | Planned | — |
| Aider | Planned | — |
challenger-agent/
├── skill/
│ └── challenge.md ← /challenge skill for Claude Code
├── src/
│ ├── cli.ts ← Standalone CLI entry point
│ ├── dump.ts ← Session list + history dump
│ ├── index.ts ← Public API
│ ├── core/
│ │ ├── types.ts ← Adapter interface
│ │ ├── challenger.ts ← Interactive challenge loop (standalone)
│ │ ├── watcher.ts ← Real-time session file watcher
│ │ └── formatter.ts ← Terminal output formatting
│ └── adapters/
│ ├── index.ts ← Adapter registry
│ └── claude.ts ← Claude Code JSONL adapter
├── install.sh ← One-command setup
├── package.json
├── tsconfig.json
└── LICENSE ← MIT
- Create
src/adapters/your-agent.tsimplementing theAdapterinterface - Register it in
src/adapters/index.ts - All commands work automatically
If you prefer not to use the install script:
# Build
npm install
npm run build
npm link
# Install skill
cp skill/challenge.md ~/.claude/commands/challenge.md
# Install claude-peers-mcp
git clone https://github.com/louislva/claude-peers-mcp.git ~/claude-peers-mcp
cd ~/claude-peers-mcp && bun install
claude mcp add --scope user --transport stdio claude-peers -- \
$(which bun) ~/claude-peers-mcp/server.tsMIT