CrowNest
Quickstart

TypeScript SDK quickstart

Create a sandbox, run a command, work with files, export an artifact, and expose a preview with the @crownest/sdk package.

This quickstart walks you through the full sandbox lifecycle with the TypeScript SDK: create a sandbox, run a command, write and read a file, export an artifact, expose a preview, and clean up. By the end you have a complete script you can drop into your own project.

Prerequisites

You need two things before you start.

[!WARNING] The raw API key is shown once, at creation time. Copy it immediately and store it somewhere safe — you can't view it again later.

Set up

Follow these steps to install the SDK and authenticate.

  1. Install the package.

    Terminal
    pnpm add @crownest/sdk

    npm and yarn work too: npm install @crownest/sdk or yarn add @crownest/sdk.

  2. Export your API key. The client reads CROWNEST_API_KEY from the environment when you don't pass apiKey explicitly; if both are missing, creating the client throws.

    Terminal
    export CROWNEST_API_KEY="cn_live_..."
  3. Create a client.

    main.ts
    import { createCrowNestClient } from "@crownest/sdk";
    
    const client = createCrowNestClient();

    You can also pass options: createCrowNestClient({ apiKey, baseUrl, fetch }). The baseUrl defaults to https://api.crownest.dev.

Walk through the lifecycle

Each step below builds on the previous one inside the same script.

  1. Create a sandbox. create returns a SandboxHandle — the sandbox resource plus bound helpers (sandbox.commands, sandbox.files, sandbox.artifacts, sandbox.previews, and sandbox.kill()), so you don't repeat the sandbox ID on every call.

    const sandbox = await client.sandboxes.create({ template: "python" });

    Templates available today are base, node, python, and python-node. You can also set ttlMs to request a lifetime and metadata to attach small string labels — see Sandboxes.

  2. Run a command. run waits for the process to exit and returns the full command record, including exitCode, stdout, and stderr.

    const result = await sandbox.commands.run("python -c 'print(40 + 2)'");
    console.log(result.exitCode, result.stdout);

    [!IMPORTANT] A non-zero exit code does not throw. The command completed; your code inside it failed. Always check result.exitCode when the outcome matters. CrowNestApiError is reserved for API-level failures.

  3. Write and read a file. All file paths are inside /workspace, the sandbox's working filesystem area.

    await sandbox.files.write("notes.txt", "hello from crownest");
    const content = await sandbox.files.read("notes.txt");
    console.log(content);

    [!NOTE] File APIs are confined to /workspace. Paths that resolve outside it, including through symlinks, are rejected with the path_outside_workspace error code.

  4. Export an artifact. The workspace disappears with the sandbox, so copy anything you want to keep to durable storage with an explicit export.

    const artifact = await sandbox.artifacts.create({ path: "notes.txt" });
    console.log(artifact.id);

    You can download it later — even after the sandbox is gone — with client.artifacts.download(artifact.id), which returns a Uint8Array.

  5. Expose a preview. When your sandbox hosts an HTTP service, create a preview to get an authenticated URL like https://p-a1b2c3.preview.crownest.dev.

    await sandbox.commands.start("python -m http.server 8000");
    const preview = await sandbox.previews.create({ port: 8000 });
    console.log(preview.url);

    start launches the server without waiting for it to exit. Previews require authentication in v1; see Previews.

  6. Kill the sandbox. This stops billing and releases the environment. Sandboxes also expire automatically at their TTL.

    await sandbox.kill();

Handle errors

API failures throw CrowNestApiError, which carries the HTTP status, a stable machine-readable code, a message, and optional details.

import { createCrowNestClient, CrowNestApiError } from "@crownest/sdk";

const client = createCrowNestClient();

try {
  await client.sandboxes.get("sbx_does_not_exist");
} catch (error) {
  if (error instanceof CrowNestApiError) {
    console.error(error.status, error.code, error.message, error.details);
  } else {
    throw error;
  }
}

See the error reference for the full list of codes.

Complete script

The end-to-end version of the steps above.

main.ts
import { createCrowNestClient } from "@crownest/sdk";

const client = createCrowNestClient();

const sandbox = await client.sandboxes.create({ template: "python" });

const result = await sandbox.commands.run("python -c 'print(40 + 2)'");
console.log(result.exitCode, result.stdout);

await sandbox.files.write("notes.txt", "hello from crownest");
const content = await sandbox.files.read("notes.txt");
console.log(content);

const artifact = await sandbox.artifacts.create({ path: "notes.txt" });
console.log("artifact:", artifact.id);

await sandbox.commands.start("python -m http.server 8000");
const preview = await sandbox.previews.create({ port: 8000 });
console.log("preview:", preview.url);

await sandbox.kill();

Next steps

On this page