The .arda
package.

One file containing your entire application, signed so a device can prove where it came from and encrypted so the machine it sits on can't read it. This page describes what's inside and the order the runtime checks it.

In progress — the runtime verifies this format; packages are produced by the control plane at deploy, which is being built

Why a package at all

The alternative is a directory of files on the device's disk. That's fine when you own the machine. It stops being fine the moment the machine is on a customer's counter, because a directory of JavaScript is a directory of JavaScript — readable, copyable and modifiable by anyone with ten minutes and a USB stick.

A package gives you three things a directory can't: proof of origin (nobody can substitute a modified application), confidentiality (your business logic isn't sitting in plain text on hardware you don't control), and binding (a copied package won't run somewhere you didn't authorise).

Structure

A .arda file is a container with a small cleartext header followed by an encrypted payload. The header carries only what the runtime needs to decide whether to proceed — never anything about your application's contents.

layout
┌─────────────────────────────────────────────┐
 magic          "ARDA" + format version          cleartext
 header         key id · binding mode · nonce   cleartext
 signature      ed25519 over header+payload     cleartext
├─────────────────────────────────────────────┤
 payload        aes-256-gcm                   
   ├── manifest    arda.json                    encrypted
   ├── index.html                                encrypted
   ├── assets/…                                  encrypted
   └── integrity    per-file digests             encrypted
└─────────────────────────────────────────────┘

The payload is decrypted into memory at load. It is not unpacked to disk, so there is no window during which your application exists as readable files on the device.

Manifest schema

arda.json lives at the root of your project and is embedded in the package at build time.

FieldTypeRequiredMeaning
namestringyesApplication identifier. Lowercase, hyphenated.
versionstringyesSemantic version. Informational — releases are identified by ID and hash.
entrystringyesPath to the entry HTML, relative to root.
rootstringnoDirectory to package. Defaults to the project root.
buildstringnoShell command run before packaging.
capabilitiesstring[]noDevice capabilities the application may use. Empty means none.
bindstringnodevice, installation, account or none. Default account.
kioskobjectnoSurface options — cursor visibility, idle blanking, orientation.
ignorestring[]noGlob patterns excluded from the bundle.
fleetstringnoDefault fleet, written by arda link.
channelstringnoDefault channel for arda push.
!
Exclude your source maps "ignore": ["*.map"] should be in almost every manifest. Encrypting a bundle and then shipping the source map beside it defeats the exercise.

Capabilities

Capabilities are declared at build time and enforced at load. An undeclared group is not present on the arda object at all — not a method that throws, but undefined. That distinction matters: a bug or a compromised dependency cannot call something that doesn't exist.

CapabilityGrants
dbarda.db() — encrypted local key/value stores.
storagearda.storage — scoped file storage.
syncarda.sync — the server bridge. Without it the app is fully offline.
net:statusRead connectivity and interface state.
net:wifiScan and join Wi-Fi networks, store credentials.
usb:readEnumerate USB devices and receive attach/detach events.
printerDiscover and print, including raw ESC/POS and drawer control.
cameraOpen cameras, capture stills and scan codes.
faceLocal face detection, enrolment and matching.
gpioDigital I/O on boards that expose it.
audioDevice-level playback and volume control.
system:powerarda.system.reboot(). Deliberately separate from the rest of system.

arda.system.info(), arda.system.log() and arda.app are always available and need no capability.

Signing and encryption

Two operations, in this order, both performed by the control plane when a release is deployed:

  1. Encrypt — the payload is encrypted with AES-256-GCM under a content key. The GCM authentication tag means any modification to the ciphertext is detected on decryption.
  2. Sign — an Ed25519 signature is computed over the header and the encrypted payload with the signing key held for your account. This proves the package was produced by ArdaForm for your account, and that nothing has altered it since.

The control plane packs, signs, stores and distributes the bytes. What the signature establishes is therefore that a package came from ArdaForm for your account and arrived unaltered — not that it was produced on a machine of yours. A device already trusts the control plane end to end: it pins that key at enrolment and fetches every byte through it, so this adds no party it was not already relying on.

Device binding

The bind field decides how portable the package is. Binding is enforced by the runtime at load, using values derived from the machine rather than supplied to it.

ModeRuns onUse when
noneAny device with the right keyDevelopment, demos, internal builds.
accountAny device registered to your accountThe usual choice. Devices can be swapped without repackaging.
installationDevices registered to a named installation or customerPer-customer licensing, where a package must not move between customers.
deviceOne specific device IDHigh-value deployments where a copied package must be worthless.
i
Trade-off Tighter binding means more repackaging when hardware changes. device binding is genuinely strict: replace a failed motherboard and the device ID changes, so the package must be reissued. Most fleets want account or installation.

Verification order

Every check must pass before the application is allowed to run. Failure at any step means the package is discarded and the previously staged release keeps running — a bad package cannot take a device out of service.

on the device
1  magic and format version recognised           else UNSUPPORTED_FORMAT
2  SHA-256 matches the update instruction        else HASH_MISMATCH
3  Ed25519 signature valid for the key id        else BAD_SIGNATURE
4  binding mode satisfied by this device         else NOT_BOUND
5  AES-GCM tag verifies on decrypt               else DECRYPT_FAILED
6  manifest parses and entry file present        else BAD_MANIFEST
7  per-file integrity digests match              else INTEGRITY_FAILED
8  capabilities resolved and bridge scoped       load

The failure code is reported back to the control plane in the update status, so a rollout that fails on a subset of devices tells you why rather than merely that.

Key management

There is no key for you to generate, store or lose. A signing key is created for your account the first time you deploy, and the control plane holds it.

  • One key per account. Every package deployed for you is signed with it, and your devices trust it from enrolment onwards.
  • You never see the private half, so it cannot leak from a repository, a laptop or a CI secret store — which is where signing keys are usually lost.
  • Rotation re-signs future packages. Packages already installed are not retroactively invalidated, and nothing on a device stops working because a key was rotated.
  • The trade is explicit: the signature proves ArdaForm produced the package for your account, not that you produced it on your own machine. If you need the second guarantee, say so — it is a different design and we would rather hear it before you depend on this one.

A separate release key, held by the ArdaPlayer release pipeline rather than by you, signs runtime binary updates. The two are independent by design: neither can be used to forge the other's artefacts.

Limits

LimitValue
Maximum package size256 MB
Maximum files per package65,535
Manifest size64 KB
Capabilities per package32

If you are approaching the size limit with media, put the media in device storage and sync it separately — bundling a gigabyte of video into every release makes every update a gigabyte download on a shop's broadband.