Writing a Bundle¶
You've been using bundles -- composing foundation with recipes, layering on python-dev. Now it's time to build one from scratch and publish it. This guide walks through the file format, composition patterns, testing, and publishing conventions.
The File Format¶
A bundle is a Markdown file with YAML frontmatter. The frontmatter declares structure; the body becomes the system prompt.
---
bundle:
name: my-toolkit
version: 1.0.0
description: A custom toolkit for my team
includes:
- bundle: git+https://github.com/microsoft/amplifier-foundation@main
---
# My Toolkit
Instructions for the AI go here as plain Markdown.
That's a complete, functional bundle. Let's break down what each piece does.
The bundle: Section¶
Every bundle starts with identity:
bundle:
name: my-toolkit # Becomes the namespace for @mentions
version: 1.0.0 # Semantic versioning
description: A custom toolkit for my team
The name matters -- it becomes the namespace you use in @my-toolkit:path references
throughout the ecosystem.
The includes: Section¶
This is where composition happens. Each entry pulls in another bundle:
includes:
- bundle: git+https://github.com/microsoft/amplifier-foundation@main
- bundle: git+https://github.com/microsoft/amplifier-bundle-recipes@main
- bundle: my-toolkit:behaviors/my-toolkit
Other YAML Sections¶
Bundles can declare any combination of these:
| Section | Purpose |
|---|---|
tools: |
Tool modules to mount (e.g., module: tool-bash) |
providers: |
LLM backend configurations |
agents: |
Agent references via include: |
hooks: |
Lifecycle observers (logging, approval, streaming) |
context: |
Additional files loaded into the system prompt |
behaviors: |
Reusable capability packages (agents + context + tools) |
spawn: |
Controls what tools sub-agents inherit |
session: |
Orchestrator and session-level configuration |
Most bundles declare very few of these. That's by design.
The Thin Bundle Pattern¶
The most important pattern in bundle authoring is thin bundles: compose from existing bundles rather than redeclaring what they already provide.
Here's what NOT to do:
# BAD: Redeclares everything foundation already provides
includes:
- bundle: foundation
tools: # foundation already has these!
- module: tool-filesystem
- module: tool-bash
session:
orchestrator: # foundation already has this!
module: loop-streaming
Here's the correct approach:
---
bundle:
name: my-team-assistant
version: 1.0.0
description: Our team's development assistant
includes:
- bundle: git+https://github.com/microsoft/amplifier-foundation@main
- bundle: my-team-assistant:behaviors/my-team-assistant
---
# Team Assistant
@my-team-assistant:context/instructions.md
---
@foundation:context/shared/common-system-base.md
All tools, hooks, orchestrator, and streaming UI come from foundation. You add only what's unique -- your behavior and your instructions.
Bundles vs Behaviors¶
This distinction matters for reusability.
A bundle is a top-level configuration that defines a complete session. It's what
you pass to amplifier run --bundle.
A behavior is a reusable capability package that lives in behaviors/ inside
a bundle. It packages agents, context, and optionally tools into a composable unit
that any bundle can include.
my-toolkit/
├── bundle.md # The top-level bundle
├── behaviors/
│ └── my-toolkit.yaml # Reusable capability package
├── agents/
│ ├── code-reviewer.md
│ └── test-writer.md
└── context/
└── instructions.md
The behavior file (behaviors/my-toolkit.yaml) wires the pieces together:
bundle:
name: my-toolkit-behavior
version: 1.0.0
description: Code review and test writing agents
agents:
include:
- my-toolkit:code-reviewer
- my-toolkit:test-writer
context:
include:
- my-toolkit:context/instructions.md
Why separate them? Because another bundle can include just your behavior without taking your entire bundle configuration. Your agents become composable building blocks for the wider ecosystem.
Source URI Formats¶
Bundles are addressable through three URI formats:
| Format | Example | When to Use |
|---|---|---|
| Git URL | git+https://github.com/microsoft/amplifier-foundation@main |
Published bundles |
| Local path | file:///home/me/my-bundle or ./bundles/variant.yaml |
Development and testing |
| Namespace path | recipes:behaviors/recipes |
Cross-bundle references |
Git URLs pin to a branch or tag with @. Local paths are useful during development
before publishing. Namespace paths reference content within already-loaded bundles
using the bundle.name as the prefix.
In Markdown body text, add @ to eagerly load content:
@foundation:context/shared/common-system-base.md. In YAML sections, use the bare
namespace:path without the @ prefix.
Building a Complete Bundle¶
Let's walk through creating a data science team bundle step by step.
1. Create the directory structure:
data-science-bundle/
├── bundle.md
├── behaviors/
│ └── data-science.yaml
├── agents/
│ └── notebook-reviewer.md
└── context/
└── instructions.md
2. Write bundle.md -- thin, just includes and instructions:
---
bundle:
name: data-science
version: 1.0.0
description: Data science team assistant
includes:
- bundle: git+https://github.com/microsoft/amplifier-foundation@main
- bundle: git+https://github.com/microsoft/amplifier-bundle-python-dev@main
- bundle: data-science:behaviors/data-science
---
# Data Science Assistant
@data-science:context/instructions.md
---
@foundation:context/shared/common-system-base.md
3. Write the behavior (behaviors/data-science.yaml):
bundle:
name: data-science-behavior
version: 1.0.0
agents:
include:
- data-science:notebook-reviewer
context:
include:
- data-science:context/instructions.md
4. Write the agent (agents/notebook-reviewer.md):
---
meta:
name: notebook-reviewer
description: "Reviews Jupyter notebooks for reproducibility, code quality,
and documentation. Use when auditing or cleaning up notebooks."
---
# Notebook Reviewer
You are a notebook review specialist...
Three existing bundles composed, one custom agent added, under 20 lines of YAML.
Testing Your Bundle¶
Test locally before publishing:
amplifier run --bundle ./data-science-bundle/bundle.md "What agents are available?"
The --bundle flag accepts a local file path. Amplifier resolves the bundle,
loads all includes, and starts a session. Iterate until everything wires up correctly.
Check that your agents are registered:
amplifier run --bundle ./data-science-bundle/bundle.md "Delegate to notebook-reviewer to review notebooks in examples/"
[Tool: delegate] agent="data-science:notebook-reviewer", instruction="Review notebooks in examples/..."
If the delegation fails, check that the agent is listed in your behavior's
agents.include and that the namespace matches your bundle.name.
Publishing Your Bundle¶
Amplifier bundles follow a naming convention for discoverability:
amplifier-bundle-<name>
For example: amplifier-bundle-recipes, amplifier-bundle-python-dev,
amplifier-bundle-stories.
To publish:
- Create a GitHub repository following the naming convention
- Put your
bundle.mdat the repository root - Include
behaviors/,agents/, andcontext/directories as needed - Tag releases with semantic versions
Others install your bundle with:
amplifier bundle add git+https://github.com/your-org/amplifier-bundle-data-science@main
The canonical example to study is amplifier-bundle-recipes -- it demonstrates
behaviors, agents, context files, and composition with foundation.
Best Practices¶
Keep bundles thin. If you're including foundation, don't redeclare its tools or hooks. Your bundle should be a short list of includes plus your unique content.
Use behaviors for reusability. Package agents and context in behaviors/ so
others can include just your capability independently.
Consolidate instructions. Put instructions in context/instructions.md, not
inline in bundle.md. This lets both your behavior and root bundle reference the
same content without duplication.
One purpose per bundle. If your bundle does code review AND deployment AND monitoring, split into three bundles with behaviors. Each composes independently.
Don't put secrets in bundles. Provider API keys and environment-specific paths
belong in ~/.amplifier/settings.yaml, not in bundle configuration.
Use @mentions in Markdown, bare paths in YAML. The @ prefix is for Markdown
body text. YAML sections use namespace:path without @. Mixing these up causes
silent failures.