Sandbox

Templates

Define, build, and publish reusable Tenki Sandbox templates, then create sessions from a published registry image reference.

A template is a reusable definition of a prepared environment. Instead of installing the same tools at the start of every session, you define the environment once, build it, and publish it, so every session created from it starts in that same known state. See Concepts for how templates relate to snapshots.

Working with a template is four steps:

  1. Define the template: a setup script, an optional start command, environment variables, and default resources.
  2. Build it. Tenki runs the setup script and captures the result as a snapshot. Builds are versioned.
  3. Publish it to your workspace registry, which gives it a reference like myworkspace/my-node-env:latest.
  4. Create sessions from that reference.

Build and use a template

import { TenkiSandbox } from "@tenkicloud/sandbox";

const sandbox = new TenkiSandbox();

// 1. Define the template
const tpl = await sandbox.createTemplate({
  name: "my-node-env",
  setupScript: "curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -y nodejs",
  startCmd: "node --version",
  env: { NODE_ENV: "production" },
});

// 2. Build it and wait until it is READY
const build = await sandbox.buildTemplate(tpl.id);
await sandbox.waitForTemplateBuild(build.id);

// 3. Publish it to the registry (workspace + name + tag form the reference)
await sandbox.publishRegistryImage({
  workspaceId: "ws-123",
  name: "my-node-env",
  fromTemplateId: tpl.id,
  tag: "latest",
  visibility: "private",
});

// 4. Create a session from the published reference
const session = await sandbox.createAndWait({ image: "myworkspace/my-node-env:latest" });
from tenki_sandbox import Client

client = Client()

# 1. Define the template
tpl = client.templates.create(
    name="my-node-env",
    setup_script="curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -y nodejs",
    start_cmd="node --version",
    env={"NODE_ENV": "production"},
)

# 2. Build it and wait until it is READY
build = client.templates.build(tpl.id)
client.templates.wait_build(build.id)

# 3. Publish it to the registry (workspace + name + tag form the reference)
client.registry.publish(
    workspace_id="ws-123",
    name="my-node-env",
    kind="template",
    source_template_id=tpl.id,
    tag="latest",
    visibility="private",
)

# 4. Create a session from the published reference
session = client.create(image="myworkspace/my-node-env:latest")
import tenkisandbox "github.com/TenkiCloud/tenki-sdk-go/sandbox"

client, err := tenkisandbox.New()

// 1. Define the template
tpl, err := client.CreateTemplate(
  ctx,
  tenkisandbox.WithTemplateName("my-node-env"),
  tenkisandbox.WithSetupScript("curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -y nodejs"),
  tenkisandbox.WithStartCmd("node --version"),
  tenkisandbox.WithEnvs(map[string]string{"NODE_ENV": "production"}),
)

// 2. Build it and wait until it is READY
build, err := client.BuildTemplate(ctx, tpl.ID)
_, err = client.WaitForTemplateBuild(ctx, build.ID)

// 3. Publish it to the registry (workspace + name + tag form the reference)
_, err = client.PublishRegistryImage(
  ctx,
  tenkisandbox.WithRegistryWorkspaceName("ws-123", "my-node-env"),
  tenkisandbox.WithRegistryTemplate(tpl.ID),
  tenkisandbox.WithRegistryTag("latest"),
  tenkisandbox.WithRegistryVisibility(tenkisandbox.RegistryVisibilityPrivate),
)

// 4. Create a session from the published reference
session, err := client.Create(ctx, tenkisandbox.WithImage("myworkspace/my-node-env:latest"))
# 1. Define the template (only --name and --setup-script are required)
tenki sandbox template create \
  --name my-node-env \
  --setup-script 'curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -y nodejs' \
  --start-cmd 'node --version' \
  --env NODE_ENV=production

# 2. Build it and wait until it is READY
tenki sandbox template build <template-id> --wait

# 3. Publish it to the workspace registry
tenki sandbox registry publish \
  --image myworkspace/my-node-env:latest \
  --from-template <template-id> \
  --visibility private

# 4. Create a session from the published reference
tenki sandbox create --image myworkspace/my-node-env:latest

The session comes up in the prepared state with no install step. Referencing a template does not trigger a build: publish a READY build first, then create sessions from it.

Templates and registry artifacts are workspace-scoped. template create takes an optional workspace; publishing takes your workspace ID, an artifact name, and a tag, which form the reference <workspace>/<artifact>[:tag] (like myworkspace/my-node-env:latest) that create --image and the registry read commands accept. Look up your workspace with the identity call; see workspace lookup.

Template fields

FieldTypeNotes
namestring, 1 to 64 charsRequired.
setup_scriptstringRequired. Shell script run at build time to prepare the environment.
start_cmdstringOptional. Runs when a session created from the template starts.
envmap of string to stringOptional environment variables.
cpu_coresintegerOptional. Default vCPU (1 to 16); omit for the platform default.
memory_mbintegerOptional. Default memory (512 to 65536 MB); omit for the default.
disk_size_gbintegerOptional. Root disk size (5 to 100 GB); omit for the default.
project_idUUIDOptional project scope.
tagsup to 20 stringsOptional, for filtering.

Each SDK uses its native casing: TypeScript setupScript, startCmd, cpuCores, memoryMb; Go WithSetupScript, WithStartCmd, WithTemplateResources, WithTemplateDiskSizeGB.

Build lifecycle

Building does the slow work once. Tenki starts a sandbox, runs your setup script to install dependencies and copy files, and captures the result as a snapshot. Every session you create from the published template starts from that snapshot, so it skips the download and install and comes up ready to use. A start command, if you set one, runs on each new session rather than during the build.

A build moves through PENDING, BUILDING, READY, and FAILED. Wait for READY before publishing from it.

  • CLI: template build <id> --wait blocks until READY (default 15 minutes; set --wait-timeout). Add --wait-durable to also wait for the snapshot upload to finish.
  • TypeScript: waitForTemplateBuild(buildId).
  • Python: client.templates.wait_build(build_id, timeout=600).
  • Go: WaitForTemplateBuild(ctx, buildID).

Templates are mutable and versioned. Edit the definition in place, and each build creates a new version; the template's latest_build tracks the newest.

Manage templates

const templates = await sandbox.listTemplates();
const tpl = await sandbox.getTemplate(templateId);
await sandbox.deleteTemplate(templateId);
templates = client.templates.list()
tpl = client.templates.get(template_id)
client.templates.delete(template_id)
templates, err := client.ListTemplates(ctx)
tpl, err := client.GetTemplate(ctx, templateID)
err = client.DeleteTemplate(ctx, templateID)
tenki sandbox template list
tenki sandbox template get <template-id>
tenki sandbox template update <template-id> --start-cmd 'node server.js'
tenki sandbox template delete <template-id>

To edit a template in place, use template update in the CLI, or updateTemplate (TypeScript) and UpdateTemplate (Go). The Python SDK has no update; edit through the CLI or another SDK.

Publish and share

The registry is a per-workspace namespace of publishable artifacts, either templates or snapshots. Each artifact has a name, versioned tags, and a visibility: private (the default), public, or shared with specific workspaces. You reference an artifact as <workspace>/<artifact>[:tag].

Publishing is shown above. To browse and resolve artifacts:

const images = await sandbox.listRegistryImages({ workspace: "myworkspace", kind: "template" });
const image = await sandbox.getRegistryImage("myworkspace/my-node-env:latest");
const resolved = await sandbox.resolveRegistryRef("myworkspace/my-node-env:latest");
images = client.registry.list("myworkspace", kind="template")
image = client.registry.get("myworkspace/my-node-env:latest")
resolved = client.registry.resolve("myworkspace/my-node-env:latest")
images, err := client.ListRegistryImages(
  ctx,
  tenkisandbox.WithRegistryWorkspace("myworkspace"),
  tenkisandbox.WithRegistryKind(tenkisandbox.RegistryImageKindTemplate),
)
image, err := client.GetRegistryImage(ctx, "myworkspace/my-node-env:latest")
resolved, err := client.ResolveRegistryRef(ctx, "myworkspace/my-node-env:latest")
tenki sandbox registry list --workspace myworkspace --kind template
tenki sandbox registry get myworkspace/my-node-env:latest
tenki sandbox registry resolve myworkspace/my-node-env:latest

To share an artifact across workspaces, publish it with shared visibility and grant access with tenki sandbox registry share --target-workspace <workspace-id>.

Errors

Template and registry calls can fail when an ID or reference is unknown, a build fails, or a name collides. Every SDK surfaces these as typed errors or exceptions; see the SDK reference for the names in each language.

LinkedIn