Skip to main content

Python ACP client library — connect to 29 AI coding agents with zero session overhead

Project description

soulacp

CI Python License

Python ACP client library — connect to AI coding agents with zero session overhead.

Features

  • 29 CLI adapters: Claude Code, Gemini, OpenCode, OpenClaw, Cursor, Codex, Qwen, Kimi, Codebuddy, Cline, Copilot, Minion, Vibe, Nova, Crow, Amp, Auggie, Autohand, Corust, DeepAgents, Factory Droid, fast-agent, Copilot LS, Goose, Junie, Kilo, pi ACP, Qoder, Stakpak
  • No own session layer: Directly manages CLI's native session
  • Zero token overhead: No middleware, no duplicate session history
  • ManagedSession: High-level API with auto session reuse, rotation, retry, fallback
  • Connection pooling: Reuse idle connections, session matching
  • Session store: Persistent user→session mapping with TTL (Memory or File cache)
  • Async streaming: Real-time response chunks via asyncio
  • Auto-retry: Exponential backoff with jitter
  • Host services: Built-in file system and terminal services for CLI tool calls
  • Pure stdlib: No external dependencies

Install

pip install soulacp

Quick Start

ManagedSession (recommended)

import asyncio
from soulacp import ManagedSession

async def main():
    async with ManagedSession(provider="claude", model="claude-sonnet-4-20250514") as session:
        # Simple query — session auto-managed
        response = await session.query("Hello!", user_id="user1")
        print(response)

        # Streaming
        async for chunk in session.stream("Write hello world", user_id="user1"):
            print(chunk, end="", flush=True)

asyncio.run(main())

ManagedSession automatically handles:

  • Session reuse: Same user_id gets same CLI session across requests
  • Session rotation: Fresh session on "prompt too long" overflow
  • Retry: Exponential backoff on transient errors
  • Fallback: Switch to alternate provider on persistent failure

Low-level API

import asyncio
from soulacp import ACPConfig, ACPConnectionPool, resolve_client_class

async def main():
    config = ACPConfig(provider="claude", model="claude-sonnet-4-20250514")
    client_class = resolve_client_class("claude")
    pool = ACPConnectionPool(config, client_class)

    async with pool.acquire() as (client, session_id):
        response = await client.query("Hello!")
        print(response)

    await pool.close_all()

asyncio.run(main())

Supported Agents

Agent Provider Model Example CLI Command
Claude Code claude claude-sonnet-4-20250514 claude or claude-code-acp
Gemini gemini gemini-3-flash-preview gemini --acp
OpenCode opencode opencode acp
OpenClaw openclaw openclaw acp
Cursor (ACP) cursor cursor-acp/default cursor-agent acp
Cursor (Legacy) cursor-cli cursor-cli/gpt-4 cursor-agent -p
Codex codex codex-acp/gpt-5 codex-acp
Qwen Code qwen qwen-acp/qwen-coder qwen-code --acp --experimental-skills
Kimi CLI kimi kimi-acp/default kimi acp
Codebuddy Code codebuddy codebuddy-acp/default codebuddy-code --acp
Cline cline cline-acp/default cline --acp
GitHub Copilot copilot copilot-acp/default copilot --acp
Minion Code minion minion-acp/default minion-code acp
Mistral Vibe vibe vibe-acp/default vibe-acp
Nova nova nova-acp/default nova acp
Crow CLI crow crow-acp/default crow-cli acp
Amp amp amp-acp/default amp-acp
Auggie auggie auggie-acp/default auggie --acp
Autohand autohand autohand-acp/default autohand-acp
Corust Agent corust corust-acp/default corust-agent-acp
DeepAgents deepagents deepagents-acp/default deepagents-acp
Factory Droid droid droid-acp/default droid exec --output-format acp
fast-agent fastagent fastagent-acp/default fast-agent-acp -x
Copilot LS copilot-ls copilot-ls-acp/default copilot-language-server --acp
Goose goose goose-acp/default goose acp
Junie junie junie-acp/default junie --acp=true
Kilo kilo kilo-acp/default kilo acp
pi ACP pi pi-acp/default pi-acp
Qoder qoder qoder-acp/default qodercli --acp
Stakpak stakpak stakpak-acp/default stakpak acp

Usage

Claude Code

import asyncio
from soulacp import ManagedSession

async def main():
    async with ManagedSession(provider="claude", model="claude-sonnet-4-20250514") as session:
        response = await session.query("Hello!")
        print(response)

asyncio.run(main())

Gemini

import asyncio
from soulacp import ManagedSession

async def main():
    async with ManagedSession(provider="gemini", model="gemini-3-flash-preview") as session:
        response = await session.query("Hello!")
        print(response)

asyncio.run(main())

Codex (OpenAI)

Codex uses ChatGPT login (no OPENAI_API_KEY required) — run codex login once, then soulacp picks up ~/.codex/auth.json automatically.

import asyncio
from soulacp import ManagedSession

async def main():
    # gpt-5.5 is the ChatGPT-auth friendly model (recommended for ManagedSession)
    async with ManagedSession(provider="codex", model="codex-acp/gpt-5.5") as session:
        response = await session.query("Hello!")
        print(response)

asyncio.run(main())

Environment variables (soulacp 0.1.5+, all optional):

Variable Values Default Purpose
CODEX_REASONING_EFFORT minimal / low / medium / high / xhigh medium Reasoning budget
CODEX_SANDBOX_MODE read-only / workspace-write / danger-full-access (codex default) File-system permission
CODEX_APPROVAL_POLICY untrusted / on-failure / on-request / never (codex default) Approval prompts
CODEX_NETWORK_ACCESS true / false false Allow network in workspace-write

To match Claude's "full autonomy" mode (no prompts, can write within workspace, network on):

export CODEX_SANDBOX_MODE=workspace-write
export CODEX_APPROVAL_POLICY=never
export CODEX_NETWORK_ACCESS=true

For API-key auth instead of ChatGPT, set OPENAI_API_KEY and pick an API-keyed model (e.g. codex-acp/gpt-5.5-codex, codex-acp/o3, codex-acp/o4-mini).

Multi-Agent

import asyncio
from soulacp import ManagedSession

async def main():
    # Claude for code generation
    async with ManagedSession(provider="claude", model="claude-sonnet-4-20250514") as claude:
        code = await claude.query("Write a sorting algorithm in Python")

    # Gemini for code review
    async with ManagedSession(provider="gemini", model="gemini-3-flash-preview") as gemini:
        review = await gemini.query(f"Review this code:\n{code}")

asyncio.run(main())

Session Management

ManagedSession + ProviderSessionStore

ManagedSession uses ProviderSessionStore internally to map (user_id, provider) to CLI session IDs:

from soulacp import ManagedSession

session = ManagedSession(provider="claude", model="claude-sonnet-4-20250514")

# First request — creates new CLI session, stores mapping
await session.query("Remember 42.", user_id="alice")

# Second request — reuses same CLI session (alice→session_abc)
await session.query("What number?", user_id="alice")

# Different user — gets different CLI session
await session.query("Hello!", user_id="bob")

Custom Session Store

from soulacp import ManagedSession, ProviderSessionStore, FileCache

# Persistent file-based session store
store = ProviderSessionStore(cache=FileCache("~/.soulacp/sessions.json"))
session = ManagedSession(provider="claude", model="claude-sonnet-4-20250514", session_store=store)

Session Lifecycle

Event Behavior
First request New CLI session created, mapping stored (TTL 7 days)
Subsequent requests Same user_id → same CLI session (reuse)
"Prompt too long" Auto-rotate to fresh session, clear old mapping
Connection error Clear mapping, retry with new session
Fallback Switch to alternate provider (e.g. claude→gemini)

Cache Backends

from soulacp import MemoryCache, FileCache

# In-memory (default) — fast, lost on restart
memory = MemoryCache(max_size=10000)

# File-based — persists across restarts
file_cache = FileCache("~/.soulacp/sessions.json", debounce_seconds=1.0)

Low-level Session Control

from soulacp import ACPConnectionPool, ACPConfig, resolve_client_class

config = ACPConfig(provider="claude", model="claude-sonnet-4-20250514")
pool = ACPConnectionPool(config, resolve_client_class("claude"))

# Explicit session reuse
async with pool.acquire() as (client, sid):
    await client.query("Remember 42.")

async with pool.acquire(session_id=sid) as (client, sid2):
    assert sid2 == sid  # Same CLI session
    response = await client.query("What number?")

Configuration

Environment Variables

Variable Default Description
ACP_PROVIDER Provider name
ACP_MODEL Model identifier
ACP_POOL_SIZE 10 Max pool connections
ACP_TIMEOUT_CONNECT 30 Connection timeout (seconds)
ACP_TIMEOUT_PROMPT 2592000 Prompt timeout (seconds, 30 days)
ACP_TIMEOUT_STREAM 2592000 Stream chunk timeout (seconds, 30 days)
ACP_POOL_IDLE_TIMEOUT 2592000 Pool idle timeout (seconds, 30 days)
ACP_AUTO_APPROVE true Auto-approve tool permissions
ACP_MAX_RETRIES 3 Max retry attempts

Programmatic

from soulacp import ACPConfig

config = ACPConfig(
    provider="claude",
    model="claude-sonnet-4-20250514",
    pool_size=5,
    timeout_connect=60,
    auto_approve_permissions=True,
    enable_fallback=True,
)

From Environment

from soulacp import ACPConfig

config = ACPConfig.from_env()

Architecture

ManagedSession (high-level API)
  ├── ProviderSessionStore (user→session mapping)
  │   └── CacheBackend (MemoryCache / FileCache)
  ├── ACPConnectionPool (connection reuse + health check)
  │   └── ACPClientBase (JSON-RPC over stdio subprocess)
  │       ├── ClaudeACPClient      ├── ClineACPClient
  │       ├── GeminiACPClient      ├── CopilotACPClient
  │       ├── OpenCodeACPClient    ├── MinionACPClient
  │       ├── OpenClawACPClient    ├── VibeACPClient
  │       ├── CursorACPClient      ├── NovaACPClient
  │       ├── CodexACPClient       ├── CrowACPClient
  │       ├── QwenACPClient        └── CursorCLIClient (legacy)
  │       ├── KimiACPClient
  │       └── CodebuddyACPClient
  └── Services
      ├── FSService (file system operations)
      └── TerminalService (subprocess execution)

Testing

# Unit tests (no CLI required)
pytest tests/ --ignore=tests/test_integration*.py -v

# Integration tests (requires specific CLI installed, auto-skips if not available)
pytest tests/test_integration.py -v          # Claude Code
pytest tests/test_integration_gemini.py -v   # Gemini
pytest tests/test_integration_codex.py -v    # Codex

# All tests
pytest tests/ -v

AIXP Labs aixp.dev

AIXP Labs develops and maintains the following core projects:

Project Description Website
HSAW Human Sovereignty and Wellbeing — Axiom 0 white paper (foundation) hsaw.dev
AILP AI List Protocol — agent discovery and capability advertising ailp.dev
AIVP AI Value Protocol — international commerce, crypto asset settlement aivp.dev
AIRP AI RMB Protocol — Mainland China commerce, RMB licensed settlement airp.dev
AIBP AI Bot Protocol — social communication and trust aibp.dev
AIAP AI Application Protocol — governance and compliance aiap.dev
AISOP AI Standard Operating Protocol — flow program definition aisop.dev
SoulBot AI agent runtime and framework soulbot.dev
SoulACP Adapter library — bridging CLI tools and LLM providers (this project) soulacp.dev

⚠️ Disclaimer

This software is experimental and provided for research and educational purposes only. Not intended for production use. Use at your own risk. The authors assume no liability for any damages arising from the use of this software. See LICENSE for full terms (Apache 2.0).

License

Apache License 2.0 - Copyright 2026 AIXP Labs AIXP.dev | SoulACP.dev


Align Axiom 0: Human Sovereignty and Wellbeing. Version: SoulACP V0.1.2. www.soulacp.dev

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

soulacp-0.1.5.tar.gz (80.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

soulacp-0.1.5-py3-none-any.whl (92.1 kB view details)

Uploaded Python 3

File details

Details for the file soulacp-0.1.5.tar.gz.

File metadata

  • Download URL: soulacp-0.1.5.tar.gz
  • Upload date:
  • Size: 80.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.9

File hashes

Hashes for soulacp-0.1.5.tar.gz
Algorithm Hash digest
SHA256 aee73d64e3410c1fa5448af847f073114dc6dfb894ed19bf5292b06e0c387f80
MD5 b822f6f6d8bf00e07985fd08d7fdc337
BLAKE2b-256 a78b7049d9987c5df28c113329307d13802847c098a42bf7cee0298ee756b343

See more details on using hashes here.

File details

Details for the file soulacp-0.1.5-py3-none-any.whl.

File metadata

  • Download URL: soulacp-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 92.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.9

File hashes

Hashes for soulacp-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 4f2c126e9d370290a835fb55f7f393d75c0b58f133caed18959f6b35caac7db7
MD5 93257dadaad4262886f32c6aa550c744
BLAKE2b-256 5af93e82744de2d16df06355c9a2df8062bd37ca1ea63b2a18ac43f43f142e85

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page