| name | duel-agents-routing |
| description | CLI, SDK, and IDE plugins for Duel Agents - an LLM routing layer that runs prompts against multiple models and picks the cheapest winning answer |
| triggers | ["set up duel agents routing","install duel agents for cursor","configure duel agents api","use duel agents sdk","route llm requests through duel","integrate duel agents with claude code","add multi-model llm routing","configure openclaw with duel agents"] |
Duel Agents Routing
Skill by ara.so — AI Agent Skills collection.
Overview
Duel Agents is an IDE-native routing layer that runs prompts against multiple LLM models simultaneously and selects the cheapest answer that meets quality thresholds. It provides:
- Automatic model selection via
duel-auto model name
- Cost optimization by choosing cheaper models when quality is sufficient
- OpenAI-compatible and Anthropic-compatible APIs
- IDE integrations for Claude Code, Cursor, Codex, and OpenClaw
- TypeScript SDK for building custom agents and applications
The service routes traffic through https://duelagents.com/v1 using Duel API keys (duel_<prefix>_<secret>).
Prerequisites
You must have a Duel API key. Raw Anthropic or OpenAI keys will not work.
- Subscribe at https://duelagents.com/dashboard/settings
- Create an API key from the dashboard
- Key format:
duel_ + 8 characters + _ + 32 characters
Installation
Quick Start (All Tools)
export DUEL_API_KEY=duel_yourprefix_yoursecret
npx @duel-agents/install all
npx @duel-agents/install doctor
Per-Tool Installation
npx @duel-agents/install claude-code
npx @duel-agents/install cursor
npx @duel-agents/install codex
npx @duel-agents/install openclaw
SDK for Custom Applications
npm install @duel-agents/sdk
Configuration
Environment Variables
| Variable | Required | Purpose |
|---|
DUEL_API_KEY | Yes | Your Duel API key from the dashboard |
DUEL_AGENTS_API_KEY | No | Alias for DUEL_API_KEY |
DUEL_PROXY_URL | No | Override proxy URL (staging environments only) |
OPENCLAW_CONFIG_PATH | No | Custom OpenClaw config file path |
Setting Environment Variables
.env file:
DUEL_API_KEY=duel_abc12345_def67890ghijklmnopqrstuvwxyz12
Shell export:
export DUEL_API_KEY=duel_abc12345_def67890ghijklmnopqrstuvwxyz12
SDK Usage
OpenAI-Compatible API
import { DuelClient } from "@duel-agents/sdk";
const duel = new DuelClient({
apiKey: process.env.DUEL_API_KEY!,
});
const response = await duel.chat.completions.create({
model: "duel-auto",
messages: [
{ role: "system", content: "You are a helpful coding assistant." },
{ role: "user", content: "Explain TypeScript generics briefly." }
],
temperature: 0.7,
max_tokens: 500,
});
console.log(response.choices[0].message.content);
Anthropic-Compatible API
import { DuelClient } from "@duel-agents/sdk";
const duel = new DuelClient({
apiKey: process.env.DUEL_API_KEY!,
});
const message = await duel.messages.create({
model: "duel-auto",
max_tokens: 1024,
messages: [
{ role: "user", content: "Write a Python function to parse JSON safely." }
],
});
console.log(message.content);
Streaming Responses
const stream = await duel.chat.completions.create({
model: "duel-auto",
messages: [{ role: "user", content: "Count to 10" }],
stream: true,
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content;
if (content) {
process.stdout.write(content);
}
}
Error Handling
import { DuelClient } from "@duel-agents/sdk";
const duel = new DuelClient({
apiKey: process.env.DUEL_API_KEY!,
});
try {
const response = await duel.chat.completions.create({
model: "duel-auto",
messages: [{ role: "user", content: "Hello" }],
});
} catch (error) {
if (error.status === 401) {
console.error("Invalid API key or subscription inactive");
} else if (error.status === 429) {
console.error("Rate limit exceeded");
} else {
console.error("Request failed:", error.message);
}
}
IDE Integrations
Claude Code
git clone https://github.com/2aronS/Duel-Agents.git
cd duel-agents
claude plugin install ./integrations/claude-plugin
npx @duel-agents/install claude-code
In Claude Code:
/duel-agents:setup
Follow the guided setup to configure your API key and preferences.
Cursor
The installer copies a skill to .cursor/skills/duel-agents/ and writes DUEL_API_KEY to your project .env.
Manual configuration required:
- Open Cursor Settings → Models
- Set Override OpenAI Base URL to:
https://duelagents.com/v1
- Set API Key to your Duel key:
duel_yourprefix_yoursecret
- Select
duel-auto as your model
npx @duel-agents/install cursor
Codex CLI
The installer writes OPENAI_BASE_URL and OPENAI_API_KEY to .env:
npx @duel-agents/install codex
OpenClaw
Patches ~/.openclaw/openclaw.json with a duel provider and sets the default model:
npx @duel-agents/install openclaw
openclaw config validate
Manual configuration (~/.openclaw/openclaw.json):
{
"providers": {
"duel": {
"apiKey": "duel_yourprefix_yoursecret",
"baseURL": "https://duelagents.com/v1"
}
},
"defaultModel": "duel/duel-auto"
}
A backup is created at openclaw.json.bak before patching.
CLI Commands
Install Command
npx @duel-agents/install <tool>
Doctor Command
Validates your setup and connectivity:
npx @duel-agents/install doctor
Checks:
- API key format validity
- Connectivity to
duelagents.com/v1
- Subscription status
- Environment variable configuration
Common Patterns
Multi-Agent System
import { DuelClient } from "@duel-agents/sdk";
const duel = new DuelClient({
apiKey: process.env.DUEL_API_KEY!,
});
async function coordinatedAgents(task: string) {
const plan = await duel.chat.completions.create({
model: "duel-auto",
messages: [
{ role: "system", content: "You are a task planning agent." },
{ role: "user", content: `Create a plan for: ${task}` }
],
});
const steps = plan.choices[0].message.content;
const execution = await duel.chat.completions.create({
model: "duel-auto",
messages: [
{ role: "system", content: "You are a task execution agent." },
{ role: "user", content: `Execute this plan:\n${steps}` }
],
});
return execution.choices[0].message.content;
}
Cost-Aware Routing
import { DuelClient } from "@duel-agents/sdk";
const duel = new DuelClient({
apiKey: process.env.DUEL_API_KEY!,
});
async function analyzeCode(code: string, complexity: "simple" | "complex") {
const response = await duel.chat.completions.create({
model: "duel-auto",
messages: [
{
role: "user",
content: `Analyze this ${complexity} code:\n\n${code}`
}
],
});
return response.choices[0].message.content;
}
Use with Existing OpenAI Code
Replace only the client initialization:
import { DuelClient } from "@duel-agents/sdk";
const client = new DuelClient({
apiKey: process.env.DUEL_API_KEY!,
});
const response = await client.chat.completions.create({
model: "duel-auto",
messages: [{ role: "user", content: "Hello" }],
});
Fallback Strategy
import { DuelClient } from "@duel-agents/sdk";
const duel = new DuelClient({
apiKey: process.env.DUEL_API_KEY!,
});
async function robustCompletion(prompt: string) {
try {
return await duel.chat.completions.create({
model: "duel-auto",
messages: [{ role: "user", content: prompt }],
});
} catch (error) {
console.warn("Duel routing failed, using direct fallback");
throw error;
}
}
Troubleshooting
Invalid API Key Format
Symptom: Invalid API key format error
Solution:
401 Unauthorized
Symptom: 401 error when running doctor or making requests
Solution:
- Key may be revoked or subscription inactive
- Check billing status at dashboard
- Generate a new API key
- Ensure key is exported:
echo $DUEL_API_KEY
Could Not Reach Duel API
Symptom: Connection errors to duelagents.com/v1
Solution:
- Verify internet connectivity
- Check if
duelagents.com is accessible: curl https://duelagents.com/v1/health
- Proxy may be temporarily down; retry after a few minutes
- Check for firewall or VPN restrictions
Cursor Still Uses OpenAI
Symptom: Cursor not routing through Duel
Solution:
- Open Settings → Models → Override OpenAI Base URL
- Set to:
https://duelagents.com/v1
- Set API key field to your
duel_* key (not OpenAI key)
- Restart Cursor
- Select
duel-auto or duel/duel-auto as model
OpenClaw Won't Start
Symptom: OpenClaw fails after Duel installation
Solution:
openclaw config validate
cp ~/.openclaw/openclaw.json.bak ~/.openclaw/openclaw.json
npx @duel-agents/install openclaw
Skill Copy Failed
Symptom: Cursor skill not found after npm install
Solution:
git clone https://github.com/2aronS/Duel-Agents.git
cd duel-agents
npm install
npm run build
npx @duel-agents/install cursor
TypeScript Type Errors
Symptom: TypeScript errors with SDK
Solution:
npm install @duel-agents/sdk@latest
npm list typescript
Model Selection
Available Models
duel-auto - Automatic routing (recommended)
- Any OpenAI model name (routed through Duel)
- Any Anthropic model name (routed through Duel)
How Auto-Routing Works
Duel analyzes:
- Prompt complexity
- Required capabilities (code, reasoning, creative)
- Token length
- Historical quality metrics
Then selects the cheapest model that meets the quality threshold for that specific request.
Advanced Configuration
Custom Base URL (Staging)
import { DuelClient } from "@duel-agents/sdk";
const duel = new DuelClient({
apiKey: process.env.DUEL_API_KEY!,
baseURL: process.env.DUEL_PROXY_URL || "https://duelagents.com/v1",
});
Timeout Configuration
import { DuelClient } from "@duel-agents/sdk";
const duel = new DuelClient({
apiKey: process.env.DUEL_API_KEY!,
timeout: 60000,
});
Repository Structure
packages/
core/ @duel-agents/core - Validation, env handling, connectivity
cli/ @duel-agents/install - Installer CLI tool
sdk/ @duel-agents/sdk - TypeScript API client
integrations/
claude-plugin/ - Claude Code plugin
cursor-skill/ - Cursor IDE skill
openclaw-skill/ - OpenClaw integration
templates/
cursor-models.override.md - Cursor configuration example
openclaw.duel.json5 - OpenClaw configuration example
Development
git clone https://github.com/2aronS/Duel-Agents.git
cd duel-agents
npm install
npm run build
npm test
npm run cli -- install doctor
License
MIT License - see repository for full text.