Lynx Lua scripting

Guide

Bundles and the manifest

A local script is one .lua file. A marketplace script is a bundle: a zip that holds a manifest.json, the entry file and any other files the script needs. The backend signs the bundle when it is published, and the device verifies that signature before it loads anything.

manifest.json

{
  "name": "shot-logger",
  "version": "1.2.0",
  "author": "sam",
  "capabilities": ["math"],
  "deps": { "sam/vectors": "2.0.1" },
  "entry": "script.lua"
}
Field Meaning
name The bundle name. Letters, digits, - and _.
version Semantic version, three numbers.
author Your marketplace author name. author/name is the bundle’s identity.
capabilities The gated capability groups the script uses. A gated global not listed here is nil. See Capabilities.
deps Libraries the script requires, each pinned to one exact version. See require and pinned dependencies.
entry The file that runs. Usually script.lua.

The runtime reads capabilities from the manifest and installs exactly those gated groups. A loose local development script is granted every group instead.

Reserved paths

A path inside the archive is refused when it:

  • starts with / or a drive letter,
  • contains ..,
  • is manifest.json in any directory other than the root,
  • collides with another entry after case folding.

Every bundle installs into its own directory, so two bundles cannot overwrite each other’s files.

Signing

When a version is published the backend hashes the archive with SHA-256 and signs the hash with the current signing key. The signature and the key id travel with the bundle. Keys rotate; an old key stays valid for verifying bundles signed while it was current.

Verification on the device

Before a bundle loads, the runtime:

  1. checks the signature against the key id’s public key,
  2. checks the archive hash matches the signed hash,
  3. reads the manifest and refuses any reserved path,
  4. resolves every dependency and verifies each one the same way,
  5. compiles the entry file as text.

A bundle that fails any step does not load, and the tab shows why. A modified bundle fails step 2.

No bytecode

Only text source compiles. A .luac file, or a file that starts with the Lua bytecode signature, is refused at compile time whether it is local or in a bundle. string.dump is removed, so a script cannot produce bytecode either.