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.

IntegrationCLI CommandFeatures
Claude CodeclaudeSDK support, session continuation, tool restrictions
Gemini CLIgeminiModel selection, multi-directory context, usage stats
Codex CLIcodexFull auto mode, sandbox modes, structured output
Cursor CLIcursor-agentForce mode, session resume, streaming

Installation

The integrations are included with PraisonAI:

bash
pip install praisonai

You’ll also need to install the respective CLI tools:

bash
# 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.com

Quick Start

Python API

python
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

bash
# 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 cursor

As Agent Tools

python
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.

python
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.

Diagram
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 cli

Manager Delegation (Default)

When using --external-agent, a manager Agent wraps the external CLI as a subagent tool, providing reasoning and planning capabilities.

python
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.

bash
# 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-direct

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

bash
# 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-key

ExternalAgentsHandler

The ExternalAgentsHandler provides a unified interface for managing external integrations:

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

python
ok, reason = handler.check_dependencies()
# (False, "your installed 'praisonai' wrapper is too old for --external-agent ...")

Three states to tell apart:

Diagram

No

Yes

No

Yes

praisonai wrapper installed?

Empty catalog
standalone still works

Has external_agent_catalog?

❌ ‘wrapper is too old’
pip install -U praisonai

✅ Full catalog

Performance

All integrations are designed with zero performance impact:

MetricResult
Import time< 1ms
Availability check (first)~1ms
Availability check (cached)~0ms
Memory overheadMinimal (lazy loading)

Lazy Loading

Integrations are only imported when used:

python
# This does NOT import any integration classes
from praisonai.integrations import get_available_integrations

# This imports only ClaudeCodeIntegration
from praisonai.integrations import ClaudeCodeIntegration

Availability Caching

CLI availability checks are cached at the class level:

python
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 result

Streaming

All integrations support streaming output:

python
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

python
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):

SituationRaised / shownFix
Name not registeredValueError: Unknown integration: <name>. Available: [...]Check the name or install the plugin
praisonai wrapper too oldRuntimeError: your installed 'praisonai' wrapper is too old for --external-agent ...pip install -U praisonai
praisonai wrapper not installedEmpty catalog, ValueError: Unknown integrationInstall praisonai if you need registry-backed agents

Using from PraisonAI UI

Next Steps