Architecture Overview¶
Amplifier is built on a modular architecture inspired by the Linux kernel model. This page provides a comprehensive overview of how all the pieces fit together.
The Linux Kernel Analogy¶
Amplifier mirrors Linux kernel concepts:
| Linux Concept | Amplifier Analog | Purpose |
|---|---|---|
| Ring 0 kernel | amplifier-core | Mechanisms only, never policy |
| Syscalls | Session operations | Few, sharp APIs |
| Loadable drivers | Modules | Compete at edges |
| Signals/Netlink | Event bus / hooks | Observe and control |
| /proc & dmesg | JSONL logs | Single canonical stream |
| Capabilities | Approval system | Deny-by-default |
| Scheduler | Orchestrator modules | Swap execution strategies |
| VM/Memory | Context manager | Conversation memory |
System Layers¶
Layer 1: Application¶
The application layer (e.g., amplifier-app-cli) handles:
- User interaction (CLI, REPL)
- Configuration resolution (profiles, settings)
- Mount Plan creation
- Approval and display systems
# Application creates Mount Plan
mount_plan = compile_profile_to_mount_plan(profile)
# Application creates session
session = AmplifierSession(mount_plan)
await session.initialize()
response = await session.execute(prompt)
Layer 2: Kernel¶
The kernel (amplifier-core, ~2,600 lines) provides:
- Mount Plan validation
- Module discovery and loading
- Session lifecycle management
- Event emission
- Coordinator infrastructure
# Kernel validates and loads
session.validate_mount_plan(mount_plan)
await session.load_modules()
# Kernel coordinates
coordinator.mount("providers", provider, name="anthropic")
await coordinator.hooks.emit("session:start", data)
Layer 3: Modules¶
Modules implement specific functionality:
- Providers: LLM API integrations
- Tools: Agent capabilities
- Orchestrators: Execution strategies
- Contexts: Memory management
- Hooks: Observability and control
# Module implements contract
class AnthropicProvider:
async def complete(self, request: ChatRequest) -> ChatResponse:
# Provider-specific implementation
...
Component Relationships¶
┌─────────────────────────────────────────────────────────────────┐
│ Application │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Profiles │ │ Config │ │ Collections│ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ └────────────────┼────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Mount Plan │ │
│ └──────┬──────┘ │
└──────────────────────────┼──────────────────────────────────────┘
│
▼
┌──────────────────────────┼──────────────────────────────────────┐
│ Kernel │
│ ┌─────────────┐ │
│ │ Session │ │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Coordinator │ │
│ └──────┬──────┘ │
│ ┌────────────────┼────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Loader │ │ Hooks │ │ Events │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└──────────────────────────┼──────────────────────────────────────┘
│
▼
┌──────────────────────────┼──────────────────────────────────────┐
│ Modules │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ Providers │ │ Tools │ │Orchestratr│ │ Context │ │
│ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Hooks │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Logging │ │ Approval│ │Redaction│ │Streaming│ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Session Execution Flow¶
User Prompt
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 1. Session receives prompt │
│ emit("prompt:submit", {prompt}) │
└──────┬──────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 2. Orchestrator takes control │
│ orchestrator.execute(prompt, context, providers, tools) │
└──────┬──────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 3. Add prompt to context │
│ context.add_message({role: "user", content: prompt}) │
└──────┬──────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 4. Call provider │
│ emit("provider:request", {...}) │
│ response = provider.complete(messages) │
│ emit("provider:response", {...}) │
└──────┬──────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 5. Process tool calls (if any) │
│ for tool_call in response.tool_calls: │
│ emit("tool:pre", {...}) │
│ result = tool.execute(input) │
│ emit("tool:post", {...}) │
│ context.add_message({role: "tool", ...}) │
│ → Loop back to step 4 if more tool calls │
└──────┬──────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 6. Return final response │
│ emit("prompt:complete", {...}) │
│ return response.text │
└─────────────────────────────────────────────────────────────┘
Key Design Decisions¶
Why a Tiny Kernel?¶
- Stability: Fewer changes = fewer breaking changes
- Auditability: Can be reviewed in an afternoon
- Maintainability: Single-throat-to-choke ownership
- Flexibility: All innovation happens at edges
Why Module Contracts?¶
- Independence: Modules develop independently
- Swappability: Replace any module without touching others
- Testing: Mock modules for isolated testing
- Competition: Multiple implementations can compete
Why Events?¶
- Observability: Everything important is observable
- Decoupling: Emitters don't know about observers
- Debugging: Complete audit trail
- Extensions: Add behavior via hooks, not code changes
Libraries¶
Supporting libraries provide higher-level functionality:
| Library | Purpose |
|---|---|
amplifier-profiles | Profile loading and inheritance |
amplifier-collections | Collection discovery and management |
amplifier-config | Three-scope configuration |
amplifier-module-resolution | Module source resolution |
These libraries are not part of the kernel—they're application-layer concerns.
For Different Audiences¶
Now that you understand the architecture, here's where to go based on what you want to do:
I Want to Use Amplifier¶
→ Start with Getting Started
→ Read CLI User Guide for the amplifier-app-cli application
I Want to Extend Amplifier with Modules¶
→ Read this Architecture section to understand the system
→ Follow Module Developer Guide for creating custom providers, tools, hooks
I Want to Build Applications on Amplifier¶
→ Read this Architecture section to understand the foundation
→ Follow Application Developer Guide for building apps on amplifier-core
→ Study Foundation Guide for using the core and libraries
I Want to Contribute to Amplifier Core¶
→ Read this Architecture section + Kernel Philosophy
→ Follow Foundation Developer Guide for working with the kernel and libraries
→ See Contributing for contribution guidelines
Next Steps¶
- Kernel Philosophy - Deep dive into kernel design
- Module System - How modules work
- Mount Plans - Configuration contract
- Event System - Observability
References¶
- → Design Philosophy - Kernel design principles and Linux kernel inspiration