Runesets

Runesets package multi-service applications with templating and values, like a small, opinionated Helm.

A runeset is a directory (or .runeset.tgz archive) that bundles several Rune resources behind a single template + values surface. Use them when one application is actually 3–10 services, secrets, and configmaps that ship together.

A runeset is the package; installing it produces a release — the stateful record of what was deployed. Every rune cast is tracked as a release, so you can list, diff, upgrade-with-prune, roll back, and uninstall it in one shot.

Anatomy

my-app/
├── runeset.yaml          # metadata + default values
├── values/
│   └── values.yaml       # values (every *.yaml here is merged)
├── casts/                # the templated resource files (required)
│   ├── api.yaml
│   ├── worker.yaml
│   └── secrets.yaml
├── templates/            # optional partials, included via {{ template: ... }}
│   └── common-labels.yaml.tmpl
└── README.md

runeset.yaml:

name: my-app
version: 1.2.0
description: API + worker + redis
namespace: default
defaults:
  image:
    tag: "1.2.0"

name doubles as the default release name, namespace as the default target namespace (-n overrides it), and defaults seeds the values map at the lowest precedence.

A cast (casts/api.yaml):

service:
  name: api
  image: "ghcr.io/example/api:{{ values:image.tag }}"
  scale: {{ values:api.replicas | default: 2 }}
  ports:
    - name: http
      port: 8080

Placeholders use {{ values:path.to.key }} for values, {{ context:releaseName }} / {{ context:namespace }} for install-time context, and | default: x for fallbacks. A referenced value that is missing (and has no default:) fails the render — typos surface before anything reaches the cluster. The full syntax is covered in Package a runeset.

Render before applying

Inspect what will be created:

rune cast ./my-app --render
rune cast ./my-app --render --set=image.tag=1.3.0
rune cast ./my-app --render --values=production.values.yaml

Install

rune cast ./my-app --release=my-app-prod --values=production.values.yaml

--release becomes the runeset's identity in the cluster — the release name (it defaults to the name in runeset.yaml). Re-running cast with the same release upgrades in place: Rune computes a 3-way plan (create / update / prune / adopt), shows it, and applies it after confirmation. Resources removed from the runeset are pruned; nothing is orphaned.

Operate the release

Once installed, manage it with rune release:

rune release list                       # all releases + revision + status
rune release status my-app-prod         # owned resources, references, revision
rune release history my-app-prod        # revision log
rune release diff my-app-prod           # what a re-cast would change
rune release rollback my-app-prod --to 2
rune release delete my-app-prod --yes   # uninstall everything it owns

Package and distribute

rune pack ./my-app -o my-app-1.2.0.runeset.tgz --sha256

Produces:

  • my-app-1.2.0.runeset.tgz — the bundle.
  • my-app-1.2.0.runeset.tgz.sha256 — checksum for verification.

Install from a URL or local archive:

rune cast https://example.com/my-app-1.2.0.runeset.tgz --release=my-app-prod
rune cast ./my-app-1.2.0.runeset.tgz --release=my-app-prod

Also supports git refs:

rune cast github.com/example/[email protected] --release=my-app-prod

Values precedence

Highest wins:

  1. --set key=value (CLI flags)
  2. --values file.yaml (extra files, last one wins)
  3. RUNE_VALUES_* environment variables
  4. values/*.yaml inside the runeset (merged in filename order)
  5. defaults: in runeset.yaml

Worked example

examples/runesets in the source tree has a working multi-service runeset you can study.

For a step-by-step walkthrough see Package a runeset.