From 51cc806e1ef142418abb30fe59fdce2d8e26c14c Mon Sep 17 00:00:00 2001 From: Mavdol Date: Sun, 4 Jan 2026 17:29:31 +0100 Subject: [PATCH 1/3] add capsule.js for npm install --- crates/capsule-cli/Cargo.lock | 4 +- crates/capsule-cli/Cargo.toml | 2 +- crates/capsule-cli/npm/bin/capsule.js | 51 ++++++++++++++++++++++ crates/capsule-cli/npm/package.json | 20 +++++---- crates/capsule-cli/pyproject.toml | 2 +- crates/capsule-core/Cargo.lock | 2 +- crates/capsule-core/Cargo.toml | 2 +- crates/capsule-sdk/javascript/package.json | 2 +- crates/capsule-sdk/python/pyproject.toml | 2 +- 9 files changed, 70 insertions(+), 17 deletions(-) create mode 100644 crates/capsule-cli/npm/bin/capsule.js diff --git a/crates/capsule-cli/Cargo.lock b/crates/capsule-cli/Cargo.lock index 84560ef..cf06fc3 100644 --- a/crates/capsule-cli/Cargo.lock +++ b/crates/capsule-cli/Cargo.lock @@ -266,7 +266,7 @@ dependencies = [ [[package]] name = "capsule-core" -version = "0.2.1" +version = "0.2.2" dependencies = [ "anyhow", "chrono", @@ -286,7 +286,7 @@ dependencies = [ [[package]] name = "capsule-run" -version = "0.2.1" +version = "0.2.2" dependencies = [ "capsule-core", "clap", diff --git a/crates/capsule-cli/Cargo.toml b/crates/capsule-cli/Cargo.toml index 73c69f1..e51a723 100644 --- a/crates/capsule-cli/Cargo.toml +++ b/crates/capsule-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "capsule-run" -version = "0.2.1" +version = "0.2.2" edition = "2024" description = "Secure WASM runtime to isolate and manage AI agent tasks" license = "Apache-2.0" diff --git a/crates/capsule-cli/npm/bin/capsule.js b/crates/capsule-cli/npm/bin/capsule.js new file mode 100644 index 0000000..072f76c --- /dev/null +++ b/crates/capsule-cli/npm/bin/capsule.js @@ -0,0 +1,51 @@ +#!/usr/bin/env node + +const { spawnSync } = require("child_process"); +const path = require("path"); +const fs = require("fs"); + +const PLATFORMS = { + "darwin-arm64": "@capsule-run/cli-darwin-arm64", + "darwin-x64": "@capsule-run/cli-darwin-x64", + "linux-x64": "@capsule-run/cli-linux-x64", + "win32-x64": "@capsule-run/cli-win32-x64", +}; + +function getPlatformPackage() { + const key = `${process.platform}-${process.arch}`; + return PLATFORMS[key]; +} + +function findBinary() { + const pkg = getPlatformPackage(); + if (!pkg) { + console.error(`Unsupported platform: ${process.platform}-${process.arch}`); + process.exit(1); + } + + try { + const pkgPath = require.resolve(`${pkg}/package.json`); + const pkgDir = path.dirname(pkgPath); + const binary = process.platform === "win32" ? "capsule.exe" : "capsule"; + const binaryPath = path.join(pkgDir, binary); + + if (fs.existsSync(binaryPath)) { + return binaryPath; + } + } catch { + // Package not found + } + + console.error(`Could not find capsule binary for ${process.platform}-${process.arch}`); + console.error(`Please ensure @capsule-run/cli is installed correctly.`); + process.exit(1); +} + +const result = spawnSync(findBinary(), process.argv.slice(2), { stdio: "inherit" }); + +if (result.error) { + console.error(result.error.message); + process.exit(1); +} + +process.exit(result.status ?? 1); diff --git a/crates/capsule-cli/npm/package.json b/crates/capsule-cli/npm/package.json index bcb73d8..2bcfe63 100644 --- a/crates/capsule-cli/npm/package.json +++ b/crates/capsule-cli/npm/package.json @@ -1,15 +1,17 @@ { "name": "@capsule-run/cli", - "version": "0.2.1", + "version": "0.2.2", "description": "Secure WASM runtime to isolate and manage AI agent tasks", + "bin": { + "capsule": "./bin/capsule.js" + }, "keywords": [ "webassembly", - "cli", "sandbox", - "agent", + "agents", "isolation", - "security", - "llm" + "llm", + "ai" ], "license": "Apache-2.0", "repository": { @@ -20,9 +22,9 @@ "node": ">=18" }, "optionalDependencies": { - "@capsule-run/cli-darwin-arm64": "0.2.1", - "@capsule-run/cli-darwin-x64": "0.2.1", - "@capsule-run/cli-linux-x64": "0.2.1", - "@capsule-run/cli-win32-x64": "0.2.1" + "@capsule-run/cli-darwin-arm64": "0.2.2", + "@capsule-run/cli-darwin-x64": "0.2.2", + "@capsule-run/cli-linux-x64": "0.2.2", + "@capsule-run/cli-win32-x64": "0.2.2" } } diff --git a/crates/capsule-cli/pyproject.toml b/crates/capsule-cli/pyproject.toml index 037caf5..8bb7561 100644 --- a/crates/capsule-cli/pyproject.toml +++ b/crates/capsule-cli/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "capsule-run" -version = "0.2.1" +version = "0.2.2" description = "Secure WASM runtime to isolate and manage AI agent tasks" license = {text = "Apache-2.0"} requires-python = ">=3.8" diff --git a/crates/capsule-core/Cargo.lock b/crates/capsule-core/Cargo.lock index afe2dfe..e0a6bd4 100644 --- a/crates/capsule-core/Cargo.lock +++ b/crates/capsule-core/Cargo.lock @@ -246,7 +246,7 @@ dependencies = [ [[package]] name = "capsule-core" -version = "0.2.1" +version = "0.2.2" dependencies = [ "anyhow", "chrono", diff --git a/crates/capsule-core/Cargo.toml b/crates/capsule-core/Cargo.toml index 2020419..5556128 100644 --- a/crates/capsule-core/Cargo.toml +++ b/crates/capsule-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "capsule-core" -version = "0.2.1" +version = "0.2.2" edition = "2024" description = "Core library for Capsule - WASM runtime for AI agent isolation" license = "Apache-2.0" diff --git a/crates/capsule-sdk/javascript/package.json b/crates/capsule-sdk/javascript/package.json index 43cd7d8..791aa1a 100644 --- a/crates/capsule-sdk/javascript/package.json +++ b/crates/capsule-sdk/javascript/package.json @@ -1,6 +1,6 @@ { "name": "@capsule-run/sdk", - "version": "0.2.1", + "version": "0.2.2", "description": "Capsule JavaScript SDK - run AI agent tasks in secure WASM sandboxes", "type": "module", "main": "./dist/index.js", diff --git a/crates/capsule-sdk/python/pyproject.toml b/crates/capsule-sdk/python/pyproject.toml index 9326e6d..5cb6e26 100644 --- a/crates/capsule-sdk/python/pyproject.toml +++ b/crates/capsule-sdk/python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "capsule" -version = "0.2.1" +version = "0.2.2" description = "Capsule Python SDK - run AI agent tasks in secure WASM sandboxes" readme = "README.md" requires-python = ">=3.8" From 5690ece104ba732bfed57cfb537f64b0e65f6f7d Mon Sep 17 00:00:00 2001 From: Mavdol Date: Sun, 4 Jan 2026 18:26:48 +0100 Subject: [PATCH 2/3] add readme.md to pypi and npm package --- crates/capsule-cli/Cargo.toml | 1 + crates/capsule-cli/docs/README-pypi.md | 104 ++++++++++++++++++++ crates/capsule-cli/npm/README.md | 108 +++++++++++++++++++++ crates/capsule-cli/npm/package.json | 7 ++ crates/capsule-cli/pyproject.toml | 1 + crates/capsule-core/Cargo.toml | 1 + crates/capsule-sdk/javascript/package.json | 5 + 7 files changed, 227 insertions(+) create mode 100644 crates/capsule-cli/docs/README-pypi.md create mode 100644 crates/capsule-cli/npm/README.md diff --git a/crates/capsule-cli/Cargo.toml b/crates/capsule-cli/Cargo.toml index e51a723..bdd541e 100644 --- a/crates/capsule-cli/Cargo.toml +++ b/crates/capsule-cli/Cargo.toml @@ -7,6 +7,7 @@ license = "Apache-2.0" repository = "https://github.com/mavdol/capsule" keywords = ["webassembly", "sandbox", "isolation", "llm", "ai"] categories = ["command-line-utilities", "wasm"] +readme = "../../README.md" [[bin]] name = "capsule" diff --git a/crates/capsule-cli/docs/README-pypi.md b/crates/capsule-cli/docs/README-pypi.md new file mode 100644 index 0000000..71a16f2 --- /dev/null +++ b/crates/capsule-cli/docs/README-pypi.md @@ -0,0 +1,104 @@ +# capsule-run + +**A secure, durable runtime for agentic workflows** + +## Overview + +Capsule is a runtime for coordinating AI agent tasks in isolated environments. It is designed to handle long-running workflows, large-scale processing, autonomous decision-making securely, or even multi-agent systems. + +Each task runs inside its own WebAssembly sandbox, providing: + +- **Isolated execution**: Each task runs isolated from your host system +- **Resource limits**: Set CPU, memory, and timeout limits per task +- **Automatic retries**: Handle failures without manual intervention +- **Lifecycle tracking**: Monitor which tasks are running, completed, or failed + +## Installation + +```bash +pip install capsule-run +``` + +## Quick Start + +Create `hello.py`: + +```python +from capsule import task + +@task(name="main", compute="LOW", ram="64MB") +def main() -> str: + return "Hello from Capsule!" +``` + +Run it: + +```bash +capsule run hello.py +``` + +## How It Works + +Simply annotate your Python functions with the `@task` decorator: + +```python +from capsule import task + +@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.""" + return {"processed": len(dataset), "status": "complete"} +``` + +When you run `capsule run main.py`, your code is compiled into a WebAssembly module and executed in a dedicated sandbox. + +## Documentation + +### Task Configuration Options + +| Parameter | Type | Description | Example | +|-----------|------|-------------|---------| +| `name` | `str` | Task identifier | `"process_data"` | +| `compute` | `str` | CPU level: `"LOW"`, `"MEDIUM"`, `"HIGH"` | `"MEDIUM"` | +| `ram` | `str` | Memory limit | `"512MB"`, `"2GB"` | +| `timeout` | `str` | Maximum execution time | `"30s"`, `"5m"` | +| `max_retries` | `int` | Retry attempts on failure | `3` | + +### Compute Levels + +- **LOW**: Minimal allocation for lightweight tasks +- **MEDIUM**: Balanced resources for typical workloads +- **HIGH**: Maximum fuel for compute-intensive operations +- **CUSTOM**: Specify exact fuel value (e.g., `compute="1000000"`) + +### HTTP Client + +Standard `requests` library isn't compatible with WASM. Use Capsule's HTTP client: + +```python +from capsule import task +from capsule.http import get, post + +@task(name="fetch", compute="MEDIUM", timeout="30s") +def main() -> dict: + response = get("https://api.example.com/data") + return {"status": response.status_code, "ok": response.ok()} +``` + +## Compatibility + +✅ **Supported:** +- Pure Python packages and standard library +- `json`, `math`, `re`, `datetime`, `collections`, etc. + +⚠️ **Not yet supported:** +- Packages with C extensions (e.g `numpy`, `pandas`) + +## Links + +- [GitHub](https://github.com/mavdol/capsule) +- [Issues](https://github.com/mavdol/capsule/issues) + +## License + +Apache-2.0 diff --git a/crates/capsule-cli/npm/README.md b/crates/capsule-cli/npm/README.md new file mode 100644 index 0000000..e59e31c --- /dev/null +++ b/crates/capsule-cli/npm/README.md @@ -0,0 +1,108 @@ +# capsule + +**A secure, durable runtime for agentic workflows** + +## Overview + +Capsule is a runtime for coordinating AI agent tasks in isolated environments. It is designed to handle long-running workflows, large-scale processing, autonomous decision-making securely, or even multi-agent systems. + +Each task runs inside its own WebAssembly sandbox, providing: + +- **Isolated execution**: Each task runs isolated from your host system +- **Resource limits**: Set CPU, memory, and timeout limits per task +- **Automatic retries**: Handle failures without manual intervention +- **Lifecycle tracking**: Monitor which tasks are running, completed, or failed + +## Installation + +```bash +npm install -g @capsule-run/cli +npm install @capsule-run/sdk +``` + +## Quick Start + +Create `hello.ts`: + +```typescript +import { task } from "@capsule-run/sdk"; + +export const main = task({ + name: "main", + compute: "LOW", + ram: "64MB" +}, (): string => { + return "Hello from Capsule!"; +}); +``` + +Run it: + +```bash +capsule run hello.ts +``` + +## How It Works + +Simply use a wrapper function to define your tasks: + +```typescript +import { task } from "@capsule-run/sdk"; + +export const analyzeData = task({ + name: "analyze_data", + compute: "MEDIUM", + ram: "512MB", + timeout: "30s", + maxRetries: 1 +}, (dataset: number[]): object => { + // Your code runs safely in a Wasm sandbox + return { processed: dataset.length, status: "complete" }; +}); + +// The "main" task is required as the entrypoint +export const main = task({ + name: "main", + compute: "HIGH" +}, () => { + return analyzeData([1, 2, 3, 4, 5]); +}); +``` + +When you run `capsule run main.ts`, your code is compiled into a WebAssembly module and executed in a dedicated sandbox. + +## Documentation + +### Task Configuration Options + +| Parameter | Type | Description | Example | +|-----------|------|-------------|---------| +| `name` | `string` | Task identifier | `"process_data"` | +| `compute` | `string` | CPU level: `"LOW"`, `"MEDIUM"`, `"HIGH"` | `"MEDIUM"` | +| `ram` | `string` | Memory limit | `"512MB"`, `"2GB"` | +| `timeout` | `string` or `number` | Maximum execution time | `"30s"`, `"5m"` | +| `maxRetries` | `number` | Retry attempts on failure | `3` | + +### Compute Levels + +- **LOW**: Minimal allocation for lightweight tasks +- **MEDIUM**: Balanced resources for typical workloads +- **HIGH**: Maximum fuel for compute-intensive operations +- **CUSTOM**: Specify exact fuel value (e.g., `compute="1000000"`) + +## Compatibility + +✅ **Supported:** +- npm packages and ES modules work + +⚠️ **Not yet supported:** +- Node.js built-ins (`fs`, `path`, `os`) are not available in the sandbox + +## Links + +- [GitHub](https://github.com/mavdol/capsule) +- [Issues](https://github.com/mavdol/capsule/issues) + +## License + +Apache-2.0 diff --git a/crates/capsule-cli/npm/package.json b/crates/capsule-cli/npm/package.json index 2bcfe63..46edd81 100644 --- a/crates/capsule-cli/npm/package.json +++ b/crates/capsule-cli/npm/package.json @@ -5,6 +5,9 @@ "bin": { "capsule": "./bin/capsule.js" }, + "files": [ + "bin/" + ], "keywords": [ "webassembly", "sandbox", @@ -18,6 +21,10 @@ "type": "git", "url": "https://github.com/mavdol/capsule.git" }, + "homepage": "https://github.com/mavdol/capsule", + "publishConfig": { + "access": "public" + }, "engines": { "node": ">=18" }, diff --git a/crates/capsule-cli/pyproject.toml b/crates/capsule-cli/pyproject.toml index 8bb7561..4471824 100644 --- a/crates/capsule-cli/pyproject.toml +++ b/crates/capsule-cli/pyproject.toml @@ -6,6 +6,7 @@ build-backend = "maturin" name = "capsule-run" version = "0.2.2" description = "Secure WASM runtime to isolate and manage AI agent tasks" +readme = "docs/README-pypi.md" license = {text = "Apache-2.0"} requires-python = ">=3.8" authors = [ diff --git a/crates/capsule-core/Cargo.toml b/crates/capsule-core/Cargo.toml index 5556128..f49ecb7 100644 --- a/crates/capsule-core/Cargo.toml +++ b/crates/capsule-core/Cargo.toml @@ -7,6 +7,7 @@ license = "Apache-2.0" repository = "https://github.com/mavdol/capsule" keywords = ["webassembly", "sandbox", "isolation", "runtime", "wasm"] categories = ["wasm"] +readme = "../../README.md" [lib] crate-type = ["rlib"] diff --git a/crates/capsule-sdk/javascript/package.json b/crates/capsule-sdk/javascript/package.json index 791aa1a..170a118 100644 --- a/crates/capsule-sdk/javascript/package.json +++ b/crates/capsule-sdk/javascript/package.json @@ -5,6 +5,11 @@ "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", + "homepage": "https://github.com/mavdol/capsule", + "repository": { + "type": "git", + "url": "https://github.com/mavdol/capsule.git" + }, "exports": { ".": { "types": "./dist/index.d.ts", From dfe05900fad39089c7673360ab73e65d51773ee2 Mon Sep 17 00:00:00 2001 From: Mavdol Date: Sun, 4 Jan 2026 18:37:00 +0100 Subject: [PATCH 3/3] Explain --verbose option --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8e08a3c..dc63ba3 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,8 @@ Run it: capsule run hello.ts ``` +> [!TIP] +> Use `--verbose` to display real-time task execution details. ## Documentation @@ -187,13 +189,13 @@ Capsule also provides an HTTP client for TypeScript/JavaScript via `@capsule-run ## Compatibility +> [!NOTE] +> TypeScript/JavaScript has broader compatibility than Python since it doesn't rely on native bindings. + **Python:** Pure Python packages and standard library modules work. Packages with C extensions (`numpy`, `pandas`) are not yet supported. **TypeScript/JavaScript:** npm packages and ES modules work. Node.js built-ins (`fs`, `path`, `os`) are not available in the sandbox. -> [!NOTE] -> TypeScript/JavaScript has broader compatibility than Python since it doesn't rely on native bindings. - ## Contributing Contributions are welcome!