3.1 Your first change
Included from Basic tier
After this you can: create a change against a node, follow it to completion, list and inspect its run, and read its logs.
Before you start — tick each one:
- Lesson 0.1 — Install and sign in (
opschain learn 0.1) - Lesson 1.2 — Build and change your own (
opschain learn 1.2)
One more thing the checklist cannot tick for you: the project needs a
git remote the server can fetch before its first change — that is where
the server reads the action from when the target is a project or an
environment. Lesson 3.3 (opschain learn 3.3) explains remotes and the
identity policy in full; section 1 below gives you the one command you
need now, so you can do that lesson properly afterwards.
In the GUI: the Actions tab on a node page opens the Run form, and the run page follows the change with its live log viewer.
A change is one action executed against one estate node, with the
server keeping the record: who ran what, where, when, with which inputs,
and every log line. In lesson 2.1 you ran an action on your own machine;
this lesson runs the same hello action on a server, where runners
execute it and the record outlives your terminal. The outcome you are
working towards is one successful change you can find again by its id.
1. Give the project a remote and an environment
On a server the action comes from somewhere the server can read. For a
project or environment target that is the project's git remote: the
repository you scaffolded in lesson 2.1 (opschain init created
.opschain/actions/hello.yaml), pushed somewhere the server can fetch it.
opschain git-remotes create acme --name origin \
--url https://git.example.com/acme/estate.git \
--username ci-bot --password-env ACME_GIT_TOKEN
created git remote acme/origin (01a13f0e-…-example)
The password rides an environment variable, never the command line (lesson 3.3 covers every credential shape). A remote is unusable until the git identity policy allows it: a security administrator allow-lists it, and marks it the default identity for the project, with
opschain security git-policies put --project acme --remote origin --default
created git identity policy entry acme/origin (default)
— the change in step 2 names that remote and revision in its payload
(git_remote_name: origin, git_rev: main), and the policy is what lets
the server act on it. Lesson 3.3 explains the policy in full.
Two more things the record will show you. The change runs as the identity that creates it, so sign in as an everyday operator with rights on the project (lesson 7.2 creates one) rather than the bootstrap admin, whose every act is break-glass. And the server does not execute the step itself: a runner does (lesson 6.2 starts one) — with none online the change queues, by name, until one is.
Then the environment the change targets, exactly as lesson 1.2 built it:
opschain nodes create acme/environments/dev
created environment /projects/acme/environments/dev (01a13f10-…-example)
2. Create a change and follow it
On a server the positional argument is the node path and --action
names the action. --follow keeps the CLI attached: it polls the change,
prints each status transition, and exits with the run's outcome (0
success, 1 failed, 3 cancelled, 4 timed out):
opschain runs create change acme/environments/dev --action hello --follow
created change 01a13f12-7c1e-7a40-9e0d-4b2f8e1d2c33 (hello on acme/dev) — pending
run 01a13f12-7c1e-7a40-9e0d-4b2f8e1d2c33 pending
run 01a13f12-7c1e-7a40-9e0d-4b2f8e1d2c33 pending → running
run 01a13f12-7c1e-7a40-9e0d-4b2f8e1d2c33 running → success
The first line is the change the server created; the rest are its
transitions. The target reads acme/dev — the CLI renders a run's
target as <project>/<environment> (the node path's codes, the
/projects/…/environments/ scaffolding dropped); you still name the
full path when you create. Without --follow you get the first line only and the
change runs on regardless — the server executes it on a runner, not in
your terminal. If the line reads queued — no online runner currently serves this run, no runner is online for the target yet: lesson 6.2
starts one.
Where the action comes from depends on the target: a project or
environment target runs an action from the repository behind the
project's git remote (the hello above); an asset runs its
template's actions (lesson 3.4). A project with several remotes names the
one to use with a payload file:
opschain runs create change acme/environments/dev --action hello -f payload.yaml
# payload.yaml
git_remote_name: origin
git_rev: main
Useful creation flags, all overlaying -f:
--override k=v— property overrides for this run only. Dots nest and values parse as JSON when valid:--override app.replicas=3. (The layered property model is lesson 1.3.)--metadata k=v— free-form metadata recorded on the change, e.g.--metadata comments="ticket OPS-123".-i key=value— a typed run input the action declares (lesson 2.2).--skip-step <path>— skip a step and its subtree (repeatable);--starting-step <path>skips everything before that step.
3. List and inspect runs
opschain runs list
ID KIND ACTION TARGET STATUS CREATED DURATION
01a13f12-7c1e-7a40-9e0d-4b2f8e1d2c33 change hello acme/dev success 2026-10-12T08:00:14Z 4.1s
opschain runs show <run-id> gives you the header and the step tree:
opschain runs show 01a13f12-7c1e-7a40-9e0d-4b2f8e1d2c33
Run: 01a13f12-7c1e-7a40-9e0d-4b2f8e1d2c33
Kind: change
Action: hello
Target: acme/dev
Status: success
Commit: 5d5af8d9c82be2f9c87cf001e041e9e8fd112ae0
Created: 2026-10-12T08:00:14Z
Started: 2026-10-12T08:00:15Z
Finished: 2026-10-12T08:00:19Z
Duration: 4.1s
✔ hello — success (4.1s)
└─ ✔ say_hello — success (3.8s)
Commit is the exact revision the server pinned from the remote — the
record says precisely which code ran. runs show --events appends the
audit trail inline (creation, every step transition, every approval or
cancellation with its actor); the same trail is in the events feed, where
every row carries the run's correlation id — lesson 5.1 reads it
there. As everywhere, -o json turns any of this into a stable machine
shape.
4. Read the logs
opschain logs 01a13f12-7c1e-7a40-9e0d-4b2f8e1d2c33
[hello/say_hello] hello from opschain
Lines are prefixed [step/path] so interleaved steps stay readable.
The variants you will use most:
opschain logs <run-id> --step hello/say_hello # one step's lines only, prefix dropped
opschain logs <run-id> --follow # stream live until Ctrl-C
opschain logs <run-id> --download run.log # write to a file instead
For big logs, --limit reads one page and prints a --cursor to resume
from. The same command is registered as opschain runs logs, a running
run's output is readable while it runs, and a workflow run's id plays
back every run its steps spawned (lesson 4.2).
Check yourself
- Run
opschain runs show <run-id> --eventsfor the change you just created: which event type records it finishing, and what status doesopschain runs listshow for it? - Does
opschain runs showreport success, and doesopschain events --filter node=*dev*showapi:changes:create,api:steps:successandapi:changes:successon your environment, in that order? That is exactly what the Academy'sfirst-governed-changeexercise reads — after the remote, the identity policy, the payload'sgit_remote_name/git_revand a runner were in place. - Verified version:
opschain academyruns thefirst-governed-changeexercise against this lesson — it reads the change's creation and success events from the server and expects the latest change on your environment to reportsuccess.
What you learned
- A server change needs a target node and a source of actions: a git remote on the project for project/environment targets, a template for assets.
runs create change <node-path> --action <name> --followcreates the change, prints each transition and exits with the run's outcome.runs listandruns show <run-id>find the run again, with the exact commit it ran;--eventsappends its audit trail.opschain logs <run-id>reads the step-prefixed log, live or to a file.
Next: lesson 3.2 — Gates, retry, cancel (opschain learn 3.2), or back to your track (opschain learn).