Skip to main content
Drive external AI CLIs from a PraisonAI agent — Claude Code is the flagship integration.
The user asks in chat; the agent invokes Claude Code or another external CLI through the integration tool.

Quick Start

integration.as_tool() returns a sync callable that is safe to call from both sync and async agent runtimes. When registering with a native async agent, prefer integration.as_async_tool() — it returns an async callable that skips the worker-thread hop.
1

Attach Claude Code as an agent tool

2

One-shot call via the integration API

3

Continue a previous Claude Code session

4

Stream events live

The timeout argument is enforced end-to-end: stream_async(timeout=...) applies a monotonic deadline to every stdout read and the final drain, so a stalled claude/gemini/codex/cursor subprocess raises TimeoutError: Stream timed out after {timeout}s: {cmd} instead of hanging forever.
5

Per-call output format

6

Register as a native async tool

as_async_tool() returns a coroutine tool named <cli>_atool (for example claude_atool). It is functionally equivalent to as_tool(), but with no thread hop — measurable when the agent invokes the CLI many times in one turn.

How It Works

The integration builds CLI arguments dynamically per call, with no instance state mutated during execution.

Stateless Session Management

reset_session() is a deprecated no-op as of PraisonAI PR #1466. Remove it from your code. Session continuation is now explicit via continue_session=True.
Because state is no longer shared on the instance, a single ClaudeCodeIntegration is safe to call concurrently from multiple tasks / threads.
Before (stateful):
After (stateless):

CLI: Manager Delegation (Default)

PraisonAI CLI offers two execution modes for external agents, providing flexibility between automated reasoning and direct execution. Usage Examples:

Configuration Options


Registry

The ExternalAgentRegistry manages all available CLI integrations with a thread-safe registry pattern with lazy module-level default. You can construct your own ExternalAgentRegistry() for test isolation or multi-tenant runs:
As of PraisonAI PR #1849, ExternalAgentRegistry.create() raises ValueError for unknown integrations (parent registry contract). Use try_create() for the previous “return None on failure” behaviour. The module-level helper create_integration(name, **kwargs) already calls try_create() under the hood and still returns None on failure — no migration needed for code that uses it.
The existing helpers get_registry(), register_integration(), create_integration(), and get_available_integrations() are still exported and still work — they now delegate to get_default_registry(). Backward-compat code does not need to change.

Invalidating the availability cache

BaseCLIIntegration caches the result of shutil.which(cli_command) for each CLI. If a CLI is installed/uninstalled mid-run (e.g. in tests, or after a setup step), invalidate the cache:
The cache is thread-safe; invalidation is also thread-safe.

Logging for embedders

The registry logs through the named logger praisonai.integrations.registry — it never configures the root logger, so importing or calling the registry will not install a handler on an embedding application’s root logger. Two warnings route through this logger: Silence or redirect them:

Registering the integration as a tool

Both methods wrap the same underlying integration.execute(query) coroutine — pick the one that matches how your agent is invoked. <cli> is the integration’s cli_command: claude_tool/claude_atool, gemini_tool/gemini_atool, codex_tool/codex_atool, and cursor-agent_tool/cursor-agent_atool.

Register a custom external agent

Register your own external agent once and it becomes reachable from every surface — --external-agent, the praisonai_code CLI handler, and the UI toggles — with no PraisonAI code changes.
As of PraisonAI PR #4156, --external-agent choices, the CLI handler’s INTEGRATIONS, and the UI’s EXTERNAL_AGENTS all read the same ExternalAgentRegistry. A registered agent shows up in all three automatically.
1

Ship as a pip plugin (recommended)

Publish your integration class to the praisonai.external_agents entry-point group:
After pip install your-plugin, aider appears in praisonai --external-agent choices, in the praisonai_code CLI handler, and as a UI toggle — no PraisonAI code changes.
Built-ins always win on name collisions. Since PraisonAI PR #4159 — and now enforced in the base PluginRegistry for every registry via PR #4176 — a plugin whose entry-point name matches a shipped built-in (claude, gemini, codex, cursor) is skipped and the shipped integration keeps the name (a DEBUG line notes the collision). Matching is case-insensitive. Pick a distinct name (e.g. aider, acme-claude) for your plugin, or use runtime register(...) (next step) for a deliberate override. See Plugin Precedence.
2

Or register at runtime

register() raises ValueError if the class does not inherit BaseCLIIntegration.

Presentation metadata

Two optional class attributes drive help text, UI labels, and install hints on every surface: Built-ins declare them too:

Single source of truth

Two registry helpers back every surface that lists external agents:
Built-ins keep declaration order (claude, gemini, codex, cursor); plugins are appended in sorted order behind them. A faulty optional plugin is logged and skipped — it never blanks the catalog. Name collisions between a third-party plugin and a built-in are resolved in favour of the built-in — a plugin can extend the catalog but never replace claude, gemini, codex, or cursor. A listed name is always a usable name. list_external_agents() is derived from external_agent_catalog(), so a plugin that fails to import disappears from both surfaces at once. A broken plugin is never advertised as a --external-agent choice and then rejected by the handler — if the name shows up in --help, in ExternalAgentsHandler().list_integrations(), or as a UI toggle, it loads.

Which entry-point group?

Two entry-point groups exist and are easy to confuse — pick by outcome: Use praisonai.external_agents for a selectable --external-agent short name and a UI toggle. Use praisonai.integrations only to make a class importable from praisonai.integrations.
Both entry-point groups apply the same precedence: built-ins always win on case-insensitive name collisions; plugins can only add new names. As of PR #4176 this guard is enforced once in the base PluginRegistry, so it holds identically for every registry — see Plugin Precedence.

Prerequisites

The claude CLI must be available on PATH or the Claude Code SDK must be installed if use_sdk=True. The integration performs a cached, thread-safe shutil.which(...) check via is_available().

Decision Flow


Best Practices

Don’t rely on instance state for session continuation. Always be explicit about when you want to continue a previous session.
Do not mutate the integration.output_format attribute between calls. Use the per-call parameter or set it once during initialization.
The reset_session() method is now a no-op. Remove these calls from your code as they serve no purpose.
A single ClaudeCodeIntegration instance can be shared across concurrent tasks safely since no instance state is mutated during calls.

Troubleshooting

The plugin failed to import, so it was dropped from the catalog and never offered as a choice. The reason is logged as Skipping external agent '<name>': failed to load (<error>) on logger praisonai.integrations.registry.See the exact error:
Fix the import error the log reports (a missing dependency, a bad entry-point path, a syntax error in the plugin), then re-run — the name reappears once the class loads.
You see:
This means your praisonai-code is newer than your praisonai wrapper — a mixed-version install. Upgrade the wrapper:

Using from PraisonAI UI

You can also enable external CLI integrations directly from the PraisonAI user interface without writing code. All PraisonAI UI entry points include toggles for external agents when the corresponding CLIs are installed. See External Agents in UI for complete documentation.

Persistence & Concurrency

Learn about thread-safe persistence features

Agent Tools

Using integrations as agent tools