Schema-driven XML message bus for multi-agent systems
Project description
xml-pipeline
Schema-driven XML message bus for multi-agent systems.
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.
Installation
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
from dataclasses import dataclass
from third_party.xmlable import xmlify
@xmlify
@dataclass
class Greeting:
name: str
2. Write a handler
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
# 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
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:
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/ for the full source.
Key Features
Typed Message Passing
Payloads are Python dataclasses with automatic XSD generation:
@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:
llm:
strategy: failover
backends:
- provider: anthropic
api_key_env: ANTHROPIC_API_KEY
- provider: openai
api_key_env: OPENAI_API_KEY
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:
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 for the full architecture.
Documentation
| Document | Description |
|---|---|
| Core Principles | Architecture overview |
| Handler Contract | How to write handlers |
| Message Pump | Pipeline processing |
| LLM Router | Multi-backend LLM support |
| Configuration | organism.yaml reference |
| Why Not JSON? | Design rationale |
Requirements
- Python 3.11+
- Dependencies: lxml, aiostream, pyyaml, httpx, cryptography
License
MIT License. See LICENSE.
XML wins. Safely. Permanently.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file xml_pipeline-0.4.0.tar.gz.
File metadata
- Download URL: xml_pipeline-0.4.0.tar.gz
- Upload date:
- Size: 118.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0e01390cc632fe19e2fdaafc5f415215e00b33eea3b53657e04c59f9dbbd2c68
|
|
| MD5 |
789e1dff8352fe18c31f2e74a286b5d3
|
|
| BLAKE2b-256 |
1e40ae68624f72845106372a3d5b7fc8cc01aca06a988c0bd39a9d9f223bbb72
|
File details
Details for the file xml_pipeline-0.4.0-py3-none-any.whl.
File metadata
- Download URL: xml_pipeline-0.4.0-py3-none-any.whl
- Upload date:
- Size: 131.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4d3a2c99cdc20dcc857153944e68f868042d8731d38bc65a30ea2e7eb31282e5
|
|
| MD5 |
0af3ac3bcbbef72109f38395d2de5e69
|
|
| BLAKE2b-256 |
54e3728c3590dcec77d57d0f51fd8ed2dbaf9b22dace19f4341205a0491b06a3
|