
AIエージェントタスクをサンドボックス化するためのセキュアなランタイム。信頼できないコードを隔離されたWebAssembly環境で実行します。
Capsule は、信頼されていないコードを分離された環境で実行するためのランタイムです。各タスクは独自の WebAssembly サンドボックス内で動作し、以下を提供します。
Python 関数に @task デコレータを付けるだけです:
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."""
# Your code runs safely in a Wasm sandbox
return {"processed": len(dataset), "status": "complete"}
npm エコシステムにフルアクセスできる task() ラッパー関数を使用します:
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" };
});
[!NOTE] ランタイムはエントリポイントとして
"main"という名前のタスクを必要とします。Python は定義されていない場合に自動的に作成しますが、明示的に設定することをお勧めします。
capsule run main.py(または main.ts)を実行すると、コードが WebAssembly モジュールにコンパイルされ、分離されたサンドボックスで実行されます。
各タスクは構成可能なリソース制限を持つ独自のサンドボックス内で動作し、障害が他のワークフロー部分に波及しないようにします。ホストシステムは、Wasm の燃料計測による CPU 割り当てからメモリ制約、タイムアウトの実施まで、実行のあらゆる側面を制御します。
pip install capsule-run
hello.py を作成します:
from capsule import task
@task(name="main", compute="LOW", ram="64MB")
def main() -> str:
return "Hello from Capsule!"
実行します:
capsule run hello.py
npm install -g @capsule-run/cli
npm install @capsule-run/sdk
hello.ts を作成します:
import { task } from "@capsule-run/sdk";
export const main = task({
name: "main",
compute: "LOW",
ram: "64MB"
}, (): string => {
return "Hello from Capsule!";
});
実行します:
capsule run hello.ts
[!TIP]
--verboseを追加すると、タスクの実行状況がリアルタイムで表示されます。
run() 関数を使うと、CLI ではなくコードからプログラム的にタスクを実行できます。args は自動的に main タスクのパラメータとして転送されます。
from capsule import run
result = await run(
file="./sandbox.py",
args=["code to execute"]
)
sandbox.py を作成します:
from capsule import task
@task(name="main", compute="LOW", ram="64MB")
def main(code: str) -> str:
return eval(code)
[!IMPORTANT] TypeScript でランナー関数を使用するには、依存関係に
@capsule-run/cliが必要です。
import { run } from '@capsule-run/sdk/runner';
const result = await run({
file: './sandbox.ts',
args: ['code to execute']
});
sandbox.ts を作成します:
import { task } from "@capsule-run/sdk";
export const main = task({
name: "main",
compute: "LOW",
ram: "64MB"
}, (code: string): string => {
return eval(code);
});
[!TIP] すぐに使える設定済みのソリューションをお探しの場合は、Python アダプター または TypeScript アダプター をご確認ください。
以下のパラメーターでタスクを構成します:
Capsule は WebAssembly の 燃料メカニズム を通じて CPU 使用率を制御します。このメカニズムは命令実行を計測します。コンピュートレベルによって、タスクが受け取る燃料の量が決まります。
compute="1000000")。実行制限を精密に制御できます。すべてのタスクは、結果と実行メタデータの両方を含む構造化された JSON エンベロープを返します:
{
"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": [{...}]
}
}
レスポンスフィールド:
success — タスクが正常に完了したかどうかを示すブール値result — タスクからの実際の戻り値(json、文字列、失敗時は null など)error — タスクが失敗した場合のエラー詳細({ error_type: string, message: string })execution — パフォーマンスメトリクス:
task_name — 実行されたタスクの名前duration_ms — 実行時間(ミリ秒)retries — 発生したリトライ回数fuel_consumed — 使用された CPU リソース(コンピュートレベルを参照)ram_used — 使用されたピークメモリ(バイト)host_requests — タスクによって行われたホストリクエストのリストタスクは allowed_hosts で指定されたドメインに対して HTTP リクエストを行うことができます。デフォルトでは、アウトバウンドリクエストは許可されません([])。アクセスを許可するドメインの許可リストを指定するか、["*"] を使用してすべてのドメインを許可します。
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();
});
タスクは allowed_files で指定されたディレクトリ内のファイルの読み取りと書き込みを行うことができます。これらのディレクトリ外のファイルへのアクセスは不可能です。
[!NOTE]
allowed_filesはディレクトリパスのみをサポートし、個別のファイルはサポートしません。
各エントリはプレーンなパス(デフォルトで読み書き可能)または明示的な mode を持つ構造化オブジェクトにできます:
"read-only"(または "ro")"read-write"(または "rw")Python の標準ファイル操作は正常に動作します。open()、os、pathlib、または任意のファイル操作ライブラリを使用してください。
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
プレーンな文字列も引き続き受け付けられます: allowed_files=["./output"] はデフォルトで読み書き可能になります。
一般的な Node.js の組み込みモジュールが利用可能です。標準の 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;
});
プレーンな文字列も引き続き受け付けられます: allowedFiles: ["./output"] はデフォルトで読み書き可能になります。
--mount)--mount フラグ(CLI)または mounts パラメーター(SDK)は、ホストディレクトリをサンドボックス内にエイリアスとしてマウントします。マウントはサブタスクに伝播し、新しいパスへのアクセスを追加しますが、allowed_files ですでに宣言されているパスのアクセスモードは変更しません。
形式: HOST_PATH[::GUEST_PATH][:ro|:rw]
CLI
# セッションワークスペースをマウントし、タスク内で "workspace" として公開
capsule run main.py --mount sessions/abc123_workspace::workspace
# 複数のディレクトリ
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"],
});
タスク内では、ゲストパスを介してディレクトリにアクセスします:
# task sees it at "workspace/", not at the full session path
with open("workspace/output.txt", "w") as f:
f.write("done")
[!NOTE]
--mountパスは相対パスである必要があり、プロジェクトルートから脱出してはいけません。絶対パスは拒否されます。
タスクは環境変数にアクセスして、設定、API キー、その他の実行時設定を読み取ることができます。
Python の標準 os.environ を使用して環境変数にアクセスします:
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}
標準の process.env を使用して環境変数にアクセスします:
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 };
});
プロジェクトルートに capsule.toml ファイルを作成して、すべてのタスクのデフォルトオプションを設定し、ワークフローメタデータを定義できます:
# capsule.toml
[workflow]
name = "My Workflow"
version = "1.0.0"
entrypoint = "src/main.py" # Default file when running `capsule run`
[tasks]
default_compute = "MEDIUM"
default_ram = "256MB"
default_timeout = "30s"
default_max_retries = 2
エントリポイントが定義されていれば、次のように実行するだけです:
capsule run
タスクレベルのオプションは、指定された場合に常にこれらのデフォルトを上書きします。
コードを実行すると、Capsule はプロジェクトルートに .capsule フォルダーを作成します。これがビルドキャッシュです。コンパイルされたアーティファクトを保存し、その後の実行を高速化します(数秒から数ミリ秒に)。
[!TIP]
.capsuleは.gitignoreに追加する必要があります。キャッシュは自身の環境に固有のものであり、自動的に再生成されます。
.capsule/
├── wasm/
│ ├── main_a1b2c3d4.wasm # Compiled WebAssembly module
│ └── main_a1b2c3d4.cwasm # Native precompiled cache
├── wit/ # Interface definitions
└── trace.db # Execution logs
capsule build を使用して事前にプリコンパイルし、初回実行時のコンパイルコストをスキップします:
capsule build main.ts # or `main.py`
ソースコード(.py や .ts など)を直接実行すると、ファイルが実行時に評価・コンパイルされます。開発には最適ですが、このコンパイルステップにより初回呼び出しに数秒のレイテンシが追加されます。サブ秒のレイテンシが重要なユースケースでは、事前にタスクをビルドする必要があります。
# 最適化された hello.wasm ファイルを生成します
capsule build hello.py --export
# コンパイル済みアーティファクトを直接実行します
capsule exec hello.wasm
[!NOTE] または、既存のコードから:
from capsule import run result = await run( file="./hello.wasm", # or `hello.py` args=[] ) print(f"Task completed: {result['result']}")
.wasm ファイルを実行するとコンパイラが完全にバイパスされるため、初期化時間がミリ秒単位に短縮され、背後でネイティブ最適化された(.cwasm)フォーマットが使用されます。
[!NOTE] TypeScript/JavaScript はネイティブバインディングに依存しないため、Python よりも互換性が広くなっています。
Python: ほとんどの標準 Python ライブラリは正常に動作します。C 拡張機能を使用するパッケージは wasm32-wasi コンパイル済みホイールが必要です。numpy や pandas などの多くの人気パッケージはまだ配布されていないため、サンドボックス内では動作しません。ただし、ホストコード(run() を使用)は、pip パッケージやネイティブ拡張機能を含む完全な Python エコシステムにアクセスできます。コード内での使用法 を参照してください。
TypeScript/JavaScript: npm パッケージと ES モジュールが動作します。一般的な Node.js の組み込みモジュールが利用可能です。組み込みモジュールで問題が発生した場合は、遠慮なくイシューを開いてください。
コントリビューションを歓迎します!
前提条件: Rust(最新安定版)、Python 3.13+、Node.js 22+
git clone https://github.com/capsulerun/capsule.git
cd capsule
# CLI のビルドとインストール
cargo install --path crates/capsule-cli
# Python SDK(編集可能インストール)
pip install -e crates/capsule-sdk/python
# TypeScript SDK(ローカル開発用にリンク)
cd crates/capsule-sdk/javascript
npm install && npm run build && npm link
# プロジェクトで: npm link @capsule-run/sdk
git checkout -b feature/amazing-featurecargo test(crates/capsule-cli または crates/capsule-core を変更する場合のみ必要)ヘルプが必要ですか? イシューを開く
Capsule は以下のオープンソースプロジェクトを基盤としています:
このプロジェクトは Apache License 2.0 の下でライセンスされています。詳細は LICENSE ファイルをご覧ください。
| パラメーター | 説明 | 型 | デフォルト | 例 |
|---|
name | タスク識別子 | str | 関数名 (Python) / 必須 (TS) | "process_data" |
compute | CPU 割り当てレベル: "LOW", "MEDIUM", または "HIGH" | str | "MEDIUM" | "HIGH" |
ram | タスクのメモリ制限 | str | 無制限 | "512MB", "2GB" |
timeout | 最大実行時間 | str | 無制限 | "30s", "5m", "1h" |
max_retries / maxRetries | 失敗時のリトライ回数 | int | 0 | 3 |
allowed_files / allowedFiles | サンドボックス内でアクセス可能なフォルダー(オプションのアクセスモード付き) | list | [] | ["./data"], [{"path": "./data", "mode": "ro"}] |
allowed_hosts / allowedHosts | サンドボックス内でアクセス可能なドメイン | list | [] | ["api.openai.com", "*.anthropic.com"] |
env_variables / envVariables | サンドボックス内でアクセス可能な環境変数 | list | [] | ["API_KEY"] |
| 部分 | 必須 | 説明 |
|---|
HOST_PATH | はい | ホストマシン上のパス(cwd からの相対パス、プロジェクトルート内に収まる必要があります) |
::GUEST_PATH | いいえ | タスクがサンドボックス内で見るパス。デフォルトは HOST_PATH |
:ro / :rw | いいえ | アクセスモード。デフォルトは読み書き可能 |