amplifier-profiles - System Design
November 30, 2025 · View on GitHub
This document describes the design and architecture of the amplifier-profiles library, which provides profile and agent loading, inheritance resolution, and Mount Plan compilation.
Related Documentation:
- API Reference - ProfileLoader, AgentLoader, compile_profile_to_mount_plan
- Profile Authoring - User guide for creating profiles
- Agent Authoring - User guide for creating agents
Purpose
Profiles are reusable, composable configuration bundles that compile to Mount Plans. They provide a simple way to manage complex module configurations and share setups across teams and projects.
Profiles solve several problems:
- Reusability: Define common configurations once, use everywhere
- Composition: Build complex configs from simple pieces via inheritance
- Shareability: Distribute profiles via Git, package managers, or file sharing
- Layering: Apply team and user customizations without modifying base profiles
- Simplicity: High-level YAML frontmatter instead of verbose Mount Plans
Profile Format
Profiles are Markdown files with YAML frontmatter:
# web-dev.md
---
profile:
name: web-dev
version: 1.0.0
description: Web development profile with React tooling
extends: base # Optional: inherit from another profile
session:
orchestrator: loop-streaming
context: context-persistent
max_tokens: 200000
compact_threshold: 0.92
providers:
- module: provider-anthropic
config:
model: claude-sonnet-4-5
api_key: ${ANTHROPIC_API_KEY}
tools:
- module: tool-filesystem
config:
allowed_paths: ["."]
require_approval: false
- module: tool-bash
- module: tool-web
hooks:
- module: hooks-logging
config:
output_dir: .amplifier/logs
- module: hooks-backup
---
[Optional system instruction or additional content can go here]
Profile Metadata
The profile section contains metadata:
- name (required): Unique identifier for the profile
- version (required): Semantic version (e.g., "1.0.0")
- description (required): Human-readable description
- extends (optional): Name of parent profile to inherit from
Session Configuration
The session section specifies core module choices:
- orchestrator (required): Which orchestrator module to use
- context (required): Which context manager to use
- max_tokens (optional): Token limit for context manager
- compact_threshold (optional): When to trigger context compaction (0.0-1.0)
- auto_compact (optional): Enable automatic compaction (boolean)
Module Lists
Modules are specified as arrays:
providers:
- module: provider-anthropic
config:
model: claude-sonnet-4-5
- module: provider-openai
config:
model: gpt-5.1-codex
Each module entry has:
- module (required): Module ID to load
- config (optional): Module-specific configuration dictionary
Agent Configuration
Agents use a "Smart Single Value" format that's simple and inheritance-friendly:
# Option 1: Load all discovered agents
agents: all
# Option 2: Disable agents completely
agents: none
# Option 3: Load specific agents by name
agents:
- zen-architect
- bug-hunter
- custom-agent
# Option 4: Omit to inherit from parent (default behavior)
# (no agents field)
Inheritance semantics:
- If
agentsis omitted in a child profile, it inherits the parent's setting - If
agentsis specified, it completely overrides the parent - Use
exclude: {agents: all}to disable inherited agents - Use
exclude: {agents: [agent-a, agent-b]}to exclude specific agents from an inherited list
Search paths: Agent search paths (where to look for agent files) are configured by the application (CLI, etc.), not in profiles. The agents field only controls which of the discovered agents to load.
Search Path Mechanism
ProfileLoader discovers profiles from multiple search paths using first-match-wins precedence. Applications inject search paths as policy:
┌──────────────────────────────────────────────────────────┐
│ HIGHER PRECEDENCE (later in search_paths list) │
│ First match wins from highest precedence path │
├──────────────────────────────────────────────────────────┤
│ Application-defined paths (examples): │
│ • Project-local: .amplifier/profiles/ │
│ • User-global: ~/.amplifier/profiles/ │
│ • App-bundled: <app>/data/profiles/ │
├──────────────────────────────────────────────────────────┤
│ LOWER PRECEDENCE (earlier in search_paths list) │
└──────────────────────────────────────────────────────────┘
Library mechanism: Accepts any list of Path objects, searches in order, returns first match.
Application policy: Decides which paths to search and in what order.
Typical pattern: Applications provide 2-4 search paths representing system defaults, user customization, and project-specific overrides.
See your application's documentation (e.g., amplifier-app-cli) for specific path conventions and environment variable support.
Profile Resolution
When a profile is activated, the system resolves it through several steps:
1. Inheritance Chain Resolution
If the profile has an extends field, the system:
- Loads the base profile
- Recursively resolves its inheritance chain
- Merges from bottom to top (base → child)
Example:
# foundation.md
---
profile:
name: foundation
session:
orchestrator: loop-basic
context: context-simple
---
# base.md
---
profile:
name: base
extends: foundation
session:
max_tokens: 100000 # Adds to foundation
tools:
- module: tool-filesystem
hooks:
- module: hooks-logging
---
# dev.md
---
profile:
name: dev
extends: base
session:
orchestrator: loop-streaming # Overrides base's orchestrator
tools:
- module: tool-web
---
Result: dev uses loop-streaming (overriding base), inherits filesystem tools and logging hooks from base, and adds tool-web.
Note on Markdown Body Inheritance: The extends: field inherits YAML configuration (session settings, module lists) but NOT the markdown body. Each profile's markdown body contains its own instructions. Use @mentions to reference shared instruction files if you want to avoid copy-pasting content across profiles.
2. Overlay Application
After resolving inheritance, the system looks for overlays:
- Bundled overlay:
<profile-name>.mdin bundled profiles - Project overlay:
<profile-name>.mdin project profiles directory - User overlay:
<profile-name>.mdin user profiles directory
Each overlay is merged with increasing precedence, allowing customization without modifying the base profile.
Example workflow:
base.md (bundled)
→ base.md (project overlay)
→ base.md (user overlay)
→ Final configuration
3. Mount Plan Compilation
The final merged profile is compiled into a Mount Plan dictionary:
# Profile YAML frontmatter
session:
orchestrator: loop-basic
context: context-simple
providers:
- module: provider-mock
# Compiles to Mount Plan
{
"session": {
"orchestrator": "loop-basic",
"context": "context-simple"
},
"providers": [
{"module": "provider-mock"}
]
}
4. Further Merging
After profile compilation, the Mount Plan can be further merged with application-specific configurations. Applications (like amplifier-app-cli) typically merge:
- User settings files
- Project settings files
- CLI option overrides
- Environment variables
This merging is app policy, not library responsibility. See individual application documentation for details.
Using Profiles
In Python Code
from amplifier_profiles import ProfileLoader, compile_profile_to_mount_plan
from amplifier_core import AmplifierSession
from pathlib import Path
# Create loader with search paths
loader = ProfileLoader(
search_paths=[
Path("data/profiles"), # Application bundled
Path.home() / ".amplifier/profiles", # User global
Path(".amplifier/profiles"), # Project local
]
)
# Load profile (overlay merging automatic)
profile = loader.load_profile("dev")
# Compile to Mount Plan
mount_plan = compile_profile_to_mount_plan(profile)
# Use with AmplifierSession
async with AmplifierSession(config=mount_plan) as session:
response = await session.execute("Hello, Amplifier!")
CLI usage: For command-line usage examples, see your application's documentation (e.g., amplifier-app-cli).
Creating Custom Profiles
Simple Profile
Create ~/.amplifier/profiles/my-profile.md:
---
profile:
name: my-profile
version: 1.0.0
description: My custom configuration
session:
orchestrator: loop-basic
context: context-simple
providers:
- module: provider-anthropic
config:
model: claude-sonnet-4-5
api_key: ${ANTHROPIC_API_KEY}
---
Use it:
amplifier profile use my-profile
Extending Bundled Profiles
Build on existing profiles:
---
profile:
name: my-dev
version: 1.0.0
description: My development setup
extends: dev # Inherit from bundled dev profile
# Add extra tools
tools:
- module: tool-custom
config:
api_url: http://localhost:8000
# Override provider model
providers:
- module: provider-anthropic
config:
model: claude-opus-4-1
api_key: ${ANTHROPIC_API_KEY}
---
Project Profiles
Create .amplifier/profiles/project-standards.md in your project:
---
profile:
name: project-standards
version: 1.0.0
description: Project-wide standards and tooling
extends: dev
session:
max_tokens: 150000 # Project standard
hooks:
- module: hooks-project-compliance
config:
enforcement_level: strict
---
Commit to version control:
git add .amplifier/profiles/project-standards.md
git commit -m "Add project profile"
Profile Overlays
Overlays allow non-destructive customization of profiles without duplicating them.
Creating an Overlay
If you want to customize the bundled dev profile:
Option 1: Project-wide customization
Create .amplifier/profiles/dev.md:
---
# This overlays the bundled dev profile
session:
max_tokens: 250000 # Project wants more tokens
tools:
- module: tool-project-specific
---
Option 2: Personal customization
Create ~/.amplifier/profiles/dev.md:
---
# Personal customizations to dev profile
providers:
- module: provider-anthropic
config:
model: claude-opus-4-1 # I prefer Opus
---
Overlay Precedence
Given a profile dev:
- Load bundled
dev.mdfrom package data - If
.amplifier/profiles/dev.mdexists, merge it (project layer) - If
~/.amplifier/profiles/dev.mdexists, merge it (user layer) - Result is the effective configuration
Environment Variables
Profiles support environment variable expansion using ${VAR} syntax:
providers:
- module: provider-anthropic
config:
api_key: ${ANTHROPIC_API_KEY}
organization: ${ANTHROPIC_ORG}
base_url: ${ANTHROPIC_API_URL}
Variables are expanded at runtime when the Mount Plan is compiled.
Undefined variables: If an environment variable is not set, it expands to an empty string.
Best Practices
Profile Naming
- Bundled profiles: Single word (e.g.,
base,dev,general) - Project profiles: Descriptive (e.g.,
frontend-dev,backend-prod) - User profiles: Personal preference (e.g.,
alice-dev,my-research)
Version Management
- Use semantic versioning:
MAJOR.MINOR.PATCH - Increment MAJOR for breaking changes
- Increment MINOR for new features
- Increment PATCH for bug fixes
- Document changes in profile description or comments
Profile Composition
- Start from bundled base profiles when possible
- Use inheritance (
extends) for "is-a" relationships - Use overlays for customization without duplication
- Keep profiles focused - one purpose per profile
Configuration Scope
- Bundled: Minimal, widely applicable, stable defaults
- Project: Project standards, shared via git, project conventions
- User: Personal preferences, API keys, local paths
Security
- Never commit API keys to version control
- Use environment variables for secrets:
${API_KEY} - Store user-specific credentials in
~/.amplifier/profiles/ - Consider using secret management tools for production
Advanced Features
Profile Inheritance Chains
Profiles can form inheritance chains:
base → dev → my-dev
Each level adds or overrides configuration from its parent.
Circular dependencies are detected and rejected.
Multiple Providers
You can configure multiple providers:
providers:
- module: provider-anthropic
config:
model: claude-sonnet-4-5
- module: provider-openai
config:
model: gpt-5.1-codex
The orchestrator will use them based on its strategy (e.g., fallback, load balancing).
Conditional Configuration
While profiles don't have built-in conditionals, you can achieve similar effects with:
- Multiple profiles: Create
dev-linux.mdanddev-windows.md - Environment variables: Use
${VAR}to make configs environment-specific - Overlays: Apply platform-specific overlays at project or user level
Troubleshooting
Profile Not Found
amplifier profile use my-profile
# Error: Profile 'my-profile' not found
Check:
- Profile file exists in one of the search paths
- Filename matches profile name (e.g.,
my-profile.md) - File has correct YAML frontmatter syntax
Debug:
amplifier profile list # See what profiles are discovered
Invalid Profile
amplifier profile validate my-profile.md
# Error: Invalid profile: ...
Common issues:
- Missing required fields (
name,version,description) - Invalid YAML frontmatter syntax
- Circular inheritance
- Non-existent parent profile in
extends
Module Not Found
amplifier run
# Error: Module 'tool-custom' not found
Check:
- Module is installed (
pip list | grep amplifier-mod) - Module ID is correct in profile
- Module search paths include the module location
Inheritance Issues
If a profile with extends doesn't work:
- Verify parent profile exists:
amplifier profile show <parent> - Check for circular inheritance
- Ensure parent profile is valid
- Use
amplifier profile show <your-profile>to see resolved configuration
Examples
Complete Examples
See the bundled profiles in amplifier_app_cli/data/profiles/ for reference:
foundation.md- Absolute minimum foundationbase.md- Core tools and hooksdev.md- Development profilegeneral.md- General-purpose profile with reliability focustest.md- Testing profile with mock providerfull.md- Kitchen sink with all modules
These profiles ship with the package and serve as templates for your own profiles.
Related Documentation
Within This Library:
- PROFILE_AUTHORING.md - User guide for creating profiles
- AGENT_AUTHORING.md - User guide for creating agents
- Main README - Complete API reference
External Dependencies:
- amplifier-core - Kernel mechanisms and Mount Plan specification
- amplifier-collections - Collection system for collection:name syntax
For Application Users: See your application's documentation (e.g., amplifier-app-cli) for CLI commands, search paths, and environment variables.