xml-pipeline/README.md
dullfig 0553ec294f Update README and pyproject.toml for PyPI release
README.md:
- Rebrand from AgentServer to xml-pipeline
- Library-focused introduction with pip install
- Quick start guide with code examples
- Console example documentation
- Concise feature overview

pyproject.toml:
- Update authors to "xml-pipeline contributors"
- Update URLs to xml-pipeline.org

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 21:48:52 -08:00

220 lines
6 KiB
Markdown

# xml-pipeline
**Schema-driven XML message bus for multi-agent systems.**
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
xml-pipeline is a Python library for building multi-agent systems with validated XML message passing. Agents communicate through typed payloads, validated against auto-generated XSD schemas, with built-in LLM routing and conversation memory.
## Why XML?
JSON was a quick hack that became the default for AI tool calling, where its brittleness causes endless prompt surgery and validation headaches. xml-pipeline chooses XML deliberately:
- **Exact contracts** — XSD validation catches malformed messages before they cause problems
- **Tolerant parsing** — Repair mode recovers from LLM output quirks
- **Self-describing** — Namespaces prevent collision, schemas are discoverable
- **No escaping hell** — Mixed content, nested structures, all handled cleanly
Read the [full rationale](docs/why-not-json.md).
## Installation
```bash
pip install xml-pipeline
# With LLM provider support
pip install xml-pipeline[anthropic] # Anthropic Claude
pip install xml-pipeline[openai] # OpenAI GPT
# With all features
pip install xml-pipeline[all]
```
## Quick Start
### 1. Define a payload
```python
from dataclasses import dataclass
from third_party.xmlable import xmlify
@xmlify
@dataclass
class Greeting:
name: str
```
### 2. Write a handler
```python
from xml_pipeline.message_bus.message_state import HandlerMetadata, HandlerResponse
@xmlify
@dataclass
class GreetingReply:
message: str
async def handle_greeting(payload: Greeting, metadata: HandlerMetadata) -> HandlerResponse:
return HandlerResponse(
payload=GreetingReply(message=f"Hello, {payload.name}!"),
to="output",
)
```
### 3. Configure the organism
```yaml
# organism.yaml
organism:
name: hello-world
listeners:
- name: greeter
payload_class: myapp.Greeting
handler: myapp.handle_greeting
description: Greets users by name
- name: output
payload_class: myapp.GreetingReply
handler: myapp.print_output
description: Prints output
```
### 4. Run it
```python
import asyncio
from xml_pipeline.message_bus import bootstrap
async def main():
pump = await bootstrap("organism.yaml")
await pump.run()
asyncio.run(main())
```
## Console Example
Try the interactive console example:
```bash
pip install xml-pipeline[console]
python -m examples.console
```
```
> @greeter Alice
[greeter] Hello, Alice! Welcome to xml-pipeline.
> @echo Hello world
[echo] Hello world
> /quit
```
See [examples/console/](examples/console/) for the full source.
## Key Features
### Typed Message Passing
Payloads are Python dataclasses with automatic XSD generation:
```python
@xmlify
@dataclass
class Calculate:
expression: str
precision: int = 2
```
The library auto-generates:
- XSD schema for validation
- Example XML for documentation
- Usage instructions for LLM prompts
### LLM Router
Multi-backend LLM support with failover:
```yaml
llm:
strategy: failover
backends:
- provider: anthropic
api_key_env: ANTHROPIC_API_KEY
- provider: openai
api_key_env: OPENAI_API_KEY
```
```python
from xml_pipeline.llm import complete
response = await complete(
model="claude-sonnet-4",
messages=[{"role": "user", "content": "Hello!"}],
)
```
### Handler Security
Handlers are sandboxed. They cannot:
- Forge sender identity (injected by pump)
- Escape thread context (managed by registry)
- Route to undeclared peers (validated against config)
- Access other threads (opaque UUIDs)
### Conversation Memory
Thread-scoped context buffer tracks message history:
```python
from xml_pipeline.memory import get_context_buffer
buffer = get_context_buffer()
history = buffer.get_thread(metadata.thread_id)
```
## Architecture
```
┌─────────────────────────────────────────────────────────────────┐
│ StreamPump │
│ • Parallel pipelines per listener │
│ • Repair → C14N → Validate → Deserialize → Route → Dispatch │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Handlers │
│ • Receive typed payload + metadata │
│ • Return HandlerResponse or None │
│ • Cannot forge identity or escape thread │
└─────────────────────────────────────────────────────────────────┘
```
See [docs/core-principles-v2.1.md](docs/core-principles-v2.1.md) for the full architecture.
## Documentation
| Document | Description |
|----------|-------------|
| [Core Principles](docs/core-principles-v2.1.md) | Architecture overview |
| [Handler Contract](docs/handler-contract-v2.1.md) | How to write handlers |
| [Message Pump](docs/message-pump-v2.1.md) | Pipeline processing |
| [LLM Router](docs/llm-router-v2.1.md) | Multi-backend LLM support |
| [Configuration](docs/configuration.md) | organism.yaml reference |
| [Why Not JSON?](docs/why-not-json.md) | Design rationale |
## Requirements
- Python 3.11+
- Dependencies: lxml, aiostream, pyyaml, httpx, cryptography
## License
MIT License. See [LICENSE](LICENSE).
---
*XML wins. Safely. Permanently.*