Runtimes, snapshots, and cleanup
Build durable sandbox workflows with events, checkpoints, snapshots, and explicit retention.
Runtimes, snapshots, and cleanup
A raw sandbox is enough for one-off compute. Use a Sandbox Runtime when your product needs a durable workflow identity with status, events, checkpoints, wait-for-user state, source preservation, or promotion.
Create a durable runtime
The runtime handle resumes or recreates its sandbox as needed and provides discoverable files, commands, and ports helpers.
import { createOpenPondClient } from "openpond-sdk";
const apiKey = process.env.OPENPOND_API_KEY?.trim();
if (!apiKey) throw new Error("OPENPOND_API_KEY is required");
const openpond = createOpenPondClient({ apiKey });
let sandboxId: string | undefined;
let runtimeId: string | undefined;
try {
const created = await openpond.sandboxes.runtimes.create({
workflowMode: "attempt",
promotionPolicy: "manual",
metadata: { source: "docs-runtime-example" },
});
runtimeId = created.id;
const runtime = openpond.sandboxes.runtimes.handle(created.id, created);
const materialized = await runtime.createSandbox({
resources: { cpu: 2, memoryGb: 4, diskGb: 16 },
budget: { maxUsd: "0.25" },
quotas: {
maxSpendUsd: "0.25",
maxDurationSeconds: 900,
idleTimeoutSeconds: 300,
maxCommands: 30,
maxOpenPorts: 1,
maxSnapshots: 2,
},
});
sandboxId = materialized.sandbox.id;
await runtime.files.write("request.txt", "Review this change\n");
const result = await runtime.commands.run({
command: "wc -w request.txt",
timeoutSeconds: 30,
});
if (result.command.status !== "succeeded") {
throw new Error(`Runtime command failed: ${result.command.exitCode}`);
}
await runtime.checkpointHint({
reason: "input_reviewed",
artifactRefs: ["request.txt"],
});
await runtime.waitForUser({
reason: "approve_next_step",
summary: "The reviewed input is ready for approval.",
});
} finally {
if (sandboxId) {
await openpond.sandboxes.delete(sandboxId, { async: true });
}
if (runtimeId) {
const runtime = openpond.sandboxes.runtimes.handle(runtimeId);
await runtime.archive();
}
}checkpointHint, waitForUser, and keepAlive record workflow intent. They are useful lifecycle signals, not substitutes for application authorization. Promotion and source-preservation actions should still require an explicit product decision.
Snapshots and forks
Create a snapshot when a prepared filesystem is worth reusing. A snapshot can be validated, published as an approved template where supported, or forked into another sandbox. Keep snapshot creation bounded with maxSnapshots, name the purpose, and record who owns retention.
Use snapshots for reproducible dependency state or review checkpoints—not as an unbounded backup strategy. A fork is a new billable sandbox and needs its own cleanup.
Lifecycle decisions
| Action | Use it when | | --- | --- | | Stop | Work will resume soon and the sandbox should retain its identity. | | Archive | The workspace must be retained for later restoration or review. | | Delete | The workspace is finished and should not keep consuming resources. | | Runtime archive | The durable workflow is complete and should leave active queues and views. |
Inspect structured sandbox state after asynchronous lifecycle calls. For long-running applications, reconcile retained sandboxes and runtimes on startup instead of assuming the previous process completed cleanup.
Spend, receipts, and retention
Set both budget.maxUsd and quotas.maxSpendUsd, along with duration, idle, command, port, and snapshot limits. Use the SDK's pricing, cost, receipt, and log methods to show users what ran and what it cost without exposing credentials or raw private artifacts.
For every workflow, decide explicitly:
- who owns the runtime and sandbox;
- how long files, snapshots, and previews remain available;
- what event or user action deletes them;
- what must be preserved before deletion;
- how cleanup failures are retried and audited.
Return to the Sandbox SDK quickstart or review files, processes, and previews.