Skip to main content
Version: v5.7.0

The Academy pack (packs:academy)

packs:academy

OpsChain Academy teaches OpsChain by having you do real work in an OpsChain server of your own, and attests that work from what the server records. The OpsChain Academy agent serves the learning path — tracks, modules and exercises, each with a scenario seeded for you alone — reads the server's state and audit events to decide whether an exercise was done, and seals the result as a signed, metadata-only evidence bundle for the Academy Server hosted by LimePoint, which keeps the ledger and issues the badge. The agent never writes to OpsChain; you do the work through the CLI, the API or the GUI exactly as you would in production, and no quiz answer ever stands in for the record.

packs:academy is the OpsChain packaging of that agent, and the gate on any academy content: it is in the Basic tier (the embedded defaults carry it, and so does the baseline union on the entitlements page, so every tier has it) and unlocks the Foundations track only. Every other track is owned by the pack that ships its surface and opens with that pack's entitlement — what the licence scopes is the curriculum the agent serves, since an exercise about a surface your estate is not entitled to cannot be performed on it.

What the licence unlocks​

The agent reads what the targeted server's licence carries (the licence_status features /api/info reports) and resolves the path against it:

  • No packs:academy — nothing is served: no path, no exercise, and every page names the entitlement that unlocks the academy.
  • packs:academy (the Basic tier and up) — the Foundations track, the platform's own.
  • A pack's entitlement — the track that pack owns. The first pack-owned tracks are change-governance (packs:change-governance), security-governance (packs:security-governance), agent-governance (packs:agent-governance) and agents (packs:agents); each is the seed of its track, and the pack's own content lands there in lockstep with the release that changes the surface.

The learner always sees the whole path: a track whose pack the licence lacks is shown locked with the pack that unlocks it ("Azure — needs packs:azure"), its exercises cannot start and hand out no hints, and the ladder skips it so the tracks after it open as if it were absent. Nothing is hidden, and nothing can be started that the licence does not carry. The gate is the agent's own, read from this server — the launcher adds none, and a licence applied or removed is read back on the agent's next page.

How the agent ships​

The agent is a separate binary, built on the LimePoint Academy Agent SDK in its own repository exactly as every other product's Academy agent is, so that the learning experience and the evidence model are the same across LimePoint products. The OpsChain binary does not embed it. Each agent release is published to the Academy Server's release catalogue — the one place every LimePoint product's agent is served from, to the organisations entitled to it — and opschain academy install resolves the agent through that catalogue, verifies the signed digest and extracts the binary under the OpsChain home directory (academy/bin/), recording what was installed beside it. This keeps a 21 MB agent out of a product binary that most installations never run, lets the agent release on its own cadence, and keeps the installed bytes verifiable against a key the learner already trusts.

How the agent is installed​

Two lanes. The default is the Academy Server; --from is the offline lane for air-gapped estates and development builds.

LaneCommandWhat is trusted
the Academy Server lane (default)opschain academy install --grant-file <grant> (or OPSCHAIN_ACADEMY_RELEASE_TOKEN), [--version x.y.z] [--channel stable|preview]the server's signed catalogue: an Ed25519 signature by the Academy signing key over the document naming each version's archives and SHA-256 digests; the download is verified against that digest, and nothing is written when it differs. The credential — the organisation's registration grant, an installed agent's deployment token or a learner token — decides the entitlement; every download is identified and recorded on the server
the file lane — a release archiveopschain academy install --from <academy-opschain-agent_<version>_<os>_<arch>.tar.gz> (.zip on Windows)the digest committed in this build: the archive is verified against the pin for this platform
the file lane — a built binaryopschain academy install --from <path to academy-opschain-agent>you — a development build or a copy carried onto an air-gapped machine; its digest and origin are recorded in installed.json as version local

The build names the server and the channel it follows (release.json: server, channel; opschain academy show reports them; --academy-server / ACADEMY_AGENT_SERVER override the server for a development stack). The catalogue's newest version on the channel is installed unless an exact --version is asked for. A version its publisher yanked — withdrawn from new installs after a regression, never deleted — is withheld from the channel's newest and refused by name to an unpinned install, but still served to an estate pinning it by exact version (rollback, reproducibility). The signing key is taken from the server (GET /v1/signing-keys) and its id recorded in installed.json; a build that pins the hosted key (signing_key in release.json) refuses a server whose current key differs. The hosted server's key is pinned once the hosted lane is provisioned.

The pin, the floor and the file lane​

The build still carries a pinned release — the version and the SHA-256 digest of each platform's archive — with two meanings: it is the digest --from <archive> verifies against, and the floor the server lane accepts (a catalogue offering only older versions is refused by name; a newer stable is never stopped). A build that pins no release takes the channel's newest through the server, and only a built binary through --from. The pin moves with a product release (scripts/academy-release-pin.sh <tag>, LimePoint's release engineering); an agent version is never re-published or moved — a broken release is followed by the next patch tag, and the broken one is yanked.

Where the agent runs​

The same binary runs in two lanes, and opschain academy serve starts either:

  • Co-located — one agent beside a shared OpsChain server serves a whole team: learners open its pages on the lab network, sign in with their company address, and the agent attests on their behalf with its own deployment key, registered once with the Academy Server through a registration grant. Each learner's exercises are seeded inside a project of their own (/projects/academy_<seed>), so learners on one server never collide.
  • Learner-local (--single-learner) — the agent on your own machine beside your own server; you enrol once from its page and your evidence is signed with a key generated there.

The agent needs two things from OpsChain, and the launcher supplies both from the ordinary CLI context: the server it reads is the targeted server (--server, OPSCHAIN_SERVER or the active context — never local mode, there is nothing to read), and the credential it reads with is a scoped API token the launcher mints under your opschain login session for that server — never the session's own access token, a few hours' credential the agent would outlive. The launcher proves the session first (renewing a stale access token through its refresh token) and refuses an expired login by name; the minted token is academy-agent <label>, lasts 30 days (or the agent's --session-ttl when longer) and is revoked when the agent exits. OPSCHAIN_ACADEMY_TOKEN set by you is used as given, with nothing minted. For a co-located agent that runs unattended, mint an API token for a read-only user (opschain tokens create --expiry 720h) and set OPSCHAIN_ACADEMY_TOKEN: the agent only ever reads, and a credential that could write is a liability it never needs. When the product stops accepting the agent's credential mid-run, the agent says so — the product refused the agent's credential (401) — rather than reporting the licence; restart it through the launcher. The agent's data directory (its store, deployment key and pack cache) defaults to <opschain home>/academy. Every agent flag maps onto an ACADEMY_AGENT_* environment variable; opschain docs cli/academy-serve lists them.

What the exercises need from the server​

Exercises are checked against the server's identity read (/api/me), the node-path reads, the properties and change reads, and the audit events feed. A server on the embedded SQLite store has no users and no event writer — identity and audit-event checks cannot be evidenced on it — so the Foundations pack requires a PostgreSQL-backed server, and the agent says so honestly in its verdicts rather than passing a check it cannot observe. The zero-configuration training posture is a PostgreSQL of your own beside the server (opschain docs storage).

Evidence and privacy​

An evidence bundle carries check verdicts and the identifiers that back them — event ids, types, timestamps, node paths when they carry your seed, principal ids — hashed and signed, chained to the bundle before it. It never carries event payloads, usernames, e-mail addresses or hostnames, and the agent's probe never projects the events feed's username. The Academy Server verifies the signature against the enrolled key, the seed, the chain and the pacing before it counts anything.

The tutor's three lanes​

The agent includes an optional tutor: a model that explains, diagnoses a failed check from the examiner's own verdicts and answers questions. The tutor never grades — a badge is earned only against the deterministic checks — and its model cost is the customer's, never LimePoint's and never the estate's by default. There are three lanes, and the agent starts with the first:

LaneWho paysWhat it is
no model (the default)nobodythe deterministic examiner plus the pack's own hints; slower, never blocked — the agent starts with no model configured and no key anywhere
bring your own providerthe estateopschain academy serve --tutor <model-provider code>: the estate's model-provider catalog supplies the kind and endpoint (Anthropic, OpenAI, OpenAI-compatible — a local model server is an OpenAI-compatible endpoint); the key stays in the agent's environment (ACADEMY_AGENT_TUTOR_KEY, or the variable --tutor-key-env names), held once per agent, never per learner, never read from the catalog
learner-side MCPthe learner, on their own subscriptionopschain academy mcp: the agent exposes a read-only Model Context Protocol server over its standard streams for the learner-local lane's learner — the current exercise and its seeded scenario, the hints, the examiner's last verdicts with their reasons, the path with every locked track named — so the learner's own Claude Code, Claude Desktop or any MCP client tutors them; the conversation never touches the agent

Every bring-your-own-provider turn is redacted of addresses and bearer-looking tokens before it reaches the provider or a transcript, and transcripts are kept per learner in the agent's store. The catalog lane refuses an entry that is disabled or whose data handling the estate has not approved before the agent starts. The platform's brokered model gateway (the key never leaving the server) is an agent-plane lane the Academy agent does not ride: it is not a registered platform agent. The examiner is untouched by all three lanes: whatever is tutoring, only the checks decide. opschain docs cli/academy-mcp shows how a client connects.

Failure modes​

SituationWhat happens
install without an Academy credential (no --grant-file / ACADEMY_AGENT_GRANT_FILE, no OPSCHAIN_ACADEMY_RELEASE_TOKEN)refused by name, naming the three credential classes and the --from lane for an air-gapped machine
install by an organisation not entitled to the agentrefused by name (not_entitled); the server records the refusal; nothing is written
install when the channel's newest was yanked, or --version names a yanked version without pinning itthe channel reports no installable version / the download is refused release_yanked with the publisher's reason; --version <that version> still installs it
the catalogue's signature does not verify, or the server's key is not the one this build pinsrefused by name; nothing is written
the download's digest differs from the signed catalogue'srefused by name; nothing is written
the catalogue's version is below the floor this build pinsrefused by name, naming both versions
the Academy Server is unreachablerefused, naming the server and pointing at --from <archive-or-binary>
install --from with --version, --channel or --academy-serverrefused by name: --from is a file lane
install --from <archive> with no release pinned in this buildrefused by name: the archive cannot be verified, so the built binary is the lane
the archive's digest differs from the pinrefused by name; nothing is written
the archive holds no agent binary for this platformrefused, naming the binary it looked for
serve without an installed agentrefused, naming opschain academy install --grant-file (or --from)
serve in local moderefused: the agent reads a running server
serve without a login for the targeted server and no OPSCHAIN_ACADEMY_TOKENrefused, naming both ways to supply one
serve under a login whose session can no longer be renewedrefused by name before the agent starts: your login for <server> has expired — run opschain login, or set OPSCHAIN_ACADEMY_TOKEN to an API token (opschain tokens create --expiry 720h); nothing is minted
the product stops accepting the agent's credential while it servesthe agent names it — the product refused the agent's credential (401) — never as a licence problem; restart it through the launcher
serve, register, sync or rotate-key without --academy-server and no ACADEMY_AGENT_SERVERrefused by name in the launcher's spelling (the agent's own --server is the OpsChain server here); status and mcp work over the data directory and are not asked for one
the targeted server's licence lacks packs:academythe agent serves no path; every page names the entitlement that unlocks the academy
a track's pack is not on the licencethe track is shown locked, naming the pack; starting it or asking for its hints is refused by name; the tracks after it open regardless
mcp over a shared (co-located) agent, or before a learner enrolledrefused by name: the lane serves the learner-local lane's one learner
the launcher receives SIGINT, SIGTERM or SIGHUPrelayed to the agent (a hangup as a termination), which shuts down on its own terms and flushes its queue; the launcher waits, kills the agent after 30 s if it is still running, and never exits ahead of it
the agent exitsits exit status is this command's (128 plus the signal number when a signal ended it)

See also​

  • opschain docs cli/academy — the command family.
  • opschain docs cli/academy-mcp — the learner-side tutor lane and how a client connects.
  • opschain docs entitlements — the Basic tier and the baseline union that grant packs:academy.
  • opschain docs model-providers — the catalog academy serve --tutor reads.