
Sichere Laufzeitumgebung zum Isolieren von KI-Agentenaufgaben. Führen Sie nicht vertrauenswürdigen Code in isolierten WebAssembly-Umgebungen aus.
Capsule ist eine Laufzeitumgebung zur Ausführung von nicht vertrauenswürdigem Code in isolierten Umgebungen. Jeder Task läuft in seiner eigenen WebAssembly-Sandbox und bietet:
Dekorieren Sie Ihre Python-Funktionen einfach mit dem @task-Dekorator:
from capsule import task
@task(name="analyze_data", compute="MEDIUM", ram="512MB", timeout="30s", max_retries=1)
def analyze_data(dataset: list) -> dict:
"""Verarbeitet Daten in einer isolierten, ressourcengesteuerten Umgebung."""
# Ihr Code läuft sicher in einer Wasm-Sandbox
return {"processed": len(dataset), "status": "complete"}
Verwenden Sie die task()-Wrapper-Funktion mit vollem Zugriff auf das npm-Ökosystem:
import { task } from "@capsule-run/sdk";
export const analyzeData = task({
name: "analyze_data",
compute: "MEDIUM",
ram: "512MB",
timeout: "30s",
maxRetries: 1
}, (dataset: number[]): object => {
// Ihr Code läuft sicher in einer Wasm-Sandbox
return { processed: dataset.length, status: "complete" };
});
[!HINWEIS] Die Laufzeitumgebung benötigt einen Task namens
"main"als Einstiegspunkt. Python erstellt automatisch einen, falls keiner definiert ist, es wird jedoch empfohlen, ihn explizit zu setzen.
Wenn Sie capsule run main.py (oder main.ts) ausführen, wird Ihr Code in ein WebAssembly-Modul kompiliert und in isolierten Sandboxes ausgeführt.
Jeder Task arbeitet innerhalb seiner eigenen Sandbox mit konfigurierbaren Ressourcenlimits, sodass Fehler eingedämmt werden und nicht auf andere Teile Ihres Workflows übergreifen. Das Host-System steuert jeden Aspekt der Ausführung, von der CPU-Zuteilung über Wasm-Fuel-Metering bis hin zu Speicherbeschränkungen und Timeout-Erzwingung.
pip install capsule-run
Erstellen Sie hello.py:
from capsule import task
@task(name="main", compute="LOW", ram="64MB")
def main() -> str:
return "Hello from Capsule!"
Führen Sie es aus:
capsule run hello.py
npm install -g @capsule-run/cli
npm install @capsule-run/sdk
Erstellen Sie hello.ts:
import { task } from "@capsule-run/sdk";
export const main = task({
name: "main",
compute: "LOW",
ram: "64MB"
}, (): string => {
return "Hello from Capsule!";
});
Führen Sie es aus:
capsule run hello.ts
[!TIPP] Fügen Sie
--verbosehinzu, um Echtzeitdetails der Task-Ausführung zu sehen.
Die run()-Funktion ermöglicht es Ihnen, Tasks programmatisch aus Ihrem Code auszuführen, anstatt die CLI zu verwenden. Die args werden automatisch als Parameter an den main-Task weitergeleitet.
from capsule import run
result = await run(
file="./sandbox.py",
args=["code to execute"]
)
Erstellen Sie sandbox.py:
from capsule import task
@task(name="main", compute="LOW", ram="64MB")
def main(code: str) -> str:
return eval(code)
[!WICHTIG] Sie benötigen
@capsule-run/cliin Ihren Abhängigkeiten, um die Runner-Funktionen in TypeScript zu verwenden.
import { run } from '@capsule-run/sdk/runner';
const result = await run({
file: './sandbox.ts',
args: ['code to execute']
});
Erstellen Sie sandbox.ts:
import { task } from "@capsule-run/sdk";
export const main = task({
name: "main",
compute: "LOW",
ram: "64MB"
}, (code: string): string => {
return eval(code);
});
[!TIPP] Wenn Sie nach einer vorkonfigurierten, einsatzbereiten Lösung suchen, schauen Sie sich den Python-Adapter oder den TypeScript-Adapter an.
Konfigurieren Sie Ihre Tasks mit diesen Parametern:
Capsule steuert die CPU-Nutzung über den Fuel-Mechanismus von WebAssembly, der die Befehlsausführung misst. Die Berechnungsstufe bestimmt, wie viel Fuel Ihr Task erhält.
compute="1000000") für präzise Kontrolle über Ausführungslimits.Jeder Task gibt einen strukturierten JSON-Envelope zurück, der sowohl das Ergebnis als auch Ausführungsmetadaten enthält:
{
"success": true,
"result": "Hello from Capsule!",
"error": null,
"execution": {
"task_name": "data_processor",
"duration_ms": 1523,
"retries": 0,
"fuel_consumed": 45000,
"ram_used": 1200000,
"host_requests": [{...}]
}
}
Antwortfelder:
success — Boolescher Wert, der angibt, ob der Task erfolgreich abgeschlossen wurderesult — Der tatsächliche Rückgabewert Ihres Tasks (json, string, null bei Fehler usw.)error — Fehlerdetails, falls der Task fehlgeschlagen ist ({ error_type: string, message: string })execution — Leistungsmetriken:
task_name — Name des ausgeführten Tasksduration_ms — Ausführungszeit in Millisekundenretries — Anzahl der aufgetretenen Wiederholungsversuchefuel_consumed — Verbrauchte CPU-Ressourcen (siehe Berechnungsstufen)ram_used — Spitzen-Speichernutzung in Byteshost_requests — Liste der vom Task durchgeführten Host-AnfragenTasks können HTTP-Anfragen an die in allowed_hosts angegebenen Domains stellen. Standardmäßig sind keine ausgehenden Anfragen erlaubt ([]). Geben Sie eine Whitelist von Domains an, um Zugriff zu gewähren, oder verwenden Sie ["*"], um alle Domains zuzulassen.
import json
from capsule import task
from urllib.request import urlopen
@task(name="main", allowed_hosts=["api.openai.com", "*.anthropic.com"])
def main() -> dict:
with urlopen("https://api.openai.com/v1/models") as response:
return json.loads(response.read().decode("utf-8"))
import { task } from "@capsule-run/sdk";
export const main = task({
name: "main",
allowedHosts: ["api.openai.com", "*.anthropic.com"]
}, async () => {
const response = await fetch("https://api.openai.com/v1/models");
return response.json();
});
Tasks können Dateien in den in allowed_files angegebenen Verzeichnissen lesen und schreiben. Ein Zugriff auf Dateien außerhalb dieser Verzeichnisse ist nicht möglich.
[!HINWEIS]
allowed_filesunterstützt nur Verzeichnispfade, keine einzelnen Dateien.
Jeder Eintrag kann ein einfacher Pfad (standardmäßig Lese-/Schreibzugriff) oder ein strukturiertes Objekt mit explizitem mode sein:
"read-only" (oder "ro")"read-write" (oder "rw")Pythons Standard-Dateioperationen funktionieren normal. Verwenden Sie open(), os, pathlib oder jede andere Dateimanipulationsbibliothek.
from capsule import task
@task(name="main", allowed_files=[
{"path": "./data", "mode": "read-only"},
{"path": "./output", "mode": "read-write"},
])
def main() -> str:
with open("./data/input.txt") as f:
content = f.read()
with open("./output/result.txt", "w") as f:
f.write(content)
return content
Einfache Zeichenketten werden weiterhin akzeptiert: allowed_files=["./output"] standardmäßig Lese-/Schreibzugriff.
Gängige Node.js-Built-ins sind verfügbar. Verwenden Sie das Standardmodul fs:
import { task } from "@capsule-run/sdk";
import fs from "fs/promises";
export const main = task({
name: "main",
allowedFiles: [
{ path: "./data", mode: "read-only" },
{ path: "./output", mode: "read-write" },
]
}, async () => {
const content = await fs.readFile("./data/input.txt", "utf8");
await fs.writeFile("./output/result.txt", content);
return content;
});
Einfache Zeichenketten werden weiterhin akzeptiert: allowedFiles: ["./output"] standardmäßig Lese-/Schreibzugriff.
--mount)Das --mount-Flag (CLI) oder der mounts-Parameter (SDK) mountet ein Host-Verzeichnis unter einem Alias in die Sandbox. Mounts werden an Subtasks weitergegeben und fügen Zugriff auf neue Pfade hinzu; sie ändern nicht den Zugriffsmodus von bereits in allowed_files deklarierten Pfaden.
Format: HOST_PATH[::GUEST_PATH][:ro|:rw]
CLI
# Einen Session-Arbeitsbereich mounten und als "workspace" im Task bereitstellen
capsule run main.py --mount sessions/abc123_workspace::workspace
# Mehrere Verzeichnisse
capsule run main.py \
--mount sessions/abc123_workspace::workspace \
--mount sessions/bce456_workspace::workspace:ro
Python SDK
from capsule import run
result = await run(
file="main.py",
mounts=[".capsule/sessions/abc123_workspace::workspace"],
)
TypeScript / JavaScript SDK
import { run } from "@capsule-run/sdk";
const result = await run({
file: "main.py",
mounts: [".capsule/sessions/abc123_workspace::workspace"],
});
Innerhalb des Tasks wird das Verzeichnis über den Gast-Pfad angesprochen:
# Der Task sieht es unter "workspace/", nicht unter dem vollständigen Session-Pfad
with open("workspace/output.txt", "w") as f:
f.write("done")
[!HINWEIS]
--mount-Pfade müssen relativ sein und dürfen den Projektstamm nicht verlassen. Absolute Pfade werden abgelehnt.
Tasks können auf Umgebungsvariablen zugreifen, um Konfiguration, API-Schlüssel oder andere Laufzeiteinstellungen zu lesen.
Verwenden Sie Pythons Standard os.environ für den Zugriff auf Umgebungsvariablen:
from capsule import task
import os
@task(name="main", env_variables=["API_KEY"])
def main() -> dict:
api_key = os.environ.get("API_KEY")
return {"api_key": api_key}
Verwenden Sie das Standard process.env für den Zugriff auf Umgebungsvariablen:
import { task } from "@capsule-run/sdk";
export const main = task({
name: "main",
envVariables: ["API_KEY"]
}, () => {
const apiKey = process.env.API_KEY;
return { apiKeySet: apiKey !== undefined };
});
Sie können eine capsule.toml-Datei im Stammverzeichnis Ihres Projekts erstellen, um Standardoptionen für alle Tasks festzulegen und Workflow-Metadaten zu definieren:
# capsule.toml
[workflow]
name = "Mein Workflow"
version = "1.0.0"
entrypoint = "src/main.py" # Standarddatei beim Ausführen von `capsule run`
[tasks]
default_compute = "MEDIUM"
default_ram = "256MB"
default_timeout = "30s"
default_max_retries = 2
Mit einem definierten Einstiegspunkt können Sie einfach ausführen:
capsule run
Task-spezifische Optionen überschreiben diese Standardwerte, wenn sie angegeben werden.
Wenn Sie Ihren Code ausführen, erstellt Capsule einen .capsule-Ordner im Stammverzeichnis Ihres Projekts. Dies ist der Build-Cache. Er speichert kompilierte Artefakte, sodass nachfolgende Ausführungen schnell sind (von Sekunden auf wenige Millisekunden).
[!TIPP]
.capsulesollte zu.gitignorehinzugefügt werden. Der Cache ist spezifisch für Ihre eigene Umgebung und wird automatisch neu generiert.
.capsule/
├── wasm/
│ ├── main_a1b2c3d4.wasm # Kompiliertes WebAssembly-Modul
│ └── main_a1b2c3d4.cwasm # Nativ vorkompilierter Cache
├── wit/ # Schnittstellendefinitionen
└── trace.db # Ausführungsprotokolle
Verwenden Sie capsule build, um vorab zu kompilieren und die Kompilierungskosten beim ersten Ausführen zu überspringen:
capsule build main.ts # oder `main.py`
Die direkte Ausführung von Quellcode (wie .py oder .ts) wertet Ihre Datei zur Laufzeit aus und kompiliert sie. Das ist für die Entwicklung großartig, fügt aber beim ersten Aufruf einige Sekunden Latenz hinzu. Für Anwendungsfälle, bei denen Latenz im Sub-Sekunden-Bereich entscheidend ist, sollten Sie Ihre Tasks vorab erstellen.
# Erzeugt eine optimierte hello.wasm-Datei
capsule build hello.py --export
# Das kompilierte Artefakt direkt ausführen
capsule exec hello.wasm
[!HINWEIS] Oder aus Ihrem bestehenden Code:
from capsule import run result = await run( file="./hello.wasm", # oder `hello.py` args=[] ) print(f"Task abgeschlossen: {result['result']}")
Die Ausführung einer .wasm-Datei umgeht den Compiler vollständig und reduziert die Initialisierungszeit auf Millisekunden, während im Hintergrund ein nativ optimiertes (.cwasm)-Format verwendet wird.
[!HINWEIS] TypeScript/JavaScript hat eine breitere Kompatibilität als Python, da es nicht auf native Bindungen angewiesen ist.
Python: Die meisten Standard-Python-Bibliotheken funktionieren einwandfrei. Pakete, die C-Erweiterungen verwenden, benötigen ein wasm32-wasi-kompiliertes Wheel. Viele beliebte Pakete wie numpy und pandas liefern noch keines aus, daher funktionieren sie innerhalb der Sandbox nicht. Ihr Host-Code (mit run()) hat jedoch Zugriff auf das gesamte Python-Ökosystem, einschließlich aller pip-Pakete und nativen Erweiterungen. Siehe In-Code-Verwendung
TypeScript/JavaScript: npm-Pakete und ES-Module funktionieren. Gängige Node.js-Built-ins sind verfügbar. Wenn Sie Probleme mit einem Built-in haben, zögern Sie nicht, ein Issue zu öffnen.
Beiträge sind willkommen!
Voraussetzungen: Rust (neueste stabile Version), Python 3.13+, Node.js 22+
git clone https://github.com/capsulerun/capsule.git
cd capsule
# CLI bauen und installieren
cargo install --path crates/capsule-cli
# Python SDK (editierbare Installation)
pip install -e crates/capsule-sdk/python
# TypeScript SDK (für lokale Entwicklung verlinken)
cd crates/capsule-sdk/javascript
npm install && npm run build && npm link
# Dann in Ihrem Projekt: npm link @capsule-run/sdk
git checkout -b feature/amazing-featurecargo test (nur nötig, wenn Sie crates/capsule-cli oder crates/capsule-core ändern)Benötigen Sie Hilfe? Eröffnen Sie ein Issue
Capsule baut auf diesen Open-Source-Projekten auf:
Dieses Projekt ist unter der Apache License 2.0 lizenziert – siehe Datei LICENSE für Details.
| Parameter | Beschreibung | Typ | Standard | Beispiel |
|---|
name | Task-Identifikator | str | Funktionsname (Python) / erforderlich (TS) | "process_data" |
compute | CPU-Zuteilungsstufe: "LOW", "MEDIUM" oder "HIGH" | str | "MEDIUM" | "HIGH" |
ram | Speicherlimit für den Task | str | unbegrenzt | "512MB", "2GB" |
timeout | Maximale Ausführungszeit | str | unbegrenzt | "30s", "5m", "1h" |
max_retries / maxRetries | Anzahl der Wiederholungsversuche bei Fehlschlag | int | 0 | 3 |
allowed_files / allowedFiles | In der Sandbox zugängliche Ordner (mit optionalem Zugriffsmodus) | list | [] | ["./data"], [{"path": "./data", "mode": "ro"}] |
allowed_hosts / allowedHosts | In der Sandbox zugängliche Domains | list | [] | ["api.openai.com", "*.anthropic.com"] |
env_variables / envVariables | In der Sandbox zugängliche Umgebungsvariablen | list | [] | ["API_KEY"] |
| Teil | Erforderlich | Beschreibung |
|---|
HOST_PATH | ja | Pfad auf dem Host-Rechner (relativ zu cwd, muss innerhalb des Projektstamms bleiben) |
::GUEST_PATH | nein | Pfad, den der Task innerhalb der Sandbox sieht. Standard: HOST_PATH |
:ro / :rw | nein | Zugriffsmodus. Standardmäßig Lese-/Schreibzugriff |