opschain packs fetch
Included from Basic tier
opschain packs fetch [name ...]
Reads .opschain/packs.yaml in the current repository and resolves
every declaration that names a git source — remote: or url: with
rev: — into the local pack cache, or only the names given. Afterwards
a local run mounts those packs from the cache with no network: the verb
is the one deliberate fetch, and re-running it is how a branch rev:
moves.
For each declaration:
- The source.
url:is used as written.remote:names one of the repository's own git remotes (git remote -v) — the local twin of a server's project-configured remotes — and resolves to that remote's fetch URL. The fetch uses the git on your PATH with its credential helpers disabled (the engine's isolated git environment): a public remote, afile://path or an SSH remote served by your agent works; a remote that needs an HTTPS credential helper does not. - The rev. A branch or tag is fetched into the home's mirror of the remote and resolved to its current commit; a full commit SHA the mirror already holds resolves offline. The result is one exact commit.
- The tree is extracted into
<opschain home>/packs/<name>/<sha>through a staging directory, so a half-written entry never serves a run. A commit already cached is kept (cachedin the status column). - The manifest. A pack manifest at the tree's repository root
(
.opschain/pack-manifest.json) is verified exactly as a signed bundle is — signature against the product keyring, then the entitlement it requires against the licence files in the home. A manifest that does not verify is refused by name and nothing is cached — stricter than a server, which runs such a pack ungated with a warning event — because a local fetch is a deliberate act and a pack whose signed identity does not verify should never land on disk unnoticed. A tree without a manifest is cached and runs ungated (unsigned). - The index
<opschain home>/packs/<name>/index.jsonrecords(source, rev) → sha, the mirror the step checkout materialises from and the verified manifest identity. A local run looks its declaration up there and refuses by name when it is missing.
At run time the mount re-verifies the cached manifest (signature and
entitlement) before anything runs, reads the compile's action files from
the cached tree, and materialises the step checkout from the mirror at
the pinned commit — the same materialisation a server run uses. The
path: key selects a pack root inside a monorepo, exactly as on a
server. A pack's own .opschain/packs.yaml dependencies are not
fetched transitively — declare each pack a local run needs in the
repository's own file.
Output
A table, one row per declaration fetched: NAME, SOURCE (credentials
scrubbed), REV, SHA, MANIFEST (the verified pack identity, or
unsigned), STATUS (fetched or cached) and CACHE (the tree's
directory). -o json prints the same rows (name, source, rev,
sha, path, cache_dir, manifest, fetched). A repository whose
packs are all bundled, bundle: or installed: prints
no git-sourced pack declarations (remote:/url:) to fetch.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Every selected declaration is in the cache. |
| 1 | A declaration failed to resolve, verify or cache (nothing after it is fetched), or the command itself failed. |
Named errors
no .opschain/packs.yaml in <repo> — nothing to fetch …..opschain/packs.yaml declares no pack "<name>" (declared: …)— a name the file does not carry.pack "<name>" resolves from <the release's bundled snapshot | the signed bundle file … | the installed pack store (…)> and needs no fetch— a named declaration that is not git-sourced.pack "<name>": remote "<remote>" is not a git remote of <repo> …—remote:names no remote of the repository; add it withgit remote add, or declareurl:.pack "<name>": rev "<rev>" does not match a Git revision (branch/tag/commit) in <source>.pack "<name>": resolving rev "<rev>" in <source> failed: …— the fetch itself (network, authentication, host key), classified.pack "<name>": its pack manifest (.opschain/pack-manifest.json) does not verify against the product keyring: …— refused; nothing cached.- The entitlement refusal — pack, entitlement and remedy — when a verified
manifest requires a
packs:<name>entitlement the home's licence files do not grant (opschain docs entitlements). packs fetch is repo-scoped and runs locally — it has no remote form; run it in the repository (or pass --local)— a server target.
A local run that reaches an unfetched declaration fails before anything
runs with pack "<name>" (<source> at <rev>) is not in the local pack cache — run opschain packs fetch once (it needs the network); local runs mount git-sourced packs from the cache only; a cache entry whose tree or
mirror has been removed names the re-fetch the same way.
Examples
Declare a pack by git source and fetch it once:
# .opschain/packs.yaml
packs:
- name: tools
url: https://github.com/example/opschain-pack-tools.git
rev: v1.4.0
opschain packs fetch
NAME SOURCE REV SHA MANIFEST STATUS CACHE
tools https://github.com/example/opschain-pack-tools.git v1.4.0 3f2a9c… unsigned fetched /home/alice/.opschain/packs/tools/3f2a9c…
Then run offline (opschain run tools:lint, with the environment flag as
usual — opschain docs cli/run).
In CI, fetch in the job's first step and run in the next; a commit rev:
already in the mirror resolves with no network at all.
See also
opschain docs cli/packs— the family.opschain docs pack-store— how a server resolves, pins and gates packs.opschain learn 2.4,opschain learn 2.6.