6.2 Your first runner
Included from Basic tier
After this you can: mint a registration token, start a runner, watch it come online, and work the troubleshooting table when it does not.
Before you start — tick each one:
- Lesson 6.1 — How a runner works, and what happens when one dies (
opschain learn 6.1)
In the GUI: the Registration tokens panel on the Runners page mints the token (the value shows once, in the mint dialog), and the Runners panel lists the new member the moment it registers.
One browser tab or terminal, one runner host, ten minutes: this lesson
enrols a runner end to end and reads it back. You need administrator
rights for the mint (updatable on /admin — a superuser qualifies;
lesson 7.2) and a host that can reach the server's URL. The Basic tier
allows 3 registered runners and 1 runner group (a second group name is
refused; joining the existing group is always fine) — apply a licence
before a larger fleet (lesson 1.5; opschain docs entitlements).
1. Mint a registration token
A registration token carries the enrolment policy — the group the runner joins, labels, a lifetime (default 1h), an optional redemption cap — so the runner side needs nothing but the token. Your login session is the credential; the value prints exactly once, at mint time:
opschain login --server https://opschain.example.com
opschain admin runner-token create --group default
<the token value — printed once; capture it now>
Capture it into a variable for the next step
(TOKEN=$(opschain admin runner-token create --group default)).
Naming a group that does not exist yet creates it with the mint
(subject to the licence's group entitlement); there is no separate
create-a-group step. In the GUI the same mint is Mint token… on the
Runners page.
2. Start the runner
On any host that can reach the server's URL:
opschain runner --server https://opschain.example.com --token "$TOKEN"
registered runner ocr_m9X6WFUT7QWg5VfO616Qk4XNdbEG6qX2 (group default)
The first start redeems the token, keeps a durable identity under its
state directory (default <opschain home>/runner; --dir chooses
another), and then serves jobs in the foreground — leave it running, and
restart it any time with the same command minus --token: the saved
identity re-attaches the same fleet member.
--server also accepts an ordered comma-separated list — the
primary first, failover targets after
(--server https://site-a.example,https://site-b.example): the runner
fails over to the next server on sustained unreachability, keeps its
in-flight job alive across the switch, and returns to the primary on
its next session handshake after the primary recovers (lesson 8.7;
opschain docs cli/runner).
3. Check the heartbeat
opschain admin runners list
GROUP NAME ID ATTRIBUTES ONLINE LAST SEEN JOB STATE
default runner-host-1 ocr_m9X6WFUT7QWg5VfO616Qk4XNdbEG6qX2 - ✓ 2026-10-12T09:51:12Z - ready
Online, last seen moments ago, state ready. Now run something
(lesson 3.1) and watch the member take the job: the JOB column reads
<step-id>#<attempt> while it holds one, and the Runners panel shows
the same row.
4. Scale deliberately
A runner takes one job at a time, so work queueing behind a busy
fleet is your scale signal (opschain admin runner-group demand default reports {queued, running} — lesson 6.3). Start more members
with the same token within its TTL, each with a fresh --dir and
--name:
opschain runner --server https://opschain.example.com --token "$TOKEN" \
--dir ~/opschain-runners/default-2 --name runner-host-2
5. When the loop does not go that smoothly
| Symptom | What it means |
|---|---|
runner is not registered and no --token was given | A first start of this state directory without a token. Pass --token — or, if this host was already enrolled, point --dir at the state directory holding its identity. |
runner is registered with <url>; remove <dir> to re-register | The state directory is enrolled with a different server. Give this enrolment a fresh --dir of its own (or remove the named directory to abandon that identity). |
registering runner: … registration token invalid | The token is unknown, expired (default TTL 1h) or has exhausted its --max-uses — the server deliberately does not say which. Mint a fresh token. |
the free licence allows 3 runners (3 in use) — apply a licence … | The licence's runner (or runner-group) limit is reached — apply a licence first (lesson 1.5). |
| The Operations area refuses you, superuser included | The server was started with --admin-token/OPSCHAIN_SERVER_ADMIN_TOKEN: the admin plane then authenticates only that static token, never a user session (lesson 0.1). Store the static token (opschain admin login --auth-token …) and mint via the CLI instead, or restart the server without it. |
| No ONLINE tick, LAST SEEN ageing | The runner stopped polling: the process died, or it cannot reach the server's URL — from inside a container, localhost is the container itself (the container gotcha in lesson 6.3). After three silent minutes the estate records warn:runner:aged_out (lesson 6.1). |
Check yourself
- Does
opschain admin runners listshow your runner online in its group? The Academy'srunner-onlineexercise reads theinfo:runner:registeredevent for that group raised since the attempt began (the online state itself is a fleet read the examiner cannot see on this release). - Which command shows the runner online, and what does the runner print when its token has already been used up?
- Verified version:
opschain academyruns therunner-onlineexercise against this lesson.
What you learned
- A registration token carries the enrolment policy and prints once; minting for a new group name creates the group.
- The first start redeems the token and keeps the identity; every later start reattaches without it.
opschain admin runners listis the heartbeat read: online, last seen, job, state.- One job per runner: more members with their own
--diris how you scale. - Every enrolment failure is a named message in the troubleshooting table.
Next: lesson 6.3 — Fleets, groups and placement (opschain learn 6.3), or back to your track (opschain learn).