Skip to main content

kernex_runtime/
lib.rs

1//! kernex-runtime: The facade crate that composes all Kernex components.
2//!
3//! Provides `Runtime` for configuring and running an AI agent runtime
4//! with sandboxed execution, multi-provider support, persistent memory,
5//! skills, and multi-agent pipeline orchestration.
6//!
7//! # Quick Start
8//!
9//! ```rust,ignore
10//! use kernex_runtime::RuntimeBuilder;
11//!
12//! #[tokio::main]
13//! async fn main() -> anyhow::Result<()> {
14//!     let runtime = RuntimeBuilder::new()
15//!         .data_dir("~/.kernex")
16//!         .build()
17//!         .await?;
18//!     Ok(())
19//! }
20//! ```
21
22use kernex_core::config::MemoryConfig;
23use kernex_core::error::KernexError;
24use kernex_memory::Store;
25use kernex_skills::{Project, Skill};
26
27/// Re-export sub-crates for convenience.
28pub use kernex_core as core;
29pub use kernex_memory as memory;
30pub use kernex_pipelines as pipelines;
31pub use kernex_providers as providers;
32pub use kernex_sandbox as sandbox;
33pub use kernex_skills as skills;
34
35/// A configured Kernex runtime with all subsystems initialized.
36pub struct Runtime {
37    /// Persistent memory store.
38    pub store: Store,
39    /// Loaded skills from the data directory.
40    pub skills: Vec<Skill>,
41    /// Loaded projects from the data directory.
42    pub projects: Vec<Project>,
43    /// Data directory path (expanded).
44    pub data_dir: String,
45}
46
47/// Builder for constructing a `Runtime` with the desired configuration.
48pub struct RuntimeBuilder {
49    data_dir: String,
50    db_path: Option<String>,
51}
52
53impl RuntimeBuilder {
54    /// Create a new builder with default settings.
55    pub fn new() -> Self {
56        Self {
57            data_dir: "~/.kernex".to_string(),
58            db_path: None,
59        }
60    }
61
62    /// Set the data directory (default: `~/.kernex`).
63    pub fn data_dir(mut self, path: &str) -> Self {
64        self.data_dir = path.to_string();
65        self
66    }
67
68    /// Set a custom database path (default: `{data_dir}/memory.db`).
69    pub fn db_path(mut self, path: &str) -> Self {
70        self.db_path = Some(path.to_string());
71        self
72    }
73
74    /// Build and initialize the runtime.
75    pub async fn build(self) -> Result<Runtime, KernexError> {
76        let expanded_dir = kernex_core::shellexpand(&self.data_dir);
77
78        // Ensure data directory exists.
79        tokio::fs::create_dir_all(&expanded_dir)
80            .await
81            .map_err(|e| KernexError::Config(format!("failed to create data dir: {e}")))?;
82
83        // Initialize store.
84        let db_path = self
85            .db_path
86            .unwrap_or_else(|| format!("{expanded_dir}/memory.db"));
87        let mem_config = MemoryConfig {
88            db_path: db_path.clone(),
89            ..Default::default()
90        };
91        let store = Store::new(&mem_config).await?;
92
93        // Load skills and projects.
94        let skills = kernex_skills::load_skills(&self.data_dir);
95        let projects = kernex_skills::load_projects(&self.data_dir);
96
97        tracing::info!(
98            "runtime initialized: {} skills, {} projects",
99            skills.len(),
100            projects.len()
101        );
102
103        Ok(Runtime {
104            store,
105            skills,
106            projects,
107            data_dir: expanded_dir,
108        })
109    }
110}
111
112impl Default for RuntimeBuilder {
113    fn default() -> Self {
114        Self::new()
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121
122    #[tokio::test]
123    async fn test_runtime_builder_creates_runtime() {
124        let tmp = std::env::temp_dir().join("__kernex_test_runtime__");
125        let _ = std::fs::remove_dir_all(&tmp);
126
127        let runtime = RuntimeBuilder::new()
128            .data_dir(tmp.to_str().unwrap())
129            .build()
130            .await
131            .unwrap();
132
133        assert!(runtime.skills.is_empty());
134        assert!(runtime.projects.is_empty());
135        assert!(std::path::Path::new(&runtime.data_dir).exists());
136
137        let _ = std::fs::remove_dir_all(&tmp);
138    }
139
140    #[tokio::test]
141    async fn test_runtime_builder_custom_db_path() {
142        let tmp = std::env::temp_dir().join("__kernex_test_runtime_db__");
143        let _ = std::fs::remove_dir_all(&tmp);
144        std::fs::create_dir_all(&tmp).unwrap();
145
146        let db = tmp.join("custom.db");
147        let runtime = RuntimeBuilder::new()
148            .data_dir(tmp.to_str().unwrap())
149            .db_path(db.to_str().unwrap())
150            .build()
151            .await
152            .unwrap();
153
154        assert!(db.exists());
155        drop(runtime);
156        let _ = std::fs::remove_dir_all(&tmp);
157    }
158}