Agent/Task API.
Quick Start
How It Works
| Step | Component | Purpose |
|---|---|---|
| 1 | User/CLI | Specifies backend via flag or YAML |
| 2 | Resolver | Factory pattern for backend creation |
| 3 | Backend | Protocol implementation (e.g., ClaudeCodeBackend) |
| 4 | Process | External CLI subprocess execution |
| 5 | Result | Parsed response returned to Agent |
Permission modes (Claude Code backend)
| Setting | Default (PR #2122) | Notes |
|---|---|---|
--permission-mode | default | Was bypassPermissions |
ClaudeCodeBackend(unsafe=...) | False | Set True + env var for bypass |
unsafe=True or only the env var set, the backend overrides to default mode and logs a warning.
Configuration Surfaces
The cli_backend YAML Field
| Shape | Example | Behavior |
|---|---|---|
| Omitted | (field absent) | No backend used; Agent uses normal LLM client. No warning logged. |
| String | cli_backend: claude-code | Resolves via resolve_cli_backend("claude-code"). |
| Dict | cli_backend: {id: claude-code, overrides: {timeout_ms: 60000}} | Resolves via resolve_cli_backend("claude-code", overrides={...}). |
| Empty string | cli_backend: "" | Raises ValueError("cli_backend string cannot be empty"). |
Dict missing id | cli_backend: {overrides: {...}} | Raises ValueError("cli_backend dict must contain an 'id' field"). |
overrides not a dict | cli_backend: {id: claude-code, overrides: "bad"} | Raises ValueError("cli_backend.overrides must be a dict"). |
| Invalid type | cli_backend: 123 | Raises ValueError("cli_backend must be string, dict, or instance, got: int"). |
| Unknown id | cli_backend: nope | Returns None + logged warning. (Registry lookup, unchanged.) |
Framework Compatibility
cli_backend is a runtime feature — it works only with an adapter whose SUPPORTS_RUNTIME_FEATURES = True (the built-in praisonai adapter has it).
framework value | cli_backend behaviour |
|---|---|
praisonai (default) | Resolved and used to delegate every agent turn. |
crewai, autogen, autogen_v4, ag2 | Raises ValueError: Runtime features (...) are not supported for framework='<x>'. Use a framework whose adapter sets SUPPORTS_RUNTIME_FEATURES = True (e.g. framework='praisonai'). Validation runs before any agent starts, so no partial run is performed. |
SUPPORTS_RUNTIME_FEATURES = True on their subclass — see Capability Flags.
This is a behaviour change in PR #1797 — previously
cli_backend was silently ignored under non-praisonai frameworks. Now it fails loudly at config-load time. A follow-up fix (PR #2004) restored this validation for framework: praisonai — previously a regression caused all cli_backend configs to fail at validation regardless of framework.Using cli_backend in Python
| Shape | Example | When to use |
|---|---|---|
str | cli_backend="claude-code" | Quickest path. Matches YAML idiom. |
dict | cli_backend={"id": "claude-code", "overrides": {...}} | Need timeout / args / model overrides. |
| instance | cli_backend=resolve_cli_backend("claude-code", overrides=...) | Pre-resolved once, reused across agents. |
callable | cli_backend=my_factory | Factory function returning a backend. |
YAML and Python now accept the exact same shapes (was previously YAML-only for dict).
Built-in Backend: claude-code
The claude-code backend executes commands via the Claude Code CLI with these default settings:
| Option | Type | Default | Description |
|---|---|---|---|
command | str | "claude" | CLI command (must be on PATH) |
args | List[str] | ["-p", "--output-format", "stream-json", ..., "--permission-mode", "default"] | Default permission mode is default (PR #2122; was bypassPermissions) |
resume_args | List[str] | ["-p", "--output-format", "stream-json", "--resume", "{session_id}"] | Arguments for resuming sessions |
output | str | "jsonl" | Output format expected from CLI |
input | str | "stdin" | How to pass prompts to CLI |
live_session | str | "claude-stdio" | Live session mode |
model_arg | str | "--model" | CLI argument for model selection |
model_aliases | Dict[str, str] | {"opus": "claude-opus-4-5", "sonnet": "claude-sonnet-4-5", "haiku": "claude-haiku-3-5"} | Model name shortcuts |
session_arg | str | "--session-id" | CLI argument for session ID |
session_mode | str | "always" | When to use sessions |
session_id_fields | List[str] | ["session_id"] | Fields containing session ID |
system_prompt_arg | str | "--append-system-prompt" | CLI argument for system prompts |
system_prompt_when | str | "first" | When to add system prompts |
image_arg | str | "--image" | CLI argument for images |
clear_env | List[str] | ["ANTHROPIC_API_KEY", "ANTHROPIC_BASE_URL", "ANTHROPIC_OAUTH_TOKEN", "CLAUDE_CODE_USE_BEDROCK", "CLAUDE_CODE_USE_VERTEX", "CLAUDE_CONFIG_DIR", "CLAUDE_CODE_OAUTH_TOKEN", "OTEL_EXPORTER_OTLP_ENDPOINT", "OTEL_EXPORTER_OTLP_HEADERS", "OTEL_RESOURCE_ATTRIBUTES", "GOOGLE_APPLICATION_CREDENTIALS", "AWS_PROFILE", "AWS_REGION", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN"] | Environment variables sanitized before subprocess |
bundle_mcp | bool | True | Enable MCP bundling |
bundle_mcp_mode | str | "claude-config-file" | MCP bundling mode |
serialize | bool | True | Queue operations to avoid conflicts |
timeout_ms | int | 300000 | Subprocess timeout (5 minutes) |
The --cli-backend CLI Flag
| Flag | Type | Behavior |
|---|---|---|
--cli-backend BACKEND_ID | string | Choices populated dynamically from list_cli_backends(). Currently: claude-code. |
--cli-backend X --external-agent Y | — | Mutually exclusive — argparse rejects with “not allowed with argument” |
Unknown id (e.g. --cli-backend bogus) | — | Rejected by argparse with “invalid choice” |
The backends Subcommand
| Command | Behavior |
|---|---|
praisonai backends list | Prints each registered backend id on its own line |
praisonai backends | Same as list (list is the default) |
praisonai backends bogus | Prints [red]Unknown backends subcommand: bogus[/red] and the list of valid subcommands |
Custom Backends (Advanced)
Register your own CLI backend for custom tools:praisonai backends list shows it, --cli-backend my-backend accepts it, and cli_backend: my-backend works in YAML.
CliBackendProtocol Reference
For backend authors implementing the protocol:config: CliBackendConfig— Configuration objectasync def execute(prompt, *, session=None, images=None, system_prompt=None, **kwargs) -> CliBackendResult— Single executionasync def stream(prompt, **kwargs) -> AsyncIterator[CliBackendDelta]— Streaming executiondef capabilities() -> RuntimeCapabilityMatrix— Required (new). Returns the capability matrix for this backend.
Breaking change:
CliBackendProtocol now requires a capabilities() -> RuntimeCapabilityMatrix method so the framework can validate capabilities at config time. Third-party backends must add this method. Without it, the backend will be treated as supporting only the reduced capability set (tool_loop, basic_chat, simple_tools).Best Practices
Prefer YAML for production
Prefer YAML for production
Use the YAML
cli_backend: field for versioned, declarative configuration. Use --cli-backend flag for quick one-off commands and testing.Set timeout overrides for slow CLIs
Set timeout overrides for slow CLIs
Use a framework whose adapter sets SUPPORTS_RUNTIME_FEATURES
Use a framework whose adapter sets SUPPORTS_RUNTIME_FEATURES
The
cli_backend field requires an adapter whose SUPPORTS_RUNTIME_FEATURES = True — the built-in framework: praisonai (the default) qualifies. PraisonAI validates this up front — if you try it with crewai, autogen, autogen_v4, or ag2, you’ll get a ValueError immediately, before any agent runs.Don't combine with --external-agent
Don't combine with --external-agent
The
--cli-backend flag and --external-agent flag are mutually exclusive. Pick one approach:- CLI Backends (new): Pluggable, configurable, YAML-supported
- External Agent (legacy): Class-based, limited configuration
Ensure claude CLI is on PATH
Ensure claude CLI is on PATH
The
claude-code backend requires the claude CLI to be installed and accessible. Install via the Claude Code SDK or ensure it’s in your system PATH.How this differs from --external-agent
The legacy
--external-agent claude and ClaudeCodeIntegration class still work and are unchanged (see External CLI Integrations). The CLI Backend Protocol is the new pluggable path: backends are registered by id, configured declaratively, and surfaced as a YAML field and --cli-backend flag.Related
Runtime Selection
Model-scoped runtime configuration (replaces cli_backend)
External CLI Integrations
Legacy class-based CLI integration approach
Agent Configuration
Core Agent configuration and usage patterns

