Skip to content

Phase 1b: CLI Backend Protocol — YAML cli_backend: field + --cli-backend CLI flag + back-compat gate #1530

@MervinPraison

Description

@MervinPraison

Overview

Phase 1a of #1519 (merged in #1521) shipped the Agent(cli_backend="claude-code") Python surface. Phase 1b completes the "3 ways to do everything" commitment in AGENTS.md by adding the YAML and CLI surfaces for the exact same CLI Backend Protocol, and adding a back-compat smoke test for the legacy --external-agent flow.

End goal: the following three snippets must produce equivalent results.

# 1. Python (already landed via #1521)
from praisonai import Agent
agent = Agent(name="coder", cli_backend="claude-code")
agent.start("Refactor utils.py")
# 2. YAML (Phase 1b)
framework: praisonai
topic: coding
roles:
  coder:
    role: Code refactorer
    goal: Refactor Python modules
    backstory: Senior engineer
    cli_backend: claude-code           # NEW
    tasks:
      refactor:
        description: Refactor utils.py
        expected_output: Refactored code
# 3. CLI (Phase 1b)
praisonai "Refactor utils.py" --cli-backend claude-code

Background

  • Merged PR feat: CLI Backend Protocol - Claude Code as first-class Agent backend (Phase 1) #1521 landed praisonaiagents.cli_backend.protocols + praisonai.cli_backends.{registry,claude} + praisonai.Agent(cli_backend=...) wrapper
  • Registry already exposes list_cli_backends()['claude-code']; new backends (codex-cli, gemini-cli) will register the same way
  • Legacy --external-agent {claude,gemini,codex,cursor} flag still exists and must keep working (back-compat gate)

Current State (verified on main @ 6ee8fdff)

Surface File Current Gap
Python src/praisonai/praisonai/agent.py Agent(cli_backend="claude-code") works
YAML (agents_generator) src/praisonai/praisonai/agents_generator.py:1250-1267 (PraisonAgent(...) kwargs) No cli_backend parse ADD cli_backend=details.get('cli_backend')
CLI src/praisonai/praisonai/cli/main.py:1061 --external-agent only ADD --cli-backend
Back-compat src/praisonai/praisonai/cli/features/external_agents.py Still works (verified) ADD smoke test covering --external-agent claude

Acceptance Criteria

API / YAML

  • agents_generator.py PraisonAgent(...) call at line 1250 forwards cli_backend=details.get('cli_backend') (one-line change)
  • agents_generator.py details.get('cli_backend') accepts either a string id ("claude-code") or a dict {id: "claude-code", overrides: {timeout_ms: 60000}} and resolves through praisonai.cli_backends.resolve_cli_backend(id, overrides=...)
  • YAML config passing cli_backend: claude-code at role level produces an agent with agent._cli_backend is not None

CLI

  • New argparse flag: praisonai --cli-backend {claude-code,...} with choices pulled dynamically from list_cli_backends() so new backends auto-appear
  • Help text: "Delegate agent turns to a CLI backend (see praisonai backends list)"
  • When --cli-backend is passed, the auto-generated agent is constructed with cli_backend=args.cli_backend
  • New subcommand praisonai backends list prints registered backend ids, one per line
  • Mutual exclusion: --cli-backend X --external-agent Yargparse error "--cli-backend and --external-agent are mutually exclusive"

Back-compat (MUST NOT BREAK)

  • praisonai "Hello" --external-agent claude --external-agent-direct still reaches ExternalAgentsHandler.get_integration("claude") unchanged
  • A new smoke test asserts --external-agent claude path still resolves the integration (mocked subprocess)

Tests

  • src/praisonai/tests/unit/test_yaml_cli_backend.py — parse YAML with cli_backend: claude-code, assert agent wired (≥ 3 tests)
  • src/praisonai/tests/unit/test_cli_backend_flag.py — argparse-level tests for --cli-backend and backends list (≥ 4 tests)
  • src/praisonai/tests/unit/test_external_agents_backcompat.py — one regression test for --external-agent claude

Perf / invariants (do not regress)

File-by-file plan

Modify

File Change LOC
src/praisonai/praisonai/agents_generator.py Add cli_backend param to PraisonAgent(...) at line 1250; accept str or dict ~6
src/praisonai/praisonai/cli/main.py Add --cli-backend argparse flag near line 1061; wire into auto-agent path; add mutual-exclusion check ~15
src/praisonai/praisonai/cli/commands/__init__.py or new backends.py Add praisonai backends list subcommand ~20

Create

File Purpose LOC
src/praisonai/tests/unit/test_yaml_cli_backend.py YAML parse tests ~80
src/praisonai/tests/unit/test_cli_backend_flag.py CLI flag tests ~80
src/praisonai/tests/unit/test_external_agents_backcompat.py Legacy flag regression ~40
examples/yaml/cli_backend.yaml Minimal YAML example with cli_backend: claude-code ~15

Verification commands (paste-runnable)

cd /Users/praison/praisonai-package

# Unit tests
PYTHONPATH=src/praisonai-agents:src/praisonai python3 -m pytest \
  src/praisonai/tests/unit/test_yaml_cli_backend.py \
  src/praisonai/tests/unit/test_cli_backend_flag.py \
  src/praisonai/tests/unit/test_external_agents_backcompat.py -v

# Smoke — YAML
PYTHONPATH=src/praisonai-agents:src/praisonai python3 -c "
import yaml
from praisonai.agents_generator import AgentsGenerator
cfg = yaml.safe_load(open('examples/yaml/cli_backend.yaml'))
# ... parse and assert agent._cli_backend is not None
"

# Smoke — CLI flag discovery
PYTHONPATH=src/praisonai-agents:src/praisonai python3 -m praisonai.cli.main backends list
# expected: claude-code

# Back-compat gate
PYTHONPATH=src/praisonai-agents:src/praisonai python3 -m praisonai.cli.main --help | grep -E '(external-agent|cli-backend)'
# BOTH flags must appear

Out of scope (track separately)

  • Phase 2: live stdio session pool, MCP bundling, bot/gateway streaming deltas
  • Additional backends (codex-cli, gemini-cli, cursor-cli) — landing the protocol plumbing only
  • Docs pages in PraisonAIDocs — follow-up

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingclaudeAuto-trigger Claude analysisdocumentationImprovements or additions to documentation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions