Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ uv run just format # auto-format with ruff

```
src/strands_compose/
├── __init__.py # Public API — load(), ComposeResult
├── __init__.py # Public API — load(), ResolvedConfig
├── models.py # Pydantic config models (AgentConfig, ModelConfig, …)
├── types.py # Shared type aliases
├── utils.py # Miscellaneous helpers
├── exceptions.py # Custom exception hierarchy
├── wire.py # Final assembly — wires all resolved objects into ComposeResult
├── wire.py # Final assembly — wires all resolved objects into ResolvedConfig
├── config/ # YAML loading, validation, interpolation
│ ├── schema.py # JSON-schema for config validation
│ ├── interpolation.py # ${VAR:-default} interpolation
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ uv run just format # auto-format with ruff

```
src/strands_compose/
├── __init__.py # Public API — load(), ComposeResult
├── __init__.py # Public API — load(), ResolvedConfig
├── models.py # Pydantic config models (AgentConfig, ModelConfig, …)
├── types.py # Shared type aliases
├── utils.py # Miscellaneous helpers
├── exceptions.py # Custom exception hierarchy
├── wire.py # Final assembly — wires all resolved objects into ComposeResult
├── wire.py # Final assembly — wires all resolved objects into ResolvedConfig
├── config/ # YAML loading, validation, interpolation
│ ├── schema.py # JSON-schema for config validation
│ ├── interpolation.py # ${VAR:-default} interpolation
Expand Down
1 change: 0 additions & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Expand Down
40 changes: 32 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.11+-blue.svg" alt="Python 3.11+"></a>
<a href="https://pypi.org/project/strands-compose/"><img src="https://img.shields.io/pypi/v/strands-compose.svg" alt="PyPI version"></a>
<a href="https://github.com/strands-agents/sdk-python"><img src="https://img.shields.io/badge/strands--agents-1.32.0-green.svg" alt="Strands Agents"></a>
<a href="LICENSE"><img src="https://img.shields.io/github/license/strands-compose/sdk-python" alt="License"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-blue.svg" alt="License"></a>
</p>
</div>

> [!IMPORTANT]
> Community project — not affiliated with AWS or the strands-agents team. Bugs here? [Open an issue](https://github.com/galuszkm/strands-compose/issues). Bugs in the underlying SDK? Head to [strands-agents](https://github.com/strands-agents/sdk-python).
> Community project — not affiliated with AWS or the strands-agents team. Bugs here? [Open an issue](https://github.com/strands-compose/sdk-python/issues). Bugs in the underlying SDK? Head to [strands-agents](https://github.com/strands-agents/sdk-python).

## What is this?

Expand Down Expand Up @@ -180,13 +180,16 @@ Split large configs across files — models in one, agents in another, MCP in a

## Getting started

Install with [uv](https://docs.astral.sh/uv/):

```bash
git clone https://github.com/strands-compose/sdk-python
cd sdk-python
uv sync --all-groups --all-extras
uv add strands-compose # Bedrock (default)
uv add strands-compose[ollama] # + Ollama
uv add strands-compose[openai] # + OpenAI
uv add strands-compose[gemini] # + Gemini
```

Install from PyPI:
Or with pip:

```bash
pip install strands-compose # Bedrock (default)
Expand Down Expand Up @@ -223,6 +226,27 @@ with resolved.mcp_lifecycle:
print(result)
```

### CLI

strands-compose ships a CLI to validate and debug configs without writing Python.

**`check`** — fast, static validation (YAML syntax, schema, variable interpolation, cross-references). No side-effects, safe for CI. Will **not** catch runtime issues like bad credentials, unreachable MCP servers, or missing Python modules.

```bash
strands-compose check config.yaml
strands-compose check base.yaml agents.yaml # merge multiple files
strands-compose check config.yaml --json # JSON output for scripts
strands-compose check config.yaml --quiet # exit code only
```

**`load`** *(recommended)* — full end-to-end validation. Builds real Python objects, starts MCP servers, and probes connectivity. Catches everything `check` catches plus import errors, auth failures, and MCP health issues.

```bash
strands-compose load config.yaml
strands-compose load config.yaml --json
strands-compose load config.yaml --quiet
```

---

## Examples
Expand Down Expand Up @@ -323,7 +347,7 @@ orchestrations:
connections:
- agent: content_team # Nested swarm as a delegate tool
description: "Content creation team."
- agent: qa_bot # Neasted agent as a delegate tool
- agent: qa_bot # Nested agent as a delegate tool
description: "Quality assurance."

entry: team_leader
Expand Down Expand Up @@ -363,7 +387,7 @@ async def main():
asyncio.run(main())
```

Event types: `TOKEN`, `REASONING`, `TOOL_START`, `TOOL_END`, `NODE_START`, `NODE_STOP`, `HANDOFF`, `COMPLETE` — each carrying `{type, agent_name, timestamp, data}`. Enough for a real-time frontend, a log aggregator, or a debugging dashboard. The `AnsiRenderer` gives you coloured terminal output out of the box — agent names, tool calls, reasoning traces, all streaming live.
Event types: `AGENT_START`, `TOKEN`, `REASONING`, `TOOL_START`, `TOOL_END`, `NODE_START`, `NODE_STOP`, `HANDOFF`, `COMPLETE`, `MULTIAGENT_START`, `MULTIAGENT_COMPLETE`, `ERROR` — each carrying `{type, agent_name, timestamp, data}`. Enough for a real-time frontend, a log aggregator, or a debugging dashboard. The `AnsiRenderer` gives you coloured terminal output out of the box — agent names, tool calls, reasoning traces, all streaming live.

---

Expand Down
3 changes: 3 additions & 0 deletions SUPPORT.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ If you encounter a bug or have a feature request:
## Security

If you discover a potential security issue, please see [SECURITY.md](SECURITY.md).

## Troubleshooting

- If you see tool name errors, ensure the sanitizer is included in your hooks list

**Import errors:**
Expand Down
2 changes: 1 addition & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>strands Compose</title>
<title>Strands Compose</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@500&display=swap" rel="stylesheet">
<style>
* {
Expand Down
26 changes: 13 additions & 13 deletions examples/10_nested/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
## What this shows

- **Referencing an orchestration inside another orchestration** — `content_team` (swarm)
is used as a child node in `pipeline` (delegate)
- **Topological sort** — strands-compose builds `content_team` before `pipeline` automatically
is used as a child node in `manager` (delegate)
- **Topological sort** — strands-compose builds `content_team` before `manager` automatically
- How agents, swarms, and graphs all become first-class nodes in a larger system

## How it works

```
pipeline (delegate)
├── content_team (swarm) — researcher ↔ writer ↔ reviewer
manager (delegate)
├── content_team (swarm) — researcher ↔ reviewer
└── qa_bot (agent) — quality-checks the final output
```

Expand All @@ -25,22 +25,22 @@ swarm and quality assurance to `qa_bot`. From the coordinator's perspective,
orchestrations:
content_team:
mode: swarm
agents: [researcher, writer, reviewer]
agents: [researcher, reviewer]
entry_name: researcher
max_handoffs: 15
max_handoffs: 10

pipeline:
manager:
mode: delegate
entry_name: coordinator
connections:
coordinator:
- agent: content_team # ← references the swarm above
description: "Content production team."
- agent: qa_bot
description: "Quality assurance check."
- agent: content_team # ← references the swarm above
description: "Content production team: researches and prepares the content."
- agent: qa_bot
description: "Quality assurance: checks the final content for accuracy and completeness."
```

strands-compose topologically sorts the orchestrations: `content_team` is built first,
then `pipeline` wraps it as a delegate tool.
then `manager` wraps it as a delegate tool.

## Good to know

Expand Down
2 changes: 1 addition & 1 deletion examples/12_streaming/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# A delegate orchestration with three agents: researcher, analyst, coordinator.
# The example shows how to stream all agent lifecycle events in real time
# using make_event_queue() from strands_compose.
# using wire_event_queue() from strands_compose.
#
# Run:
# uv run python examples/12_streaming/main.py
Expand Down
2 changes: 1 addition & 1 deletion examples/14_agent_factory/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Your factory must return a `strands.Agent` instance.
## Prerequisites

```bash
pip install strands-agents strands-agents-builder strands-compose
pip install strands-compose
```

## Run
Expand Down
4 changes: 2 additions & 2 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ Each example is a self-contained folder with a `README.md`, `config.yaml`, and `
| 02 | [02_vars_and_anchors](./02_vars_and_anchors/) | Variables & YAML anchors — DRY configuration patterns |
| 03 | [03_tools](./03_tools/) | `tools:` list — auto-loading Python functions as agent tools |
| 04 | [04_session](./04_session/) | `session_manager:` — persistent memory across turns |
| 05 | [05_hooks](./05_hooks/) | `hooks:` — `MaxToolCallsGuard`, `ToolNameSanitizer`, `StopGuard` |
| 05 | [05_hooks](./05_hooks/) | `hooks:` — `MaxToolCallsGuard`, `ToolNameSanitizer`, and custom hooks |
| 06 | [06_mcp](./06_mcp/) | MCP — all three connection modes: local server (`mcp_servers:`), external URL (`url:`), stdio (`command:`) |
| 07 | [07_delegate](./07_delegate/) | `mode: delegate` — coordinator routes to specialist agents |
| 08 | [08_swarm](./08_swarm/) | `mode: swarm` — peer agents hand off autonomously |
| 09 | [09_graph](./09_graph/) | `mode: graph` — explicit DAG pipeline between agents |
| 10 | [10_nested](./10_nested/) | Nested orchestration — Swarm inside a Delegate, `node_as_tool()` |
| 10 | [10_nested](./10_nested/) | Nested orchestration — Swarm inside a Delegate |
| 11 | [11_multi_file_config](./11_multi_file_config/) | Split config across files — infrastructure in one YAML, agents in another |
| 12 | [12_streaming](./12_streaming/) | `wire_event_queue()` — stream every token, tool call, and completion live |
| 13 | [13_graph_conditions](./13_graph_conditions/) | Conditional graph edges — `condition:`, `reset_on_revisit`, `max_node_executions` |
Expand Down
27 changes: 26 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,32 @@ version = "0.1.0"
description = "Zero-code YAML-driven agent orchestration over strands-agents"
readme = "README.md"
requires-python = ">=3.11"
license = "Apache-2.0"
authors = [
{ name = "Michal Galuszka", email = "michal.galuszka1@gmail.com" },
]
keywords = ["agents", "multi-agent", "orchestration", "yaml", "strands", "llm", "ai"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development :: Libraries",
"Typing :: Typed",
]
dependencies = [
"strands-agents~=1.32.0",
"pydantic>=2.12.5",
"pyyaml>=6.0.0",
"mcp>=1.24.0",
]

[project.scripts]
strands-compose = "strands_compose.cli:main"

[project.optional-dependencies]
agentcore-memory = [
"bedrock-agentcore>=1.4.0",
Expand All @@ -25,6 +44,13 @@ gemini = [
"strands-agents[gemini]~=1.32.0",
]

[project.urls]
Homepage = "https://github.com/strands-compose/sdk-python"
Repository = "https://github.com/strands-compose/sdk-python"
"Bug Tracker" = "https://github.com/strands-compose/sdk-python/issues"
Documentation = "https://github.com/strands-compose/sdk-python/tree/main/docs"
Changelog = "https://github.com/strands-compose/sdk-python/blob/main/CHANGELOG.md"

[dependency-groups]
dev = [
"ty>=0.0.17",
Expand All @@ -39,7 +65,6 @@ dev = [
"rust-just>=1.42.4",
"commitizen>=4.8.4",
"pre-commit>=4.3.0",
"starlette>=0.27.0",
]

[build-system]
Expand Down
Loading
Loading