Skip to content

Workspace spec

Last updated: 2026-08-13

microagent.yaml records the inputs needed to recreate a workspace from source control. It is the declarative form of microagent create: each field corresponds to a create flag, and when both are given, CLI flags override matching spec fields. Use the file when the workspace definition should live in the repo; use flags for one-off overrides.

Pass it explicitly with --file to create, run, or dispatch. A spec in the current directory is never read implicitly. With the optional agent: block (below), a spec doubles as an Agentfile — a build-free recipe for running an agent in an isolated workspace.

A minimal spec needs only a few lines:

name: research
image: docker.io/library/ubuntu:24.04
profile: medium
setup:
- mkdir -p /workspace
entrypoint: /app/start.sh

Everything else is optional. The kitchen-sink example:

name: research
image: docker.io/library/ubuntu:24.04
profile: medium
restart: on-failure
entrypoint: /app/start.sh
shell: /bin/bash
hostname: research
setup:
- mkdir -p /workspace
- echo ready > /workspace/status
files:
- src: ./agent.py
dst: /app/agent.py
mode: "0644"
env:
MICROAGENT_NAME: research
model: unsloth/Qwen3-4B-Instruct-2507-GGUF/Qwen3-4B-Instruct-2507-Q4_K_M.gguf
modelRunner:
backend: llamacpp
gpu: off
args: ["--no-ui"]
modelMediation:
mode: policy
policyFile: ./model-policy.json
policyTimeout: 250ms
resources:
memoryMiB: 2048
cpuCount: 2
sizeMiB: 8192
mediation:
enabled: true
required: true
port: 2048
target: 127.0.0.1:9900
failClosed: true
health:
exec: ["python3", "-c", "import socket; socket.create_connection(('127.0.0.1', 8080), 1)"]
intervalSeconds: 15
timeoutSeconds: 2
retries: 3
startPeriodSeconds: 10
disks:
- name: workspace
path: /tmp/workspace.ext4
mountpoint: /workspace
mode: rw
bundles:
- name: config
path: ./config.tar
mountpoint: /config
mode: ro
outputs:
- name: report
path: /workspace/report.json
agent:
entry: python /app/agent.py
egress: mitm
allow: [api.anthropic.com]
lockAllowlist: true
cred-swap: [anthropic]
broker:
upstream: https://api.anthropic.com
secret: anthropic=env:ANTHROPIC_API_KEY
assurance: semantic
grant: ./anthropic-grant.yaml
env: [ANTHROPIC_BASE_URL]

The optional agent: block turns a spec into an Agentfile. It carries the few agent-defining knobs the rest of the spec cannot express, while base image, dependency install, files, and env reuse the normal top-level fields. There is no image to build. microagent dispatch --file agent.yaml pulls the thin base, runs setup in the booted guest, drops files, and runs entry under the egress envelope — installing the SDK at boot rather than baking a fat image. See examples/agents.

Terminal window
microagent dispatch --file agent.yaml

CLI flags override the block (for example --egress mitm beats agent.egress, --exec beats agent.entry); agent.allow and agent.cred-swap union with the corresponding flags. A --broker-*/--broker-endpoint broker supplied on the command line wins outright — agent.broker/agent.brokers only fills an otherwise-unset broker.

Terminal window
microagent create --file microagent.yaml

CLI flags override spec fields, so this is valid:

Terminal window
microagent create --file microagent.yaml --name research-2 --profile large
FieldDescription
nameWorkspace name
imageOCI image reference
profileResource profile: tiny, small, medium, or large
restartRestart policy: never, on-failure, or always
entrypointCommand to run when the workspace starts
serviceLong-running shell command to run as the VM service (the --service-command flag)
shellInteractive console shell path. Defaults to /bin/sh; the path must exist inside the guest
hostnameGuest hostname. Defaults to the workspace name sanitized as a Linux hostname
setupCommands to run before first start
setupFilesHost script files whose contents run as setup commands after setup; paths relative to the spec file or absolute
filesSource files to copy into the workspace rootfs
files[].srcHost path, relative to the spec file or absolute
files[].dstAbsolute guest path to write
files[].modeOptional octal file mode string, such as "0755"
envGuest environment variables
modelHuggingFace GGUF ref of a locally served model to pair the workspace with; every start re-pairs it, and a CLI --model flag overrides the field. See model
modelRunner.backendModel runner backend: llamacpp, vllm, or custom
modelRunner.gpuModel runner GPU intent: off, on, or auto
modelRunner.backendModelBackend model id for runners such as vLLM
modelRunner.servedModelOpenAI-compatible served model name for runners such as vLLM
modelRunner.commandCustom runner argv template; supports {model}, {host}, {port}, and {addr}
modelRunner.nameCustom runner name recorded in runner state
modelRunner.healthPathCustom runner health probe path
modelRunner.argsExtra runner argv entries
modelMediation.modeModel mediation mode: off, local-allow, or policy
modelMediation.policyFileStructured model mediation policy file path
modelMediation.policyURLExternal model mediation policy endpoint URL
modelMediation.policyTimeoutModel mediation policy timeout, such as 250ms or 2s
resources.memoryMiBMemory override
resources.cpuCountCPU override
resources.sizeMiBRootfs disk size override
resources.headroomMiBWritable space guaranteed beyond the image content when the size is derived (default: 512)
network.modeNetwork mode: user (default) or isolated
network.forwardsPublished ports; each entry takes protocol (default tcp), host, hostPort, guestPort
network.dnsGuest DNS server list
network.routesExtra guest static routes
network.ipStatic guest IP override
network.subnetGuest subnet override
network.gatewayGuest gateway override
network.ipv6Static guest IPv6 CIDR override
network.ipv6SubnetGuest IPv6 subnet override
network.ipv6GatewayGuest IPv6 gateway override
mediationGuest-to-host vsock mediation channel contract
mediation.enabledEnables the mediation declaration
mediation.requiredRequires the channel for workspace startup
mediation.portGuest vsock port used by the agent
mediation.targetHost address and port for the enforcer/orchestrator
mediation.failClosedTreats a required channel break as closed by default
healthLiveness probe; an unhealthy workspace is restarted by supervise under the restart policy
health.execProbe command run in the guest through structured exec when the selected backend exposes execReady; healthy on exit 0. Declare either exec or httpGet
health.httpGetProbe path for a host-side GET against a published guest port (for example /healthz); healthy on a non-error status
health.portPublished guest port the httpGet probe targets
health.intervalSecondsSeconds between probes (default 30)
health.timeoutSecondsPer-probe timeout (default 5)
health.retriesConsecutive failures before the workspace is considered unhealthy (default 3)
health.startPeriodSecondsGrace period after start before probing begins (default 0)
disksExisting ext4 disks to attach
disks[].sourcePathPath the disk content came from; for bundles: entries it is the source tar (defaults to path)
disks[].bundleSet automatically: false for disks: entries, true for bundles: entries (visible in persisted manifests)
bundlesTar bundles to build into ext4 disks and attach
outputsDeclared output artifact paths inside the workspace
agent.entryThe agent’s run command (the one-shot exec); a CLI --exec overrides it
agent.egressEgress mode: broker, mitm, or off; a CLI --egress overrides it
acknowledgeCapabilityRiskTop-level operator reason accepting private data plus injected files/disks plus unmediated outbound; persisted with the workspace
agent.allowExtra egress hosts to allowlist; unioned with --egress-allow
agent.lockAllowlistDrop the allow-broad grant. On apply, true replaces the prior allowlist with agent.allow and clears old passthrough hosts; a running workspace must halt/start
agent.cred-swapBuilt-in providers to inject host-side, each PROVIDER[=env:NAME|file:PATH|vault:PATH] (reference only, never a literal); unioned with --cred-swap. See credential swap
agent.broker.upstreamEgress broker upstream base URL; the broker injects request credentials host-side. A CLI --broker-upstream overrides the block
agent.broker.secretBroker credential NAME=<scheme>:<ref> (reference only, never a literal); held host-side only, the guest sends @secret:NAME references
agent.broker.envGuest env vars pointed at the broker, each KEY[=VALUE] (empty value = the broker URL)
agent.broker.proxyAlso set HTTPS_PROXY/HTTP_PROXY in the guest to the broker (CONNECT tunneling)
agent.broker.captureOpt in to raw capture of pre-swap broker requests to an owner-only file; off by default (the default record is the minimized decision stream)
agent.broker.caPEM bundle path this broker’s upstream TLS client trusts; empty means system roots
agent.broker.assuranceRequired contract: semantic or explicit lower-assurance trusted-upstream
agent.broker.grantYAML/JSON semantic grant, resolved relative to the Agentfile; required for semantic
agent.brokersDeclare multiple broker endpoints instead of a single agent.broker; each block has the same fields. Setting both forms is rejected

The less obvious fields in YAML form - a long-running service, setup from a script file, and the network: block:

service: /usr/local/bin/homebridge
setupFiles:
- ./setup.sh # file contents run as one setup command
network:
mode: user
forwards:
- protocol: tcp
host: 127.0.0.1
hostPort: 8581
guestPort: 8581
dns: [1.1.1.1]
  • create - the command this file drives
  • apply - apply spec changes to an existing workspace
  • profiles - the named resource profiles
  • supervise - acts on restart and health