Skip to main content

OTA updates & versioning

A Kog device has two independently updatable layers, and that split is what makes updates fast and safe:

LayerContainsTypical sizeUpdated by
App bundleYour compiled app (bytecode + assets refs)tens of KBkog deploy
Runtime firmwareLVGL, JS engine, Kog host, driversa few MBkog flash (occasional)

Day-to-day, you only ever ship app bundles.

App bundle updates​

npx kog deploy # over USB: builds and installs via the OTA path (signed when a key is configured)

kog deploy builds your app (and signs it, if you've configured a signing key; see Signing), then stages it to the board over the USB dev-link. The bundle is written to a staging partition, verified (integrity hash, Ed25519 signature check, and ABI check), and armed. On the next boot it runs as a trial: the runtime promotes it only after it runs healthily for 10 event-loop ticks spanning at least 500 ms with no uncaught exception. A trial that throws first is never promoted, and the next boot falls back (see the caution below about restoring the previous app). A bad deploy can't brick a device: kog flash always recovers it.

Because OTA install doesn't itself reboot, kog deploy resets the board for you after staging so the new app boots immediately. Pass --no-reset to leave the running app in place; it boots the new bundle on the next manual reset.

Deploy is USB-only — there is no Wi-Fi code-push path. (Wi-Fi on the device is for your app's own networking, not for pushing code.)

Development vs. production posture​

kog deploy puts the board in production posture: as it stages the bundle, the firmware writes dev_mode=0 to NVS, so the deployed app boots standalone with the hot-reload dev-link turned off (the full RAM goes to your app). This is the mirror of kog flash, which leaves the board in development posture so kog dev can hot-reload it. To go back to developing on a deployed board, run kog flash again.

Failed-trial recovery (known issue, fix planned right after this release)

The deploy happy path (stage → trial-boot → confirm → promote) is validated on hardware. But if a deployed app fails its trial boot, the board self-heals to a safe state (production posture, hot-reload off), and the previous app may not be restored. Recover with kog flash, which restores development posture (and dev mode). A focused fix for the failed-trial recovery path is planned right after this release.

Stdlib fingerprint is cross-artifact consistent

The device firmware and the in-browser/CLI bytecode producer compute the same stdlib fingerprint for a given generation. (The value changes whenever the stdlib's atom table does.) The fingerprint hashes only the pointer-free atom-string prefix (excluding the link-address table entries that used to make the xtensa and wasm32 builds differ), so device and producer agree. The generation handshake (spec/16 §8.7.1) uses it: kog dev compares the device's hello fingerprint with the producer's before each push, and the browser dev-link does the same when it connects. A mismatch is refused with a reflash hint. Engine selection itself still uses the bytecode version.

The ABI contract​

Your app bundle is compiled against a specific runtime ABI: the versioned vocabulary of widgets, properties, and host functions. The rule: bundle ABI must exactly match device ABI.

You can't get this wrong accidentally:

  • kog dev/deploy query the device's ABI before pushing and refuse a mismatch. To fix one:
    • Device older: reflash the board's runtime with kog flash. This rewrites the board's NVS settings (dev mode, plus Wi-Fi from your kog.config).
    • Device newer: update your CLI with npm i -D kog@latest.
  • The device independently re-verifies at install and at boot.

Runtime releases only bump the ABI on breaking protocol changes. Many runtime versions share an ABI, so reflashing the runtime with kog flash is an occasional event, not a routine one.

Signing​

App bundles can be Ed25519-signed. A development board is keyless: kog flash provisions no OTA public key, so per spec/05 §2 the board accepts unsigned bundles. kog deploy pushes unsigned by default, which keeps the dev loop frictionless. For production, provision the board with your OTA public key and configure the matching signing key (kog.config ota.signingKey, KOG_SIGNING_KEY, or --signing-key); kog deploy then Ed25519-signs the bundle and the board refuses unsigned or foreign bundles.