:: In active development. Codebase tracks the dev branch. Explore at your own risk. Official release coming soon.
Skip to content

Updating a Project

A built project is a frozen snapshot. vesl-nockup reaches it through several independent channels, and none of them auto-propagate — an update is pulled, not pushed. Cargo.lock freezes the Rust graph, the template files are your copies, and app.hoon is yours. A vesl-nockup release changes nothing in a built project until you reinstall the nockup-graft binary, run nockup package install, or run cargo update.

What an update reaches

ChannelCarriesReaches the project via
nockup-graft binarythe graft composerre-running cargo install --git … --bin nockup-graft
zkvesl/vesl-graft packagethe Hoon graft library under hoon/lib/nockup package install
vesl templatescaffold files (Cargo.toml, build.rs, main.rs, app.hoon)only nockup project init — never an existing project
Bundled crates (vesl-core, vesl-hull, vesl-test)the Rust SDKgit-deps in Cargo.toml, frozen by Cargo.lock until cargo update
Pins (NOCK_PIN, VESL_CORE_PIN, VESL_WALLET_PIN)the nockchain and vesl-core revs baked into a scaffoldtemplate Cargo.toml revs, set once at scaffold time

The vesl template channel never re-touches a project once it is scaffolded. The nockup-graft binary and the vesl-graft package update on separate schedules and are not version-locked — update both in the same pass so the composer and the manifests it reads stay in step.

The update sequence

Run from the project root, in order.

  1. Commit or stash all work. nockup graft update rewrites app.hoon; an isolated diff is reviewable, a mixed one is not.
  2. Snapshot live state. For a running deployment, vesl-checkpoint::snapshot the kernel before recompiling. See State & Snapshots.
  3. Update the composer:
    bash
    cargo install --git https://github.com/zkvesl/vesl-nockup --bin nockup-graft --force
    Do this first — nockup graft update cannot replace its own running binary, and stops with this instruction if the refreshed library needs a newer one.
  4. Run the update:
    bash
    nockup graft update hoon/app/app.hoon
    One verb for the recomposition: it runs nockup package install, previews the recomposition with the nockup graft doctor health report, prompts for confirmation, then writes via inject --apply. Read the preview before pressing y — a hand-edited-block finding means a customization inside a banner pair is about to be overwritten. --yes skips the prompt for CI.
  5. Reconcile Cargo.toml. A pin bump changes the nockchain and vesl-core revs the project should resolve to. The nockup package install that step 4 runs re-applies vesl-graft's [[patches]]; confirm the [patch] block agrees, then cargo update -p vesl-core rather than a blanket cargo update.
  6. Recompile:
    bash
    ./compile.sh
    compile.sh wraps hoonc and fails loud if hoonc exits 0 with no jam written.
  7. Rebuild: cargo +nightly build. The scaffold's build.rs re-runs nockup graft doctor, so a residual finding shows up in the build output.
  8. Resume. After a snapshot, vesl-checkpoint::resume from the new out.jam, then re-poke to restore state — resume reinitializes graft state to per-graft defaults.
  9. Re-run the lifecycle suite with vesl-test to confirm the kernel still behaves.

nockup graft update absorbs the old install/preview/apply trio. Driving nockup graft inject --apply by hand still works when you want composition without the orchestrator.

Re-injection is not a merge

nockup graft inject owns the region between each :: graft-inject:<graft>:<marker>:begin and :end banner pair. Every --apply — and every nockup graft update — strips that region and re-emits it from the manifest. It does not merge.

Edits inside a banner pair are discarded

Domain code added at the :: nockup:* markers but outside any banner pair — causes, peeks, ?- arms — survives a re-inject untouched. Code typed between a graft's begin and end banners does not: the next re-injection overwrites it, whether or not the manifest changed.

The common trap is replacing a verification gate by editing the gate body inside a %settle-* arm. That arm lives inside the settle-graft:poke block, so the next re-injection reverts it to the default hash gate. Change the gate through [graft.gates] in the manifest instead — see Swapping a Gate.

nockup graft doctor flags a hand-edited block before it is lost — it runs on every cargo build (the scaffold's build.rs invokes it) and in nockup graft update's preview.

The inverse case — a local edit to a graft library file (<name>-graft.hoon) that leaves inject reporting injected 0/N; skipped … but ./compile.sh still bakes the edit into out.jam — is covered in Inject → Manifest SHA vs Library Edits. Manifest TOML edits drive re-inject; library Hoon edits drive re-compile only.

When an update breaks the build

Update-time failures are catalogued in Common Pitfalls. The ones an update specifically provokes:

SymptomCause
hoonc exits 0, no out.jama newer graft library pulled a Hoon import the project's frozen hoon/common, hoon/dat, or hoon/jams subset doesn't satisfy — refresh those trees from a vesl-nockup checkout
hoonc fails mint-lost / -lost %<tag>the composer and the manifests are out of step — re-run steps 3 and 4 together
cargo build fails on ibig / UBiga pin moved; the [patch] block no longer matches the nockchain rev vesl-core resolves to — realign it (step 7)
poke returns Ok(vec![]), stderr slog: invalid causethe kernel re-composed with a renamed cause-tag the hull still calls by its old name — update the hull, and guard future renames with assert_kernel_cause_tag!
post-resume pokes emit nothingthe snapshot predates a graft-composition change — see Manual Migration
nockup graft inject / update errors manifest schema too newthe graft library declares a newer manifest schema than the installed nockup-graft — update the binary (step 3) and re-run

See Also