Skip to content

docs: new CLI Backend Protocol + cli_backend Agent parameter (PR #1521 / Issue #1519) #235

@MervinPraison

Description

@MervinPraison

Context

PraisonAI PR MervinPraison/PraisonAI#1521 (merged 2026-04-23, Phase 1 of issue #1519) introduces a CLI Backend Protocol that lets any Agent delegate an entire conversation turn to an external CLI tool (Claude Code, and future codex-cli / gemini-cli) instead of calling an LLM directly.

This is a new programmatic feature exposed through the Python SDK and is distinct from the existing praisonai --external-agent claude CLI flag documented at docs/cli/claude-cli.mdx. A new documentation page must be created.

Decision: Create New Content (not an update)

I searched docs/ in PraisonAIDocs — there is no existing documentation for:

  • The cli_backend= parameter on Agent
  • CliBackendProtocol, CliBackendConfig, CliSessionBinding, CliBackendResult, CliBackendDelta
  • The CLI backend registry (register_cli_backend, resolve_cli_backend, list_cli_backends)
  • praisonai.Agent wrapper vs praisonaiagents.Agent core behavior for CLI backends

docs/cli/claude-cli.mdx is unrelated (covers the --external-agent CLI flag, a manager-delegation pattern, not Agent-level backend delegation).


What to Document

Target Location

Per AGENTS.md folder rules:

  • DO NOT create in docs/concepts/ (human-approved only)
  • CREATE in docs/features/cli-backend.mdx
  • Add to docs.json under the Features group only

Suggested Frontmatter

---
title: "CLI Backend"
sidebarTitle: "CLI Backend"
description: "Delegate Agent turns to external CLI tools like Claude Code"
icon: "terminal"
---

Feature Summary (user-facing)

CLI Backend lets you plug an external CLI coding assistant (like Claude Code) into a PraisonAI Agent so that every turn runs through that CLI instead of the built-in LLM. The agent keeps its name, role, instructions, tools-wrapper behaviour, and session continuity — only the "brain" swaps out.

Simplest example (the one to put at the top of the page, agent-centric per AGENTS.md):

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")

Why users care:

  • Use Claude Code's file-editing / tool-use capabilities inside an Agent workflow
  • Keep PraisonAI's Task/Process/memory/knowledge orchestration
  • Swap backend per agent (some agents local-LLM, one agent Claude Code)
  • Session continuity: agent_id is used as the CLI session id, so multi-turn chats resume

SDK Ground Truth (verified against source)

1. New Agent(cli_backend=...) parameter

File: praisonai-package/src/praisonai-agents/praisonaiagents/agent/agent.py:555 and docstring at :653-659.

Accepted value Behaviour
str e.g. "claude-code" Resolved via wrapper registry. Only works when importing from praisonai, not praisonaiagents
CliBackendProtocol instance Used directly
callable returning a protocol instance Invoked once at Agent init
None (default) Standard LLM execution

Two-import behaviour (critical for users — must be explained):

# Works: string resolution happens in the wrapper
from praisonai import Agent
agent = Agent(cli_backend="claude-code")

# Also works: resolve the backend yourself
from praisonaiagents import Agent
from praisonai.cli_backends import resolve_cli_backend
agent = Agent(cli_backend=resolve_cli_backend("claude-code"))

Using a string with the core praisonaiagents.Agent raises TypeError with a message pointing users at the two fixes above (source: agent.py:4729-4734).

2. New public exports in praisonaiagents

From praisonai-agents/praisonaiagents/__init__.py:205-211:

  • CliBackendProtocol — runtime-checkable typing.Protocol
  • CliBackendConfig — dataclass (declarative config, mirrors OpenClaw's shape)
  • CliSessionBinding — session state container
  • CliBackendResult — result of .execute()
  • CliBackendDelta — streamed delta from .stream()

3. New public exports in praisonai

From praisonai/praisonai/cli_backends/__init__.py:

  • register_cli_backend(backend_id, factory) — register a new backend
  • resolve_cli_backend(backend_id, overrides=None) — resolve to instance, optional config overrides
  • list_cli_backends() — list registered IDs
  • ClaudeCodeBackend — built-in Claude Code implementation

Built-ins auto-register on import: currently only "claude-code".

4. CliBackendConfig fields (full table — copy verbatim into doc)

From praisonaiagents/cli_backend/protocols.py:13-59.

Field Type Default Purpose
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)

5. Built-in ClaudeCodeBackend defaults (from praisonai/cli_backends/claude.py:24-73)

  • 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"
  • 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]document this: env is sanitised before spawning Claude, so ambient credentials won't leak
  • bundle_mcp=True, bundle_mcp_mode="claude-config-file", serialize=True, timeout_ms=300_000

6. How the Agent wires it

From agent.py:1926-1928 and _chat_via_cli_backend at :4738-4807:

  • Session id = agent._session_id if set, else f"agent-{agent.agent_id}"
  • System prompt built from system_prompt > backstory + role + goal
  • Images extracted from attachments (filtered to .png/.jpg/.jpeg/.gif/.bmp/.webp)
  • Calls backend.execute(prompt=..., session=..., images=..., system_prompt=...)
  • Errors raise RuntimeError with agent name + session id in message

Required Page Structure (per AGENTS.md)

Follow the exact page template in AGENTS.md §2. Sections, in order:

  1. Hero one-liner — "CLI Backend delegates Agent turns to an external CLI tool like Claude Code."
  2. Hero Mermaid diagramgraph LR showing: Agent → CLI Backend → external CLI (claude) → Result → Agent. Use the standard color scheme (#8B0000 agent, #189AB4 backend, #10B981 result).
  3. Quick Start (<Steps>):
    • Step 1: minimal string usage with from praisonai import Agent
    • Step 2: with a custom CliBackendConfig (e.g. override timeout_ms and model_aliases)
  4. How It Works — sequence diagram (User → Agent → CliBackend → claude CLI subprocess → Agent → User), plus short table of the 4 steps (build command, spawn subprocess with sanitised env, parse jsonl output, return CliBackendResult).
  5. Which option when? diagramgraph TB decision tree for choosing between cli_backend="claude-code" (simple), cli_backend=resolve_cli_backend("claude-code", overrides={...}) (tuned), cli_backend=MyBackend() (custom). Required per AGENTS.md §6.1 for multi-option pages.
  6. Configuration Options — the full CliBackendConfig table from §4 above, plus a ClaudeCodeBackend defaults block from §5.
  7. Common Patterns (3 patterns, each ~10 lines):
    • Pattern A — Swap backend per agent in a team: one Agent uses llm="gpt-4o", another uses cli_backend="claude-code", wired together with PraisonAIAgents / Task.
    • Pattern B — Tune timeout and model aliases: use resolve_cli_backend("claude-code", overrides={"timeout_ms": 900_000}).
    • Pattern C — Register a custom CLI backend: define a class implementing .config, async execute, async stream; register_cli_backend("my-cli", lambda: MyBackend()); use cli_backend="my-cli".
  8. User interaction flow (required per AGENTS.md §1.1 item 11) — short paragraph + mini sequence diagram showing what the user sees when they run agent.start("...") with cli_backend="claude-code" (subprocess spawn, streaming text, final result).
  9. Best Practices (<AccordionGroup>, 4 items):
    • Prefer from praisonai import Agent when passing a string backend id
    • Bump timeout_ms for long coding tasks (default 5 min)
    • Remember Claude CLI must be installed and authenticated (link to docs/cli/claude-cli.mdx install section)
    • clear_env strips ambient ANTHROPIC_API_KEY etc. — expect Claude to use its own auth profile
  10. Related (<CardGroup cols={2}>):
    • docs/cli/claude-cli.mdx (CLI flag version)
    • docs/concepts/agents.mdx

Cross-references to Update

  • docs/cli/claude-cli.mdx — add a callout at the top: "For programmatic use inside a Python Agent, see docs/features/cli-backend.mdx."
  • docs/concepts/agents.mdxDO NOT EDIT (human-approved folder). Instead, note in the new page that it extends the Agent class.
  • docs.json — add docs/features/cli-backend under the Features group, NOT under Concepts.
  • docs/features/DOCS_PARITY.md — flip CLI backend / external CLI integration from ❌/⚠️ to ✅ if listed.

Writing Style Reminders (from AGENTS.md)

  • Non-developer friendly; first code block must be ≤ 5 lines and make the reader think "is it really this easy?"
  • Progressive disclosure: simplest form first, config later, custom backend last
  • Mermaid diagram for every distinct concept on the page
  • Active voice, no "In this section we will…"
  • All code examples must run verbatim (imports included, no your-api-key-here placeholders)

Acceptance Criteria

  • New file docs/features/cli-backend.mdx exists and follows the AGENTS.md template exactly
  • First code example uses from praisonai import Agent and is ≤ 6 lines
  • Full CliBackendConfig field table present (24 fields, matching source)
  • ClaudeCodeBackend default config block present, including the clear_env list
  • Hero Mermaid diagram with standard color scheme
  • Decision-tree Mermaid for choosing string vs overrides vs custom backend
  • Sequence diagram for user interaction flow
  • Three common-pattern code blocks (team, overrides, custom backend)
  • docs.json updated — entry under Features, NOT Concepts
  • Cross-reference note added to docs/cli/claude-cli.mdx
  • No edits to docs/concepts/

Source Files to Re-read Before Writing

  1. praisonai-package/src/praisonai-agents/praisonaiagents/cli_backend/protocols.py — full config/protocol surface
  2. praisonai-package/src/praisonai-agents/praisonaiagents/agent/agent.py lines 552–660, 1926–1935, 4694–4810 — how the Agent uses the backend
  3. praisonai-package/src/praisonai/praisonai/cli_backends/claude.py — default ClaudeCodeBackend config
  4. praisonai-package/src/praisonai/praisonai/cli_backends/registry.py — registry API
  5. praisonai-package/src/praisonai/praisonai/agent.py — wrapper Agent, string resolution

Always re-read these before making any documentation change (SDK-first cycle, AGENTS.md §1.2).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingclaudeTrigger Claude Code analysisdocumentationImprovements or additions to documentationenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions