Sandbox API と SDK リファレンス
Lizard SDK は、Lizard (lizard.build) の Sandboxes 用クライアントです: TypeScript と JavaScript 向けには npm の @lizard-build/sdk、Python 向けには PyPI の lizard-sdk(lizard としてインポート)があります。どちらも同じ HTTP API を呼び出します。このページでは、sandbox の各呼び出しを TypeScript と Python の名前で一覧にし、両方の言語の例を示します。手順に沿って最初の実行を試すには クイックスタート を、Sandboxes とは何かについては 概要 を読んでください。
インストールと認証
npm install @lizard-build/sdk
pip install lizard-sdk
export LIZARD_API_KEY="<your-api-key>"Settings → API keys で、または lizard keys create <name> で API キーを作成します。SDK は LIZARD_API_KEY を読み取ります。別のキーを使うには apiKey(Python では api_key)を渡します。各 sandbox にはプロジェクトが必要です。projectId(Python では project_id)、または project に ID、slug、名前を渡します。
作成オプション
| TypeScript | Python |
|---|---|
projectId / project | project_id / project |
timeoutMs | timeout_ms |
region | region |
volumeName / volumeId | volume_name / volume_id |
size | size |
snapshotId | snapshot_id |
envs | envs |
metadata | metadata |
lizardToken | lizard_token |
apiKey | api_key |
import { Sandbox } from '@lizard-build/sdk';
const sandbox = await Sandbox.create('base', {
projectId: 'proj_123',
size: 'small',
timeoutMs: 10 * 60 * 1000,
envs: { MODE: 'test' },
metadata: { task: 'report-42' },
});from lizard import Sandbox
sandbox = Sandbox.create(
"base",
project_id="proj_123",
size="small",
timeout_ms=10 * 60 * 1000,
envs={"MODE": "test"},
metadata={"task": "report-42"},
)- 最初の引数は、ランタイムとテンプレート にあるカタログのテンプレートです。指定しない場合、SDK は
baseを起動します。 sizeは'small'、'medium'、'large'のいずれかで、それぞれ 2 vCPU / 4 GB、4 vCPU / 8 GB (既定)、8 vCPU / 16 GB です。サイズと料金を参照してください。スナップショットから復元した sandbox にはsizeは適用されず、元の sandbox のサイズで動作します。timeoutMsの既定は 300000(5 分)です。0は期限を無効にします。リソースと有効期間 を参照してください。- 必要に応じてリージョンを指定してください。カタログへの掲載は空き容量を保証しません。ボリュームを接続する場合は
regionを指定しないでください: sandbox はボリュームのある場所で実行されます。 metadataは独自のラベルです。getInfo()とlist()がこれを返します。lizardTokenはliz_で始まる API キーを sandbox に書き込み、sandbox 内でlizardを使えるようにします。sandbox 内のどのプロセスもこのキーを読み取れるため、ワークスペース単位のキーを渡してください。
メソッド
| TypeScript | Python | 機能 |
|---|---|---|
Sandbox.create(template, options) | Sandbox.create(template, ...) | カタログのテンプレートからプロジェクト内に作成。 |
Sandbox.connect(sandboxId) | Sandbox.connect(sandbox_id) | 既存の sandbox に接続。自動再開はしません。 |
Sandbox.list({ projectId }) | Sandbox.list(project_id=...) | アクセスできる Sandboxes を一覧表示。状態を確認してください。 |
sandbox.getInfo() | sandbox.get_info() | 状態、ランタイム、メタデータを取得。 |
sandbox.process.exec(cmd, opts) | sandbox.process.exec_(cmd, ...) | シェルコマンドまたは argv 配列を実行し、stdout、stderr、終了コードを返す。 |
sandbox.process.list() | sandbox.process.list() | exec で起動したプロセスを一覧表示。 |
sandbox.process.kill(pid, signal) | sandbox.process.kill(pid, signal) | プロセスとその子プロセスにシグナルを送る。既定は SIGTERM。 |
sandbox.fs.write(path, data) | sandbox.fs.write(path, data) | テキストまたはバイトを書き込み、親ディレクトリを作成。 |
sandbox.fs.read(path) | sandbox.fs.read(path) | UTF-8 テキストを読み取る。 |
sandbox.fs.readBytes(path) | sandbox.fs.read_bytes(path) | ファイルのバイトを読み取る。 |
sandbox.fs.list(path) | sandbox.fs.list(path) | ディレクトリの項目を一覧表示。 |
sandbox.fs.stat(path) | sandbox.fs.stat(path) | 種類、サイズ、モード、所有者、更新日時を返す。 |
sandbox.fs.makeDir(path) | sandbox.fs.make_dir(path) | ディレクトリと不足する親を作成。 |
sandbox.fs.move(from, to) | sandbox.fs.move(src, dst) | ファイルまたはディレクトリを移動。 |
sandbox.fs.remove(path) | sandbox.fs.remove(path) | ファイルまたはディレクトリを削除。 |
sandbox.exposePort(port) | sandbox.expose_port(port) | ポートを公開し、url、hostname、アクセストークンを返す。 |
sandbox.getHost(port) | sandbox.get_host(port) | ポートを公開してホスト名を返す。リクエストには sandbox.accessToken が必要。 |
sandbox.unexpose(port) | sandbox.unexpose(port) | 公開したポートを削除。 |
sandbox.setTimeout(ms) | sandbox.set_timeout(ms) | 残りの有効期間を設定。最小 1000 ミリ秒。 |
sandbox.pause() / sandbox.resume() | sandbox.pause() / sandbox.resume() | 一時停止または再開をキューに入れ、すぐに戻る。 |
sandbox.waitForStatus(status) | sandbox.wait_for_status(status) | paused または running を待つ。一時停止に失敗した場合はエラーを投げる。 |
sandbox.fork({ count }) | sandbox.fork(count=...) | 実行中の sandbox を、メモリとプロセスを含めて 1~10 個コピー。 |
sandbox.snapshot(name, { poolSize }) | sandbox.snapshot(name, pool_size=...) | メモリと /workspace のファイルを非公開スナップショットとして保存。 |
Sandbox.waitForSnapshot(snapshotId) | Sandbox.wait_for_snapshot(snapshot_id) | スナップショットの準備完了を待つ。 |
Sandbox.restore(snapshotId) | Sandbox.restore(snapshot_id) | スナップショットから新しい sandbox を起動。 |
Sandbox.deleteSnapshot(snapshotId) | Sandbox.delete_snapshot(snapshot_id) | スナップショットを削除。そこから復元した sandbox は実行を続ける。 |
sandbox.kill() | sandbox.kill() | sandbox を停止し、ボリュームを切り離す。 |
コマンドを実行する
process.exec(Python では exec_)はコマンドを実行し、終了するまで待ちます。コマンドの実行中に出力を受け取るには、onStdout または onStderr(Python では on_stdout、on_stderr)を渡します。その場合も、呼び出しは最後に結果全体を返します。文字列の代わりに argv 配列を渡すとシェルを経由しません。信頼できないテキストを引数として渡すには、これが安全な方法です。
const result = await sandbox.process.exec('npm test', {
workdir: '/app',
envs: { NODE_ENV: 'test' },
timeoutMs: 120_000,
onStdout: (chunk) => process.stdout.write(chunk),
});
if (result.exitCode !== 0) throw new Error(result.stderr);
await sandbox.process.exec(['grep', '-rn', '--', userQuery, '/workspace']);result = sandbox.process.exec_(
"npm test",
workdir="/app",
envs={"NODE_ENV": "test"},
timeout_ms=120_000,
on_stdout=lambda chunk: print(chunk, end=""),
)
if result.exit_code != 0:
raise RuntimeError(result.stderr)
sandbox.process.exec_(["grep", "-rn", "--", user_query, "/workspace"])コマンドの結果には stdout、stderr、終了コードが含まれます。0 以外の終了コードは自分で確認する結果であり、リクエストの失敗は例外を投げます。タイムアウトは 1~600 秒です。process.exec は envs、workdir、user を受け付けます。user を渡さない限り、コマンドは root として実行されます。作成時の envs は、Firecracker の sandbox ではすべてのコマンドに渡されます。pod の sandbox では無視されるため、コマンドごとに渡してください。
ファイル
fs.write はテキストまたはバイトを書き込み、fs.read はテキストを読み取ります。バイナリファイルはバイトとして書き込み、fs.readBytes(Python では read_bytes)で読み戻します。絶対パスを使ってください。存在しないパスは NotFoundError を投げます。
await sandbox.fs.write('/app/data.csv', 'x,y\n1,2\n');
const text = await sandbox.fs.read('/app/data.csv');
const entries = await sandbox.fs.list('/app');
const png = await sandbox.fs.readBytes('/app/chart.png');sandbox.fs.write("/app/data.csv", "x,y\n1,2\n")
text = sandbox.fs.read("/app/data.csv")
entries = sandbox.fs.list("/app")
png = sandbox.fs.read_bytes("/app/chart.png")/workspace の Persistent Volumes 以外にあるファイルは、sandbox の停止後に消えます。
ポート
sandbox 内で 0.0.0.0 上のサーバーを起動し、そのポートを公開します。すべてのリクエストにはアクセストークンが必要です。X-Lizard-Access-Token ヘッダーで送るか、ブラウザーでは一度だけ ?lizard_token= として渡します。プレビュー URL を参照してください。
const { url, hostname, accessToken } = await sandbox.exposePort(3000);
console.log(url); // open in a browser; it carries the token
await fetch(`https://${hostname}/api`, { headers: { 'X-Lizard-Access-Token': accessToken } });
await sandbox.unexpose(3000);import httpx
exposed = sandbox.expose_port(3000)
print(exposed.url) # open in a browser; it carries the token
httpx.get(f"https://{exposed.hostname}/api", headers={"X-Lizard-Access-Token": exposed.access_token})
sandbox.unexpose(3000)一時停止、スナップショット、fork
これらの呼び出しは、ファイルだけでなくメモリと実行中のプロセスも保持します。それぞれで何が保持されるか、復元がどう課金されるか、何が失敗するかは クイックスタート で説明しています。
await sandbox.pause();
await sandbox.waitForStatus('paused');
await sandbox.resume();
await sandbox.waitForStatus('running');
const saved = await sandbox.snapshot('ready-env');
const copy = await Sandbox.restore(saved.id);
for (const f of await sandbox.fork({ count: 2 })) {
if (f.sandbox) await f.sandbox.process.exec('echo hi');
else console.warn('fork failed:', f.error);
}sandbox.pause()
sandbox.wait_for_status("paused")
sandbox.resume()
sandbox.wait_for_status("running")
saved = sandbox.snapshot("ready-env")
copy = Sandbox.restore(saved["id"])
for f in sandbox.fork(count=2):
if f.sandbox:
f.sandbox.process.exec_("echo hi")
else:
print("fork failed:", f.error)fork はコピーごとに 1 つのエントリを返します: 新しい sandbox、またはアカウントの sandbox 上限などのエラーです。各コピーは元の sandbox と同じように課金されます。
状態を保持してコードを実行する
CodeSandbox は interpreter テンプレートを起動し、runCode(Python では run_code)でコードを実行します。このテンプレートでは、Python はコンテキストごとに状態を保持する Jupyter カーネルで実行されるため、変数は呼び出し間で引き継がれ、結果に image/png のグラフを含めることができます。JavaScript と bash は、呼び出しごとに新しいプロセスとして実行されます。コードインタープリターを参照してください。
ボリューム
sandbox 間で /workspace を保持するには、Persistent Volumes を名前で接続します:
import { Sandbox, Volume } from '@lizard-build/sdk';
await Volume.getOrCreate('proj_123', 'agent-workdir', { sizeGb: 10 });
const sandbox = await Sandbox.create('base', { projectId: 'proj_123', volumeName: 'agent-workdir' });from lizard import Sandbox, Volume
Volume.get_or_create("proj_123", "agent-workdir", size_gb=10)
sandbox = Sandbox.create("base", project_id="proj_123", volume_name="agent-workdir")未対応の API
ファイル監視はまだ利用できません。sandbox.fork() は、ボリュームが接続されている場合は 409 を、pod として実行される sandbox では 501 を返します。Sandbox.connect は一時停止中や停止済みの sandbox を再開しません。一時停止中の sandbox には resume() を呼び出してください。SSH プロトコルでのアクセスはできません。lizard sandbox ssh は CLI の認証情報で対話型シェルを開きます。
エラー
API の失敗時には、以下のエラーが投げられます(Python では raise されます)。各エラーは HTTP ステータスと、API が送った場合は code を持ちます。
| エラー | 意味 |
|---|---|
PaymentRequiredError | HTTP 402: 何かを作成する前に、アカウントで Pro を開始するか請求書を支払う必要があります。url は開くべきページです。 |
AuthenticationError | HTTP 401 または 403: キーが無効か、アクセス権がありません。 |
NotFoundError | HTTP 404: sandbox、ファイル、スナップショットが存在しないか、期限切れです。 |
ConflictError | HTTP 409: ボリュームが接続された sandbox の fork など、状態の競合。 |
TimeoutError | HTTP 408 または 504。 |
LizardError | 未対応の操作を含む、その他の API の失敗。 |
同時に実行する sandbox が多すぎる場合や、起動が多すぎる場合は HTTP 429 が返ります。アカウントの上限 を参照してください。
HTTP API
SDK は https://lizard.build にある Lizard の REST API を呼び出します。API キーは Authorization: Bearer liz_... として、または X-API-Key ヘッダーで送ります。
| 呼び出し | リクエスト |
|---|---|
| 作成 | template、projectId、size、timeoutMs、envs、metadata、region、volumeName を指定して POST /api/sandboxes。sandboxId 付きで 201 を返します |
| 状態の取得 | GET /api/sandboxes/{id} |
| 一覧 | GET /api/sandboxes、または 1 つのプロジェクトについては GET /api/projects/{projectId}/sandboxes |
| コマンドの実行 | cmd、envs、workdir、user、timeoutMs を指定して POST /api/sandboxes/{id}/exec。stdout、stderr、exitCode を返します |
| 有効期間の変更 | timeoutMs を指定して POST /api/sandboxes/{id}/timeout |
| 一時停止または再開 | POST /api/sandboxes/{id}/pause、POST /api/sandboxes/{id}/resume |
| ポートの公開 | POST /api/sandboxes/{id}/expose/{port}。同じパスへの DELETE で削除します |
| 停止 | DELETE /api/sandboxes/{id} |
curl -X POST https://lizard.build/api/sandboxes \
-H "Authorization: Bearer $LIZARD_API_KEY" \
-H "Content-Type: application/json" \
-d '{"template": "base", "projectId": "proj_123", "timeoutMs": 300000}'直接の API は、timeoutMs を渡さない限り、期限なしで sandbox を作成します。
保存と課金
課金、送信トラフィック、停止後に何が残るかは、保存と課金 にまとめています。サイズと時間単価は 制限 にあります。
更新日