Metadata-Version: 2.4
Name: coding-agent-wrapper
Version: 0.1.1
Summary: Unified Python library and CLI for orchestrating coding agents (Claude Code, Codex, etc.) with MCP tool servers and credential management.
Project-URL: Homepage, https://github.com/zzjas/caw
Project-URL: Repository, https://github.com/zzjas/caw
Author-email: Zijie <zijie4@illinois.edu>
License-Expression: Apache-2.0
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.10
Requires-Dist: mcp>=1.0
Requires-Dist: rich>=13.0
Requires-Dist: typer>=0.9
Requires-Dist: uvicorn>=0.30
Provides-Extra: dev
Requires-Dist: mypy; extra == 'dev'
Requires-Dist: prek; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest-xdist>=3.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.9; extra == 'dev'
Description-Content-Type: text/markdown

# caw

**Coding Agent Wrapper** — a Python library and CLI for orchestrating coding agents (Claude Code, Codex) with a unified interface, MCP tool servers, and credential management for Docker containers.

## Install

```bash
pip install coding-agent-wrapper
```

Import `caw`:

```python
import caw
```

For local development:

```bash
pip install -e .
```

Requires Python 3.10+.

## Library: Unified Agent Interface

caw wraps multiple coding agent CLIs behind a single `Agent` / `Session` API. Swap providers without changing your code.

### Quick start

```python
from caw import Agent

agent = Agent()  # defaults to claude_code
traj = agent.completion("Explain what this repository does")
print(traj.result)
print(f"{traj.usage.total_tokens} tokens, ${traj.usage.cost_usd:.4f}")
```

### Multi-turn sessions

```python
from caw import Agent

agent = Agent(provider="claude_code", model="opus", reasoning="high")
agent.set_system_prompt("You are a security reviewer.")

with agent.start_session() as session:
    turn1 = session.send("Review src/auth.py for vulnerabilities")
    print(turn1.result)

    turn2 = session.send("Now check src/api.py")
    print(turn2.result)

# session.end() called automatically, returns full Trajectory
```

### Providers

| Provider | CLI | Provider name |
|----------|-----|---------------|
| Claude Code | `claude` | `claude_code` |
| Codex | `codex` | `codex` |

Set via constructor, environment variable, or at runtime:

```python
agent = Agent(provider="codex")
# or
os.environ["CAW_PROVIDER"] = "codex"
# or
agent.set_provider("codex")
```

### MCP tool servers

Attach MCP servers so the agent can call external tools:

```python
from caw import Agent, MCPServer

agent = Agent()
agent.add_mcp_server(MCPServer(
    name="my_db",
    command="python",
    args=["-m", "my_mcp_server"],
))
```

### ToolKit: declarative tool servers

Define tools as Python classes. caw spins up an HTTP MCP server automatically:

```python
from caw import Agent, ToolKit, tool

class UserDB(ToolKit, server_name="user_db"):
    def __init__(self):
        self.users = ["Alice", "Bob"]

    @tool(description="List all users")
    async def list_users(self) -> str:
        return ", ".join(self.users)

    @tool(description="Add a user")
    async def add_user(self, name: str) -> str:
        self.users.append(name)
        return f"Added {name}"

db = UserDB()
agent = Agent(system_prompt="You have access to a user database.")
agent.add_tool_server(db.as_server())

traj = agent.completion("Add Eve to the user database, then list all users")
```

### Subagents

Register child agents that the parent can invoke as tools:

```python
from caw import Agent, AgentSpec

reviewer = AgentSpec(
    name="security_reviewer",
    description="Reviews code for security issues",
    system_prompt="You are a security expert. Review the given code.",
)

agent = Agent()
agent.add_subagent(reviewer)
traj = agent.completion("Review the auth module for vulnerabilities")

# Subagent trajectories are captured:
for sub in traj.subagent_trajectories:
    print(f"  subagent: {sub.agent}, {sub.num_turns} turns")
```

### Data models

Every interaction produces a `Trajectory` with structured data:

```
Trajectory
├── agent, model, session_id, created_at
├── turns: list[Turn]
│   ├── input: str
│   ├── output: list[TextBlock | ThinkingBlock | ToolUse]
│   │   └── ToolUse.subagent_trajectory: Trajectory | None
│   ├── usage: UsageStats
│   └── duration_ms: int
├── usage: UsageStats (own)
└── total_usage: UsageStats (own + all nested subagents)
```

Sessions are persisted to JSONL in `caw_data/` by default.

### Environment variables

| Variable | Purpose |
|----------|---------|
| `CAW_PROVIDER` | Default provider (`claude_code`, `codex`) |
| `CAW_MODEL` | Default model name |
| `CAW_EFFORT` | Default reasoning effort (`high`, `medium`, `low`) |

---

## CLI: `caw auth` — Credential Management for Docker Containers

Manages coding agent OAuth credentials so they stay in sync between your host and Docker containers. Supports Claude Code and Codex. Host credential files are never modified — they are bind-mounted into the container at run time.

```bash
caw auth setup                        # snapshot configs, write mount manifest
caw auth status                       # token expiry, last modified, mount flags
docker run $(caw auth docker-flags) -v ./project:/work my-image
caw auth teardown                     # rm -rf ~/.caw/auth/  (host files untouched)
```

See [`caw/auth/README.md`](caw/auth/README.md) for details on how it works, container setup, and supported agents.

## License

[Apache-2.0](LICENSE)
