CrowNest
TypeScript SDK

Code

Run interpreter-style code snippets, keep state in Code Contexts, stream Code Run events, and promote rich outputs with the TypeScript SDK.

client.code runs Python, JavaScript, or TypeScript snippets inside a live Sandbox. A SandboxHandle exposes the same helpers as sandbox.code.*, so most code can stay sandbox-scoped instead of passing the Sandbox id repeatedly.

Use Commands for top-level process records and shell commands. Use Code Runs for notebook-style snippets, stateful interpreter work, rich outputs, and streamed execution events. Code Runs are not durable resources; export files or promote outputs to Artifacts when you need persistence.

Default language

The TypeScript SDK defaults Code Contexts and Code Runs to python when you omit language. Pass javascript or typescript when you want those interpreters.

run

Run a snippet and wait for the result.

run(
  sandboxId: `sbx_${string}`,
  input: RunCodeInput,
): Promise<RunCodeResult>

RunCodeInput:

FieldTypeDefaultDescription
codestringrequiredSource to execute, capped at 256 KiB.
language"python" | "javascript" | "typescript""python"Interpreter language.
contextId`cctx_${string}`SDK-createdExisting Code Context to reuse.
cwdstring/workspaceWorking directory inside the Workspace.
timeoutMsnumber60000Code Run timeout in milliseconds, maximum 600000.
artifactPolicy"inline_only" | "promote"inline_onlyWhether artifact-capable rich outputs should be promoted to Artifacts.
idempotencyKeystringSDK-generatedIdempotency key with a 24-hour retry window for the completed Code Run.
main.ts
const result = await sandbox.code.run({
  code: `
total = sum([10, 20, 12])
print(f"total={total}")
total
`,
});

for (const chunk of result.stdout) process.stdout.write(chunk);
console.log(result.outputs);

RunCodeResult includes sandboxId, contextId, language, executionCount, stdout, stderr, outputs, optional truncation flags, optional error, and durationMs.

Code Contexts

A Code Context keeps language state inside one Sandbox. Use it when values, imports, or loaded data should persist across runs.

createContext(
  sandboxId: `sbx_${string}`,
  input?: CreateCodeContextInput,
): Promise<CodeContextRef>

listContexts(sandboxId: `sbx_${string}`): Promise<readonly CodeContextRef[]>

getContext(
  sandboxId: `sbx_${string}`,
  contextId: `cctx_${string}`,
): Promise<CodeContextRef>
stateful.ts
const context = await sandbox.code.createContext({ language: "python" });
const contexts = await sandbox.code.listContexts();
const sameContext = await sandbox.code.getContext(context.id);

await sandbox.code.run({
  contextId: context.id,
  code: "import math\nradius = 4",
});

const result = await sandbox.code.run({
  contextId: context.id,
  code: "print(math.pi * radius ** 2)",
});

console.log(result.stdout.join(""));

await sandbox.code.deleteContext(context.id);

CreateCodeContextInput accepts language, cwd, timeoutMs, and idempotencyKey. Context creation defaults to /workspace and a 30000 ms context timeout, with a maximum of 600000 ms. Deleting a context is best-effort against the provider, but CrowNest metadata is authoritative.

If you omit contextId from run, CrowNest lazily creates or reuses one default Code Context for the Sandbox and language. The result always returns the contextId that was used.

Rich outputs

Code Runs return outputs rather than forcing everything through stdout. Each output is one of:

KindDescription
inlineSmall text, markdown, JSON, data, chart, or LaTeX value in the response.
artifactPromoted output stored as an Artifact, with artifactId and content type.
rejectedOutput CrowNest could not inline or promote, with a stable rejection reason.

Use artifactPolicy: "promote" when code may produce images, HTML, SVG, or larger structured results that should survive after the Sandbox is gone. Promotion requires the artifact:create scope.

plot.ts
import { writeFile } from "node:fs/promises";

const result = await sandbox.code.run({
  artifactPolicy: "promote",
  code: `
import matplotlib.pyplot as plt

plt.figure()
plt.plot([1, 2, 3], [2, 5, 4])
plt.title("Weekly score")
plt.show()
`,
});

const image = result.outputs.find(
  (output) => output.kind === "artifact" && output.format === "png",
);

if (image?.kind === "artifact") {
  const bytes = await client.artifacts.download(image.artifactId);
  await writeFile("weekly-score.png", bytes);
}

Inline output is capped, and total inline output is capped across one Code Run. Large or unsafe outputs may be rejected with reasons such as output_too_large, requires_artifact_promotion, or unsafe_active_content.

runStream

Stream interpreter events as the Code Run executes.

runStream(
  sandboxId: `sbx_${string}`,
  input: RunCodeInput,
): AsyncIterable<CodeRunEvent>

CodeRunEvent:

EventShape
stdout{ type: "stdout", data: string }
stderr{ type: "stderr", data: string }
output{ type: "output", data: CodeOutput }
error{ type: "error", data: CodeExecutionError }
complete{ type: "complete", data: RunCodeResult }
stream.ts
let finalResult;

for await (const event of sandbox.code.runStream({
  code: `
import time
for idx in range(3):
    print(f"step {idx}")
    time.sleep(0.2)
`,
})) {
  if (event.type === "stdout") process.stdout.write(event.data);
  if (event.type === "stderr") process.stderr.write(event.data);
  if (event.type === "error") {
    console.error(event.data.message);
  }
  if (event.type === "complete") {
    finalResult = event.data;
  }
}

console.log(finalResult?.executionCount);

Stream replay is result-only in v1. Reusing a completed idempotency key emits a single complete event with the stored result.

Execution errors

Interpreter failures are part of the Code Run result, not SDK transport errors. A Python exception resolves normally with result.error, and may also appear as a streaming error event.

const result = await sandbox.code.run({ code: "1 / 0" });

if (result.error) {
  console.error(result.error.name);
  console.error(result.error.message);
  console.error(result.error.traceback?.join("\n"));
}

API-level failures still throw CrowNestApiError, for example forbidden, not_found, sandbox_destroyed, code_source_too_large, unsupported_code_language, or quota_exceeded.

JavaScript and TypeScript

Pass language when you do not want Python.

const js = await sandbox.code.run({
  language: "javascript",
  code: "console.log(JSON.stringify({ ok: true }))",
});

const ts = await sandbox.code.run({
  language: "typescript",
  code: "const answer: number = 42; console.log(answer)",
});

Code Contexts are language-specific. Keep separate contexts if you switch between Python, JavaScript, and TypeScript in the same Sandbox.

Next steps

On this page