Metadata-Version: 2.5
Name: agentd
Version: 0.10.0
Summary: agent daemon
License-File: LICENSE
Requires-Python: >=3.10
Requires-Dist: aiohttp>=3.9
Requires-Dist: cryptography>=42
Requires-Dist: h11>=0.14
Requires-Dist: h2>=4.1
Requires-Dist: httpx>=0.27.0
Requires-Dist: litellm>=1.80.0
Requires-Dist: mcp-subscribe
Requires-Dist: mcp>=1.25.0
Requires-Dist: openai-agents>=0.6.4
Requires-Dist: openai>=1.76.0
Requires-Dist: pyyaml>=6.0.2
Requires-Dist: tldextract>=5
Requires-Dist: tomli>=2; python_full_version < '3.11'
Description-Content-Type: text/markdown

# agentd

Run agents behind the OpenAI client API, sandboxed.

- **PTC**: the model writes bash/python fences instead of JSON tool calls; MCP servers and `@tool` functions show up as skills.
- **Harnesses**: run Claude Code, Codex, OpenCode or omp through the same API and switch between them mid-conversation.
- **Sandboxes**: all agent code runs in a libkrun microVM or a Docker container, with no network and no credentials.
- **Egress**: optional network access through a host proxy that injects fnox secrets, so the sandbox never holds them.
- **agentd serve**: sessions, background turns and schedules as an API, reachable from other boxes over p2claw.

## Install

```bash
uv add agentd
```

Then set up a sandbox:

```bash
# macOS (Apple Silicon)
brew tap slp/krun
brew trust --formula slp/krun/libkrun slp/krun/libkrunfw slp/krun/virglrenderer-krun
brew install slp/krun/libkrun
python -m agentd.sandbox.rootfs build agents    # base image (needs Docker)

# Linux (KVM)
agentd-sandbox linux setup

# macOS via Colima (M3+, macOS 15+)
agentd-sandbox colima setup

# or Docker
python -m agentd.sandbox.rootfs build agents
```

Wheels for macOS arm64 and Linux x86_64/aarch64 include the launcher, `agentd-net` and (for Linux and Colima) libkrun, so nothing gets compiled. From a checkout, run `agentd/sandbox/build.sh` first.

`agentd-sandbox status` shows what's ready. Details, custom images and mounts: [docs/sandboxes.md](docs/sandboxes.md).

## PTC

```python
from agentd import patch_openai_with_ptc, display_events, tool
from openai import OpenAI

@tool
def calculate(expression: str) -> str:
    """Evaluate a math expression."""
    return str(eval(expression, {"__builtins__": {}}))

client = patch_openai_with_ptc(OpenAI(), cwd="./workspace")
stream = client.responses.create(model="claude-sonnet-5", input="List files, then calculate 12*12", stream=True)

for event in display_events(stream):
    if event.type == "text_delta":
        print(event.text, end="")
    elif event.type == "code_execution":
        print(f"\n$ {event.code}\n{event.output}")
```

More: [docs/ptc.md](docs/ptc.md).

## Harnesses

```python
client = patch_openai_with_ptc(OpenAI(), cwd="./workspace", harness="claude-code")
r = client.responses.create(model="claude-sonnet-5", input="Add a test for utils.py and run it")
r = client.responses.create(input="Review that test", previous_response_id=r.id, harness="codex")
```

`harness=` is `"ptc"` (default), `"claude-code"`, `"codex"`, `"opencode"` or `"omp"`. Each runs the real CLI inside the sandbox; credentials stay on the host behind a proxy. `agentd.available(client)` says which harnesses are ready and what models they have. Resume, transcripts, custom model servers: [docs/harnesses.md](docs/harnesses.md).

## Network and secrets

```python
from agentd import KrunExecutor
from agentd.egress import Egress
from agentd.egress.approvals import Approvals

executor = KrunExecutor(egress=Egress(
    allow=["pypi.org", "files.pythonhosted.org"],
    approvals=Approvals(webhook="https://approver.example/hook"),
))
```

Sandboxes get placeholders; the proxy swaps in real values from fnox only for the hosts, methods and paths its rules allow. Anything else is refused or sent to your approval webhook. libkrun only. [docs/egress-and-secrets.md](docs/egress-and-secrets.md).

## agentd serve

```bash
agentd serve
```

Serves sessions over Unix sockets: turns, background runs, schedules, transcripts. Other boxes reach it over p2claw, and `agentd.remote.Fleet` drives them. [docs/agentd-serve.md](docs/agentd-serve.md).

## Plain tool calling

`patch_openai_with_mcp(OpenAI())` runs MCP tool calls in a regular `tool_calls` loop with any LiteLLM provider, and `uvx agentd config.yaml` runs YAML-configured agents that react to MCP resource changes. [docs/tool-calling.md](docs/tool-calling.md).

Coming from 0.8: [docs/upgrading-0.9.md](docs/upgrading-0.9.md).

## License

MIT
