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

# Templates

> Build and manage custom sandbox templates using the TypeScript Template class, TemplateBase fluent builder, and BuildInfo types.

```typescript theme={null}
import { Template, TemplateBase } from '@declaw/sdk';
import type { BuildInfo, TemplateBuildStatus, CopyItem, TemplateBuildOpts, GetBuildStatusOpts } from '@declaw/sdk';
```

Templates let you pre-build sandbox images with specific packages, files, and environment variables. Once built, reference a template by alias in `Sandbox.create({ template: 'my-alias' })`.

## TemplateBase

`TemplateBase` is a fluent class for defining template contents. Chain methods to build the definition, then pass it to `Template.build()`.

```typescript theme={null}
import { TemplateBase } from '@declaw/sdk';

const template = new TemplateBase()
  .fromBaseImage('ubuntu:22.04')
  .aptInstall('python3', 'python3-pip', 'nodejs', 'npm')
  .runCmd(['pip3', 'install', 'pandas', 'numpy'])
  .copy('./local_setup.sh', '/usr/local/bin/setup.sh', 0o755)
  .setEnvs({ PYTHONPATH: '/home/user', NODE_ENV: 'production' })
  .setStartCmd('sleep infinity');
```

### `.fromBaseImage(image?)`

Set the base Docker image.

<ParamField body="image" type="string" default="'ubuntu:22.04'">
  Docker image tag.
</ParamField>

**Returns** `this`

***

### `.aptInstall(...packages)`

Install apt packages.

```typescript theme={null}
template.aptInstall('git', 'curl', 'jq');
```

<ParamField body="packages" type="string[]" required>
  One or more package names to install via `apt-get install`.
</ParamField>

**Returns** `this`

***

### `.runCmd(cmds)`

Add a build-time command (equivalent to a Dockerfile `RUN`).

```typescript theme={null}
template.runCmd(['pip3', 'install', 'torch', '--index-url', 'https://download.pytorch.org/whl/cpu']);
```

<ParamField body="cmds" type="string[]" required>
  Command as an array of strings (executable + arguments).
</ParamField>

**Returns** `this`

***

### `.copy(src, dst, mode?)`

Copy a local file into the image at build time.

```typescript theme={null}
template.copy('./requirements.txt', '/app/requirements.txt');
template.copy('./startup.sh', '/usr/local/bin/startup.sh', 0o755);
```

<ParamField body="src" type="string" required>
  Local path to the file.
</ParamField>

<ParamField body="dst" type="string" required>
  Destination path inside the image.
</ParamField>

<ParamField body="mode" type="number">
  Unix file permission bits (e.g. `0o755` for executable).
</ParamField>

**Returns** `this`

***

### `.setEnvs(envs)`

Set environment variables baked into the image.

```typescript theme={null}
template.setEnvs({ APP_ENV: 'production', PORT: '8080' });
```

<ParamField body="envs" type="Record<string, string>" required>
  Key-value pairs to set as environment variables.
</ParamField>

**Returns** `this`

***

### `.setStartCmd(cmd)`

Set a command to run when the sandbox boots.

```typescript theme={null}
template.setStartCmd('python3 /app/server.py');
```

<ParamField body="cmd" type="string" required>
  Shell command to execute on sandbox start.
</ParamField>

**Returns** `this`

***

### `.toJSON()`

Serialize the template to a JSON-friendly object for the API.

**Returns** `Record<string, any>`

***

## Template

`Template` is a static class for submitting and querying template builds. All methods are async.

### `Template.build()`

Submit a template build and wait for completion.

```typescript theme={null}
import { Template, TemplateBase } from '@declaw/sdk';

const template = new TemplateBase()
  .aptInstall('python3-pip')
  .runCmd(['pip3', 'install', 'pandas']);

const info: BuildInfo = await Template.build(template, 'data-analysis', {
  cpuCount: 2,
  memoryMb: 2048,
  onBuildLogs: (log) => console.log(log),
  apiKey: 'your-api-key',
  domain: '104.198.24.180:8080',
});

console.log('Template ID:', info.templateId);
```

<ParamField body="template" type="TemplateBase" required>
  The template definition to build.
</ParamField>

<ParamField body="alias" type="string" required>
  Human-readable name used as `template` in `Sandbox.create()`.
</ParamField>

<ParamField body="opts" type="TemplateBuildOpts">
  Optional build options.
</ParamField>

### `TemplateBuildOpts`

<ParamField body="cpuCount" type="number">
  Number of CPUs for the build worker.
</ParamField>

<ParamField body="memoryMb" type="number">
  Memory in MB for the build worker.
</ParamField>

<ParamField body="onBuildLogs" type="(log: string) => void">
  Callback invoked for each log line during the build.
</ParamField>

<ParamField body="apiKey" type="string">
  API key override.
</ParamField>

<ParamField body="domain" type="string">
  Domain override.
</ParamField>

<ParamField body="requestTimeout" type="number">
  Per-request HTTP timeout in milliseconds.
</ParamField>

**Returns** `Promise<BuildInfo>`

***

### `Template.buildInBackground()`

Submit a template build and return immediately without waiting.

```typescript theme={null}
const info = await Template.buildInBackground(template, 'my-template', {
  apiKey: 'your-api-key',
  domain: '104.198.24.180:8080',
});
console.log('Build started:', info.buildId);
```

Parameters are the same as `Template.build()` except `onBuildLogs` is excluded.

**Returns** `Promise<BuildInfo>`

***

### `Template.getBuildStatus()`

Poll the status of a background build.

```typescript theme={null}
const status = await Template.getBuildStatus('build-id', {
  apiKey: 'your-api-key',
  domain: '104.198.24.180:8080',
});
console.log(status.status);       // "pending" | "running" | "succeeded" | "failed"
console.log(status.logs.at(-1));  // latest log line
```

<ParamField body="buildId" type="string" required>
  Build ID from a previous `build()` or `buildInBackground()` call. Must be
  alphanumeric with hyphens/underscores.
</ParamField>

<ParamField body="opts" type="GetBuildStatusOpts">
  Optional: `apiKey`, `domain`, `requestTimeout`.
</ParamField>

**Returns** `Promise<TemplateBuildStatus>`

***

## Data models

### `BuildInfo`

```typescript theme={null}
interface BuildInfo {
  buildId: string;
  status: string;
  templateId?: string;  // Set once build succeeds
}
```

### `TemplateBuildStatus`

```typescript theme={null}
interface TemplateBuildStatus {
  buildId: string;
  status: string;      // "pending" | "running" | "succeeded" | "failed"
  logs: string[];      // Accumulated build log lines
}
```

### `CopyItem`

```typescript theme={null}
interface CopyItem {
  src: string;
  dst: string;
  mode?: number;
}
```

### `GetBuildStatusOpts`

```typescript theme={null}
interface GetBuildStatusOpts {
  apiKey?: string;
  domain?: string;
  requestTimeout?: number;
}
```

***

## Polling a background build

```typescript theme={null}
import { Template, TemplateBase } from '@declaw/sdk';

const template = new TemplateBase()
  .aptInstall('nodejs', 'npm')
  .runCmd(['npm', 'install', '-g', 'typescript']);

const info = await Template.buildInBackground(template, 'node-ts', {
  apiKey: 'your-api-key',
  domain: '104.198.24.180:8080',
});

let status = await Template.getBuildStatus(info.buildId, {
  apiKey: 'your-api-key',
  domain: '104.198.24.180:8080',
});

while (status.status === 'pending' || status.status === 'running') {
  await new Promise((r) => setTimeout(r, 3000));
  status = await Template.getBuildStatus(info.buildId, {
    apiKey: 'your-api-key',
    domain: '104.198.24.180:8080',
  });
  console.log(`Build ${status.status}: ${status.logs.at(-1) ?? ''}`);
}

if (status.status !== 'succeeded') {
  throw new Error('Template build failed');
}
```

## Using a template

```typescript theme={null}
import { Sandbox } from '@declaw/sdk';

const sbx = await Sandbox.create({
  template: 'data-analysis',  // alias set during build
  apiKey: 'your-api-key',
  domain: '104.198.24.180:8080',
});

// pandas is already installed
const result = await sbx.commands.run(
  'python3 -c "import pandas; print(pandas.__version__)"',
);
console.log(result.stdout);
await sbx.kill();
```
