1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//! Factory and routing logic for instantiating Composite Capsules.
use std::path::PathBuf;
use crate::capsule::{Capsule, CompositeCapsule};
use crate::error::CapsuleResult;
use crate::manifest::CapsuleManifest;
use astrid_mcp::SecureMcpClient;
/// Responsible for translating a declarative `Capsule.toml` manifest into
/// a live, unified `CompositeCapsule` packed with the correct execution engines.
pub struct CapsuleLoader {
mcp_client: SecureMcpClient,
}
impl CapsuleLoader {
/// Create a new Capsule Loader.
#[must_use]
pub fn new(mcp_client: SecureMcpClient) -> Self {
Self { mcp_client }
}
/// Parse a `CapsuleManifest` and build a unified `CompositeCapsule`.
///
/// This method is the "router" of the Manifest-First architecture. It inspects
/// the declarative TOML and provisions the correct runtime environments (WASM,
/// Host Process, Static Context) securely into a single Capsule object.
///
/// # Errors
/// Returns a `CapsuleError` if the manifest is invalid or requests an
/// unsupported engine configuration.
pub fn create_capsule(
&self,
manifest: CapsuleManifest,
capsule_dir: PathBuf,
) -> CapsuleResult<Box<dyn Capsule>> {
let mut composite = CompositeCapsule::new(manifest.clone())?;
// 1. WASM Component Engine (Pure WASM or Compiled OpenClaw)
if !manifest.components.is_empty() {
composite.add_engine(Box::new(crate::engine::WasmEngine::new(
manifest.clone(),
capsule_dir.clone(),
)));
}
// 2. Legacy Host MCP Engine (The Airlock Override)
for server in &manifest.mcp_servers {
// If server.server_type == "stdio", then the user is explicitly requesting
// a host process breakout.
if server.server_type.as_deref() == Some("stdio") {
composite.add_engine(Box::new(crate::engine::McpHostEngine::new(
manifest.clone(),
server.clone(),
capsule_dir.clone(),
self.mcp_client.clone(),
)));
}
}
// 3. Static Context Engine
// Always added. Handles injecting context_files, static commands, and skills
// directly into the OS memory without booting any VMs or Processes.
composite.add_engine(Box::new(crate::engine::StaticEngine::new(
manifest.clone(),
capsule_dir.clone(),
)));
composite.set_source_dir(capsule_dir);
Ok(Box::new(composite))
}
}