1.3 Properties and settings: the overlay
Included from Basic tier
After this you can: describe the overlay — project → environment → asset → change, most specific wins — give a node a property of its own, shape one run with overrides, and read the converged view a run actually saw.
Before you start — tick each one:
- Lesson 1.2 — Build and change your own (
opschain learn 1.2)
In the GUI: the Properties and Settings tabs on every node page — always last in the tab strip, behind the divider.
Actions rarely hard-code the values they need — the database host, the replica count, the deployment window. In OpsChain that data lives in properties, layered over the estate so each environment and asset carries exactly its own view, and settings tune how OpsChain itself behaves, layered the same way. In this lesson you learn the overlay, write one property onto the project you built, shape a single run with an override, and read back what a run actually saw.
1. The overlay model
Properties are JSON documents attached at every level, merged most specific wins:
project → environment → asset → change override
Set app.replicas: 2 on the project, override it with 3 on the prod
environment, and a change on a prod asset sees 3 — every other
environment still sees 2. A change-level override sits on top of
everything, for that one run only. Expressions can also read
another node's merged view with estate('<node path>') — see
opschain docs expressions.
Two more things feed the merge:
- The repository layer. Properties committed in your repo
(
.opschain/properties/...— lesson 2.1's layout) merge underneath the stored layers of the same node, so git-authored defaults are always overridable from the server. - Templates. A templated asset inherits its template version's properties underneath the asset's own.
Settings follow the same shape with one extra layer at the bottom — the
server's global settings — then project → environment → asset →
change settings_overrides.
Properties are yours and reach your running steps (${{ properties.… }}
in lesson 2.2); settings are OpsChain's (notification rules, runner
placement, timeouts) and steer the platform. Keep secrets out of both —
a secret belongs in the vault and is referenced as
secret-vault://<path>/<key> (lesson 3.5).
2. Give a node a property of its own
Every node you create gets an empty stored properties document. Read the project's:
opschain properties show acme
path: /projects/acme
id: 01a1b3a0-…
version: 1
created_at: 2026-11-07T00:40:12Z
data:
{}
Write the document you want — the whole document — to a file and apply it:
# greeting.yaml
academy:
greeting: hello world
opschain properties edit acme -f greeting.yaml
updated properties of /projects/acme: version 1 → 2
properties edit replaces the stored data wholesale, as a new
version — it does not merge. The file holds exactly the keys you want
the document to hold afterwards, so to add a key to an existing
document, show it first, add the key to what you got, and send the
whole thing back. Read it back:
opschain properties show acme
path: /projects/acme
id: 01a1b3a0-…
version: 2
created_at: 2026-11-07T00:41:03Z
data:
{
"academy": {
"greeting": "hello world"
}
}
opschain settings show|edit are the settings twins. Lesson 1.4 covers
the version trail this write just extended, and what happens when two
people edit at once.
3. Shape a single run
Change-level overrides ride the run, touch nothing stored, and win over every layer:
opschain runs create change acme/environments/dev/assets/web --action deploy \
--override app.replicas=5 --override app.debug=true
created change 01a1b3a1-… (deploy on acme/environments/dev/assets/web) — pending
Dots nest (app.replicas=5 becomes {"app": {"replicas": 5}}) and
values parse as JSON when valid. For settings overrides, or a bigger
payload, use a file:
# payload.yaml
action: deploy
property_overrides:
app:
replicas: 5
settings_overrides: {}
opschain runs create change acme/environments/dev/assets/web -f payload.yaml
4. Read what a run actually saw
Every change records its converged view — the merged result of all
layers at execution time — and runs converged reads it:
opschain runs converged 01a1b3a1-…
The merged data prints first, then every value attributed to the layer that won it:
{
"academy": {
"greeting": "hello world"
},
"app": {
"replicas": 5
}
}
PROPERTY SOURCE
academy.greeting Project: ACME Shop (acme)
app.replicas Change: Change properties
--exclude-layer <layer>re-converges without a layer (repeatable) — peelchange, thenasset, thenenvironment, and watch a value fall through to the layer below.--step <step-id>narrows to one step's pinned view (the same addressing as the gate verbs).--settingsreads the converged settings instead: the diff against the server's global settings, attributed per setting (the settings converge takes no layer filters).
Under the hood these are ordinary API reads, usable directly with your
bearer token (lesson 0.3 showed you api routes):
opschain api routes --contains converged
METHOD PATH AUTH SUMMARY
GET /api/changes/{id}/converged_properties user Show the properties a change converged at execution time.
GET /api/changes/{id}/converged_settings user Show the settings a change converged at execution time.
GET /api/steps/{id}/converged_properties user Show the properties a step converged at execution time.
GET /api/steps/{id}/converged_settings user Show the settings a step converged at execution time.
The response carries the merged data, the attribution under
meta.property_sources.by_property, and the same exclude_layers[]
query parameter. The node-path variants
(…/assets/web/converged_properties) answer "what would a change here
see right now", before you run anything. Workflow runs record no
converged view of their own — each change the workflow created records
one.
Check yourself
- Which layer wins when the project and the asset both set the same key — and after
properties edit -f, does the document hold the file's keys merged in, or exactly the file's keys? - Verified version:
opschain academyruns thebuild-an-estateexercise against this lesson.
What you learned
- Properties merge project → environment → asset → change override, most specific wins; settings add the server's global layer underneath.
properties edit <path> -f <file>replaces a node's stored document wholesale as a new version —showfirst, then send the whole document back.--override k=vshapes one run without touching anything stored.runs converged <change-id>prints what a run actually saw, each value attributed to the layer that won it.
Next: lesson 1.4 — Editing, history and promotion (opschain learn 1.4), or back to your track (opschain learn).