External Agents
Integrate external AI coding CLI tools as PraisonAI agent tools
External Agents
PraisonAI provides seamless integration with external AI coding CLI tools, allowing you to use Claude Code, Gemini CLI, Codex CLI, and Cursor CLI as agent tools.
Built-in Integrations
These ship with PraisonAI. --external-agent and ExternalAgentsHandler.list_integrations() return these built-ins plus any registered plugins — the set is registry-driven, not fixed. See Register a custom external agent.
| Integration | CLI Command | Features |
|---|---|---|
| Claude Code | claude | SDK support, session continuation, tool restrictions |
| Gemini CLI | gemini | Model selection, multi-directory context, usage stats |
| Codex CLI | codex | Full auto mode, sandbox modes, structured output |
| Cursor CLI | cursor-agent | Force mode, session resume, streaming |
Installation
The integrations are included with PraisonAI:
pip install praisonaiYou’ll also need to install the respective CLI tools:
# Claude Code
curl -fsSL https://claude.ai/install.sh | bash
# Gemini CLI
npm install -g @anthropic-ai/gemini-cli
# Codex CLI
npm install -g @openai/codex
# Cursor CLI
# Download from cursor.comQuick Start
Python API
from praisonai.integrations import (
ClaudeCodeIntegration,
GeminiCLIIntegration,
CodexCLIIntegration,
CursorCLIIntegration,
get_available_integrations
)
# Check which integrations are available
availability = get_available_integrations()
print(availability)
# {'claude': True, 'gemini': True, 'codex': False, 'cursor': True}
# Create an integration
claude = ClaudeCodeIntegration(workspace="/path/to/project")
# Execute a coding task
result = await claude.execute("Refactor the auth module")
print(result)CLI Usage
# Use external agents from the command line
praisonai "Refactor the code" --external-agent claude
praisonai "Analyze codebase" --external-agent gemini
praisonai "Fix bugs" --external-agent codex
praisonai "Add tests" --external-agent cursorAs Agent Tools
from praisonai import Agent
from praisonai.integrations import ClaudeCodeIntegration
# Create integration
claude = ClaudeCodeIntegration(workspace="/path/to/project")
# Get tool
tool = claude.as_tool()
# Use with agent
agent = Agent(
name="Code Assistant",
role="Software Developer",
goal="Help with coding tasks",
tools=[tool]
)
result = agent.start("Refactor the authentication module")As a native async agent tool
Preferred when the agent runs on agent.astart(...) (or any async entrypoint) — the tool is awaited directly on the running loop with no thread hop.
from praisonaiagents import Agent
from praisonai.integrations import ClaudeCodeIntegration
claude = ClaudeCodeIntegration(workspace="/path/to/project")
agent = Agent(
name="Code Assistant",
role="Software Developer",
goal="Help with coding tasks",
tools=[claude.as_async_tool()], # registers as `claude_atool`
)
await agent.astart("Refactor the authentication module")as_async_tool() was added in PraisonAI PR #4022; as_tool() still works and is now also safe to call from inside an async agent runtime.
CLI Usage: Manager Delegation vs Direct Proxy
PraisonAI now offers two modes for external CLI integration, balancing power and simplicity.
sequenceDiagram
participant User
participant Manager as Manager Agent
participant CLI as External CLI Tool
participant User2 as User (Direct)
participant CLI2 as External CLI Tool (Direct)
Note over User,CLI: Manager Delegation (Default)
User->>Manager: "Refactor auth.py"
Manager->>CLI: Call claude_tool
CLI-->>Manager: Result
Manager-->>User: Aggregated response
Note over User2,CLI2: Direct Proxy (--external-agent-direct)
User2->>CLI2: "Refactor auth.py"
CLI2-->>User2: Direct result
classDef user fill:#8B0000,stroke:#7C90A0,color:#fff
classDef manager fill:#F59E0B,stroke:#7C90A0,color:#fff
classDef cli fill:#189AB4,stroke:#7C90A0,color:#fff
classDef result fill:#10B981,stroke:#7C90A0,color:#fff
class User,User2 user
class Manager manager
class CLI,CLI2 cliManager Delegation (Default)
When using --external-agent, a manager Agent wraps the external CLI as a subagent tool, providing reasoning and planning capabilities.
from praisonaiagents import Agent
from praisonai.integrations import ClaudeCodeIntegration
claude = ClaudeCodeIntegration(workspace=".")
manager = Agent(
name="Manager",
instructions="Delegate coding tasks to claude_tool.",
tools=[claude.as_tool()],
llm="gpt-4o-mini",
)
manager.start("Refactor the auth module")When to use manager delegation:
- Multi-step tasks requiring planning
- Need reasoning across multiple tools
- Want aggregated responses
- Complex workflows with decision-making
Manager LLM: Defaults to gpt-4o-mini, configurable via --llm or MODEL_NAME environment variable.
Direct Proxy (Escape Hatch)
Use --external-agent-direct for pass-through behavior — fastest execution with no manager overhead.
# Manager delegation (new default)
praisonai "Say hi in 5 words" --external-agent claude
# Direct proxy (escape hatch)
praisonai "Say hi in 5 words" --external-agent claude --external-agent-directWhen to use direct proxy:
- Single-shot calls
- Scripting scenarios
- Fastest execution needed
- No manager LLM overhead wanted
Environment Variables
Set the appropriate API keys for each integration:
# Claude Code
export ANTHROPIC_API_KEY=your-key
# or
export CLAUDE_API_KEY=your-key
# Gemini CLI
export GEMINI_API_KEY=your-key
# or
export GOOGLE_API_KEY=your-key
# Cursor CLI
export CURSOR_API_KEY=your-key
# OpenAI (for Codex)
export OPENAI_API_KEY=your-keyExternalAgentsHandler
The ExternalAgentsHandler provides a unified interface for managing external integrations:
from praisonai.cli.features import ExternalAgentsHandler
handler = ExternalAgentsHandler()
# List available integrations — built-ins plus any registered plugins
integrations = handler.list_integrations()
print(integrations) # ['claude', 'gemini', 'codex', 'cursor']
# After registering an "aider" plugin:
# ['claude', 'gemini', 'codex', 'cursor', 'aider']
# Check availability
availability = handler.check_availability()
print(availability)
# {'claude': True, 'gemini': True, 'codex': False, 'cursor': True}
# Get a specific integration
claude = handler.get_integration("claude", workspace="/project")On a mixed-version install — a newer praisonai-code against a praisonai wrapper predating external_agent_catalog — check_dependencies() returns (False, "…too old…") instead of passing and then yielding an empty catalog:
ok, reason = handler.check_dependencies()
# (False, "your installed 'praisonai' wrapper is too old for --external-agent ...")Three states to tell apart:
Performance
All integrations are designed with zero performance impact:
| Metric | Result |
|---|---|
| Import time | < 1ms |
| Availability check (first) | ~1ms |
| Availability check (cached) | ~0ms |
| Memory overhead | Minimal (lazy loading) |
Lazy Loading
Integrations are only imported when used:
# This does NOT import any integration classes
from praisonai.integrations import get_available_integrations
# This imports only ClaudeCodeIntegration
from praisonai.integrations import ClaudeCodeIntegrationAvailability Caching
CLI availability checks are cached at the class level:
from praisonai.integrations import ClaudeCodeIntegration
claude1 = ClaudeCodeIntegration()
claude2 = ClaudeCodeIntegration()
# Both use the same cached availability check
print(claude1.is_available) # Checks filesystem
print(claude2.is_available) # Uses cached resultStreaming
All integrations support streaming output:
from praisonai.integrations import ClaudeCodeIntegration
claude = ClaudeCodeIntegration()
async for event in claude.stream("Add error handling to main.py"):
print(event)
# {'type': 'assistant', 'content': '...'}
# {'type': 'tool_use', 'name': 'Write', ...}
# {'type': 'result', 'content': '...'}Error Handling
from praisonai.integrations import ClaudeCodeIntegration
claude = ClaudeCodeIntegration(timeout=60)
try:
result = await claude.execute("Complex refactoring task")
except TimeoutError:
print("Task timed out")
except Exception as e:
print(f"Error: {e}")The CLI execution path distinguishes an unknown name (ValueError) from a version-skewed install (RuntimeError):
| Situation | Raised / shown | Fix |
|---|---|---|
| Name not registered | ValueError: Unknown integration: <name>. Available: [...] | Check the name or install the plugin |
praisonai wrapper too old | RuntimeError: your installed 'praisonai' wrapper is too old for --external-agent ... | pip install -U praisonai |
praisonai wrapper not installed | Empty catalog, ValueError: Unknown integration | Install praisonai if you need registry-backed agents |