Templates

Define what a sandbox starts from, and build versions of it.

A template is what a sandbox starts from. Building it produces a version, and a version holds everything a sandbox needs: the image, the size it gets by default, and the environment inside it. A sandbox created from the template starts from one of those versions.

Set your org and project with tektona ctx before you begin.

Naming a template

A template reference carries a scope and a name:

ReferenceWhat it means
go-devA template in your current project
project/go-devThe same thing, written out
org/go-devA template your organization owns
tektona/sandbox-baseA template Tektona provides

Add :<tag> to pick a tag: go-dev:stable. No tag means the default tag.

The scope always comes from your CLI context. A manifest never carries an org or a project, so you can commit one and it works in every project.

An image, and nothing else

You have an image — one you built, or a public one — and you want a sandbox running it. That is two commands, and no file:

tektona template create go-dev --image ghcr.io/tektona-ai/sandbox-base:0.5.0 --default-cpu 4 --default-memory 8
tektona sandbox create go-dev

The first waits, and prints the build's steps and log as they arrive. It exits non-zero when the build fails. Its version takes the default tag, which is what the bare go-dev in the second command resolves.

build run creates the template too when it does not exist, so the command to rebuild from a newer image is the command you already know. It moves no tag on its own, whichever it is doing, so name one to promote what it builds:

tektona template build run go-dev --image ghcr.io/tektona-ai/sandbox-base:0.6.0 --tag default

Only create gives a tag without being asked, and only to the template it is creating. A build never moves a tag it was not given.

The flags cover this case. Everything past it — a bigger build machine, an environment, a pinned user — lives in a manifest.

The manifest

A manifest is the complete surface. init writes one to start from:

tektona template init go-dev
tektona template init go-dev --image ubuntu:24.04

That writes ./go-dev.template.tektona.yaml, named after the template, so a repository holds one file per template. Give it a path to write somewhere else, and --force to overwrite a file that is already there.

init takes the name alone, not a reference: a manifest carries no scope, so tektona template init org/go-dev is refused.

# yaml-language-server: $schema=https://schemas.tektona.ai/sandbox-template/v1.json
apiVersion: tektona.ai/v1
kind: SandboxTemplate

metadata:
  name: go-dev
  displayName: Go development

spec:
  build: # what the version is built from
    image: ghcr.io/tektona-ai/sandbox-base:0.5.0
    resources: # the size of the sandbox that runs the build
      cpu: 8
      memory: 16

  sandbox: # what a sandbox made from the version gets
    defaultResources:
      cpu: 4
      memory: 8
      disk: 20
    env:
      - name: NODE_ENV
        value: development
    user: dev
    workdir: /workspace

The first line points your editor at the schema. An editor that runs yaml-language-server then completes these keys and marks mistakes as you type.

One rule decides what an edit costs. metadata changes nothing about a sandbox, so it applies on its own. Everything under spec belongs to a version, and only a build mints one:

tektona template update -f go-dev.template.tektona.yaml   # applies metadata, builds nothing
tektona template build run -f go-dev.template.tektona.yaml    # applies metadata, then builds

A resize therefore costs a build, the same as a new base image does. The build names the image again, from the file or from --image, and a pull of an image the platform already has is fast.

build -f creates the template when it does not exist yet. update -f reads the same file and applies its metadata block only; it says so when the file carries a spec.

Commands

CommandWhat it does
tektona template init <name> [path]Write a template manifest file. --image writes the base image into it
tektona template create <template-ref>Create a template, and optionally build its first version. --image is what builds one
tektona template update <template-ref>Change a template's details. Builds nothing
tektona template build run <template-ref>Build a version, and wait for it
tektona template lsList the templates you can use, with the versions, tags, sandboxes and storage each holds
tektona template get <template-ref>Show one template: what it is called, what it holds and what it costs
tektona template version ls <template-ref>List a template's versions, newest first
tektona template version get <template-ref> <version-id>Show one version: what it was built from, what a sandbox made from it gets, and whether a create through it works
tektona template version archive <template-ref> <version-id>Refuse a create from one version. activate allows it again
tektona template version rm <template-ref> <version-id>Delete one version, and every tag pointing at it
tektona template version prune <template-ref>Delete every version of a template that no tag points at and no sandbox records
tektona template tag ls <template-ref>List a template's tags, with the version each points at
tektona template tag get <template-ref> <tag>Show one tag and the version under it, and whether a create through it works
tektona template tag set <template-ref> <tag> <version-id>Point a tag at a version, creating the tag when it does not exist
tektona template tag rm <template-ref> <tag>Delete a tag. The version it pointed at stays
tektona template archive <template-ref>Refuse a create from a template
tektona template activate <template-ref>Put it back
tektona template rm <template-ref>Delete a template, its versions, their tags and its builds. Asks first when it has build records; --yes skips. Refused while a sandbox uses it. Alias delete
tektona template build ls [<template-ref>]List builds in the current scope, narrowed to a template when you name one
tektona template build get <build-id>Show one build: what it built from, what it produced and how it ended
tektona template build logs <build-id>Print a build's steps and log. -f waits for one still running. --tail N prints only the last N lines, --head N only the first N, and --tail N -f follows from where the tail ended
tektona template build cancel <build-id>Cancel a running build. Aliases stop and abort

JSON output

ls, info and logs take -o json, and all three print what the API returned.

ls prints the templates as objects, not the summary the table shows. logs prints one JSON document per line while it follows a build — {"line": ...} for a log line, {"step": ...} when a step changes, and one {"build": ...} at the end. Read it a line at a time; the last line carries the version.

Flags

Every flag names the manifest block it writes, so there is nothing to remember about where a value lands. --image is the exception, and short because it is the one flag nearly every build passes.

FlagWrites
--default-cpu / --default-memory / --default-diskspec.sandbox.defaultResources
--sandbox-env / --sandbox-user / --sandbox-workdirspec.sandbox
-i, --imagespec.build.image
--build-cpu / --build-memory / --build-diskspec.build.resources
--runspec.build.steps — one command per flag, repeatable
--build-env / --build-user / --build-workdirspec.build
--build-egress-network-policy / --build-egress-proxy-profilespec.build
--display-name / --descriptionmetadata
--tagThe tag this build moves on success. Omitted, no tag moves
-f, --fileRead a manifest instead of flags

--sandbox-env and --build-env both take KEY=VAL and repeat. --sandbox-env reaches the sandbox; --build-env reaches the commands and nothing else.

user, workdir and env are keys of both blocks, and the block is the whole difference: under spec.build they apply to the commands, and under spec.sandbox to a sandbox made from the version. The flags carry the block, so --build-user and --sandbox-user can never be confused.

Pass no --build-user and the commands run as the image's own user, in its WORKDIR. Ubuntu and Alpine declare no user, so their commands run as root. An image that declares one needs --build-user root to install packages.

Every flag above writes a spec block, so create and build take them and update does not. update takes --display-name, --description and -f.

The flags cover the common case. Anything they do not reach lives in a manifest — a per-step user or workdir, and the shell the steps run through.

A manifest and the flags do not mix

With -f, the file owns every value it can carry — metadata and both spec blocks. Pass a flag that writes one of them as well and the command refuses it by name, rather than applying one input and dropping the other. Edit the file, or drop -f and pass every flag.

--image is the one exception, and it overrides the file: a base image is what varies between builds of one manifest. --tag and --detach are not part of a manifest, so they combine with -f freely.

tektona template build run --file go-dev.template.tektona.yaml --image ubuntu:22.04 --tag 22.04

Versions and tags

Every build produces a version, and a version never changes. A tag is a name that points at one, and a build moves the tag it names:

tektona template build run go-dev --tag stable
tektona template build run go-dev:stable   # the same thing
tektona sandbox create go-dev:stable

create reads a tag the same way, because it mints a version too. Both commands take --tag, and --tag wins when a reference names one as well.

A build with no --tag moves no tag. That is how you build an image, test it, and only then decide it is good. The version is reached by its id, which the build prints, and tektona template version ls lists:

tektona template build run go-dev                 # no tag moves
tektona template version ls go-dev --tagged=false   # the versions no tag points at
tektona sandbox create go-dev --template-version 01JABCDEF0123456789ABCDEFG

--tagged takes three states. Left out, version ls lists every version. --tagged lists the versions a tag points at, and --tagged=false lists the rest.

Once you decide a version is good, move the tag onto it. This runs no build:

A template can carry at most 500 tags, but tag set still moves an existing tag at this limit.

tektona template tag ls go-dev
tektona template tag set go-dev stable 01JABCDEF0123456789ABCDEFG
tektona template tag rm go-dev old

Name the template, then the tag. go-dev:stable is how you read a tag — sandbox create and build run resolve that form — and these commands write one, so the tag is an argument of its own.

The version may be an older one, which is how you roll back. Deleting a tag leaves its version in place, still reachable by its id.

Only build run and create take a tag in the reference, because both mint a version for the tag to land on. Every other command names a template, and refuses a reference carrying a tag rather than ignoring it.

Pinning a version fixes everything about it, the size included: a version holds its own spec.sandbox, so two versions of one template can have different defaults.

Sizes

spec.sandbox.defaultResources is what a sandbox made from the version gets. spec.build.resources is the size of the sandbox that runs the build. They are two different machines.

A create overrides the version's defaults one field at a time:

tektona sandbox create go-dev --cpu 8

That sandbox gets 8 cores and keeps the version's memory and disk.

What a sandbox started from

A sandbox records the reference it asked for and the version it got. tektona sandbox get prints all three:

  Template
    Reference            go-dev
    Tag                  stable
    Version              01JABCDEF0123456789ABCDEFG

The version is the one the create resolved. A tag that moves to a newer version later does not change it, so this still says what the sandbox runs.

A create that pinned a version id asked for no tag, and the tag reads as a dash. A create that named no tag asked for default, and the tag says so.

tektona sandbox ls --wide adds a TEMPLATE column with the same reference. -o json carries reference, name, scope, tag and version_id on both commands.

Archiving

Archiving refuses a create from a template. The create is refused, sandboxes already running on it keep running, and activate reverses it.

Your archived template stays in tektona template ls, with archived in its STATUS column, so you can find it and activate it. An archived tektona/* template leaves the listing: it is Tektona's, so you can neither activate it nor create from it. You still read it with tektona template get tektona/<name>.

tektona template archive go-dev
tektona template activate go-dev

Archive one version instead, and the template stays usable:

tektona template version archive go-dev 01JABCDEF0123456789ABCDEFG
tektona template version activate go-dev 01JABCDEF0123456789ABCDEFG

A tag pointing at the version does not stop the archive. The tag stays where it is and keeps naming the version. A sandbox create through that tag fails while the version is archived, and activating the version makes the tag work again.

To remove a version outright, tektona template version rm deletes it and every tag pointing at it. A sandbox that records the version blocks the delete, a paused or stopped one included, and the refusal counts them.

To clear a whole template at once, tektona template version prune removes every version of it that nothing uses:

tektona template version prune go-dev

A version is unused when no tag points at it and no sandbox records it. The command lists what it removes and asks first; --yes skips the question. It never removes a version a tag points at, and never one a sandbox records — a paused sandbox counts, one whose teardown has not finished counts, and so does every fork. It reports how many it removed, and how many it kept for each reason.

A create resolves the template before the version, so an archived template refuses a create through every version below it. Those versions still read active, so version ls, version get and tag get print the effective answer beside the state: refused: the template is archived names the template as the level to activate.

tektona template rm takes the whole template: its versions, their tags and its build records, a running build included. It cannot be undone. Archive the template instead to refuse new sandboxes reversibly.

The build records outlive the template. A build you know the id of still reads after its template is gone: tektona template build get <id> answers with the status, the error, the timings and the resources it ran on, and marks the template deleted. Its log reads too, for as long as the log itself is kept — seven days from when each line was written.

They are the part nothing else holds, so the delete still asks first when the template has any, and says how many:

$ tektona template rm go-dev
This deletes go-dev and its 12 build records. They cannot be recovered.
Type y to continue:

--yes skips the question, and is required when stdin is not a terminal, so a scripted delete says what it means instead of stopping on a prompt nobody can answer. A template with no build records is deleted by one command either way.

tektona template get reports the same number as stats.builds.total, so you can see it before you delete. It is not succeeded plus failed: a pending or a running build is in neither, and the delete takes those too.

The delete reports what it destroyed:

$ tektona template rm go-dev --yes
Deleted go-dev. 12 build records went with it, and cannot be recovered.

A build whose template is gone is reachable by its id and appears in no list: tektona template build ls reads within a template, and there is no longer one to read within. Keep the id if you want the record. Tektona removes a record whose template has been gone for 90 days.

Archiving frees no storage. tektona template get reports what an archived template still holds. The lifecycle rules restart each version's window from the archive and reclaim from there, and they never take the 3 newest versions.

A sandbox that records any version of the template refuses the delete, the way one sandbox refuses a version delete. The refusal names up to 5 sandboxes and says how many more there are.

There is no override. To delete a template in use, delete the sandboxes first, then delete the template. Archive the template meanwhile: it refuses new sandboxes and leaves the existing ones alone.

A paused sandbox counts, and so does one whose teardown has not finished. A fork counts too: a fork inherits the version its parent recorded, so "delete the sandboxes first" means the whole fork tree, not just the sandbox you created.

tektona sandbox ls --template <ref> does not list the same set — it shows only what you own and hides a sandbox whose delete has started. The refusal names the command that lists all of them:

tektona admin sandbox ls --template <ref> --include-deleted --all-projects

Those two flags are different axes: --include-deleted widens which states are listed, --all-projects widens which projects. A refusal on an org template needs both. The command needs project admin, and org owner for --all-projects. Without that role, tektona sandbox ls --template <ref> --include-deleted --scope all shows the ones you can see, which is fewer.

tektona template get and tektona template ls both report how many sandboxes a template holds, so you see the number before you run the delete. A platform template (tektona/...) shows a dash instead: its sandboxes span every organization, and no one deletes a platform template.

Choosing a base image

References resolve the way docker pull resolves them. A name with no tag and no digest means :latest, so fedora and fedora:latest are the same image. A @sha256: digest pins exact bytes.

Every build records the digest it resolved onto the version it mints, so the version is reproducible whichever form you write. A moving tag decides which bytes the next build picks up, not which bytes an existing version holds.

Common bases work, ubuntu:24.04 and python:3.13-bookworm among them. Your image does not have to ship an init: Tektona's init is the first process in the sandbox and runs your image's ENTRYPOINT or CMD.

An image with no shell builds too. The sandbox runs, serves its ports and takes a tektona sandbox cp; only tektona ssh has nothing to open a session with, and the build says so.

Start from a platform base. tektona template ls shows every template you can use, and tektona template version ls shows the image and the unpacked size of each version, so the tektona/* entries tell you what the platform currently offers:

tektona template ls
tektona template version ls tektona/sandbox-base

The SIZE column is the unpacked image. A sandbox disk smaller than that is refused, so it is the number a --disk has to clear.

tektona template ls gives each template a VERSIONS, TAGS and STORAGE column. VERSIONS counts the archived versions as well as the active ones, because an archived version still holds storage. STORAGE counts an image two of the template's versions share once, and it says what the template holds rather than what deleting it frees: two templates that pull the same base image share one copy and both report it. It is blank for a template whose images all predate the size the platform records now.

ghcr.io/tektona-ai/sandbox-base works, and is what tektona template init writes.

If you only want a sandbox and not a template of your own, create one from a platform template directly, with no build at all:

tektona sandbox create tektona/sandbox-base

What a build does

A build resolves the image reference, pulls it, and converts it. When the build names commands, it then starts a sandbox on that image, runs the commands in order, and saves the result as the version's image. spec.sandbox travels with the build and is recorded on the version it mints.

A build with no commands stops after the convert.

Cancelling a build

A build you no longer want is cancelled by its id:

tektona template build cancel 01BUILD

The command returns at once. Tektona then deletes the build sandbox, releases the builder and frees the base image, which takes seconds. The build reads cancelling while that happens, and cancelled when it is done.

A cancelled build is not a failed build. It publishes no version, it moves no tag, and tektona template build logs 01BUILD -f exits zero — so a build you cancel does not fail the job you cancelled it from. Ctrl-C ends the following only; the build goes on.

tektona template build get <build-id> says who cancelled a build, which is the question to ask when you find one cancelled that you did not cancel.

Cancelling a build needs the same access as starting one.

A build ends on its own after 90 minutes.

On this page