Integrate the TypeScript SDK
DynoCap provides a native TypeScript/JavaScript SDK (@dynocap/sdk) for developers building AI agent harnesses, automated evaluators, or developer tool integrations.
The SDK communicates directly with the local user daemon over UNIX domain socket ~/.dynocap/daemon.sock (mode 0600).
Installation
Within the dynocap repository or a local workspace linking the package:
{
"dependencies": {
"@dynocap/sdk": "file:./sdk/typescript"
}
}npm installPattern 1: Managing Project Tasks (Task API)
The Task class provides the full project lifecycle: cloning a workspace, executing commands, streaming output, previewing diffs, and exporting results.
import { Task, SandboxError } from "@dynocap/sdk";
async function runAgent() {
try {
// 1. Start a task with an imported project directory
const task = await Task.start({
name: "pr-fixer",
projectPath: "./my-project",
runtimes: [{ name: "node", version: "24" }],
network: "none", // offline by default
ttlSeconds: 1800, // 30-minute sandbox lifetime
});
console.log(`Spawned task ${task.id} (name: ${task.name})`);
// 2. Execute a command in /workspace
const result = await task.exec("npm test", {
timeoutSeconds: 60,
});
console.log(`Exit code: ${result.exitCode}`);
console.log(`Stdout: ${result.stdout}`);
// 3. Inspect a real-time diff preview
const preview = await task.diff();
console.log(`Verified patch path: ${preview.patchPath}`);
// 4. Finish the task: exports result & destroys the VM
const finished = await task.finish();
console.log(`Final patch exported to: ${finished.patchPath}`);
console.log(`Result directory: ${finished.resultDirectory}`);
} catch (error) {
if (error instanceof SandboxError) {
console.error(`DynoCap error [${error.kind}]: ${error.message}`);
} else {
throw error;
}
}
}
runAgent();Pattern 2: Raw Ephemeral Sandboxes (Sandbox API)
If you only need an isolated minimal Linux execution environment without importing a project workspace or generating diffs, use Sandbox:
import { Sandbox } from "@dynocap/sdk";
async function executeInSandbox() {
// Boot raw sandbox
const sandbox = await Sandbox.create({
name: "eval-box",
cpus: 2,
memoryMB: 1024,
network: "none",
ttlSeconds: 300,
});
// Run command
const execResult = await sandbox.exec("uname -a && cat /etc/alpine-release", {
timeoutSeconds: 10,
});
console.log(execResult.stdout);
// Clean up
await sandbox.destroy();
}Re-attaching to Existing Tasks
Tasks can be re-opened by their friendly name or immutable ID across different processes:
import { Task } from "@dynocap/sdk";
// Open existing task by name
const task = await Task.open("pr-fixer", {
requireOffline: true, // throw if sandbox has network access enabled
});
// Run further commands
await task.exec("npm run build");Streaming Standard Input & Terminal Transcripts
The SDK allows piping standard input bytes and capturing combined terminal transcripts:
// Pipe stdin bytes to a guest process
const inputBytes = new TextEncoder().encode("console.log(process.version);\n");
const res = await task.exec("node", {
stdin: inputBytes,
});
// Run in a pseudo-terminal (PTY)
const ttyRes = await task.exec("npm test", {
terminal: { rows: 24, cols: 80 },
});
// ttyRes.stdout contains combined terminal transcript (including ANSI controls)
console.log(ttyRes.stdout);Listing and Housekeeping
Query managed sandboxes and purge expired tasks:
import { listManaged, removeManaged } from "@dynocap/sdk";
// List all active and retained tasks
const entries = await listManaged();
for (const entry of entries) {
console.log(
`${entry.name ?? entry.id}: phase=${entry.phase}, TTL=${entry.sandboxExpiresAtUnix}`
);
}
// Purge a completed task and remove retained logs/results
await removeManaged("pr-fixer", { purge: true });This page is also plain Markdown, for agents and for you.