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

# Authoring

## Base image

Every template starts from a source environment. The SDK supports several entry points depending on how much control you need.

* `fromPythonImage(...)` / `from_python_image(...)` for a standard Python runtime
* `fromUbuntuImage(...)` / `from_ubuntu_image(...)` or `fromDebianImage(...)` / `from_debian_image(...)` for a standard Linux base
* `fromNodeImage(...)` / `from_node_image(...)` and `fromBunImage(...)` / `from_bun_image(...)` for language-specific bases
* `fromImage(...)` / `from_image(...)` for an arbitrary container image
* `fromDockerfile(...)` / `from_dockerfile(...)` when your Dockerfile is already the source of truth
* `fromBaseImage()` / `from_base_image()` to start from the platform default base
* `fromTemplate(...)` / `from_template(...)` to layer on top of another template

`fromPythonImage("3.12")` and `from_python_image("3.12")` are equivalent to starting from:

```dockerfile Dockerfile icon="docker" theme={"system"}
FROM python:3.12
```

## Private registries

If your base image lives in a private registry, pass credentials when defining the template source.

The JS and Python SDKs support:

* generic registry credentials with username and password
* AWS registry credentials
* GCP registry credentials
* Huawei Cloud registry credentials

Generic private registry example:

<CodeGroup>
  ```ts JavaScript & TypeScript icon="js" theme={"system"}
  import { Template } from "novita-sandbox"

  const template = Template().fromRegistry(
    "registry.example.com/team/myimage:latest",
    {
      username: process.env.REGISTRY_USERNAME,
      password: process.env.REGISTRY_PASSWORD,
    }
  )

  const build = await Template.build(template, "my-private-image-template")
  console.log(build.templateId)
  ```

  ```python Python icon="python" theme={"system"}
  import os

  from novita_sandbox.core import Template

  template = Template().from_registry(
      "registry.example.com/team/myimage:latest",
      username=os.environ.get("REGISTRY_USERNAME"),
      password=os.environ.get("REGISTRY_PASSWORD"),
  )

  build = Template.build(template, "my-private-image-template")
  print(build.template_id)
  ```
</CodeGroup>

## Defining template

The builder API lets you compose the final environment directly in code. Common definition steps include:

* `runCmd(...)` / `run_cmd(...)` to install packages or run provisioning commands
* `copy(...)` to include local files
* `makeDir(...)`, `remove(...)`, `rename(...)`, and `makeSymlink(...)` for filesystem shaping
* `setEnvs(...)` / `set_envs(...)` for environment variables
* `pipInstall(...)`, `npmInstall(...)`, `bunInstall(...)`, and `aptInstall(...)` for package setup
* `gitClone(...)` / `git_clone(...)` to bring code into the image

Example:

<CodeGroup>
  ```ts JavaScript & TypeScript icon="js" theme={"system"}
  import { Template } from "novita-sandbox"

  const template = Template()
    .fromPythonImage("3.12")
    .setWorkdir("/app")
    .setEnvs({
      APP_ENV: "production",
      PORT: "8000",
    })
    .runCmd("pip install fastapi uvicorn")
    .copy("app.py", "/app/app.py")
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox.core import Template

  template = (
      Template()
      .from_python_image("3.12")
      .set_workdir("/app")
      .set_envs(
          {
              "APP_ENV": "production",
              "PORT": "8000",
          }
      )
      .run_cmd("pip install fastapi uvicorn")
      .copy("app.py", "/app/app.py")
  )
  ```
</CodeGroup>

## Start & ready commands

Use a start command when the template should boot a long-running service during the build result, and use a ready command to define when that service is considered healthy.

This is useful for web apps, API servers, background workers, and any template that should already be initialized when a sandbox starts.

<CodeGroup>
  ```ts JavaScript & TypeScript icon="js" theme={"system"}
  import { Template } from "novita-sandbox"

  const template = Template()
    .fromPythonImage("3.12")
    .runCmd("pip install fastapi uvicorn")
    .copy("app.py", "/home/user/app.py")
    .setStartCmd(
      "uvicorn app:app --host 0.0.0.0 --port 8000",
      "python - <<'PY'\nimport urllib.request\nurllib.request.urlopen('http://127.0.0.1:8000', timeout=2)\nPY"
    )
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox.core import Template

  template = (
      Template()
      .from_python_image("3.12")
      .run_cmd("pip install fastapi uvicorn")
      .copy("app.py", "/home/user/app.py")
      .set_start_cmd(
          "uvicorn app:app --host 0.0.0.0 --port 8000",
          "python - <<'PY'\nimport urllib.request\nurllib.request.urlopen('http://127.0.0.1:8000', timeout=2)\nPY",
      )
  )
  ```
</CodeGroup>

You can also configure readiness separately with `setReadyCmd(...)` / `set_ready_cmd(...)`.
