{"id":35251561,"url":"https://github.com/mavdol/capsule","last_synced_at":"2026-03-02T13:13:28.347Z","repository":{"id":327137405,"uuid":"1107667634","full_name":"mavdol/capsule","owner":"mavdol","description":"A secure, durable runtime for AI agents. Run untrusted code in isolated WebAssembly sandboxes.","archived":false,"fork":false,"pushed_at":"2026-02-24T11:59:35.000Z","size":7660,"stargazers_count":215,"open_issues_count":2,"forks_count":11,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-02-24T15:50:40.678Z","etag":null,"topics":["agent","agentic-workflow","ai","devtools","javascript","llm","python","rust","sandbox","typescript","wasm","webassembly"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mavdol.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-01T13:01:33.000Z","updated_at":"2026-02-24T12:10:33.000Z","dependencies_parsed_at":"2025-12-20T03:00:46.603Z","dependency_job_id":"c3f83ece-3c48-4887-8540-06186036fd9a","html_url":"https://github.com/mavdol/capsule","commit_stats":null,"previous_names":["mavdol/capsule"],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/mavdol/capsule","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mavdol%2Fcapsule","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mavdol%2Fcapsule/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mavdol%2Fcapsule/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mavdol%2Fcapsule/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mavdol","download_url":"https://codeload.github.com/mavdol/capsule/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mavdol%2Fcapsule/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29999283,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-02T09:59:02.300Z","status":"ssl_error","status_checked_at":"2026-03-02T09:59:02.001Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent","agentic-workflow","ai","devtools","javascript","llm","python","rust","sandbox","typescript","wasm","webassembly"],"created_at":"2025-12-30T06:47:42.364Z","updated_at":"2026-03-02T13:13:28.342Z","avatar_url":"https://github.com/mavdol.png","language":"Rust","funding_links":[],"categories":["Libraries","Tools","Code Execution"],"sub_categories":["Virtualization","Host Runtimes"],"readme":"\u003cdiv align=\"center\"\u003e\n\n# ```Capsule```\n\n**A secure, durable runtime for AI agents**\n\n[![CI](https://github.com/mavdol/capsule/actions/workflows/ci.yml/badge.svg)](https://github.com/mavdol/capsule/actions/workflows/ci.yml)\n\n[Getting Started](#getting-started) • [Documentation](#documentation-v063) • [Contributing](#contributing)\n\n\u003c/div\u003e\n\n---\n\n## Overview\n\n```Capsule``` is a runtime for coordinating AI agent tasks in isolated environments. It is designed to handle untrusted code execution, long-running workflows, large-scale processing, or even multi-agent systems.\n\nEach task runs inside its own WebAssembly sandbox, providing:\n\n- **Isolated execution**: Each task runs isolated from your host system\n- **Resource limits**: Set CPU, memory, and timeout limits per task\n- **Automatic retries**: Handle failures without manual intervention\n- **Lifecycle tracking**: Monitor which tasks are running, completed, or failed\n\nThis enables safe task-level execution of untrusted code within AI agent systems.\n\n## How It Works\n\n### With Python\n\nSimply annotate your Python functions with the `@task` decorator:\n\n```python\nfrom capsule import task\n\n@task(name=\"analyze_data\", compute=\"MEDIUM\", ram=\"512MB\", timeout=\"30s\", max_retries=1)\ndef analyze_data(dataset: list) -\u003e dict:\n    \"\"\"Process data in an isolated, resource-controlled environment.\"\"\"\n    # Your code runs safely in a Wasm sandbox\n    return {\"processed\": len(dataset), \"status\": \"complete\"}\n```\n\n### With TypeScript / JavaScript\n\nUse the `task()` wrapper function with full access to the npm ecosystem:\n\n```typescript\nimport { task } from \"@capsule-run/sdk\";\n\nexport const analyzeData = task({\n  name: \"analyze_data\",\n  compute: \"MEDIUM\",\n  ram: \"512MB\",\n  timeout: \"30s\",\n  maxRetries: 1\n}, (dataset: number[]): object =\u003e {\n  // Your code runs safely in a Wasm sandbox\n  return { processed: dataset.length, status: \"complete\" };\n});\n\n// The \"main\" task is required as the entrypoint\nexport const main = task({\n    name: \"main\",\n    compute: \"HIGH\"\n}, () =\u003e {\n  return analyzeData([1, 2, 3, 4, 5]);\n});\n\n```\n\n\u003e [!NOTE]\n\u003e The runtime requires a task named `\"main\"` as the entry point. Python will create one automatically if none is defined, but it's recommended to set it explicitly.\n\nWhen you run `capsule run main.py` (or `main.ts`), your code is compiled into a WebAssembly module and executed in a dedicated sandbox to isolate tasks.\n\nEach task operates within its own sandbox with configurable resource limits, ensuring that failures are contained and don't cascade to other parts of your workflow. The host system controls every aspect of execution, from CPU allocation via Wasm fuel metering to memory constraints and timeout enforcement.\n\n### Response Format\n\nEvery task returns a structured JSON envelope containing both the result and execution metadata:\n```json\n{\n  \"success\": true,\n  \"result\": \"Hello from Capsule!\",\n  \"error\": null,\n  \"execution\": {\n    \"task_name\": \"data_processor\",\n    \"duration_ms\": 1523,\n    \"retries\": 0,\n    \"fuel_consumed\": 45000\n  }\n}\n```\n\n**Response fields:**\n- `success` — Boolean indicating whether the task completed successfully\n- `result` — The actual return value from your task (json, string, null on failure etc.)\n- `error` — Error details if the task failed (`{ error_type: string, message: string }`)\n- `execution` — Performance metrics:\n  - `task_name` — Name of the executed task\n  - `duration_ms` — Execution time in milliseconds\n  - `retries` — Number of retry attempts that occurred\n  - `fuel_consumed` — CPU resources used (see [Compute Levels](#compute-levels))\n\n## Getting Started\n\n### Python\n\n```bash\npip install capsule-run\n```\n\nCreate `hello.py`:\n\n```python\nfrom capsule import task\n\n@task(name=\"main\", compute=\"LOW\", ram=\"64MB\")\ndef main() -\u003e str:\n    return \"Hello from Capsule!\"\n```\n\nRun it:\n\n```bash\ncapsule run hello.py\n```\n\n### TypeScript / JavaScript\n\n```bash\nnpm install -g @capsule-run/cli\nnpm install @capsule-run/sdk\n```\n\nCreate `hello.ts`:\n\n```typescript\nimport { task } from \"@capsule-run/sdk\";\n\nexport const main = task({\n  name: \"main\",\n  compute: \"LOW\",\n  ram: \"64MB\"\n}, (): string =\u003e {\n  return \"Hello from Capsule!\";\n});\n```\n\nRun it:\n\n```bash\ncapsule run hello.ts\n```\n\n\u003e [!TIP]\n\u003e Add `--verbose` to see real-time task execution details.\n\n## Production\n\nRunning source code directly (like `.py` or `.ts`) evaluates and compiles your file at runtime. While great for development, this compilation step adds a few seconds of latency on first call. For use cases where sub-second latency is critical, you should build your tasks ahead of time.\n\n```bash\n# Generates an optimized hello.wasm file\ncapsule build hello.py --export\n\n# Execute the compiled artifact directly\ncapsule exec hello.wasm\n```\n\n\u003e [!NOTE]\n\u003e Or from your existing code:\n\u003e\n\u003e ```python\n\u003e from capsule import run\n\u003e\n\u003e result = await run(\n\u003e    file=\"./hello.wasm\", # or `hello.py`\n\u003e    args=[]\n\u003e )\n\u003e\n\u003e print(f\"Task completed: {result['result']}\")\n\u003e ```\n\u003e\n\u003e See [in-code usage documentation](#in-code-usage) for details on both Python and TypeScript integration.\n\n\nExecuting a `.wasm` file bypasses the compiler completely, reducing initialization time to milliseconds while using a natively optimized (`.cwasm`) format behind the scenes.\n\n## Documentation (v0.6.3)\n\n### Task Configuration Options\n\nConfigure your tasks with these parameters:\n\n| Parameter | Description | Type | Default | Example |\n|-----------|-------------|------|---------|---------|\n| `name` | Task identifier | `str` | function name (Python) / *required* (TS) | `\"process_data\"` |\n| `compute` | CPU allocation level: `\"LOW\"`, `\"MEDIUM\"`, or `\"HIGH\"` | `str` | `\"MEDIUM\"` | `\"HIGH\"` |\n| `ram` | Memory limit for the task | `str` | unlimited | `\"512MB\"`, `\"2GB\"` |\n| `timeout` | Maximum execution time | `str` | unlimited | `\"30s\"`, `\"5m\"`, `\"1h\"` |\n| `max_retries` / `maxRetries` | Number of retry attempts on failure | `int` | `0` | `3` |\n| `allowed_files` / `allowedFiles` | Folders accessible in the sandbox | `list` | `[]` | `[\"./data\", \"./output\"]` |\n| `allowed_hosts` / `allowedHosts` | Domains accessible in the sandbox | `list` | `[\"*\"]` | `[\"api.openai.com\", \"*.anthropic.com\"]` |\n| `env_variables` / `envVariables` | Environment variables accessible in the sandbox | `list` | `[]` | `[\"API_KEY\"]` |\n\n### Compute Levels\n\nCapsule controls CPU usage through WebAssembly's **fuel mechanism**, which meters instruction execution. The compute level determines how much fuel your task receives.\n- **LOW** provides minimal allocation for lightweight tasks\n- **MEDIUM** offers balanced resources for typical workloads\n- **HIGH** grants maximum fuel for compute-intensive operations\n- **CUSTOM** to specify an exact fuel value (e.g., `compute=\"1000000\"`) for precise control over execution limits.\n\n### Project Configuration (Optional)\n\nYou can create a `capsule.toml` file in your project root to set default options for all tasks and define workflow metadata:\n\n```toml\n# capsule.toml\n\n[workflow]\nname = \"My AI Workflow\"\nversion = \"1.0.0\"\nentrypoint = \"src/main.py\"  # Default file when running `capsule run`\n\n[tasks]\ndefault_compute = \"MEDIUM\"\ndefault_ram = \"256MB\"\ndefault_timeout = \"30s\"\ndefault_max_retries = 2\n```\n\nWith an entrypoint defined, you can simply run:\n\n```bash\ncapsule run\n```\n\nTask-level options always override these defaults when specified.\n\n### HTTP Client API\n\n#### Python\n\nThe standard Python `requests` library and socket-based networking aren't natively compatible with WebAssembly's sandboxed I/O model. Capsule provides its own HTTP client that works within the Wasm environment:\n\n```python\nfrom capsule import task\nfrom capsule.http import get, post, put, delete\n\n@task(name=\"http_example\", compute=\"MEDIUM\", timeout=\"30s\")\ndef main() -\u003e dict:\n    \"\"\"Example demonstrating HTTP client usage within a task.\"\"\"\n\n    # GET request\n    response = get(\"https://api.example.com/data\")\n\n    # POST with JSON body\n    response = post(\"https://api.example.com/submit\", json={\"key\": \"value\"})\n\n    # Response methods\n    is_ok = response.ok()           # Returns True if status code is 2xx\n    status = response.status_code    # Get the HTTP status code\n    data = response.json()           # Parse response as JSON\n    text = response.text()           # Get response as text\n\n    return {\"status\": status, \"success\": is_ok}\n```\n\n#### TypeScript / JavaScript\n\nStandard libraries like `fetch` are already compatible, so no custom HTTP client is needed for TypeScript/JavaScript.\n\n```typescript\nimport { task } from \"@capsule-run/sdk\";\n\nexport const main = task({\n    name: \"main\",\n    compute: \"MEDIUM\"\n}, async () =\u003e {\n    const response = await fetch(\"https://api.example.com/data\");\n    return response.json();\n});\n```\n\n### Network Access\n\nTasks can make HTTP requests to domains specified in `allowed_hosts`. By default, all outbound requests are allowed (`[\"*\"]`). Restrict access by providing a whitelist of domains.\n\n#### Python\n\n```python\nfrom capsule import task\nfrom capsule.http import get\n\n@task(name=\"main\", allowed_hosts=[\"api.openai.com\", \"*.anthropic.com\"])\ndef main() -\u003e dict:\n    response = get(\"https://api.openai.com/v1/models\")\n    return response.json()\n```\n\n#### TypeScript / JavaScript\n\n```typescript\nimport { task } from \"@capsule-run/sdk\";\n\nexport const main = task({\n    name: \"main\",\n    allowedHosts: [\"api.openai.com\", \"*.anthropic.com\"]\n}, async () =\u003e {\n    const response = await fetch(\"https://api.openai.com/v1/models\");\n    return response.json();\n});\n```\n\n### File Access\n\nTasks can read and write files within directories specified in `allowed_files`. Any attempt to access files outside these directories is not possible.\n\n\u003e [!NOTE]\n\u003e Currently, `allowed_files` supports directory paths, not individual files.\n\n#### Python\n\nPython's standard file operations work normally. Use `open()`, `os`, `pathlib`, or any file manipulation library.\n\n```python\nfrom capsule import task\n\n@task(name=\"restricted_writer\", allowed_files=[\"./output\"])\ndef restricted_writer() -\u003e None:\n    with open(\"./output/result.txt\", \"w\") as f:\n        f.write(\"result\")\n\n@task(name=\"main\")\ndef main() -\u003e str:\n    restricted_writer()\n```\n\n#### TypeScript / JavaScript\n\nCommon Node.js built-ins are available. Use the standard `fs` module:\n\n```typescript\nimport { task } from \"@capsule-run/sdk\";\nimport fs from \"fs/promises\";\n\nexport const restrictedWriter = task({\n    name: \"restricted_writer\",\n    allowedFiles: [\"./output\"]\n}, async () =\u003e {\n    await fs.writeFile(\"./output/result.txt\", \"result\");\n});\n\nexport const main = task({ name: \"main\", allowedFiles: [\"./data\"] }, async () =\u003e {\n    await restrictedWriter();\n    return await fs.readFile(\"./data/input.txt\", \"utf8\");\n});\n```\n\n### Environment Variables\n\nTasks can access environment variables to read configuration, API keys, or other runtime settings.\n\n#### Python\n\nUse Python's standard `os.environ` to access environment variables:\n```python\nfrom capsule import task\nimport os\n\n@task(name=\"main\", env_variables=[\"API_KEY\"])\ndef main() -\u003e dict:\n    api_key = os.environ.get(\"API_KEY\")\n    return {\"api_key\": api_key}\n```\n\n#### TypeScript / JavaScript\n\nUse the standard `process.env` to access environment variables:\n```typescript\nimport { task } from \"@capsule-run/sdk\";\n\nexport const main = task({\n    name: \"main\",\n    envVariables: [\"API_KEY\"]\n}, () =\u003e {\n    const apiKey = process.env.API_KEY;\n    return { apiKeySet: apiKey !== undefined };\n});\n```\n\n### In-Code Usage\n\nThe `run()` function lets you execute tasks programmatically from your code instead of using the CLI. The `args` are automatically forwarded as parameters to the `main` task.\n\n#### Python\n\n```python\nfrom capsule import run\n\nresult = await run(\n    file=\"./sandbox.py\", # or `sandbox.wasm`\n    args=[\"code to execute\"]\n)\n```\n\nCreate `sandbox.py`:\n\n```python\nfrom capsule import task\n\n@task(name=\"main\", compute=\"LOW\", ram=\"64MB\")\ndef main(code: str) -\u003e str:\n    return exec(code)\n```\n\n#### TypeScript / JavaScript\n\n\u003e [!IMPORTANT]\n\u003e You need `@capsule-run/cli` in your dependencies to use the runner functions in TypeScript.\n\n```typescript\nimport { run } from '@capsule-run/sdk/runner';\n\nconst result = await run({\n  file: './sandbox.ts', // or `sandbox.wasm`\n  args: ['code to execute']\n});\n```\n\nCreate `sandbox.ts`:\n\n```typescript\nimport { task } from \"@capsule-run/sdk\";\n\nexport const main = task({\n  name: \"main\",\n  compute: \"LOW\",\n  ram: \"64MB\"\n}, (code: string): string =\u003e {\n  return eval(code);\n});\n```\n\n### Cache Management\n\nWhen you run your code, Capsule creates a `.capsule` folder in your project root. This is the build cache. It stores compiled artifacts so subsequent runs are fast (from seconds to few milliseconds).\n\n\u003e [!TIP]\n\u003e `.capsule` should be added to `.gitignore`. The cache is specific to your own environment and will be regenerated automatically.\n\n```\n.capsule/\n├── wasm/\n│   ├── main_a1b2c3d4.wasm    # Compiled WebAssembly module\n│   └── main_a1b2c3d4.cwasm   # Native precompiled cache\n├── wit/                       # Interface definitions\n└── trace.db                   # Execution logs\n```\n\nUse `capsule build` to precompile ahead of time and skip the compilation cost on the first run:\n\n```bash\ncapsule build main.ts # or `main.py`\n```\n\n## Compatibility\n\n\u003e [!NOTE]\n\u003e TypeScript/JavaScript has broader compatibility than Python since it doesn't rely on native bindings.\n\n**Python:** Only pure Python is supported in sandboxes (no C extensions like `numpy` or `pandas`). However, your host code using `run()` has access to the full Python ecosystem, any pip package and native extensions. (see [in-code usage](#in-code-usage))\n\n**TypeScript/JavaScript:** npm packages and ES modules work. Common Node.js built-ins are available. If you have any trouble with a built-in, do not hesitate to open an issue.\n\n## Contributing\n\nContributions are welcome!\n\n### Development setup\n\n**Prerequisites:** Rust (latest stable), Python 3.13+, Node.js 22+\n\n```bash\ngit clone https://github.com/mavdol/capsule.git\ncd capsule\n\n# Build and install CLI\ncargo install --path crates/capsule-cli\n\n# Python SDK (editable install)\npip install -e crates/capsule-sdk/python\n\n# TypeScript SDK (link for local dev)\ncd crates/capsule-sdk/javascript\nnpm install \u0026\u0026 npm run build \u0026\u0026 npm link\n\n# Then in your project: npm link @capsule-run/sdk\n```\n\n### How to contribute\n\n1. **Fork** the repository\n2. **Create** a feature branch: `git checkout -b feature/amazing-feature`\n3. **Run tests**: `cargo test` (only needed if modifying `crates/capsule-cli` or `crates/capsule-core`)\n4. **Open** a Pull Request\n\nNeed help? [Open an issue](https://github.com/mavdol/capsule/issues)\n\n## Credits\n\nCapsule builds on these open source projects:\n\n- [componentize-py](https://github.com/bytecodealliance/componentize-py) – Python to WebAssembly Component compilation\n- [jco](https://github.com/bytecodealliance/jco) – JavaScript toolchain for WebAssembly Components\n- [wasmtime](https://github.com/bytecodealliance/wasmtime) – WebAssembly runtime\n- [WASI](https://github.com/WebAssembly/WASI) – WebAssembly System Interface\n\n## License\n\nThis project is licensed under the **Apache License 2.0** - see the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmavdol%2Fcapsule","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmavdol%2Fcapsule","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmavdol%2Fcapsule/lists"}