Vendor a dependency closure for an offline build
Lock a dependency closure with aontu sync and commit aontu_meta/vendor/ so a build resolves every import with no network at all.
Rendered from
docs/how-to/vendor-a-dependency-closure.md
in the engine repository, where a correction belongs, and where the
test suite executes every example on this page.
An @"…" import whose first segment carries a dot is a module import
rather than a file path, and modules resolve from local stores only:
evaluation never reaches the network. The stores are aontu_meta/vendor/
in your project and a user cache keyed by canon-hash. aontu sync is
the verb that fills both; a synced project evaluates with neither a
cache nor a network, which is what this guide is for.
Declare the dependency in the project’s pkg.aon:
pkg: { path:"corp.example/app" main:"main.aon" }
dep: "corp.example/schemas/service": v: "1.4.2"
and import it from the entry file, main.aon:
svc: @"corp.example/schemas/service"
svc: name: "auth"
The package itself is an ordinary source tree with its own pkg.aon
and entry file. Here it already sits in the vendor tree, copied by hand
from the platform team’s repository, which is its own guide:
vendor a module by hand. Its
aontu_meta/vendor/corp.example/schemas/service/pkg.aon:
pkg: { path:"corp.example/schemas/service" version:"1.4.2" main:"service.aon" }
and its entry,
aontu_meta/vendor/corp.example/schemas/service/service.aon:
name: string
port: *8080|integer
sync resolves the closure, fetches nothing it already holds, writes
the lockfile and verifies every pin; evaluation then needs nothing
outside the project directory:
$ aontu sync
verdict: ok
corp.example/schemas/service 1.4.2 aon1-oQs6Ng6XxP2FHQGTYescREGDrDPfLLW1Liq4OS8Gs2E
$ aontu main.aon
{
"svc": {
"name": "auth",
"port": 8080
}
}
The default filled and the schema held, all from the vendored tree.
The lockfile sync wrote is one canonical, diffable, JSON-parseable
line:
# pkg-lock.aon (generated by `aontu sync`; do not edit)
{"lock":{"corp.example/schemas/service":{"archive":"sha256:f0e8…","canon":"aon1-oQs6Ng6XxP2FHQGTYescREGDrDPfLLW1Liq4OS8Gs2E","v":"1.4.2"}}}
The canon pin is the module’s meaning, recomputed and compared on
every later evaluation (vendor by hand shows what
that catches); archive is the digest of the tree’s canonical archive,
which aontu pkg verify compares before it evaluates anything. A
package acquired from a repository carries a third pin, manifest, the
digest of what its publisher signed. Commit aontu_meta/pkg-lock.aon
and aontu_meta/vendor/ together: that pair is the offline build, the
tree to bake into a container image, an air-gapped checkout, or an
agent sandbox.
In CI, freeze
sync is idempotent, so running it in CI is safe; what CI must not do
is let it rewrite the lockfile without anyone noticing. --frozen
resolves and fetches what a locked version needs, and refuses when the
lockfile would change. Add a dependency to pkg.aon without syncing:
pkg: { path:"corp.example/app" main:"main.aon" }
dep: "corp.example/schemas/service": v: "1.4.2"
dep: "corp.example/schemas/common": v: "1.0.0"
$ aontu sync --frozen
verdict: frozen
lockfile would change: corp.example/schemas/common: unlocked -> 1.0.0
$ echo $?
1
Nothing was fetched and nothing was written: the refusal came before
the first request. A pin that would move says repinned, and a
dependency that left the package file says dropped. Run sync
without the flag where the lockfile is meant to change, review its
diff like code, and let CI hold the result.
aontu pkg verify is the narrower gate: it checks every pin against
the stores and reaches for nothing, which is what to run beside the
tests when the project is already synced (validate in CI
is the surrounding job). The verbs’ full contract is
aontu sync and
aontu pkg; the module resolution
rules are in the language reference.
Publishing the package a consumer syncs is
publish a package, and the live version (cold
start through tamper, confinement, a local repository and the publish
gate) is use-cases/11-shared-modules.