> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ns.rocks/llms.txt
> Use this file to discover all available pages before exploring further.

# Defining template

> Compose template builder steps for packages, files, envs, users, and workdirs.

## Install packages

<CodeGroup>
  ```python Python SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  from nullspace import Template

  builder = (
      Template()
      .from_ubuntu_image("22.04")
      .apt_install(["git", "curl", "ripgrep"])
      .pip_install(["requests", "pytest"])
      .npm_install(["typescript"], g=True)
      .bun_install(["vite"], g=True)
  )
  ```

  ```typescript TypeScript SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  // Note: the TypeScript builder does not expose bunInstall yet.
  const builder = client.templates
    .builder()
    .fromUbuntuImage("22.04")
    .aptInstall(["git", "curl", "ripgrep"])
    .pipInstall(["requests", "pytest"])
    .npmInstall(["typescript"], { global: true });
  ```

  ```bash CLI theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  nullspace template build \
    --from-ubuntu-image 22.04 \
    --apt-install git,curl,ripgrep \
    --pip-install requests,pytest \
    --npm-install typescript --npm-global \
    --bun-install vite --bun-global \
    --name agent-template
  ```

  ```bash HTTP API theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  # Each builder step maps to an entry in the request "steps" array. Builds are
  # large/SSE — see the API reference for the full CreateTemplateRequest schema.
  curl -N -X POST "${NULLSPACE_API_URL}/v1/templates/build" \
    -H "Authorization: Bearer ${NULLSPACE_API_KEY}" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "agent-template",
      "base_image": "ubuntu:22.04",
      "steps": [
        {"action": "apt_install", "packages": ["git", "curl", "ripgrep"]},
        {"action": "pip_install", "packages": ["requests", "pytest"]},
        {"action": "npm_install", "packages": ["typescript"], "g": true},
        {"action": "bun_install", "packages": ["vite"], "g": true}
      ]
    }'
  ```
</CodeGroup>

Common base-image helpers include `from_ubuntu_image()`,
`from_python_image()`, `from_bun_image()`, `from_dockerfile()`, and
`from_dockerfile_content()`.

Package installers accept lists. For `npm_install()` and `bun_install()`,
`g=True` performs a global install.

## Files, repos, and commands

<CodeGroup>
  ```python Python SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  builder = (
      Template()
      .from_python_image("3.12")
      .copy("./app.py", "/workspace/app.py")
      .copy_items([("./pyproject.toml", "/workspace/pyproject.toml")])
      .git_clone("https://github.com/pypa/sampleproject.git", "/workspace/sampleproject")
      .run_cmd("python3 -m compileall /workspace")
  )
  ```

  ```typescript TypeScript SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  // Note: the TypeScript builder does not expose copyItems yet; use copy().
  const builder = client.templates
    .builder()
    .fromPythonImage("3.12")
    .copy("./app.py", "/workspace/app.py")
    .copy("./pyproject.toml", "/workspace/pyproject.toml")
    .gitClone(
      "https://github.com/pypa/sampleproject.git",
      "/workspace/sampleproject",
    )
    .runCmd("python3 -m compileall /workspace");
  ```

  ```bash CLI theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  nullspace template build \
    --from-python-image 3.12 \
    --copy-src ./app.py --copy-dst /workspace/app.py \
    --copy-src ./pyproject.toml --copy-dst /workspace/pyproject.toml \
    --git-clone https://github.com/pypa/sampleproject.git --git-path /workspace/sampleproject \
    --run-cmd "python3 -m compileall /workspace" \
    --name agent-template
  ```

  ```bash HTTP API theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  # COPY steps need an uploaded build_context, so the raw build body is large.
  # See the API reference for the full CreateTemplateRequest + build_context schema.
  ```
</CodeGroup>

See the [API reference](../api-reference) for the full template build request
and `build_context` upload schema.

Use `set_file_context()` when a build needs a local context directory for copy
steps. Use registry-auth helpers before pulling private images.

## Environment, user, and workdir

<CodeGroup>
  ```python Python SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  builder = (
      builder
      .set_build_envs({"PIP_INDEX_URL": "https://example.invalid/simple"})
      .set_runtime_envs({"APP_ENV": "production"})
      .set_workdir("/workspace")
      .set_user("user")
  )
  ```

  ```typescript TypeScript SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  // Note: the TypeScript builder does not expose setRuntimeEnvs yet.
  builder
    .setBuildEnvs({ PIP_INDEX_URL: "https://example.invalid/simple" })
    .setWorkdir("/workspace")
    .setUser("user");
  ```

  ```bash CLI theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  nullspace template build \
    --from-python-image 3.12 \
    --set-build-env PIP_INDEX_URL=https://example.invalid/simple \
    --set-runtime-env APP_ENV=production \
    --set-workdir /workspace \
    --set-user user \
    --name agent-template
  ```

  ```bash HTTP API theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  # build_envs is a top-level object; runtime defaults (envs, user, workdir) live
  # under runtime_config. Builds stream over SSE — see the API reference.
  curl -N -X POST "${NULLSPACE_API_URL}/v1/templates/build" \
    -H "Authorization: Bearer ${NULLSPACE_API_KEY}" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "agent-template",
      "base_image": "python:3.12",
      "build_envs": {"PIP_INDEX_URL": "https://example.invalid/simple"},
      "runtime_config": {
        "default_envs": {"APP_ENV": "production"},
        "default_workdir": "/workspace",
        "default_user": "user"
      }
    }'
  ```
</CodeGroup>

Build envs are visible only during build steps. Runtime envs are persisted into
machines launched from the template.

## File operations

<CodeGroup>
  ```python Python SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  builder = (
      builder
      .make_dir("/workspace/logs")
      .make_symlink("/workspace/app.py", "/usr/local/bin/app.py")
      .rename("/workspace/app.py", "/workspace/main.py")
      .remove("/tmp/cache", recursive=True, force=True)
  )
  ```

  ```typescript TypeScript SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  // Note: the TypeScript builder exposes makeDir; makeSymlink, rename, and
  // remove are not available yet — use the Python SDK, CLI, or HTTP API.
  builder.makeDir("/workspace/logs");
  ```

  ```bash CLI theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  nullspace template build \
    --from-python-image 3.12 \
    --make-dir /workspace/logs \
    --make-symlink-target /workspace/app.py --make-symlink-path /usr/local/bin/app.py \
    --rename-src /workspace/app.py --rename-dst /workspace/main.py \
    --remove /tmp/cache --remove-recursive --remove-force \
    --name agent-template
  ```

  ```bash HTTP API theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  # Each file operation is a "steps" entry. Builds stream over SSE — see the
  # API reference for the full CreateTemplateRequest schema.
  curl -N -X POST "${NULLSPACE_API_URL}/v1/templates/build" \
    -H "Authorization: Bearer ${NULLSPACE_API_KEY}" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "agent-template",
      "base_image": "python:3.12",
      "steps": [
        {"action": "make_dir", "path": "/workspace/logs"},
        {"action": "make_symlink", "target": "/workspace/app.py", "path": "/usr/local/bin/app.py"},
        {"action": "rename", "src": "/workspace/app.py", "dst": "/workspace/main.py"},
        {"action": "remove", "path": "/tmp/cache", "recursive": true, "force": true}
      ]
    }'
  ```
</CodeGroup>

## Render before build

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
print(builder.to_json())
print(builder.to_dockerfile())
```

Rendered templates are useful for review, CI diffs, and `nullspace template
render json|dockerfile` parity.

```bash theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
nullspace template render json --from-python-image 3.12 --apt-install git --name agent-template
nullspace template render dockerfile --from-python-image 3.12 --apt-install git --name agent-template
```

Build resource and cache options live on the build call:

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
build = Template.build(
    builder,
    name="agent-template",
    tags=["stable"],
    cpu_count=4,
    memory_mb=2048,
    skip_cache=True,
)
```

The same options are available on `Template.build_in_background()` and
`builder.to_json(...)`.

## Related

* [Base images](./base-images)
* [Build logs](./build-logs)
* [Template reference](../reference/cli)
