From 04743ea15d6c265ed19508a5e65aeaaf43b35d6a Mon Sep 17 00:00:00 2001 From: Mavdol Date: Sat, 13 Dec 2025 16:58:53 +0100 Subject: [PATCH 1/8] Upgrade Roadmap and Readme --- README.md | 2 ++ ROADMAP.md | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ab88c0a..1d736d1 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,8 @@ Packages with C extensions like `numpy` and `pandas` are not yet supported in th #### v0.2.0: The Orchestrator +> 💡 Community Driven: The path from v0.2 onwards is flexible. While we have a vision for a Daemon mode your feedback defines the priority. + **Status:** Planned **Goal:** Turning the runner into a stable, persistent system. diff --git a/ROADMAP.md b/ROADMAP.md index 337eca4..51b3b82 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,11 +2,13 @@ This document tracks the development status of Capsule. We follow a "Release Early, Release Often" philosophy. +> Note: Features marked as Planned are subject to change based on community feedback and real-world usage patterns. We prioritize what users actually need. + --- ## v0.1.0: The Python Runner (MVP) -**Status:** 🚧 In Progress +**Status:** ✅ Done **Goal:** Validating the core Host/Guest technology and Python interoperability. From d35ceaa5df772dbbc7848bebf6f0b5e29f48a527 Mon Sep 17 00:00:00 2001 From: Mavdol Date: Sun, 14 Dec 2025 12:34:12 +0100 Subject: [PATCH 2/8] Update readme --- README.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 1d736d1..933866d 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ https://github.com/user-attachments/assets/dc0043d5-da42-4ead-b66e-0b7025046aa1 ## 🎯 What is Capsule? -Modern AI agents are evolving from simple, single-threaded scripts into **distributed multi-agent architectures** that coordinate dozens of sub-agents in parallel. These systems handle long-running workflows, large-scale data processing, and complex decision-making tasks that require: +Modern AI agents are evolving from simple, single-threaded scripts into **distributed multi-agent architectures** that coordinate sub-agents in parallel. These systems handle long-running workflows, large-scale data processing, and complex decision-making tasks that require: - 🔒 **Robust isolation** between untrusted code and your host system - 📊 **Fine-grained resource control** (CPU, RAM, timeout limits) @@ -30,25 +30,27 @@ Modern AI agents are evolving from simple, single-threaded scripts into **distri ## 🚀 How It Works -Capsule leverages **WebAssembly (Wasm)** to create secure, isolated execution environments for each task. Here's what makes it powerful: - -1. **Decorator-Based**: Simply annotate your Python functions with `@task` -2. **Automatic Compilation**: Python code is compiled to Wasm on-the-fly -3. **Isolated Execution**: Each task runs in its own sandboxed Wasm instance -4. **Resource Limits**: Enforce CPU, RAM, and time constraints per task -5. **Fault Recovery**: Automatic retries on failure without affecting other tasks +Capsule leverages **WebAssembly (Wasm)** to create secure, isolated execution environments for each task. Simply annotate your Python functions with `@task` decorator : ```python from capsule import task -@task(name="analyze_data", compute="MEDIUM", ram="512MB", timeout="30s") +@task(name="analyze_data", compute="MEDIUM", ram="512MB", timeout="30s", max_retries=1) def analyze_data(dataset: list) -> dict: """Process data in an isolated, resource-controlled environment.""" # Your code runs safely in a Wasm sandbox return {"processed": len(dataset), "status": "complete"} ``` -This diagram illustrates the complete journey of a task from your command line invocation to execution within the Rust core: +The task is then executed by the Capsule runtime, which handles: + +1. **Automatic Compilation**: Python code is compiled to Wasm on-the-fly +2. **Isolated Execution**: Each task runs in its own sandboxed Wasm instance +3. **Resource Limits**: Enforce CPU, RAM, and time constraints per task +4. **Fault Recovery**: Automatic retries on failure without affecting other tasks + + +This diagram illustrates the complete journey of a task from your command line invocation to execution within the Rust core ![Process Flow](./assets/task-execution-flow.png) @@ -259,7 +261,7 @@ We welcome contributions from the community! Here's how you can help: 3. **Add tests** if applicable: `cargo test` 4. **Open** a Pull Request -Need help or have questions? [Open an issue](https://github.com/mavdol/capsule/issues) ! +Need help or have questions? [Open an issue](https://github.com/mavdol/capsule/issues) ## 📄 License From c18240964a9b8aa2263efea63e4c95e008e594d2 Mon Sep 17 00:00:00 2001 From: Mavdol Date: Mon, 15 Dec 2025 21:00:43 +0100 Subject: [PATCH 3/8] colors to capsule logs --- crates/capsule-cli/Cargo.lock | 17 +++++++++ crates/capsule-core/Cargo.lock | 11 ++++++ crates/capsule-core/Cargo.toml | 1 + .../src/wasm/utilities/task_reporter.rs | 38 +++++++++++++------ 4 files changed, 56 insertions(+), 11 deletions(-) diff --git a/crates/capsule-cli/Cargo.lock b/crates/capsule-cli/Cargo.lock index 6abf42d..c7464be 100644 --- a/crates/capsule-cli/Cargo.lock +++ b/crates/capsule-cli/Cargo.lock @@ -273,6 +273,7 @@ name = "capsule-core" version = "0.1.0" dependencies = [ "anyhow", + "colored", "humantime", "indicatif", "nanoid", @@ -364,6 +365,16 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "colored" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +dependencies = [ + "lazy_static", + "windows-sys 0.59.0", +] + [[package]] name = "console" version = "0.15.11" @@ -1255,6 +1266,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "leb128" version = "0.2.5" diff --git a/crates/capsule-core/Cargo.lock b/crates/capsule-core/Cargo.lock index c386172..12ccff3 100644 --- a/crates/capsule-core/Cargo.lock +++ b/crates/capsule-core/Cargo.lock @@ -249,6 +249,7 @@ name = "capsule-core" version = "0.1.0" dependencies = [ "anyhow", + "colored", "humantime", "indicatif", "nanoid", @@ -304,6 +305,16 @@ dependencies = [ "thiserror 2.0.17", ] +[[package]] +name = "colored" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +dependencies = [ + "lazy_static", + "windows-sys 0.59.0", +] + [[package]] name = "console" version = "0.15.11" diff --git a/crates/capsule-core/Cargo.toml b/crates/capsule-core/Cargo.toml index bd3af5d..637ee71 100644 --- a/crates/capsule-core/Cargo.toml +++ b/crates/capsule-core/Cargo.toml @@ -18,6 +18,7 @@ tokio = "1.48.0" wasmtime = { version = "29.0.0", features = ["component-model", "async"] } wasmtime-wasi = "29.0.0" indicatif = "0.17" +colored = "2.1" [dev-dependencies] rustfmt = "0.10.0" diff --git a/crates/capsule-core/src/wasm/utilities/task_reporter.rs b/crates/capsule-core/src/wasm/utilities/task_reporter.rs index 1311e61..c1d12d4 100644 --- a/crates/capsule-core/src/wasm/utilities/task_reporter.rs +++ b/crates/capsule-core/src/wasm/utilities/task_reporter.rs @@ -2,6 +2,7 @@ use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; +use colored::Colorize; use indicatif::{ProgressBar, ProgressStyle}; pub struct TaskReporter { @@ -38,7 +39,10 @@ impl TaskReporter { self.finish_spinner(); self.start_time = Instant::now(); if self.verbose { - println!("Capsule log: ▶ Starting task '{}' ({})", task_name, task_id); + println!("Capsule log: {} Starting task {} ({})", + "▶".cyan(), + format!("'{}'", task_name).cyan(), + task_id); } } @@ -48,8 +52,11 @@ impl TaskReporter { let elapsed = self.start_time.elapsed(); let time_str = self.format_duration(elapsed); println!( - "Capsule log: ✔ Task '{}' completed ({})", - task_name, time_str + "Capsule log: {} Task {} {} ({})", + "✔".green(), + format!("'{}'", task_name).cyan(), + "completed".green(), + time_str ); } } @@ -59,8 +66,11 @@ impl TaskReporter { if self.verbose { let time_str = self.format_duration(elapsed); println!( - "Capsule log: ✔ Task '{}' completed ({})", - task_name, time_str + "Capsule log: {} Task {} {} ({})", + "✔".green(), + format!("'{}'", task_name).cyan(), + "completed".green(), + time_str ); } } @@ -68,18 +78,24 @@ impl TaskReporter { pub fn task_failed(&mut self, task_name: &str, error: &str) { self.finish_spinner(); if self.verbose { - println!("Capsule log: ✗ Task '{}' failed: {}", task_name, error); + println!("Capsule log: {} Task {} failed: {}", + "✗".red(), + format!("'{}'", task_name).cyan(), + error.red()); } else { - eprintln!("Capsule log: ✗ {}", error); + eprintln!("Capsule log: {} {}", "✗".red(), error.red()); } } pub fn task_timeout(&mut self, task_name: &str) { self.finish_spinner(); if self.verbose { - println!("Capsule log: ✗ Task '{}' timed out", task_name); + println!("Capsule log: {} Task {} {}", + "✗".red(), + format!("'{}'", task_name).cyan(), + "timed out".red()); } else { - eprintln!("Capsule log: ✗ Task timed out"); + eprintln!("Capsule log: {} {}", "✗".red(), "Task timed out".red()); } } @@ -105,7 +121,7 @@ impl TaskReporter { if let Some(msg) = completion_message && self.verbose { - println!("✓ {} ({})", msg, time_str); + println!("{} {} ({})", "✓".green(), msg.green(), time_str); } } @@ -120,7 +136,7 @@ impl TaskReporter { } pub fn error(&self, message: &str) { - eprintln!("{}", message); + eprintln!("{}", message.red()); } pub fn format_duration(&self, duration: std::time::Duration) -> String { From dac3870fb56bdf81e76468197089a012e6aa00fb Mon Sep 17 00:00:00 2001 From: Mavdol Date: Mon, 15 Dec 2025 23:45:01 +0100 Subject: [PATCH 4/8] Update readme --- README.md | 6 +++--- ROADMAP.md | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 933866d..00ffc42 100644 --- a/README.md +++ b/README.md @@ -226,13 +226,13 @@ response.text() # Get response as text ### Important Limitations -Packages with C extensions like `numpy` and `pandas` are not yet supported in the current version. Support for compiled extensions is planned for future releases as we expand WebAssembly compatibility. +Packages with C extensions like `numpy` and `pandas` are not yet supported in the current version. Support for compiled extensions is planned for future releases as Capsule expands WebAssembly compatibility. ## 📅 What's Next #### v0.2.0: The Orchestrator -> 💡 Community Driven: The path from v0.2 onwards is flexible. While we have a vision for a Daemon mode your feedback defines the priority. +> 💡 Community Driven: The path from v0.2 onwards is flexible. While the initial vision is for a Daemon mode your feedback defines the priority. **Status:** Planned @@ -254,7 +254,7 @@ Want to follow along with Capsule's development journey? I share detailed engine ## 🤝 Contributing -We welcome contributions from the community! Here's how you can help: +Contributions are welcome! Here's how you can help: 1. **Fork** the repository 2. **Create** a feature branch: `git checkout -b feature/amazing-feature` diff --git a/ROADMAP.md b/ROADMAP.md index 51b3b82..c6668c9 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,8 +1,8 @@ # 📌 Roadmap -This document tracks the development status of Capsule. We follow a "Release Early, Release Often" philosophy. +This document tracks the development status of Capsule. -> Note: Features marked as Planned are subject to change based on community feedback and real-world usage patterns. We prioritize what users actually need. +> Note: Features marked as Planned are subject to change based on community feedback and real-world usage patterns. --- From f36d759ab950d0af9fab82f9d5a7f6280a71faf6 Mon Sep 17 00:00:00 2001 From: Mavdol Date: Tue, 16 Dec 2025 00:02:38 +0100 Subject: [PATCH 5/8] Fix the path wasm for windows users --- .../capsule-core/src/wasm/compiler/python.rs | 50 ++++++++++++++++--- .../src/wasm/utilities/task_reporter.rs | 18 ++++--- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/crates/capsule-core/src/wasm/compiler/python.rs b/crates/capsule-core/src/wasm/compiler/python.rs index a9ea1c5..d6fd95f 100644 --- a/crates/capsule-core/src/wasm/compiler/python.rs +++ b/crates/capsule-core/src/wasm/compiler/python.rs @@ -41,6 +41,35 @@ pub struct PythonWasmCompiler { } impl PythonWasmCompiler { + fn get_python_command() -> String { + let candidates = vec!["python3", "python"]; + + for cmd in candidates { + if Command::new(cmd) + .arg("--version") + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status() + .is_ok() + { + return cmd.to_string(); + } + } + + "python3".to_string() + } + + fn normalize_path_for_command(path: &Path) -> PathBuf { + #[cfg(windows)] + { + let path_str = path.to_string_lossy(); + if path_str.starts_with(r"\\?\") { + return PathBuf::from(&path_str[4..]); + } + } + path.to_path_buf() + } + pub fn new(source_path: &Path) -> Result { let source_path = source_path.canonicalize().map_err(|e| { PythonWasmCompilerError::FsError(format!("Cannot resolve source path: {}", e)) @@ -123,21 +152,27 @@ from capsule.app import TaskRunner, exports fs::write(&bootloader_path, bootloader_content)?; + let wit_path_normalized = Self::normalize_path_for_command(&wit_path); + let cache_dir_normalized = Self::normalize_path_for_command(&self.cache_dir); + let python_path_normalized = Self::normalize_path_for_command(python_path); + let sdk_path_normalized = Self::normalize_path_for_command(&sdk_path); + let output_wasm_normalized = Self::normalize_path_for_command(&self.output_wasm); + let output = Command::new("componentize-py") .arg("-d") - .arg(&wit_path) + .arg(&wit_path_normalized) .arg("-w") .arg("capsule-agent") .arg("componentize") .arg("_capsule_boot") .arg("-p") - .arg(&self.cache_dir) + .arg(&cache_dir_normalized) .arg("-p") - .arg(python_path) + .arg(&python_path_normalized) .arg("-p") - .arg(&sdk_path) + .arg(&sdk_path_normalized) .arg("-o") - .arg(&self.output_wasm) + .arg(&output_wasm_normalized) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .output()?; @@ -261,12 +296,13 @@ from capsule.app import TaskRunner, exports } fn find_sdk_via_python(&self) -> Result { - let output = Command::new("python3") + let python_cmd = Self::get_python_command(); + let output = Command::new(&python_cmd) .arg("-c") .arg("import capsule; import os; print(os.path.dirname(os.path.dirname(capsule.__file__)), end='')") .output() .map_err(|e| { - PythonWasmCompilerError::FsError(format!("Failed to execute python3: {}", e)) + PythonWasmCompilerError::FsError(format!("Failed to execute {}: {}", python_cmd, e)) })?; if !output.status.success() { diff --git a/crates/capsule-core/src/wasm/utilities/task_reporter.rs b/crates/capsule-core/src/wasm/utilities/task_reporter.rs index c1d12d4..82cefb6 100644 --- a/crates/capsule-core/src/wasm/utilities/task_reporter.rs +++ b/crates/capsule-core/src/wasm/utilities/task_reporter.rs @@ -39,10 +39,12 @@ impl TaskReporter { self.finish_spinner(); self.start_time = Instant::now(); if self.verbose { - println!("Capsule log: {} Starting task {} ({})", + println!( + "Capsule log: {} Starting task {} ({})", "▶".cyan(), format!("'{}'", task_name).cyan(), - task_id); + task_id + ); } } @@ -78,10 +80,12 @@ impl TaskReporter { pub fn task_failed(&mut self, task_name: &str, error: &str) { self.finish_spinner(); if self.verbose { - println!("Capsule log: {} Task {} failed: {}", + println!( + "Capsule log: {} Task {} failed: {}", "✗".red(), format!("'{}'", task_name).cyan(), - error.red()); + error.red() + ); } else { eprintln!("Capsule log: {} {}", "✗".red(), error.red()); } @@ -90,10 +94,12 @@ impl TaskReporter { pub fn task_timeout(&mut self, task_name: &str) { self.finish_spinner(); if self.verbose { - println!("Capsule log: {} Task {} {}", + println!( + "Capsule log: {} Task {} {}", "✗".red(), format!("'{}'", task_name).cyan(), - "timed out".red()); + "timed out".red() + ); } else { eprintln!("Capsule log: {} {}", "✗".red(), "Task timed out".red()); } From 982b157b9183d5ef3df46518f2898a33904fcefb Mon Sep 17 00:00:00 2001 From: Mavdol Date: Tue, 16 Dec 2025 00:23:19 +0100 Subject: [PATCH 6/8] Delete examples --- README.md | 96 ++++++++++--------------------------------------------- 1 file changed, 16 insertions(+), 80 deletions(-) diff --git a/README.md b/README.md index 00ffc42..dd757ee 100644 --- a/README.md +++ b/README.md @@ -98,77 +98,6 @@ capsule run hello.py That's it! Your Python function just ran in a secure WebAssembly sandbox. 🎉 -## 📖 Examples - -### Basic Task with Resource Limits - -```python -from capsule import task - -@task( - name="process_batch", - compute="MEDIUM", - ram="256MB", - timeout="60s", - max_retries=3 -) -def process_batch(items: list) -> dict: - """Process a batch of items with resource constraints.""" - results = [] - for item in items: - # Process each item - results.append(process_item(item)) - - return {"processed": len(results), "results": results} -``` - -### Making HTTP Requests - -Standard libraries like `requests` are disabled for security. Use Capsule's built-in HTTP client: - -```python -from capsule import task -from capsule.http import get, post - -@task(name="fetch_data", compute="MEDIUM", timeout="30s") -def fetch_data(api_url: str) -> dict: - """Fetch data from an external API.""" - response = get(api_url) - - if response.ok(): - data = response.json() - print(f"✅ Fetched {len(data)} items") - return data - else: - print(f"❌ Request failed: {response.status_code}") - return {"error": response.status_code} - -@task(name="post_results", compute="LOW", timeout="15s") -def post_results(api_url: str, payload: dict) -> bool: - """Post results to an API endpoint.""" - response = post(api_url, json=payload) - return response.ok() -``` - -### Task with Environment Variables - -```python -from capsule import task - -@task( - name="authenticated_task", - compute="LOW", - env_vars={"API_KEY": "your-api-key", "ENVIRONMENT": "production"} -) -def authenticated_task() -> str: - """Access environment variables within the task.""" - import os - api_key = os.getenv("API_KEY") - env = os.getenv("ENVIRONMENT") - - return f"Running in {env} with key: {api_key[:4]}..." -``` - ## 📚 Documentation ### Task Configuration Options @@ -197,19 +126,26 @@ Capsule controls CPU usage through WebAssembly's **fuel mechanism**, which meter Standard Python networking relies on sockets, which aren't natively compatible with WebAssembly's sandbox model. For security and portability, Capsule provides its own HTTP client that works seamlessly within the Wasm environment while maintaining strict isolation boundaries: ```python +from capsule import task from capsule.http import get, post, put, delete -# GET request -response = get("https://api.example.com/data") +@task(name="http_example", compute="MEDIUM", timeout="30s") +def main() -> dict: + """Example demonstrating HTTP client usage within a task.""" + + # GET request + response = get("https://api.example.com/data") + + # POST with JSON body + response = post("https://api.example.com/submit", json={"key": "value"}) -# POST with JSON body -response = post("https://api.example.com/submit", json={"key": "value"}) + # Response methods + is_ok = response.ok() # Returns True if status code is 2xx + status = response.status_code # Get the HTTP status code + data = response.json() # Parse response as JSON + text = response.text() # Get response as text -# Response methods -response.ok() # Returns True if status code is 2xx -response.status_code # Get the HTTP status code -response.json() # Parse response as JSON -response.text() # Get response as text + return {"status": status, "success": is_ok} ``` ## 🔧 Compatibility From b3ee461443edc2177bb3a920e493721d78e0a9c4 Mon Sep 17 00:00:00 2001 From: Mavdol Date: Tue, 16 Dec 2025 00:29:56 +0100 Subject: [PATCH 7/8] change repetitive part --- README.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/README.md b/README.md index dd757ee..82f747d 100644 --- a/README.md +++ b/README.md @@ -42,12 +42,7 @@ def analyze_data(dataset: list) -> dict: return {"processed": len(dataset), "status": "complete"} ``` -The task is then executed by the Capsule runtime, which handles: - -1. **Automatic Compilation**: Python code is compiled to Wasm on-the-fly -2. **Isolated Execution**: Each task runs in its own sandboxed Wasm instance -3. **Resource Limits**: Enforce CPU, RAM, and time constraints per task -4. **Fault Recovery**: Automatic retries on failure without affecting other tasks +When you run your task, Capsule compiles your Python code to WebAssembly on-the-fly and executes it in a dedicated sandbox. The runtime enforces the constraints you've defined (CPU allocation, memory limits, and timeouts) while automatically handling retries if something goes wrong. This diagram illustrates the complete journey of a task from your command line invocation to execution within the Rust core From 76421dec623eb6f7dd7c999ecf8b32294db49d2c Mon Sep 17 00:00:00 2001 From: Mohamed Diallo Date: Tue, 16 Dec 2025 01:02:36 +0100 Subject: [PATCH 8/8] Revise README with new Python version and links Updated Python version requirement and modified links. --- README.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 82f747d..b1aec1d 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,9 @@ [![License](https://img.shields.io/badge/license-Apache_2.0-blue)](LICENSE) [![Rust](https://img.shields.io/badge/built_with-Rust-orange)](https://www.rust-lang.org/) +https://github.com/user-attachments/assets/539f7c72-6847-4a25-9a76-d55028267cd7 -https://github.com/user-attachments/assets/dc0043d5-da42-4ead-b66e-0b7025046aa1 - -[Getting Started](#-quick-start) • [Examples](#-examples) • [Documentation](#-documentation) • [Contributing](#-contributing) +[Getting Started](#-quick-start) • [Documentation](#-documentation) • [Contributing](#-contributing) @@ -42,9 +41,6 @@ def analyze_data(dataset: list) -> dict: return {"processed": len(dataset), "status": "complete"} ``` -When you run your task, Capsule compiles your Python code to WebAssembly on-the-fly and executes it in a dedicated sandbox. The runtime enforces the constraints you've defined (CPU allocation, memory limits, and timeouts) while automatically handling retries if something goes wrong. - - This diagram illustrates the complete journey of a task from your command line invocation to execution within the Rust core ![Process Flow](./assets/task-execution-flow.png) @@ -56,7 +52,7 @@ When you run `capsule run main.py`, your Python code is compiled into a WebAssem ### Prerequisites - **Rust** (latest stable) - [Install Rust](https://rustup.rs/) -- **Python 3.11+** - [Install Python](https://www.python.org/downloads/) (Only for the V0.1) +- **Python 3.13+** - [Install Python](https://www.python.org/downloads/) ### Installation @@ -161,10 +157,10 @@ Packages with C extensions like `numpy` and `pandas` are not yet supported in th ## 📅 What's Next -#### v0.2.0: The Orchestrator - > 💡 Community Driven: The path from v0.2 onwards is flexible. While the initial vision is for a Daemon mode your feedback defines the priority. +#### v0.2.0: The Orchestrator + **Status:** Planned **Goal:** Turning the runner into a stable, persistent system.