# How to Define an ActorTemplate with Specific Container Configurations in Agent Substrate

> Learn to define an ActorTemplate with specific container configurations using YAML manifests. Pin OCI images, mount volumes, and set security contexts for reproducible snapshots.

- Repository: [Agent Substrate/substrate](https://github.com/agent-substrate/substrate)
- Tags: how-to-guide
- Published: 2026-08-22

---

**You define an ActorTemplate by authoring a YAML manifest with an `ActorTemplateSpec` that declares containers with pinned OCI images, volume mounts, and security contexts, ensuring all images contain "@" for digest pinning to maintain reproducible snapshots.**

Agent Substrate uses a Kubernetes-style custom resource called **ActorTemplate** to declaratively describe the complete runtime layout of an actor. The specification is defined in [`pkg/api/v1alpha1/actortemplate_types.go`](https://github.com/agent-substrate/substrate/blob/main/pkg/api/v1alpha1/actortemplate_types.go) and enforced by the admission controller at [`cmd/atecontroller/internal/controllers/actortemplate_controller.go`](https://github.com/agent-substrate/substrate/blob/main/cmd/atecontroller/internal/controllers/actortemplate_controller.go). By configuring the `ActorTemplateSpec`, you control everything from container images and commands to persistent storage and Linux capabilities.

## Understanding the ActorTemplateSpec Structure

The `ActorTemplateSpec` serves as the top-level configuration object for defining actor runtime behavior. According to the source code in [`pkg/api/v1alpha1/actortemplate_types.go`](https://github.com/agent-substrate/substrate/blob/main/pkg/api/v1alpha1/actortemplate_types.go), the spec contains five primary fields:

- **containers** – An array of `Container` objects defining the workload containers
- **volumes** – A list of `Volume` objects for storage and configuration injection
- **snapshotsConfig** – Configuration for snapshot storage and resume behavior
- **sandboxClass** – The isolation runtime selector (`gvisor` or `microvm`)
- **resources** – Compute limits (`cpu` and `memory`) that drive sandbox sizing

The controller validates these fields using kubebuilder **XValidation** rules to ensure every volume is referenced by at least one container and that all naming conventions follow DNS-label patterns.

## Configuring Containers with Specific Images and Commands

Each container in the `containers` array is a `Container` type that supports precise runtime configuration. The controller enforces strict validation on several fields:

**Image requirements.** The `image` field must contain an "@" symbol to specify a pinned digest (e.g., `nginx@sha256:123abc...`). This ensures snapshots remain reproducible across resume operations. Tags without digests are rejected during admission.

**Entrypoint overrides.** Use `command` to replace the image's `ENTRYPOINT` and `args` to replace `CMD`. Variable expansion is **not** performed on these values.

**Environment variables.** The `env` field accepts an array of `EnvVar` objects, but only literal values are permitted. The system does not support config map or secret references in this version.

**Readiness probes.** The optional `readyz` field defines an HTTP probe (`ContainerReadyz`). The actor status remains non-Ready until this endpoint returns HTTP 200. Configure `httpGet.port`, `httpGet.path`, and `timeoutSeconds` to control probe behavior.

**Volume mounts.** Bind declared volumes into the container using `volumeMounts`, which requires a `name` matching a defined volume and a `mountPath` that must be a clean absolute Unix path.

**Security context.** The `securityContext` field accepts a `SecurityContext` object that manages Linux capabilities through the `capabilities` sub-field.

## Defining Volumes and Storage Sources

Volumes are declared in the `volumes` array as `Volume` objects, each requiring a unique `name` and exactly one `VolumeSource`. The source code defines four distinct volume types:

- **image** – Mounts a read-only OCI image as a volume
- **externalVolumeTemplate** – Dynamically provisions CSI-like storage with configurable capacity and `storageClassName`
- **systemInfo** – Projects actor metadata and trust bundles into the filesystem
- **durableDir** – Creates a persistent directory on the rootfs that survives resume operations and participates in snapshots

Validation rules require that every declared volume must be referenced by at least one container's `volumeMounts`, and volume names must follow DNS-label conventions.

## Security Contexts and Linux Capabilities

The `securityContext.capabilities` field controls privilege escalation through capability addition or removal. Key constraints implemented in the controller include:

- Capabilities must be specified **without** the `CAP_` prefix (use `NET_BIND_SERVICE`, not `CAP_NET_BIND_SERVICE`)
- The special value `ALL` is explicitly rejected for both `add` and `drop` operations
- Allowed capability strings follow strict pattern validation defined in the CRD

## SnapshotsConfig, SandboxClass, and Resource Limits

**SnapshotsConfig** determines where snapshots are stored via the `location` field (e.g., `s3://my-bucket/snapshots`) and controls `onResume` behavior, allowing selection between cold-boot or golden snapshot restores.

**SandboxClass** selects the isolation runtime. Valid values are `gvisor` or `microvm`. This choice impacts capability availability and snapshot support; for example, `Golden` snapshots are only supported when using the `microvm` sandbox class.

**Resources** accepts standard Kubernetes-style `limits` for `cpu` and `memory`. The system only respects `limits`; `requests` and `claims` fields are ignored. For `microvm` sandboxes, the memory limit must be at least **256 MiB** to accommodate the 128 MiB host reserve plus 128 MiB guest minimum.

## Complete ActorTemplate YAML Example

Below is a minimal yet complete manifest named `demo-template` that demonstrates multi-container configuration, external volume provisioning, durable directories, and capability management:

```yaml
apiVersion: substrate.io/v1alpha1
kind: ActorTemplate
metadata:
  name: demo-template
spec:
  sandboxClass: gvisor               # Run on gVisor workers

  snapshotsConfig:
    location: s3://my-bucket/snapshots
  containers:
  - name: nginx
    image: docker.io/library/nginx@sha256:123abc...   # pinned image

    command: ["/usr/sbin/nginx"]
    args: ["-g", "daemon off;"]
    env:
    - name: ENV
      value: production
    readyz:
      httpGet:
        port: 80
        path: /readyz
      timeoutSeconds: 10
    volumeMounts:
    - name: static-content
      mountPath: /usr/share/nginx/html
    securityContext:
      capabilities:
        add: ["NET_BIND_SERVICE"]
  - name: sidecar
    image: ghcr.io/example/sidecar@sha256:abcdef...
    args: ["--log-level=info"]
    volumeMounts:
    - name: static-content
      mountPath: /data
  volumes:
  - name: static-content
    externalVolumeTemplate:
      capacity: 1Gi
      storageClassName: standard
  - name: config-dir
    durableDir: {}

```

To expose actor metadata inside containers, add a system information volume:

```yaml
  volumes:
  - name: sysinfo
    systemInfo:
      dataSources:
      - actorMetadata:
          items:
          - field: name
            path: meta/name
          - field: uid
            path: meta/uid

```

This configuration creates files at `/sysinfo/meta/name` and `/sysinfo/meta/uid` inside any container mounting the `sysinfo` volume.

## Key Source Files for ActorTemplate Development

The following files in the `agent-substrate/substrate` repository contain the authoritative definitions and logic:

- [`pkg/api/v1alpha1/actortemplate_types.go`](https://github.com/agent-substrate/substrate/blob/main/pkg/api/v1alpha1/actortemplate_types.go) – Core CRD Go types including `ActorTemplateSpec`, `Container`, `Volume`, and `SecurityContext`
- [`cmd/atecontroller/internal/controllers/actortemplate_controller.go`](https://github.com/agent-substrate/substrate/blob/main/cmd/atecontroller/internal/controllers/actortemplate_controller.go) – Admission and reconciliation logic that enforces validation rules
- [`manifests/ate-install/generated/ate.dev_actortemplates.yaml`](https://github.com/agent-substrate/substrate/blob/main/manifests/ate-install/generated/ate.dev_actortemplates.yaml) – Example manifests showing production usage patterns
- [`cmd/ateapi/internal/controlapi/actor_template.go`](https://github.com/agent-substrate/substrate/blob/main/cmd/ateapi/internal/controlapi/actor_template.go) – Control-plane API implementation serving ActorTemplate objects to clients

## Summary

- **ActorTemplates** use the `ActorTemplateSpec` to declaratively define container runtime configurations in Agent Substrate.
- **Container images must use pinned digests** containing "@" to ensure reproducible snapshots and successful admission.
- **Volumes** support multiple backend types including external CSI-like storage, durable directories, and system information projection.
- **Security contexts** manage Linux capabilities without the `CAP_` prefix and reject the `ALL` meta-capability.
- **Validation rules** enforce DNS-label naming, absolute mount paths, volume reference completeness, and minimum memory limits (256 MiB) for microvm sandboxes.

## Frequently Asked Questions

### What image format is required for ActorTemplate containers?

Container images must specify a pinned digest using the "@" symbol, such as `docker.io/library/nginx@sha256:123abc...`. The admission controller rejects images that use only tags without digests to ensure snapshot reproducibility across actor resumes.

### How do I expose actor metadata to my containers?

Mount a `systemInfo` volume that contains an `actorMetadata` data source. The volume projects specific fields like `name` and `uid` as files into the container filesystem at your specified paths, accessible under the mount point you define in `volumeMounts`.

### Why does my microvm sandbox fail to create with 128 MiB memory limits?

The `microvm` sandbox class reserves 128 MiB for the host side and requires a minimum of 128 MiB for the guest VM, totaling 256 MiB. The controller enforces this minimum through XValidation rules, so you must set `resources.limits.memory` to at least `256Mi` when using the microvm sandbox class.

### Can I use environment variables from ConfigMaps or Secrets in ActorTemplates?

No, the current implementation only supports literal values in the `env` field of container specifications. As defined in [`pkg/api/v1alpha1/actortemplate_types.go`](https://github.com/agent-substrate/substrate/blob/main/pkg/api/v1alpha1/actortemplate_types.go), the `EnvVar` type accepts only direct value assignments, and the controller does not perform variable expansion from external sources.