Progressive examples demonstrating how to use Amplifier Foundation, organized by learning progression.
# Set your API key
export ANTHROPIC_API_KEY='your-key-here'
# Run the first example
cd amplifier-foundation
uv run python examples/01_hello_world.pyGoal: Get running in 15 minutes
01_hello_world.py - Your first AI agent
The simplest possible Amplifier agent. Load foundation, compose with provider, execute a prompt. See the basic flow that all applications follow.
02_custom_configuration.py - Tailor agents via composition
See how to add tools, use streaming orchestrators, and customize behavior by composing different modules. Composition over configuration - swap capabilities, not flags.
03_custom_tool.py - Build domain-specific capabilities
Build custom tools (WeatherTool, DatabaseTool) that integrate seamlessly. Learn the Tool protocol: name, description, input_schema, execute().
Goal: Understand how Amplifier works internally
04_load_and_inspect.py - Load and inspect bundles
Learn how load_bundle() works and what a bundle contains. See the mount plan structure.
05_composition.py - Bundle composition and merge rules
Understand how compose() merges configuration. See how session, providers, tools, and instruction fields combine.
06_sources_and_registry.py - Loading from remote sources
Learn source formats (git, file, package). Use BundleRegistry for named bundle management.
07_full_workflow.py - Complete workflow with execution
See the full flow: prepare() → create_session() → execute(). Interactive demo with provider selection and LLM execution.
Goal: Production patterns and complex systems
08_cli_application.py - CLI application architecture See application architecture patterns: configuration management, logging, error handling, lifecycle management. Build reusable application classes.
09_multi_agent_system.py - Coordinate specialized agents Create specialized agents (Architect, Implementer, Reviewer) with different tools and instructions. See sequential workflows and context passing between agents.
23_spawn_with_agents.py - Spawn sub-sessions with named agents
Wire the session.spawn capability for agent delegation using the two sanctioned agent-config shapes: inline overlays (partial mount-plan dicts) and agent .md files (resolved via load_bundle()). Shows that a generic observability hook composed into the parent bundle is inherited by every spawned child via compose=True — no per-child wiring required.
Goal: Practical use cases and advanced patterns
10_meeting_notes_to_actions.py - Text processing workflow Transform meeting notes into structured action items. Shows practical document processing.
11_provider_comparison.py - Compare LLM providers Run the same prompt across multiple providers. Useful for evaluation and selection.
12_approval_gates.py - Human-in-the-loop patterns Add approval gates for sensitive operations. See hooks for control flow.
13_event_debugging.py - Session observability Debug and monitor session events. Learn the event system for observability.
14_session_persistence.py - Save and restore sessions Persist session state across runs. Enable conversation continuity.
17_multi_model_ensemble.py - Ensemble patterns Combine multiple models for improved results. Advanced orchestration patterns.
18_custom_hooks.py - Build custom hooks Create hooks for logging, redaction, and control. Extend session behavior.
19_github_actions_ci.py - CI/CD integration Run Amplifier in GitHub Actions. Automation and testing patterns.
20_calendar_assistant.py - External API integration Build a calendar assistant with external API calls. Real-world integration patterns.
21_bundle_updates.py - Bundle update detection Check for and apply updates to bundle sources. Two-phase pattern: check status (no side effects) → refresh (side effects). Foundation provides mechanism, app provides policy.
Start here to understand Amplifier basics:
- 01_hello_world.py - See it work immediately
- 02_custom_configuration.py - Understand composition
- 03_custom_tool.py - Build your first custom capability
Learn patterns for production-quality applications:
- Tier 1: 01-03 (get started)
- Tier 2: 04-07 (understand core concepts)
- Tier 3: 08-09 (see production patterns)
Deep dive into how Amplifier works:
- 04_load_and_inspect.py - Bundle structure
- 05_composition.py - Merge rules and composition
- 06_sources_and_registry.py - Module resolution and sources
- 07_full_workflow.py - Complete preparation and execution flow
Composable configuration units that produce mount plans for AmplifierSession. A bundle specifies which modules to load, how to configure them, and what instructions to provide.
bundle = Bundle(
name="my-agent",
providers=[...], # LLM backends
tools=[...], # Capabilities
hooks=[...], # Observability
instruction="..." # System prompt
)Combine bundles to create customized agents. Later bundles override earlier ones, allowing progressive refinement.
foundation = await load_bundle("foundation")
custom = Bundle(name="custom", tools=[...])
composed = foundation.compose(custom) # custom overrides foundationDownload and activate all modules before execution. The prepare() method resolves module sources (git URLs, local paths) and makes them importable.
prepared = await composed.prepare() # Downloads modules if needed
session = await prepared.create_session()Specify where to download modules from. Every module needs a source field for prepare() to resolve it.
tools=[
{
"module": "tool-filesystem",
"source": "git+https://github.com/microsoft/amplifier-module-tool-filesystem@main"
}
]Custom tools implement a simple protocol - no inheritance required:
class MyTool:
@property
def name(self) -> str:
return "my-tool"
@property
def description(self) -> str:
return "What this tool does..."
@property
def input_schema(self) -> dict:
return {
"type": "object",
"properties": {
"param": {"type": "string"}
},
"required": ["param"]
}
async def execute(self, input: dict) -> ToolResult:
return ToolResult(success=True, output="result")The minimal Amplifier application:
foundation = await load_bundle(foundation_path)
provider = await load_bundle(provider_path)
composed = foundation.compose(provider)
prepared = await composed.prepare()
session = await prepared.create_session()
async with session:
response = await session.execute("Your prompt")Compose tools into your agent:
tools = Bundle(
name="tools",
tools=[
{"module": "tool-filesystem", "source": "git+https://..."},
{"module": "tool-bash", "source": "git+https://..."},
]
)
composed = foundation.compose(provider).compose(tools)Register custom tools after session creation:
# After session is created
await session.coordinator.mount("tools", MyTool(), name="my-tool")
# Then use in session
async with session:
response = await session.execute("Use my custom tool")Sequential agent workflow:
# Agent 1: Design
architect = foundation.compose(provider).compose(architect_config)
prepared1 = await architect.prepare()
session1 = await prepared1.create_session()
async with session1:
design = await session1.execute("Design the system")
# Agent 2: Implement (uses Agent 1 output)
implementer = foundation.compose(provider).compose(implementer_config)
prepared2 = await implementer.prepare()
session2 = await prepared2.create_session()
async with session2:
code = await session2.execute(f"Implement: {design}")Modules need source fields so prepare() can download them:
{"module": "tool-bash", "source": "git+https://..."}This is normal - modules are downloaded from GitHub and cached in ~/.amplifier/cache/. Subsequent runs are fast.
Set your provider's API key:
export ANTHROPIC_API_KEY='your-key-here'
# or
export OPENAI_API_KEY='your-key-here'Examples assume you're running from the amplifier-foundation directory:
cd amplifier-foundation
uv run python examples/XX_example.pyIf path errors occur, check that Path(__file__).parent.parent resolves to the amplifier-foundation directory.
Amplifier favors swapping modules over toggling flags. Want streaming? Use orchestrator: loop-streaming. Want different tools? Compose a different tool bundle. No complex configuration matrices.
Tools, providers, hooks, and orchestrators implement protocols (duck typing), not base classes. No framework inheritance required - just implement the interface.
Module sources are explicit in configuration. No implicit discovery or magic imports. If you need a module, specify where it comes from: git repository, local path, or package name.
Modules are resolved and downloaded before execution (prepare()), not during runtime. This ensures deterministic behavior and clear error messages.
- Read the docs: amplifier-foundation documentation
- Explore modules: Check out pre-built modules on GitHub
- Build your own: Use 03_custom_tool.py as a template for custom capabilities
- Study patterns: 08_cli_application.py shows application architecture best practices
- GitHub Issues: Report bugs or ask questions
- Discussions: Share your use cases and get help from the community
- Documentation: Read the full documentation for detailed API reference