Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,7 @@
"icon": "gear",
"pages": [
"docs/features/cli",
"docs/features/cli-backend",
"docs/features/async-agent-scheduler",
"docs/features/hooks",
"docs/features/hook-events",
Expand Down
4 changes: 4 additions & 0 deletions docs/cli/claude-cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ icon: "message-bot"

## Overview

<Note>
For programmatic use inside a Python Agent, see [CLI Backend](/docs/features/cli-backend).
</Note>

![Using Claude Model for Creative Tasks](./claude-cli-using-claude-model-for-creativ.gif)

Claude Code CLI is Anthropic's AI-powered coding assistant that can read files, run commands, search the web, edit code, and more. PraisonAI integrates with Claude CLI to use it as an external agent.
Expand Down
313 changes: 313 additions & 0 deletions docs/features/cli-backend.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,313 @@
---
title: "CLI Backend"
sidebarTitle: "CLI Backend"
description: "Delegate Agent turns to external CLI tools like Claude Code"
icon: "terminal"
---

CLI Backend delegates Agent turns to external CLI tools like Claude Code instead of using the built-in LLM directly.

```mermaid
graph LR
subgraph "CLI Backend Flow"
A[🤖 Agent] --> B[🔄 CLI Backend]
B --> C[💻 claude CLI]
C --> D[✅ Result]
D --> A
end

classDef agent fill:#8B0000,stroke:#7C90A0,color:#fff
classDef backend fill:#189AB4,stroke:#7C90A0,color:#fff
classDef cli fill:#F59E0B,stroke:#7C90A0,color:#fff
classDef result fill:#10B981,stroke:#7C90A0,color:#fff

class A agent
class B backend
class C cli
class D result
```

## Quick Start

<Steps>
<Step title="Simple Usage">
Comment on lines +8 to +33
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Start the page with an agent-centric code snippet before prose/diagram.

Line 8 currently begins with narrative text; this violates the docs rule requiring an agent-first example at the top.

As per coding guidelines, “Documentation pages must start with an agent-centric code example at the top, showing how to implement from the agent perspective.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/features/cli-backend.mdx` around lines 8 - 33, Add an agent-first code
example at the very top of docs/features/cli-backend.mdx (before the mermaid
diagram and any prose) that demonstrates an agent invoking the CLI Backend
(e.g., using the "CLI Backend" to call the "claude CLI") so the page starts with
a concrete agent-centric usage snippet; update the "Simple Usage" Step if
present to reference this new snippet and ensure the agent example shows inputs,
invocation of the backend, and expected result so readers see the agent
perspective immediately.

```python
from praisonai import Agent

agent = Agent(
name="Coder",
instructions="You are a senior Python engineer",
cli_backend="claude-code"
)

agent.start("Refactor auth.py to use dependency injection")
```
Comment on lines +35 to +44
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

First Quick Start example must be ≤ 6 lines.

The first code block is currently longer than the acceptance limit. Please compress it to a minimal runnable snippet.

Proposed compact example
 ```python
 from praisonai import Agent
-
-agent = Agent(
-    name="Coder",
-    instructions="You are a senior Python engineer",
-    cli_backend="claude-code"
-)
-
-agent.start("Refactor auth.py to use dependency injection")
+agent = Agent(name="Coder", instructions="You are a senior Python engineer", cli_backend="claude-code")
+agent.start("Refactor auth.py to use dependency injection")
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @docs/features/cli-backend.mdx around lines 35 - 44, The first Quick Start
code block exceeds the 6-line limit; compress it to a minimal runnable snippet
by collapsing the multi-line Agent construction into a single line and keeping
the agent.start call on the next line—update the usage of Agent and agent.start
(and the cli_backend parameter) so the snippet becomes two concise lines while
preserving the same arguments and behavior.


</details>

<!-- fingerprinting:phantom:triton:hawk:dc55a149-079f-4de6-bada-664dd0e05fe4 -->

<!-- This is an auto-generated comment by CodeRabbit -->

</Step>

<Step title="With Configuration">
```python
from praisonai import Agent
from praisonai.cli_backends import resolve_cli_backend

agent = Agent(
name="Coder",
instructions="You are a senior Python engineer",
cli_backend=resolve_cli_backend("claude-code", overrides={
"timeout_ms": 900_000,
"model_aliases": {"opus": "claude-opus-4-5"}
})
)
```
</Step>
</Steps>

---

## How It Works

```mermaid
sequenceDiagram
participant User
participant Agent
participant CliBackend
participant claude

User->>Agent: Request
Agent->>CliBackend: Execute prompt
CliBackend->>claude: Spawn subprocess
claude-->>CliBackend: JSONL stream
CliBackend-->>Agent: CliBackendResult
Agent-->>User: Response
```

| Step | Description |
|------|-------------|
| **Build Command** | Construct CLI args from config and session |
| **Spawn Process** | Launch subprocess with sanitized environment |
| **Parse Output** | Process JSONL/JSON response stream |
| **Return Result** | Package into CliBackendResult |

---

## Which Option When?

```mermaid
graph TB
Start[Choose CLI Backend Option] --> Simple{Simple Use?}
Simple -->|Yes| StringBackend["cli_backend='claude-code'"]
Simple -->|No| Advanced{Need Config?}
Advanced -->|Timeout/Model| Overrides["resolve_cli_backend('claude-code', overrides={...})"]
Advanced -->|Custom CLI| Custom["MyBackend() instance"]

StringBackend --> Works1[✅ Works with praisonai import]
Overrides --> Works2[✅ Tuned configuration]
Custom --> Works3[✅ Full control]

classDef simple fill:#10B981,stroke:#7C90A0,color:#fff
classDef config fill:#F59E0B,stroke:#7C90A0,color:#fff
classDef custom fill:#6366F1,stroke:#7C90A0,color:#fff

class StringBackend simple
class Overrides config
class Custom custom
```

---

## Configuration Options

Full `CliBackendConfig` options:

| Option | Type | Default | Purpose |
|--------|------|---------|---------|
Comment on lines +121 to +122
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use the required config table schema (Description, not Purpose).

Line 121 defines Purpose; the required column set is Option | Type | Default | Description.

Header fix
-| Option | Type | Default | Purpose |
+| Option | Type | Default | Description |

As per coding guidelines, “Configuration documentation must include a table with columns: Option, Type, Default, Description for all SDK config options.”

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| Option | Type | Default | Purpose |
|--------|------|---------|---------|
| Option | Type | Default | Description |
|--------|------|---------|---------|
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/features/cli-backend.mdx` around lines 121 - 122, The table header uses
"Purpose" instead of the required "Description"; update the table header row so
the columns read "Option | Type | Default | Description" (replace the "Purpose"
column), and scan the surrounding content for any other instances of the
"Purpose" column in this docs block to ensure the documentation follows the
required config table schema for SDK config options.

| `command` | `str` | (required) | CLI executable, e.g. `"claude"` |
| `args` | `List[str]` | `[]` | Base args |
| `resume_args` | `Optional[List[str]]` | `None` | Args for resume; supports `"{session_id}"` placeholder |
| `session_arg` | `Optional[str]` | `None` | Flag for session id, e.g. `"--session-id"` |
| `session_mode` | `str` | `"none"` | `"always" \| "existing" \| "none"` |
| `session_id_fields` | `List[str]` | `[]` | Fields that bind a session |
| `output` | `str` | `"text"` | `"text" \| "json" \| "jsonl"` |
| `input` | `str` | `"arg"` | `"arg" \| "stdin"` |
| `max_prompt_arg_chars` | `Optional[int]` | `None` | Switch to stdin above this length |
| `model_arg` | `Optional[str]` | `None` | e.g. `"--model"` |
| `model_aliases` | `Dict[str, str]` | `{}` | Short → full id (e.g. `"opus"` → `"claude-opus-4-5"`) |
| `system_prompt_arg` | `Optional[str]` | `None` | e.g. `"--append-system-prompt"` |
| `system_prompt_when` | `str` | `"always"` | `"first" \| "always" \| "never"` |
| `system_prompt_mode` | `str` | `"append"` | `"append" \| "replace"` |
| `image_arg` | `Optional[str]` | `None` | e.g. `"--image"` |
| `image_mode` | `str` | `"repeat"` | `"repeat" \| "list"` |
| `clear_env` | `List[str]` | `[]` | Env vars to strip before launching CLI |
| `env` | `Dict[str, str]` | `{}` | Env vars to set |
| `live_session` | `Optional[str]` | `None` | e.g. `"claude-stdio"` |
| `bundle_mcp` | `bool` | `False` | Pass MCP servers through to the CLI |
| `bundle_mcp_mode` | `Optional[str]` | `None` | e.g. `"claude-config-file"` |
| `serialize` | `bool` | `False` | Queue calls to avoid concurrent conflicts |
| `no_output_timeout_ms` | `Optional[int]` | `None` | Kill if no bytes for this long |
| `timeout_ms` | `int` | `300_000` | Overall timeout (5 min default) |

### ClaudeCodeBackend Defaults

```python
# Built-in ClaudeCodeBackend configuration
command="claude"
args=["-p", "--output-format", "stream-json", "--include-partial-messages",
"--verbose", "--setting-sources", "user", "--permission-mode", "bypassPermissions"]
output="jsonl", input="stdin", live_session="claude-stdio"
session_arg="--session-id", session_mode="always"
model_aliases={"opus":"claude-opus-4-5","sonnet":"claude-sonnet-4-5","haiku":"claude-haiku-3-5"}
system_prompt_arg="--append-system-prompt", system_prompt_when="first"
image_arg="--image"
# Environment sanitization - ambient credentials stripped before spawning Claude
clear_env=["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"]
bundle_mcp=True, bundle_mcp_mode="claude-config-file", serialize=True, timeout_ms=300_000
```
Comment on lines +117 to +167
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add the missing required API/behavior documentation blocks.

The page still needs explicit coverage for:

  • two-import behavior with concrete TypeError explanation/fixes,
  • full list of newly exported SDK symbols (both praisonaiagents and praisonai),
  • Agent wiring details (session-id logic, system prompt composition, image extraction, backend.execute(...), RuntimeError path).

These are explicit PR objectives and currently not clearly documented in this file.

Also applies to: 259-300

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/features/cli-backend.mdx` around lines 117 - 167, Add explicit
documentation blocks covering (1) the two-import behavior: describe the
TypeError thrown when both imports are used, how to detect it and the
recommended fixes (use only praissonaiagents or praisonai or adjust import
order), (2) a complete exported-symbols list for both praissonaiagents and
praisonai (enumerate public classes/functions), and (3) detailed agent wiring:
explain session-id logic (session_arg, session_mode, session_id_fields), system
prompt composition (system_prompt_arg, system_prompt_when, system_prompt_mode),
image extraction rules (image_arg, image_mode), how backend.execute(...) is
invoked, and the RuntimeError path and when it is raised; include examples or
expected error messages for each to satisfy the PR objectives.


---

## Common Patterns

### Pattern A — Swap Backend Per Agent in a Team

```python
from praisonaiagents import Agent, Task, PraisonAIAgents
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The example in Pattern A uses from praisonaiagents import Agent while passing a string ID ("claude-code") to the cli_backend parameter. This contradicts the "Best Practices" section (line 262) which recommends using from praisonai import Agent for automatic string resolution. Using the core package directly with a string ID may lead to resolution errors.

from praisonai import Agent, Task, PraisonAIAgents


# Regular LLM agent
analyst = Agent(
name="Analyst",
instructions="Analyze requirements",
llm="gpt-4o"
)

# CLI backend agent
coder = Agent(
name="Coder",
instructions="Write production code",
cli_backend="claude-code"
)
Comment on lines +176 to +190
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Pattern A likely misdocuments backend wiring for praisonaiagents.Agent.

This example uses from praisonaiagents import Agent with cli_backend="claude-code", but the page later says string IDs are auto-resolved via praisonai wrapper. Keep this example consistent (either use from praisonai import Agent or resolve the backend explicitly).

Safer fix using explicit resolution
-from praisonaiagents import Agent, Task, PraisonAIAgents
+from praisonaiagents import Agent, Task, PraisonAIAgents
+from praisonai import resolve_cli_backend
@@
 coder = Agent(
     name="Coder",
     instructions="Write production code",
-    cli_backend="claude-code"
+    cli_backend=resolve_cli_backend("claude-code")
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/features/cli-backend.mdx` around lines 176 - 190, The example
misdocuments backend wiring for Agent by importing Agent from praisonaiagents
while relying on string-ID auto-resolution provided by the praisonai wrapper;
fix by making the example consistent: either import Agent from praisonai (e.g.,
use the praisonai wrapper import instead of praisonaiagents) or keep the
praisonaiagents import and explicitly resolve/pass the backend (resolve the
backend ID via the praisonai wrapper or factory and pass the resolved backend
object into Agent via the cli_backend parameter); update the snippet to use the
Agent symbol with a correctly-resolved backend (cli_backend) so the docs match
runtime behavior.


task = Task(description="Build a REST API for user management")
agents = PraisonAIAgents(agents=[analyst, coder], tasks=[task])
agents.start()
```

### Pattern B — Tune Timeout and Model Aliases

```python
from praisonai import Agent
from praisonai.cli_backends import resolve_cli_backend

agent = Agent(
name="Coder",
instructions="Complex refactoring tasks",
cli_backend=resolve_cli_backend("claude-code", overrides={
"timeout_ms": 900_000, # 15 minutes for complex tasks
"model_aliases": {"fast": "claude-haiku-3-5", "best": "claude-opus-4-5"}
})
)
```

### Pattern C — Register a Custom CLI Backend

```python
from praisonaiagents import CliBackendProtocol, CliBackendConfig
from praisonai.cli_backends import register_cli_backend
Comment on lines +216 to +217
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The code block for Pattern C is missing the import for the Agent class used on line 234. Additionally, to be consistent with the best practices defined later in the document, it should use the praisonai wrapper for Agent when working with string-based backend IDs (like the "my-cli" ID registered on line 231).

from praisonai import Agent
from praisonaiagents import CliBackendProtocol, CliBackendConfig
from praisonai.cli_backends import register_cli_backend


class MyCustomBackend:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For better clarity and to ensure the custom backend adheres to the expected interface, it is recommended to have the class explicitly inherit from CliBackendProtocol, which is already imported in this snippet.

class MyCustomBackend(CliBackendProtocol):

def __init__(self):
self.config = CliBackendConfig(command="my-cli", timeout_ms=60_000)

async def execute(self, prompt, **kwargs):
# Custom implementation
pass

async def stream(self, prompt, **kwargs):
# Custom streaming implementation
pass

register_cli_backend("my-cli", lambda: MyCustomBackend())

# Usage
agent = Agent(cli_backend="my-cli")
```
Comment on lines +216 to +235
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Pattern C example is not runnable as-is (Agent is undefined).

Line 234 uses Agent(...) without importing Agent, so this snippet fails directly.

Import fix
-from praisonaiagents import CliBackendProtocol, CliBackendConfig
+from praisonai import Agent
+from praisonaiagents import CliBackendProtocol, CliBackendConfig

As per coding guidelines, “Every Python code example must include all necessary imports and run without modification.”

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
from praisonaiagents import CliBackendProtocol, CliBackendConfig
from praisonai.cli_backends import register_cli_backend
class MyCustomBackend:
def __init__(self):
self.config = CliBackendConfig(command="my-cli", timeout_ms=60_000)
async def execute(self, prompt, **kwargs):
# Custom implementation
pass
async def stream(self, prompt, **kwargs):
# Custom streaming implementation
pass
register_cli_backend("my-cli", lambda: MyCustomBackend())
# Usage
agent = Agent(cli_backend="my-cli")
```
from praisonaiagents import Agent, CliBackendProtocol, CliBackendConfig
from praisonai.cli_backends import register_cli_backend
class MyCustomBackend:
def __init__(self):
self.config = CliBackendConfig(command="my-cli", timeout_ms=60_000)
async def execute(self, prompt, **kwargs):
# Custom implementation
pass
async def stream(self, prompt, **kwargs):
# Custom streaming implementation
pass
register_cli_backend("my-cli", lambda: MyCustomBackend())
# Usage
agent = Agent(cli_backend="my-cli")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/features/cli-backend.mdx` around lines 216 - 235, The example is missing
the Agent import so it isn't runnable; update the snippet to include the
required import(s) at the top (e.g., import Agent from the library) so the final
lines using Agent(cli_backend="my-cli") work; ensure the header imports include
Agent plus the existing CliBackendConfig, CliBackendProtocol and
register_cli_backend references and keep the MyCustomBackend,
register_cli_backend("my-cli", ...) and Agent(...) symbols unchanged so the
example runs as-is.


---

## User Interaction Flow

When you run `agent.start("...")` with `cli_backend="claude-code"`, the agent spawns a Claude CLI subprocess in the background. You see streaming text output as Claude works, then get the final result packaged into the agent's response.

```mermaid
sequenceDiagram
participant You
participant Agent
participant Process

You->>Agent: agent.start("Fix bug in auth.py")
Agent->>Process: spawn claude CLI subprocess
Process-->>Agent: streaming JSONL deltas
Agent-->>You: "Looking at auth.py..."
Agent-->>You: "Found the issue..."
Agent-->>You: "Fixed authentication bug"
```

---

## Best Practices

<AccordionGroup>
<Accordion title="Use praisonai import for string backend IDs">
Prefer `from praisonai import Agent` when passing a string backend id like `"claude-code"`. The wrapper layer handles string resolution automatically.

```python
# ✅ Good - wrapper resolves string
from praisonai import Agent
agent = Agent(cli_backend="claude-code")

# ❌ Harder - manual resolution required
from praisonaiagents import Agent
from praisonai.cli_backends import resolve_cli_backend
agent = Agent(cli_backend=resolve_cli_backend("claude-code"))
```
</Accordion>

<Accordion title="Bump timeout_ms for long coding tasks">
Default timeout is 5 minutes. Complex refactoring or large file operations may need longer.

```python
cli_backend=resolve_cli_backend("claude-code", overrides={
"timeout_ms": 900_000 # 15 minutes
})
```
</Accordion>

<Accordion title="Ensure Claude CLI is installed and authenticated">
The CLI backend requires Claude CLI to be installed and authenticated. See [Claude CLI installation guide](./claude-cli#installation) for setup instructions.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Claude CLI docs link is likely broken from this path.

./claude-cli#installation is relative to docs/features/ and may not resolve correctly. Use the absolute docs route.

Link fix
-See [Claude CLI installation guide](./claude-cli#installation) for setup instructions.
+See [Claude CLI installation guide](/docs/cli/claude-cli#installation) for setup instructions.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
The CLI backend requires Claude CLI to be installed and authenticated. See [Claude CLI installation guide](./claude-cli#installation) for setup instructions.
The CLI backend requires Claude CLI to be installed and authenticated. See [Claude CLI installation guide](/docs/cli/claude-cli#installation) for setup instructions.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/features/cli-backend.mdx` at line 288, Replace the relative link
'./claude-cli#installation' in the CLI backend docs line with the absolute docs
route so the link resolves correctly from anywhere; specifically locate the
string './claude-cli#installation' in docs/features/cli-backend.mdx and change
it to the absolute path (for example '/docs/features/claude-cli#installation')
ensuring the anchor '#installation' is preserved.


```bash
# Install Claude CLI first
curl -fsSL https://claude.ai/install.sh | bash
claude setup-token
```
</Accordion>

<Accordion title="Environment sanitization strips ambient credentials">
`clear_env` removes `ANTHROPIC_API_KEY` and other ambient credentials before spawning Claude. Expect Claude to use its own auth profile rather than environment variables.
</Accordion>
</AccordionGroup>

---

## Related

<CardGroup cols={2}>
<Card title="Claude CLI" icon="message-bot" href="/docs/cli/claude-cli">
CLI flag version for external agent delegation
</Card>
<Card title="Agents" icon="user" href="/docs/concepts/agents">
Core Agent class and configuration
</Card>
</CardGroup>