runtimo_core/lib.rs
1//! Runtimo Core — Agent-centric capability runtime.
2//!
3//! Runtimo provides structured execution, resource limits, crash recovery,
4//! and two-layer telemetry (hardware + process tracking) for machines that
5//! cannot be factory-reset. Every capability execution captures before/after
6//! snapshots, with full audit trails and undo support.
7//!
8//! # Architecture
9//!
10//! - **Capabilities** — Pluggable operations implementing the [`Capability`] trait
11//! - **Jobs** — Lifecycle-tracked execution units (Job, [`JobState`])
12//! - **Telemetry** — Hardware awareness ([`Telemetry`])
13//! - **Process Snapshot** — Running process awareness ([`ProcessSnapshot`])
14//! - **WAL** — Append-only crash recovery log ([`WalWriter`]/[`WalReader`])
15//! - **Backup** — Undo support via pre-mutation file backups ([`BackupManager`])
16//! - **Resource Guards** — Circuit breaker via [`LlmoSafeGuard`]
17//!
18//! # Quick Start
19//!
20//! ```rust
21//! use runtimo_core::{FileRead, Capability, Context};
22//! use serde_json::json;
23//!
24//! let cap = FileRead;
25//! assert_eq!(cap.name(), "FileRead");
26//! ```
27//!
28//! # Execution with Full Telemetry
29//!
30//! ```rust,ignore
31//! use runtimo_core::{FileRead, execute_with_telemetry};
32//! use serde_json::json;
33//! use std::path::Path;
34//!
35//! let cap = FileRead;
36//! let result = execute_with_telemetry(
37//! &cap,
38//! &json!({"path": "/tmp/test.txt"}),
39//! false,
40//! Path::new("/tmp/runtimo.wal"),
41//! ).unwrap();
42//! assert!(result.success);
43//! ```
44//!
45//! # Performance (Measured on AMD EPYC 7B13)
46//!
47//! | Operation | Latency | Notes |
48//! |-----------|---------|-------|
49//! | Cold start | <1s | Binary load + init |
50//! | FileRead | <10ms | Small files (<1KB) |
51//! | FileWrite | <50ms | Includes backup copy |
52//! | Telemetry capture | <100ms | 15+ shell subprocesses |
53//! | Process snapshot | <50ms | ps aux parse |
54//! | Memory baseline | <50MB | RSS at idle |
55//!
56//! # Feature Flags
57//!
58//! No optional features currently. All functionality is included by default.
59
60// Allow idiomatic test lints in test mode as panic/unwrap/indexing are standard in tests.
61#![cfg_attr(
62 test,
63 allow(
64 clippy::unwrap_used,
65 clippy::expect_used,
66 clippy::indexing_slicing,
67 clippy::unused_result_ok
68 )
69)]
70
71pub mod backup;
72/// Pluggable capability implementations (file I/O, shell, git, etc.).
73pub mod capabilities;
74/// Core trait and registry for pluggable operations.
75pub mod capability;
76/// Shell command execution helper.
77pub mod cmd;
78/// Global configuration and path resolution.
79pub mod config;
80/// Capability executor with telemetry and safety guards.
81pub mod executor;
82/// Job identity, state machine, and WAL event types.
83pub mod job;
84/// LLM safety guard — CPU/RAM circuit breakers and entropy source.
85pub mod llmosafe;
86/// Health monitoring with alerting.
87pub mod monitor;
88/// Process snapshot, zombie detection, and top-N queries.
89pub mod processes;
90mod schema;
91/// Session tracking for reliable SSH.
92pub mod session;
93/// System telemetry capture and reporting.
94pub mod telemetry;
95/// Path validation against allowed-prefix lists.
96pub mod validation;
97/// Write-ahead log for crash recovery.
98pub mod wal;
99
100pub use backup::BackupManager;
101pub use capabilities::{FileRead, FileWrite, GitExec, Kill, ShellExec, Undo};
102pub use capability::{Capability, CapabilityRegistry, Context, Output};
103pub use config::RuntimoConfig;
104pub use executor::{execute_with_telemetry, execute_with_telemetry_and_session};
105pub use job::{Job, JobId, JobState};
106pub use llmosafe::LlmoSafeGuard;
107pub use monitor::HealthMonitor;
108pub use processes::ProcessSnapshot;
109pub use telemetry::Telemetry;
110pub use wal::{WalEvent, WalEventType, WalReader, WalWriter};
111
112/// Error types for runtimo-core.
113///
114/// Covers all failure modes: state transitions, schema validation,
115/// capability execution, WAL/backup errors, resource limits, and telemetry.
116#[allow(clippy::exhaustive_enums)] // new variants are semver-breaking regardless
117#[derive(Debug, thiserror::Error)]
118pub enum Error {
119 /// Invalid job state transition attempted.
120 #[error("Invalid job state transition: {from:?} -> {to:?}")]
121 InvalidTransition { from: JobState, to: JobState },
122
123 /// JSON schema validation failed for capability arguments.
124 #[error("Schema validation failed: {0}")]
125 SchemaValidationFailed(String),
126
127 /// Requested capability not found in registry.
128 #[error("Capability not found: {0}")]
129 CapabilityNotFound(String),
130
131 /// Capability execution failed.
132 #[error("Execution failed: {0}")]
133 ExecutionFailed(String),
134
135 /// Write-Ahead Log operation failed.
136 #[error("WAL error: {0}")]
137 WalError(String),
138
139 /// Backup/restore operation failed.
140 #[error("Backup error: {0}")]
141 BackupError(String),
142
143 /// Session operation failed (create, load, save, list).
144 #[error("Session error: {0}")]
145 SessionError(String),
146
147 /// System resource limit exceeded (CPU, RAM, or zombie count).
148 #[error("Resource limit exceeded: {0}")]
149 ResourceLimitExceeded(String),
150
151 /// Telemetry capture failed.
152 #[error("Telemetry error: {0}")]
153 TelemetryError(String),
154
155 /// Cognitive safety violation detected by LLMOSafe.
156 #[error("Cognitive safety violation: {0}")]
157 CognitiveSafetyViolation(String),
158}
159
160/// Result alias for runtimo-core operations.
161pub type Result<T> = std::result::Result<T, Error>;
162
163/// Utility functions for path management.
164pub mod utils {
165 use std::path::PathBuf;
166
167 /// Returns the data directory following XDG spec.
168 pub fn data_dir() -> PathBuf {
169 std::env::var("XDG_DATA_HOME")
170 .ok()
171 .map(PathBuf::from)
172 .or_else(|| {
173 std::env::var("HOME")
174 .ok()
175 .map(|h| PathBuf::from(h).join(".local/share"))
176 })
177 .unwrap_or_else(std::env::temp_dir)
178 .join("runtimo")
179 }
180
181 /// Returns the WAL path (env override or default).
182 pub fn wal_path() -> PathBuf {
183 std::env::var("RUNTIMO_WAL_PATH")
184 .map_or_else(|_| data_dir().join("wal.jsonl"), PathBuf::from)
185 }
186
187 /// Returns the backup directory (env override or default).
188 pub fn backup_dir() -> PathBuf {
189 std::env::var("RUNTIMO_BACKUP_DIR")
190 .map_or_else(|_| data_dir().join("backups"), PathBuf::from)
191 }
192
193 /// Generates a unique ID from 16 random bytes (32 hex chars).
194 ///
195 /// Uses `/dev/urandom` for collision resistance — P(collision) < 10⁻¹⁵
196 /// even at 100 IDs/sec for 1 hour. Falls back to timestamp if urandom
197 /// is unavailable (e.g., non-Linux platforms).
198 #[must_use]
199 pub fn generate_id() -> String {
200 let mut bytes = [0u8; 16];
201 if std::fs::File::open("/dev/urandom")
202 .ok()
203 .and_then(|mut f| std::io::Read::read_exact(&mut f, &mut bytes).ok())
204 .is_some()
205 {
206 #[allow(clippy::format_collect)]
207 bytes.iter().map(|b| format!("{b:02x}")).collect()
208 } else {
209 // Fallback: timestamp-based (collision possible but rare)
210 let ts = std::time::SystemTime::now()
211 .duration_since(std::time::UNIX_EPOCH)
212 .unwrap_or_default()
213 .as_nanos();
214 format!("{:x}", ts)
215 }
216 }
217}