3.4 Templates and versions
Included from Basic tiertemplates
After this you can: create a template, pin a version to an exact revision, assign it to assets, and run the version lifecycle with its in-use protections.
Before you start — tick each one:
- Lesson 3.3 — Git remotes and the identity policy (
opschain learn 3.3)
In the GUI: the Templates tab on a project page, beside Git remotes — versions, the assets pinned to each, lock/unlock/archive.
Lesson 1.1 ended with an asset pinned to a template version; this lesson is where that version comes from. A template names which remote its content comes from, a template version pins a revision — branch, tag or commit — of that repository, and every asset pinned to a version takes its action catalog from that exact commit. By the end you will have cut a version, moved assets onto it, and seen the server refuse to pull a version out from under the assets that use it.
1. Create a template and pin its first version
Both can be made in one command, against the remote from lesson 3.3:
opschain templates create acme \
--code web_tier --name "Web Tier" \
--git-remote infra \
--version 1.0.0 --git-rev v1.0
created template acme/web_tier (01a14002-…-example)
created version 1.0.0 (ready, git rev v1.0 (0a1b2c3))
The server resolves --git-rev against the remote right away: the
version stores both the revision you asked for and the exact commit it
resolved to, so what a version means never drifts — and a commit you
rehearsed locally with --ref before pushing (lesson 2.6) is exactly
what pinned assets will run. A revision that does not exist in the
repository is a named 422 (Git rev must match a Git revision (branch/tag/commit) in the template's Git remote), not a stored
mistake.
Template codes are immutable and lowercase ([a-z0-9_]+). The
repository itself carries the template's content — its actions under
.opschain/templates/<code>/actions/ — authored exactly as lessons 2.1
and 2.4 taught, which is why a template version is "a revision of a
repo" and nothing more.
2. Assign a version to assets
Assets met templates in lesson 1.1: nodes create … --template web_tier:1.0.0 pins at creation. templates assign is the fleet move —
repoint existing assets at a version in one command:
opschain templates assign acme/web_tier --version 1.1.0 \
--asset acme/environments/dev/assets/web \
--asset acme/environments/dev/assets/api
assigned version 1.1.0 of acme/web_tier to 2 asset(s)
Each asset must already belong to this template (the server refuses a cross-template assignment by name), and you need update rights on the template and on every named asset.
How template actions reach the asset catalog. Assigning (or pinning
at creation) opens a new entry in the asset's version history and
refreshes its action catalog in the background — the server checks out
the version's pinned commit and derives the actions it declares. Until
the refresh lands, the previous catalog keeps serving, so a broken
revision never leaves an asset with no actions. From there it is
lesson 3.1's world: opschain actions list shows the catalog, and
runs create change executes from it.
opschain nodes show acme/environments/dev/assets/web # template: web_tier:1.1.0
opschain actions list --project acme --env dev --asset web # the refreshed catalog
Declarative YAML action files are the default authoring lane and run on
any runner. A template whose repository also carries an actions.rb or
a MintModel document — applicable only to existing MintPress customers
and those using the MintPress SDK or the packs:mintpress feature —
has those actions derived on a Ruby-capable runner and merged into the
same catalog, gated by the packs:mintpress entitlement per step;
opschain docs packs-mintpress covers that lane in full.
3. The version lifecycle
Across a whole project, the GUI's Asset versions by environment view
draws the matrix: assets as rows, the project's environments as columns,
the pinned version in each cell with its locked / floating / archived
badges, and every cell that differs from a baseline environment tinted —
the one-glance answer to "is prod on the same version as test". It is a
view of the project's Assets page only: switch the page from Table to
Versions by environment beside the toolbar. The view lists every asset
of the project — the project-level assets first, under the environment -
with the cell showing the template version each is on, then the
environment-scoped assets against every environment, the right-most
environment the baseline until you pick another. An environment's Assets
page shows the table only. The dashboard panel of the same name shows one
project's matrix, project-level assets included, and opens the project's
view. On the command line, templates show is the lifecycle dashboard:
opschain templates show acme/web_tier
code: web_tier
id: 01a14002-…-example
project: acme
name: Web Tier
description: -
type: asset
git_remote: infra
archived: false
versions:
VERSION STATE GIT REV LOCKED ARCHIVED IN USE
1.0.0 ready v1.0 (0a1b2c3) no no -
1.1.0 ready main (9f8e7d6) no no 2 asset(s)
New versions come from version upsert — the same command updates an
existing version's revision or description:
opschain templates version upsert acme/web_tier --version 1.2.0 --git-rev release/1.2
upserted version 1.2.0 of acme/web_tier (ready, git rev release/1.2 (4c5d6e7))
opschain templates version upsert acme/web_tier --version 1.2.0 --fetch
--fetch re-resolves the stored revision against the remote — a version
pinned to a branch picks up its new head; --float makes that the
version's standing behaviour: the server fetches every Git remote on its
periodic schedule (every 15 minutes unless the remote, the project or the
global settings say otherwise — git-remotes show prints the last and
next fetch) and repins each floating version whose branch moved, rolling
the assets pinned to it onto the new commit and refreshing their action
catalogs, with an info:template_version:rev_repinned event on the
record. That background refresh runs as the version's creator, so a
floating version cannot be owned by a break-glass account: creating or
switching a version to floating as one is refused by name — pin the
revision, or create the version as an everyday user. The branch a
floating version follows is a watched ref: the
fetch that moves it also records info:git_remote:ref_moved (the old and
new commits, fast_forward or forced), the event a trigger can fire a
workflow on — opschain docs triggers ("The git ref-move source") has
the recipe, and opschain git-remotes refs acme/origin lists what is
watched. Versions that assets are in use by are
protected: changing or fetching their revision, unlocking them, or
archiving them is refused with a named error —
opschain templates version archive acme/web_tier --version 1.1.0
Error: the server answered HTTP 422: Template version cannot be archived as the version is currently in use
— and --ignore-in-use is the deliberate override: it accepts the risk
and, for a revision change, rolls the pinned assets onto the newly
resolved commit (their catalogs refresh again).
lock is the release freeze: a locked version accepts no revision or
metadata changes until unlocked.
opschain templates version lock acme/web_tier --version 1.1.0
locked version 1.1.0 of acme/web_tier
archive retires a version from assignment without deleting anything;
unarchive brings it back. The everyday flow is: upsert the next
version → assign it → lock what production runs. The GUI's screens
ride the same calls over the v2 API (opschain docs api-v2), with the
same in-use refusals.
Check yourself
- Archive the version your assets pin: what does the server answer, and which column of
templates showtells you why before you try?
What you learned
- A template names a remote; a version pins a revision of it and stores the exact commit it resolved to, so a version never drifts.
templates assign --version … --asset …repins assets in one move and refreshes their action catalogs in the background, the old catalog serving until the new one lands.version upsertcuts or repins versions,--fetchfollows a moving branch once,--floatfollows it on every periodic fetch of the remote, andlockfreezes a release.- A version in use refuses a revision change, unlock or archive by name;
--ignore-in-useis the explicit override that rolls the assets forward with it.
Next: lesson 3.5 — Secrets and the vault (opschain learn 3.5), or back to your track (opschain learn).