# Capsule files

A capsule: the recipe for a short-lived Linux sandbox. Which packages to install, which users to create, which file systems and secrets to mount and which commands to run when it starts. It ends when its commands finish (with `autoTerminate`), when it is stopped, or when it runs out of time.

What capsules are for, and how to use them: [Capsules](https://docs.maitento.com/concepts/capsules.md).

## Where the file goes

`capsules/`, or any sub-folder of it. The file name without `.mtr` is the capsule's name.

A resource's name is its file name without `.mtr` (an app's is its folder's name). Use letters, digits, `_`, `-` and `.` (but not `..`), at most 128 characters. Two files of the same kind may not have the same name, even in different sub-folders or with different capitals.

## Properties

Every property is optional.

### `template`

Optional. Text.

A base image name, recorded with the capsule. Every capsule runs on the same image today (with Python 3, Node.js 22, .NET 8, Java 17, git and build tools), so it does not change what runs.

```hcl
template = "ubuntu:22.04"
```

### `packages`

Optional. List of text.

Extra Debian packages to install with `apt` when the capsule starts, such as `["jq", "sqlite3"]`. Lowercase letters, digits, `+`, `-` and `.`; each named once.

```hcl
packages = [ "jq", "sqlite3" ]
```

### `users`

Optional. [List of blocks](#each-item-of-users).

Linux users to create. Commands run as the default user unless they say otherwise.

### `vfs`

Optional. [List of blocks](#each-item-of-vfs).

Virtual file systems to mount. Each one appears at `/mnt/<mountName>`.

### `secrets`

Optional. [List of blocks](#each-item-of-secrets).

Secrets to mount. Each one is written to the file `/mnt/secrets/<mountName>`, readable by the default user.

### `startup`

Optional. [List of blocks](#each-item-of-startup).

Commands to run, in order, when the capsule starts. Their output is not kept.

### `autoTerminate`

Optional. `true` or `false`. Default: `false`.

Stop the capsule as soon as its startup commands have finished.

```hcl
autoTerminate = true
```

### `maxDuration`

Optional. Duration, `"hh:mm:ss"`.

The longest the capsule may run, as `"hh:mm:ss"`, counted from when it starts. Ten minutes when it is not set. A capsule still starting up then fails; a ready one finishes, and the command it is running is stopped.

```hcl
maxDuration = "00:05:00"
```

## Each item of `users`

A Linux user the capsule creates: `{ name = "builder" sudoAs = ["deployer"] }`.

### `users` › `name`

**Required.** Text.

The user name: lowercase letters, digits, `_` and `-`, starting with a letter or `_`, at most 32 characters, and not `root`.

```hcl
name = "sandbox"
```

### `users` › `sudoAs`

Optional. List of text.

Other users of the capsule this user may run commands as, with `sudo`. Never `root`.

```hcl
sudoAs = [ "deployer" ]
```

## Each item of `vfs`

A virtual file system mounted in the capsule: `{ vfs = @ref("sales-data") mountName = "data" }`.

### `vfs` › `vfs`

**Required.** Reference to a virtual file system.

The virtual file system. Create it before you deploy.

Virtual file systems are not part of a project: create them in the portal, with the SDK or with `mt vfs-create` before you deploy.

```hcl
vfs = @ref("sales-data")
```

### `vfs` › `mountName`

**Required.** Text.

Where it appears: `/mnt/<mountName>`.

```hcl
mountName = "data"
```

## Each item of `secrets`

A secret written to a file in the capsule: `{ secret = @ref("deploy-key") mountName = "deploy-key" }`.

### `secrets` › `secret`

**Required.** Reference to a secret.

The secret. Create it before you deploy.

Secrets are not part of a project: create them in the portal, with the SDK or with `mt secret-create` before you deploy.

```hcl
secret = @ref("orders-api-key")
```

### `secrets` › `mountName`

**Required.** Text.

The file name: the secret's value is written to `/mnt/secrets/<mountName>`.

```hcl
mountName = "data"
```

## Each item of `startup`

A command the capsule runs when it starts: `{ command = "python3" arguments = ["report.py"] }`.

### `startup` › `command`

**Required.** Text.

The program to run, such as `"python3"` or `"bash"`.

```hcl
command = "python3"
```

### `startup` › `arguments`

Optional. List of text.

The program's arguments. Each is passed as one word exactly as given, so spaces and quotes inside an argument reach the program. To pipe or redirect, run `sh` with arguments `["-c", "<line>"]`.

```hcl
arguments = ["/mnt/data/summarise.py"]
```

### `startup` › `runAsUser`

Optional. Text.

The user to run the command as, one of the capsule's `users`. The default user when not set.

```hcl
runAsUser = "builder"
```

### `startup` › `maxDuration`

Optional. Duration, `"hh:mm:ss"`.

The longest the command may run, as `"hh:mm:ss"`. Five minutes when it is not set.

```hcl
maxDuration = "00:02:00"
```

### `startup` › `wait`

Optional. `true` or `false`. Default: `true`.

Wait for the command to finish before the next one starts. Set `false` to start it and move on.

```hcl
wait = true
```

## A complete example

From the [21-sandboxes](https://github.com/maitento/maitento/tree/main/examples/21-sandboxes) example project:

```hcl title="capsules/sales-report.mtr"
// A capsule is a short-lived Linux sandbox. This one mounts the sales-data file system,
// runs a Python script on the CSV in it, and stops when the script finishes.
autoTerminate = true
maxDuration = "00:05:00"

// The file system must exist before you deploy: create it and upload the data first.
vfs = [
  {
    vfs = @ref("sales-data")
    mountName = "data"
  }
]

startup = [
  {
    command = "python3"
    arguments = ["/mnt/data/summarise.py"]
    wait = true
    maxDuration = "00:02:00"
  }
]
```
