VM templates for agents
A VM template sets an agent up in one command. One template holds everything the agent needs:
- its VM: the image, resources, command, network and published ports;
- the broker policies that keep its API keys on your Mac;
- its volumes, for data that outlives the VM;
- the setup to run inside the VM once it is up.
koala template list # the VM and policy templateskoala template inspect hermes # what one makes, and its parameterskoala create hermes --template hermes # make itkoala template update # get newer templates, when you want themThe built-in template is hermes, the Hermes agent.
Its file is examples/hermes/template.json in Koala’s Homebrew tap. You can
also write your own. An agent without a template is
set up with koala create flags, as the OpenClaw example’s
script does.
What koala create --template does
Section titled “What koala create --template does”-
It checks everything first. It renders the template on your Mac, then checks the manager:
- the VM name is free;
- any policy of the same name is identical;
- anything the VM uses that the template doesn’t create exists.
If something is wrong, it stops, and nothing has changed.
-
It shows the plan:
- the VM;
- everything the VM can reach (internet, broker grants, published ports, volumes, shared directories);
- the keys, policies and volumes it creates or reuses;
- the setup commands.
-
It asks
Continue? [y/N]. With--yes, it doesn’t ask. -
It makes it all:
- It asks for any missing key, without echoing it, and stores the key in
your login keychain, as
koala policy createdoes. - It stores the policies, creates the volumes and the VM, then starts the VM. The first start downloads the image, which can take a while.
- It waits until the agent is ready, runs the setup commands in the VM (their output is shown), and restarts the VM if the template asks for that.
- It asks for any missing key, without echoing it, and stores the key in
your login keychain, as
-
It prints
hermes is running, and the template’s notes: where the agent listens, and how to use it.
The plan for the built-in hermes template looks like this:
Template hermes v1 (built in): The Hermes agent's gateway, with its model key on your Mac and no internetParameters: credential=hermes-openai image=docker.io/nousresearch/hermes-agent:latest model=gpt-4.1-mini origin=https://api.openai.com port=8642 tls-pin=It will make: VM hermes: docker.io/nousresearch/hermes-agent:latest, lean service, 2 CPUs, 2048 MiB memory, 6144 MiB disk publish tcp 127.0.0.1:8642 -> 8642 (loopback) volume hermes-data -> /opt/data (rw) internet off broker openai -> policy hermes-openai credential hermes-openai: koala asks for the key policy hermes-openai: openai v1, https://api.openai.com, models gpt-4.1-mini, key hermes-openai volume hermes-data: 2048 MiB, new then waits, up to 300 s, until this succeeds in the VM: curl -fsS -m 2 -o /dev/null http://127.0.0.1:8642/health runs in the VM: hermes config set model.provider custom ... then restarts the VM and leaves the VM running.Continue? [y/N]Parameters
Section titled “Parameters”A template’s parameters are its settings. koala template inspect
lists them, with their defaults. Set one with --set NAME=VALUE, repeated
for each:
# Another modelkoala create hermes --template hermes --set model=gpt-4.1
# Another OpenAI-compatible providerkoala create hermes --template hermes --set origin=https://api.mistral.ai --set model=mistral-small-latest
# A second Hermes, on another portkoala create hermes-2 --template hermes --set port=8643- Names are derived from the VM’s name.
koala create hermes-2makes the policyhermes-2-openai, the keyhermes-2-openaiand the volumehermes-2-data. - To share one stored key between agents, name it:
--set credential=openai. --cpus,--memoryand--diskchange the VM’s resources, as withkoala create.- To change anything else, copy the template, or
change the VM afterwards with
koala edit.
Parameters are not secret. The plan shows them, and they end up in the VM’s
definition and its policies. Never pass a key with --set: keys come from
the prompt, or from stdin with --value-stdin, which sets the template’s
one key.
What is reused
Section titled “What is reused”- A volume that exists is used as it is, with its data. So after
koala stop hermes --waitandkoala rm hermes, running the samekoala createagain gives a new VM with the old data. - A policy that exists and is identical is reused. One that differs is
refused: see it with
koala policy inspect, and remove it withkoala policy rmif you no longer need it. - A key that is stored is used without asking. With
--value-stdin, the key from stdin replaces it.
If a step fails
Section titled “If a step fails”koala create --template stops at the first step that fails. It doesn’t
undo anything. It says:
- what it did before stopping;
- the commands that would finish the job by hand;
- the commands that remove what this run made (
koala stop,koala rm,koala volume rm,koala policy rm,koala credential rm).
Ctrl-C stops it the same way.
Your own templates
Section titled “Your own templates”Start from a built-in template:
koala template inspect hermes --json > my-agent.json# edit my-agent.jsonkoala template inspect ./my-agent.jsonkoala create my-agent --template ./my-agent.jsonA template is a JSON file:
{"format": 1, "name": "my-agent", "version": 1, "description": "What it runs", "parameters": {"port": {"description": "The port on your Mac", "type": "integer", "default": 8080}}, "policies": [{"name": "{{vm}}-openai", "template": "openai", "models": ["gpt-4.1-mini"]}], "volumes": [{"name": "{{vm}}-data", "size": "1GiB"}], "vm": {"mode": "service", "image": {"kind": "oci", "reference": "docker.io/example/my-agent:1", "platform": "linux/arm64"}, "network": {"internet": false, "allow": [{"kind": "broker", "name": "openai", "policy": "{{vm}}-openai"}], "publish": [{"protocol": "tcp", "hostAddress": "127.0.0.1", "hostPort": "{{port}}", "guestPort": 8080}]}, "volumes": [{"name": "{{vm}}-data", "destination": "/data", "readOnly": false}]}, "setup": {"ready": {"command": ["test", "-d", "/data"], "timeoutSeconds": 60}, "commands": [{"command": ["my-agent", "init"]}], "restart": false}, "notes": ["It listens on http://127.0.0.1:{{port}}"]}-
vmis a VM spec, as in akoala create -ffile (Jobs and VMs), without itsname.- The mode is
serviceorenvironment. - Koala adds labels that name the template (
koala inspectshows them).
- The mode is
-
policiesare made from built-in policy templates:templateandnameare required;credential,origin,tlsPin,groupsandmodelsare optional, as the flags ofkoala policy create.
Each policy must be used by one of the VM’s broker grants.
-
volumesare created if missing, withsizeinkoala volume create’s form. Each must be one of the VM’s volumes. -
setupruns once, inside the VM, after its first start:readyis retried every 2 seconds until it succeeds, for up totimeoutSeconds;- each of
commandsmust then succeed; restartrestarts the VM afterwards.
Each command is a list of arguments, not a shell line. Add
userto run one as another guest user. -
parameterseach have adescription, an optionaltype(stringorinteger) and an optionaldefault. A parameter with no default must be set.{{NAME}}in any value is replaced by the parameter’s value, and{{vm}}by the VM’s name.- A value that is exactly
"{{port}}", for an integer parameter, becomes a number. - Replaced text is never read again for
{{.
-
notesare printed at the end.
Koala checks a template strictly before using it. Unknown fields and
references to parameters that don’t exist are errors, given with the place
in the file, such as at /vm/network/publish/0/hostPort.
Newer templates
Section titled “Newer templates”Templates come with Koala, and newer ones can be published between
releases. koala template update downloads them, with the
policy templates (which koala policy templates
lists):
koala template updateupdated the templates from https://raw.githubusercontent.com/kunalkushwaha/homebrew-koala/main/serial 7, signed by koala-release-1 vm hermes v2: replaces built-in v1 policy openai v1: same as built-in-
Until a template changes, nothing changes. Each line says
same as built-in, and your koala keeps using its own copy, sotemplate listshows no(downloaded). -
It runs only when you ask. Koala never fetches templates on its own.
-
It keeps only what Koala’s release key signed. The templates’ index is signed with the key that signs Koala’s releases. Your koala checks it against the key in its own installation, then checks each file against the index. If any check fails, nothing changes.
-
It never goes back. An index older than the one you have is refused.
-
A downloaded template is used when its version is higher than the one built into your koala.
koala template listandkoala policy templatesmark it(downloaded).- A VM made from it has the label
koala.dev/template-source: downloaded.
-
What you already made doesn’t change. A policy made from an older template is updated with
koala policy upgrade, which shows the change first (Day to day). -
The templates are kept in
~/Library/Application Support/Koala/templates, and checked again each time koala uses them. If they were changed, koala says so, ignores them and uses its built-ins.koala template updatedownloads them again. -
--source URLreads another copy of Koala’s Homebrew tap:- an
https://address; http://on this Mac only (127.0.0.1,::1orlocalhost);- a folder, as
file:///path/to/homebrew-koala/.
The signature is still required, so a copy can’t change what you get.
- an
-
It needs a released koala (Homebrew or a release archive), which carries the release key. A koala built from source has none, and refuses.
Safety
Section titled “Safety”- Read the plan, especially for a template from a file. A template can ask for anything a VM definition can: internet access, your Mac’s services, directories from your Mac, published ports on your LAN. The plan lists all of it before anything changes.
- A template can also use what you already have. A broker policy or a
volume that the VM uses, but the template doesn’t make, is named in the
plan as
yours, not made by this template. Such a VM can use that policy’s key, or that volume’s data. - Templates run nothing on your Mac. Setup commands run inside the VM,
as
koala execwould run them. - A downloaded template is as safe as Koala’s review of it. The signature proves it was published with Koala’s releases. The plan still shows everything it asks for before anything changes.
- Keys never appear in a template. They come from the prompt or stdin, and stay in your login keychain. The VM gets broker grants, not keys.