Lock and sync
Two commands sit under everything else. nsx lock decides what the app depends on and
writes it down. nsx sync makes modules/ match what was written down. Keeping them
separate is what lets a build be checked without being changed.
nsx configure runs both for you: it locks if there is no nsx.lock, then syncs. You only
reach for them directly when you want one without the other, which is most of the time in
CI.
What nsx lock writes
Section titled “What nsx lock writes”nsx lock walks the graph from the board’s baseline plus your declared modules, resolves
every dependency, and records the result per target board in nsx.lock.
Each module gets a project, a kind, the constraint it was resolved from, and a
resolved block. For a git-backed module that block carries the URL, the tag, the exact
commit and a content hash of the tree at that commit. The lock also records the NSX
version that wrote it and a hash of the nsx.yml it read, which is how drift is detected
later.
Five kinds appear, and they differ in where the content comes from:
| Kind | Source of truth | Re-fetched by sync |
|---|---|---|
git |
A repository at a resolved commit | Yes |
packaged |
A source tree shipped inside the NSX package | Yes |
local |
An external directory you named with source.path |
Yes, mirrored |
vendored |
modules/<name>/ in your own repository |
No |
unresolved |
Last known content, when upstream could not be reached | No, hash verified |
Because resolution happens per board, two targets on different SoC families can legitimately
land on different module sets in the same lock file. The full schema is on the generated
nsx.lock reference.
Pinning a module
Section titled “Pinning a module”By default a module resolves to whatever revision NSX’s registry pins for it. To hold one
module somewhere else, give the entry a revision in nsx.yml:
modules: - name: nsx-audio revision: v0.4.1revision accepts a tag, a branch or a commit. NSX resolves it through the remote at lock
time and records the commit it landed on, so the lock is exact even when the constraint is
not:
- A commit is already exact. It resolves to itself and never moves.
- A tag is exact in practice. It resolves to the commit the tag points at, and it is recorded alongside the commit so the lock says which tag you asked for.
- A branch is a moving constraint. It resolves to the tip at lock time, and re-running
nsx lock --updatemoves it. Between updates the lock still pins a single commit, so the build does not shift underneath you.
Pin a branch only when you are tracking something you also control. nsx outdated is the
tool for noticing that a pinned module has fallen behind, rather than a floating ref that
moves without telling you.
What nsx sync does
Section titled “What nsx sync does”nsx sync reads nsx.lock and makes modules/ match it. It never writes the lock: if
syncing could change what you depend on, the split between the two commands would be
pointless.
It is idempotent and cheap on the second run, because it hashes what is already on disk
and skips anything that matches. --force re-vendors every fetchable module regardless.
Checking without changing
Section titled “Checking without changing”Three flags turn this pair into a build check.
nsx lock --check # report manifest and resolution drift, write nothingnsx sync --frozen # fail if modules/ differs from the lock; fetch only what is missingnsx outdated --exit-code # fail if a git module lags its upstreamnsx lock --check is read-only. It prints what would change and exits non-zero if
anything would, which catches an nsx.yml edit that was never locked.
nsx sync --frozen refuses to correct. Every form of drift becomes an error naming the
module:
Vendored module 'my-sensor' content drifted from lock ...Local source for 'my-sensor' at /home/you/src/my-sensor has drifted ...Module 'my-sensor' at modules/my-sensor does not match nsx.lock ...A module that is missing, as on a fresh clone where modules/ is gitignored, is not drift.
--frozen fetches it at the commit in nsx.lock (git modules need network access) and fails
if its content hash differs from the lock. The same holds for the cmake/nsx tree that ships
with neuralspotx: after upgrading neuralspotx, run nsx lock once before using --frozen.
--frozen is also accepted by configure, build, flash and view, where it applies
to the implicit sync those commands would otherwise perform.
Updating on purpose
Section titled “Updating on purpose”nsx outdated # what has moved upstreamnsx lock --update # re-resolve everything to upstream tipnsx lock --update --module nsx-audio # re-resolve one modulensx update # re-resolve and sync in one stepnsx outdated only reports on git-backed modules, because a packaged or vendored module
has no upstream tip to compare against. It tells you which modules it skipped and why, and
--json gives checked, skipped and outdated_count for a script.
nsx update is lock --update followed by sync. It prompts before changing the lock
unless you pass --yes.
Review the diff to nsx.lock before committing an update. It is the only record of what
your firmware is built from.
When upstream is unreachable
Section titled “When upstream is unreachable”If a module’s remote cannot be reached during a lock, NSX records the module as
unresolved and keeps the last known content hash rather than dropping it. The app still
builds from what is on disk, and the lock says plainly that the entry was not confirmed
against upstream. Re-run nsx lock with network access to resolve it properly.