Compare commits

..

3 Commits

Author SHA1 Message Date
Ben Potter f80f36d674 feat: remove agent metadata for incus-nixos 2026-06-04 09:53:49 -05:00
Ben Potter d1d2d5b433 feat(bpmct/templates): add incus-vm and incus-nixos templates (#910)
## Description

Adds two new templates under `registry/bpmct` for running workspaces on
[Incus](https://linuxcontainers.org/incus/) (the open-source LXD fork).

### `incus-vm`

Provisions a full KVM virtual machine on a remote Incus host using
cloud-init. This is a VM variant of the existing `coder/incus` system
container template.

Key differences from `coder/incus`:
- Launches a **virtual machine** (`type = "virtual-machine"`) rather
than a system container
- Supports **remote Incus hosts** via `incus remote add` — the Coder
provisioner does not need to be co-located with the Incus host
- `arch` parameter (`amd64` / `arm64`) threads through the agent, image
fetch, and Incus architecture hint — so the same template works on both
x86-64 and aarch64 hosts
- Token rotation handled on every workspace start via a `null_resource`
provisioner (necessary since cloud-init only runs once on first boot)

### `incus-nixos`

Provisions a NixOS virtual machine on a remote Incus host. NixOS
requires a different provisioning approach from the cloud-init-based
`incus-vm` template.

Key design points:
- Uses Incus's official NixOS images (`nixos/<channel>`)
- Provisions entirely via `nixos-rebuild switch` — no cloud-init
- Writes `/etc/nixos/coder.nix` and `/etc/nixos/configuration.nix` via
`incus exec` on first boot
- Idempotent: subsequent starts skip the rebuild and just refresh the
agent token
- `nixos_channel` is a Terraform `variable` (admin sets at push time);
no user-facing image picker since the whole point of the template is
NixOS

## Type of Change

- [ ] New module
- [x] New template
- [ ] Bug fix
- [ ] Feature/enhancement
- [ ] Documentation
- [ ] Other

## Template Information

**Paths:**
- `registry/bpmct/templates/incus-vm`
- `registry/bpmct/templates/incus-nixos`

## Testing & Validation

- [x] Tests pass (`bun test`)
- [x] Code formatted (`bun fmt`)
- [x] Changes tested locally (both templates deployed and workspaces
verified healthy on aarch64 Raspberry Pi provisioners)

## Related Issues

None

## Video

https://www.loom.com/share/f009972a51af452dbbe9eda9f9760d3e
2026-06-04 09:44:37 -05:00
dependabot[bot] 358ca6804b chore(deps): bump crate-ci/typos from 1.46.3 to 1.47.0 in the github-actions group (#906)
Signed-off-by: dependabot[bot] <support@github.com>
2026-06-02 13:19:02 +05:00
6 changed files with 764 additions and 2 deletions
+1 -1
View File
@@ -93,7 +93,7 @@ jobs:
- name: Validate formatting
run: bun fmt:ci
- name: Check for typos
uses: crate-ci/typos@7b04f660f4ee4f048d18fd341887cf28dfbedfe2 # v1.46.3
uses: crate-ci/typos@f8a58b6b53f2279f71eb605f03a4ae4d10608f45 # v1.47.0
with:
config: .github/typos.toml
validate-readme-files:
+1 -1
View File
@@ -8,4 +8,4 @@ status: community
# Ben Potter
Tinkerer and Product Manager at Coder. Building modules to make dev environments better.
Tinkerer and Product Manager at Coder.
@@ -0,0 +1,75 @@
---
display_name: Incus NixOS VM
description: Run a NixOS virtual machine on a local Incus host
icon: ../../../../.icons/lxc.svg
verified: false
tags: [local, incus, vm, nixos]
---
# Incus NixOS VM
Provision a NixOS KVM virtual machine on an [Incus](https://linuxcontainers.org/incus/) host. The image is pulled from [images.linuxcontainers.org](https://images.linuxcontainers.org) and cached on the host.
NixOS does not support cloud-init. This template uses `nixos-rebuild switch` via `incus exec` to configure the workspace user and start the Coder agent. The rebuild only runs on first boot; subsequent starts rotate the agent token and restart the service directly.
## Prerequisites
### 1. Install Incus on the VM host
Follow the [Incus installation guide](https://linuxcontainers.org/incus/docs/main/installing/) for your distro. On Debian/Ubuntu:
```sh
sudo apt-get install incus
sudo incus admin init
```
### 2. Run the Coder provisioner on the same machine
This template uses the local Incus socket, so the Coder provisioner must run on the same machine as Incus. See [provisioner daemons](https://coder.com/docs/admin/provisioners).
### 3. Ensure the host has KVM
```sh
ls /dev/kvm
```
If the device is missing, enable virtualisation in your BIOS/UEFI or, in a nested setup, pass through the `kvm` module.
### 4. Create a storage pool (if needed)
```sh
incus storage create default btrfs
incus storage list
```
### 5. Push the template
```sh
# amd64 host:
coder templates push incus-nixos --directory . --variable arch=amd64
# arm64 host:
coder templates push incus-nixos --directory . --variable arch=arm64
```
The `storage_pool` variable defaults to `default`. Override if needed:
```sh
coder templates push incus-nixos --directory . \
--variable arch=arm64 \
--variable storage_pool=fast-nvme
```
The `nixos_channel` variable controls which NixOS channel is used for `nixos-rebuild`. It must match the image version (default: `nixos-25.11`).
## Usage
1. Create a workspace from this template and choose CPU, memory, and disk.
2. Connect via `coder ssh <workspace>` or use VS Code in the browser via the [VS Code extension](https://coder.com/docs/user-guides/workspace-access/vscode).
3. Install packages declaratively by editing `/etc/nixos/coder.nix` and running `sudo nixos-rebuild switch`.
## Notes
- `code-server` is not installed by this template. The Coder agent is started as a plain systemd service. Install editors via nix packages in `coder.nix`.
- The first workspace start takes several minutes while `nixos-rebuild switch` runs. Subsequent starts are fast.
- Advanced Incus remotes (targeting a separate host over the network) are not supported by this template. See the `incus-vm` template for guidance on adding remote support.
@@ -0,0 +1,287 @@
terraform {
required_providers {
coder = {
source = "coder/coder"
version = ">= 2.4.0"
}
incus = {
source = "lxc/incus"
version = "~> 1.0"
}
null = {
source = "hashicorp/null"
version = "~> 3.0"
}
}
}
provider "incus" {}
variable "arch" {
description = "CPU architecture of the VM host. Set this when pushing the template to match your Incus host. Valid values: amd64, arm64."
type = string
default = "amd64"
validation {
condition = contains(["amd64", "arm64"], var.arch)
error_message = "arch must be amd64 or arm64."
}
}
variable "storage_pool" {
description = "Incus storage pool for the root disk. Run `incus storage list` on the host to see available pools."
type = string
default = "default"
}
variable "nixos_channel" {
description = "NixOS channel to use for nixos-rebuild. Must match the image version (e.g. nixos-25.11)."
type = string
default = "nixos-25.11"
}
data "coder_workspace" "me" {}
data "coder_workspace_owner" "me" {}
data "coder_parameter" "cpu" {
name = "cpu"
display_name = "CPU"
description = "Number of vCPUs."
type = "number"
default = 2
icon = "https://raw.githubusercontent.com/matifali/logos/main/cpu-3.svg"
mutable = true
order = 1
validation {
min = 1
max = 16
}
}
data "coder_parameter" "memory" {
name = "memory"
display_name = "Memory (GB)"
type = "number"
default = 4
icon = "/icon/memory.svg"
mutable = true
order = 2
validation {
min = 1
max = 64
}
}
data "coder_parameter" "disk" {
name = "disk"
display_name = "Disk (GB)"
type = "number"
default = 30
icon = "/icon/database.svg"
mutable = true
order = 3
validation {
min = 10
max = 500
}
}
locals {
workspace_user = lower(data.coder_workspace_owner.me.name)
agent_token = data.coder_workspace.me.start_count == 1 ? coder_agent.main[0].token : ""
agent_init_script = data.coder_workspace.me.start_count == 1 ? coder_agent.main[0].init_script : ""
# NixOS images on images.linuxcontainers.org use "nixos/<ver>" with no arch suffix.
# The channel version (e.g. "25.11") is extracted from var.nixos_channel.
nixos_version = replace(var.nixos_channel, "nixos-", "")
image_alias = "nixos/${local.nixos_version}"
# PATH required for incus exec commands on NixOS VMs. The Nix store is not
# on the default system PATH until after the first nixos-rebuild switch.
nix_path = "/nix/var/nix/profiles/system/sw/bin:/run/current-system/sw/bin:/nix/var/nix/profiles/default/bin:/run/wrappers/bin"
}
resource "coder_agent" "main" {
count = data.coder_workspace.me.start_count
arch = var.arch
os = "linux"
}
resource "incus_image" "nixos" {
source_image = {
remote = "images"
name = local.image_alias
type = "virtual-machine"
architecture = var.arch == "amd64" ? "x86_64" : "aarch64"
}
}
resource "incus_instance" "dev" {
running = data.coder_workspace.me.start_count == 1
name = "coder-${lower(data.coder_workspace_owner.me.name)}-${lower(data.coder_workspace.me.name)}"
image = incus_image.nixos.fingerprint
type = "virtual-machine"
config = {
"limits.cpu" = tostring(data.coder_parameter.cpu.value)
"limits.memory" = "${data.coder_parameter.memory.value}GiB"
"security.secureboot" = false
"boot.autostart" = data.coder_workspace.me.start_count == 1
"user.coder-agent-token" = local.agent_token
}
device {
name = "root"
type = "disk"
properties = {
path = "/"
pool = var.storage_pool
size = "${data.coder_parameter.disk.value}GiB"
}
}
lifecycle {
ignore_changes = [
config["user.coder-agent-token"],
image,
]
}
}
# NixOS does not support cloud-init. Provisioning steps:
# 1. Wait for the incus-agent to be ready (virtio serial channel).
# 2. Push the Coder agent binary (/opt/coder/init) and token env file.
# 3. On first boot: write coder.nix and an updated configuration.nix
# that imports the Incus VM module, then run nixos-rebuild switch.
# Leave a marker so subsequent starts skip the rebuild.
# 4. On subsequent starts: overwrite init.env + restart coder-agent.
resource "null_resource" "provision" {
count = data.coder_workspace.me.start_count
triggers = {
agent_token = local.agent_token
instance = incus_instance.dev.name
}
depends_on = [incus_instance.dev]
provisioner "local-exec" {
command = <<-EOT
set -e
INSTANCE="${incus_instance.dev.name}"
WUSER="${local.workspace_user}"
NIX_PATH="${local.nix_path}"
CHANNEL="${var.nixos_channel}"
echo "Waiting for incus-agent..."
for i in $(seq 1 60); do
incus exec "$INSTANCE" -- true 2>/dev/null && break
echo " attempt $i/60..."
sleep 5
done
echo "Pushing Coder agent binary..."
TMPDIR=$(mktemp -d)
echo "${base64encode(local.agent_init_script)}" | base64 -d > "$TMPDIR/init"
chmod 755 "$TMPDIR/init"
incus exec "$INSTANCE" -- env PATH="$NIX_PATH" mkdir -p /opt/coder
incus file push "$TMPDIR/init" "$INSTANCE/opt/coder/init"
incus exec "$INSTANCE" -- env PATH="$NIX_PATH" chmod 755 /opt/coder/init
rm -rf "$TMPDIR"
printf 'CODER_AGENT_TOKEN=${local.agent_token}\nCODER_AGENT_URL=${data.coder_workspace.me.access_url}\n' \
| incus file push - "$INSTANCE/opt/coder/init.env" --mode 0600
# Fast path: already provisioned -- just rotate token and restart.
if incus exec "$INSTANCE" -- test -f /etc/nixos/.coder-provisioned 2>/dev/null; then
echo "Already provisioned; restarting coder-agent..."
incus exec "$INSTANCE" -- env PATH="$NIX_PATH" systemctl restart coder-agent.service
echo "Done."
exit 0
fi
# First boot: write NixOS config and rebuild.
echo "Writing /etc/nixos/coder.nix..."
cat <<'NIXEOF' | incus exec "$INSTANCE" -- env PATH="$NIX_PATH" bash -c 'cat > /etc/nixos/coder.nix'
{ config, pkgs, lib, ... }:
{
users.users."${local.workspace_user}" = {
isNormalUser = true;
uid = 1000;
home = "/home/${local.workspace_user}";
shell = pkgs.bash;
extraGroups = [ "wheel" ];
};
security.sudo.wheelNeedsPassword = false;
nix.settings.trusted-users = [ "root" "${local.workspace_user}" ];
systemd.services.coder-agent = {
description = "Coder Agent";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
User = "${local.workspace_user}";
EnvironmentFile = "/opt/coder/init.env";
ExecStart = "/opt/coder/init";
Environment = "PATH=/run/current-system/sw/bin:/run/wrappers/bin:/usr/local/bin:/usr/bin:/bin";
Restart = "always";
RestartSec = 10;
TimeoutStopSec = 90;
KillMode = "process";
OOMScoreAdjust = -900;
SyslogIdentifier = "coder-agent";
};
};
}
NIXEOF
echo "Writing /etc/nixos/configuration.nix..."
cat <<'NIXEOF' | incus exec "$INSTANCE" -- env PATH="$NIX_PATH" bash -c 'cat > /etc/nixos/configuration.nix'
{ modulesPath, ... }:
{
imports = [
"$${modulesPath}/virtualisation/incus-virtual-machine.nix"
./incus.nix
./coder.nix
];
systemd.network = {
enable = true;
networks."50-enp5s0" = {
matchConfig.Name = "enp5s0";
networkConfig = {
DHCP = "ipv4";
IPv6AcceptRA = true;
};
linkConfig.RequiredForOnline = "routable";
};
};
system.stateVersion = "${local.nixos_version}";
}
NIXEOF
echo "Restoring nixos channel if needed..."
incus exec "$INSTANCE" -- env PATH="$NIX_PATH" HOME=/root bash -c "
if [ ! -e /nix/var/nix/profiles/per-user/root/channels/nixos ]; then
nix-channel --add https://channels.nixos.org/$CHANNEL nixos
nix-channel --update nixos
fi
"
echo "Running nixos-rebuild switch..."
incus exec "$INSTANCE" -- env PATH="$NIX_PATH" HOME=/root bash -c "
NIXOS_CH=\$(ls -d /nix/var/nix/profiles/per-user/root/channels/nixos 2>/dev/null || echo '')
nixos-rebuild switch -I nixpkgs=\"\$NIXOS_CH\" -I nixos-config=/etc/nixos/configuration.nix \
|| { EC=\$?; [ \$EC -eq 4 ] || exit \$EC; }
"
incus exec "$INSTANCE" -- env PATH="$NIX_PATH" touch /etc/nixos/.coder-provisioned
incus exec "$INSTANCE" -- env PATH="$NIX_PATH" bash -c \
"mkdir -p /home/$WUSER && chown 1000:1000 /home/$WUSER"
echo "NixOS provisioning complete."
EOT
}
}
@@ -0,0 +1,96 @@
---
display_name: Incus VM
description: Run a full virtual machine on a local Incus host
icon: ../../../../.icons/lxc.svg
verified: false
tags: [local, incus, vm, virtual-machine]
---
# Incus VM
Provision a full KVM virtual machine on an [Incus](https://linuxcontainers.org/incus/) host. Unlike the system container template, this creates an isolated VM with its own kernel. Images are pulled from [images.linuxcontainers.org](https://images.linuxcontainers.org) and cached on the host.
## Prerequisites
### 1. Install Incus on the VM host
Follow the [Incus installation guide](https://linuxcontainers.org/incus/docs/main/installing/) for your distro. On Debian/Ubuntu:
```sh
sudo apt-get install incus
sudo incus admin init
```
Verify it's working:
```sh
incus list
```
### 2. Run the Coder provisioner on the same machine
This template uses Incus via the local Unix socket, so the Coder provisioner (or `coderd` itself) must run on the same machine as Incus. The simplest setup is a [provisioner daemon](https://coder.com/docs/admin/provisioners) running directly on the Incus host.
### 3. Set the architecture when pushing the template
The `arch` variable must match your Incus host's CPU architecture. Pass it when pushing:
```sh
# For amd64 (x86-64) hosts:
coder templates push incus-vm --directory . --variable arch=amd64
# For arm64 (aarch64) hosts:
coder templates push incus-vm --directory . --variable arch=arm64
```
### 4. Ensure the VM host has KVM
VMs require hardware virtualisation. Check on the host:
```sh
ls /dev/kvm
```
If the device is missing, enable virtualisation in your BIOS/UEFI or, in a nested setup, pass through the `kvm` module.
### 5. Create a storage pool (if needed)
The template uses an Incus storage pool to back the VM root disk. If you don't already have one:
```sh
incus storage create default btrfs
```
List existing pools:
```sh
incus storage list
```
The pool name defaults to `default` and can be overridden when pushing the template with `--variable storage_pool=<name>`.
## Usage
1. Push this template to your Coder deployment:
```sh
coder templates push incus-vm --directory . --variable arch=amd64
```
2. Create a workspace and select an image and resource sizes.
3. Connect via `coder ssh <workspace>` or open VS Code in the browser.
## Advanced: using a remote Incus host
By default this template connects to the local Incus socket. If you want the provisioner to target a separate Incus host over the network, add a `remote` parameter and use `incus remote add` to register the host on the provisioner machine:
```sh
# On the Incus host — generate a trust token:
incus config trust add coder-provisioner
# On the provisioner — add the remote:
incus remote add my-server https://<host-ip>:8443 --token <paste-token>
```
Then update `main.tf` to accept a `remote` parameter and pass it to the `incus_image` and `incus_instance` resources. See the [Incus remote docs](https://linuxcontainers.org/incus/docs/main/remotes/) for details.
+304
View File
@@ -0,0 +1,304 @@
terraform {
required_providers {
coder = {
source = "coder/coder"
version = ">= 2.4.0"
}
incus = {
source = "lxc/incus"
version = "~> 1.0"
}
null = {
source = "hashicorp/null"
version = "~> 3.0"
}
}
}
provider "incus" {}
variable "arch" {
description = "CPU architecture of the VM host. Set this when pushing the template to match your Incus host. Valid values: amd64, arm64."
type = string
default = "amd64"
validation {
condition = contains(["amd64", "arm64"], var.arch)
error_message = "arch must be amd64 or arm64."
}
}
variable "storage_pool" {
description = "Incus storage pool for the root disk. Run `incus storage list` on the host to see available pools."
type = string
default = "default"
}
data "coder_workspace" "me" {}
data "coder_workspace_owner" "me" {}
data "coder_parameter" "image" {
name = "image"
display_name = "Image"
description = "Base image name from images.linuxcontainers.org (e.g. `ubuntu/noble/cloud`). The template architecture is appended automatically."
type = "string"
default = "ubuntu/noble/cloud"
icon = "/icon/image.svg"
mutable = true
order = 1
option {
name = "Ubuntu 24.04 LTS (Noble)"
value = "ubuntu/noble/cloud"
icon = "/icon/ubuntu.svg"
}
option {
name = "Ubuntu 22.04 LTS (Jammy)"
value = "ubuntu/jammy/cloud"
icon = "/icon/ubuntu.svg"
}
option {
name = "Debian 12 (Bookworm)"
value = "debian/12/cloud"
icon = "/icon/debian.svg"
}
}
data "coder_parameter" "cpu" {
name = "cpu"
display_name = "CPU"
description = "Number of vCPUs."
type = "number"
default = 2
icon = "https://raw.githubusercontent.com/matifali/logos/main/cpu-3.svg"
mutable = true
order = 2
validation {
min = 1
max = 16
}
}
data "coder_parameter" "memory" {
name = "memory"
display_name = "Memory (GB)"
type = "number"
default = 4
icon = "/icon/memory.svg"
mutable = true
order = 3
validation {
min = 1
max = 64
}
}
data "coder_parameter" "disk" {
name = "disk"
display_name = "Disk (GB)"
type = "number"
default = 30
icon = "/icon/database.svg"
mutable = true
order = 4
validation {
min = 10
max = 500
}
}
resource "coder_agent" "main" {
count = data.coder_workspace.me.start_count
arch = var.arch
os = "linux"
metadata {
display_name = "CPU Usage"
key = "0_cpu_usage"
script = "coder stat cpu"
interval = 10
timeout = 1
}
metadata {
display_name = "RAM Usage"
key = "1_ram_usage"
script = "coder stat mem"
interval = 10
timeout = 1
}
metadata {
display_name = "Disk"
key = "2_disk"
script = "coder stat disk --path /"
interval = 60
timeout = 1
}
}
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/code-server/coder"
version = "~> 1.0"
agent_id = coder_agent.main[0].id
}
resource "incus_image" "image" {
source_image = {
remote = "images"
name = "${data.coder_parameter.image.value}/${var.arch}"
type = "virtual-machine"
architecture = var.arch == "amd64" ? "x86_64" : "aarch64"
}
}
resource "incus_instance" "dev" {
running = data.coder_workspace.me.start_count == 1
name = "coder-${lower(data.coder_workspace_owner.me.name)}-${lower(data.coder_workspace.me.name)}"
image = incus_image.image.fingerprint
type = "virtual-machine"
config = {
"limits.cpu" = tostring(data.coder_parameter.cpu.value)
"limits.memory" = "${data.coder_parameter.memory.value}GiB"
"security.secureboot" = false
"boot.autostart" = data.coder_workspace.me.start_count == 1
"user.coder-agent-token" = local.agent_token
"cloud-init.user-data" = <<-EOF
#cloud-config
hostname: ${lower(data.coder_workspace.me.name)}
users:
- name: ${local.workspace_user}
uid: 1000
groups: sudo
shell: /bin/bash
sudo: ALL=(ALL) NOPASSWD:ALL
write_files:
- path: /opt/coder/init
permissions: "0755"
encoding: b64
content: ${base64encode(local.agent_init_script)}
- path: /opt/coder/init.env
permissions: "0600"
content: |
CODER_AGENT_TOKEN=${local.agent_token}
CODER_AGENT_URL=${data.coder_workspace.me.access_url}
- path: /etc/systemd/system/coder-agent.service
permissions: "0644"
content: |
[Unit]
Description=Coder Agent
After=network-online.target
Wants=network-online.target
[Service]
User=${local.workspace_user}
EnvironmentFile=/opt/coder/init.env
ExecStart=/opt/coder/init
Restart=always
RestartSec=10
TimeoutStopSec=90
KillMode=process
OOMScoreAdjust=-900
SyslogIdentifier=coder-agent
[Install]
WantedBy=multi-user.target
runcmd:
- systemctl enable --now coder-agent.service
EOF
}
device {
name = "root"
type = "disk"
properties = {
path = "/"
pool = var.storage_pool
size = "${data.coder_parameter.disk.value}GiB"
}
}
lifecycle {
ignore_changes = [
config["cloud-init.user-data"],
config["user.coder-agent-token"],
image,
]
}
}
resource "null_resource" "token_refresh" {
count = data.coder_workspace.me.start_count
triggers = {
agent_token = local.agent_token
instance = incus_instance.dev.name
}
depends_on = [incus_instance.dev]
provisioner "local-exec" {
command = <<-EOT
INSTANCE="${incus_instance.dev.name}"
echo "Waiting for VM agent..."
for i in $(seq 1 40); do
incus exec "$INSTANCE" -- true 2>/dev/null && break
echo "Attempt $i: not ready, waiting..."
sleep 5
done
echo "Waiting for cloud-init..."
incus exec "$INSTANCE" -- bash -c '
for i in $(seq 1 60); do
[ -f /var/lib/cloud/instance/boot-finished ] && break
sleep 5
done
'
echo "Refreshing agent token..."
printf 'CODER_AGENT_TOKEN=${local.agent_token}\nCODER_AGENT_URL=${data.coder_workspace.me.access_url}\n' \
| incus exec "$INSTANCE" -- bash -c 'cat > /opt/coder/init.env && chmod 600 /opt/coder/init.env'
incus exec "$INSTANCE" -- systemctl restart coder-agent.service
EOT
}
}
resource "coder_metadata" "info" {
count = data.coder_workspace.me.start_count
resource_id = incus_instance.dev.name
item {
key = "instance"
value = incus_instance.dev.name
}
item {
key = "image"
value = "images:${data.coder_parameter.image.value}/${var.arch}"
}
item {
key = "storage_pool"
value = var.storage_pool
}
item {
key = "arch"
value = var.arch
}
item {
key = "cpu"
value = tostring(data.coder_parameter.cpu.value)
}
item {
key = "memory"
value = "${data.coder_parameter.memory.value} GiB"
}
item {
key = "disk"
value = "${data.coder_parameter.disk.value} GiB"
}
}
locals {
workspace_user = lower(data.coder_workspace_owner.me.name)
agent_token = data.coder_workspace.me.start_count == 1 ? coder_agent.main[0].token : ""
agent_init_script = data.coder_workspace.me.start_count == 1 ? coder_agent.main[0].init_script : ""
}