# Templates (https://tenki.cloud/docs/sandbox/templates)

> For the complete documentation index, see [llms.txt](https://tenki.cloud/llms.txt)

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](/docs/sandbox/concepts#templates) 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 [#build-and-use-a-template]

**TypeScript**
```typescript
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" });
```

**Python**
```python
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")
```

**Go**
```go
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"))
```

**CLI**
```bash
# 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](/docs/sandbox/volumes#workspace-id-lookup).

Template fields [#template-fields]

| Field          | Type                    | Notes                                                                 |
| -------------- | ----------------------- | --------------------------------------------------------------------- |
| `name`         | string, 1 to 64 chars   | Required.                                                             |
| `setup_script` | string                  | Required. Shell script run at build time to prepare the environment.  |
| `start_cmd`    | string                  | Optional. Runs when a session created from the template starts.       |
| `env`          | map of string to string | Optional environment variables.                                       |
| `cpu_cores`    | integer                 | Optional. Default vCPU (`1` to `16`); omit for the platform default.  |
| `memory_mb`    | integer                 | Optional. Default memory (`512` to `65536` MB); omit for the default. |
| `disk_size_gb` | integer                 | Optional. Root disk size (`5` to `100` GB); omit for the default.     |
| `project_id`   | UUID                    | Optional project scope.                                               |
| `tags`         | up to 20 strings        | Optional, for filtering.                                              |

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

Build lifecycle [#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 [#manage-templates]

**TypeScript**
```typescript
const templates = await sandbox.listTemplates();
const tpl = await sandbox.getTemplate(templateId);
await sandbox.deleteTemplate(templateId);
```

**Python**
```python
templates = client.templates.list()
tpl = client.templates.get(template_id)
client.templates.delete(template_id)
```

**Go**
```go
templates, err := client.ListTemplates(ctx)
tpl, err := client.GetTemplate(ctx, templateID)
err = client.DeleteTemplate(ctx, templateID)
```

**CLI**
```bash
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 [#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:

**TypeScript**
```typescript
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");
```

**Python**
```python
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")
```

**Go**
```go
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")
```

**CLI**
```bash
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 [#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](/docs/sandbox/sdk#errors) for the names in each language.
