Skip to main content

Applications

The System → Applications page installs, upgrades, removes and builds .gemapp packages — complete, versioned units of GEM configuration that can be moved between installations and installed more than once.

Where Import / Export moves individual artifacts as a one-way JSON bundle, an application is a package with an identity. GEM records everything it created, so it can later be upgraded to a new version or removed cleanly, leaving the rest of the site untouched.

Elevated access required

Every action on this page requires an elevated role. A package can carry custom driver code and web service scripts, both of which execute on the controller — installing one is a code path into your server. See Roles.

What an application is

A .gemapp file contains:

  • a manifest — the package's identity (app_id, version, author), what it requires of the target system, and the settings it asks for at install time
  • its artifacts — devices, zones, UIs, macros, drivers and everything else listed under Contents, in the same form Import / Export uses
  • its assets — theme fonts and images, and anything else that isn't configuration text

Packages are not encrypted. That is deliberate: you should be able to inspect a package before you install it.

Ownership is what makes it an application

When GEM installs a package it writes a ledger of every row it touched, and records each one as either:

  • owned — the install created this row. An upgrade may update it; an uninstall removes it.
  • referenced — the row already existed and the package merely points at it (a subsystem it hung zones from, a widget it re-used by name). Referenced rows are never modified on upgrade and never deleted on uninstall. Somebody else made them.

This is why an application can be removed cleanly and a plain import cannot.

Installing

  1. Go to System → Applications → Install and choose a .gemapp file. It uploads in chunks, so package size isn't limited by the usual message ceiling.
  2. GEM reads the package and reports back without writing anything:
    • identity, version, author and content digest
    • whether the package's requirements are met (GEM version, drivers, licensed features, macro step types) — every unmet requirement is listed at once
    • whether it contains code that runs on the server, and exactly which artifacts
    • any settings the package asks for
    • an item-by-item list of what will be created and what already exists
  3. Answer any settings, choose how existing items should be handled, and click Install.

Handling things that already exist

Each item that collides with existing configuration can be handled three ways:

ChoiceEffect
Use existing (default)The package points at what's already there. The existing row is recorded as referenced and is never touched.
Copy under new nameA parallel row is created with a suffixed name. Nothing existing is changed.
ReplaceThe existing row is overwritten with the package's version. It is recorded as referenced, so a later uninstall will not delete it.

An Already exists badge in the preview is a link — click it to open that record in a reference modal over the wizard and see exactly what Replace would overwrite, without losing the upload, the settings you have answered, or the choices you have already made on the other rows. The same applies to the artifact lists on the install result and on an installed application's detail panel.

Handling things that are missing

A package names its dependencies by name. When it points at something this installation doesn't have — a subsystem, a device, a command set — that item appears under Missing References, and the install is held until each one has an answer:

ChoiceEffect
Use an existing …Pick a record already on this system. The package binds to it and records it as referenced, so uninstalling leaves it alone.
Create itGEM creates a minimal record with that name. Offered only for subsystems, site modes and site spaces — the types where a name is enough to build a usable row. It is recorded as owned, so uninstalling removes it again.

Once you have picked a record for a reference, a check link appears beside the dropdown — it opens the record you chose in a reference modal over the wizard. Picking the wrong row welds the package to it silently, and confirming which amp_1 you just selected should not cost you the upload, the settings you have answered and every resolution already made.

Click Re-check after answering to confirm the references resolve. This is not a warning you can skip: the first unresolved reference stops the install, and everything already written is rolled back.

Licence terms

A package can carry an agreement you have to accept before it installs. It is shown in full, before anything is written, alongside the provenance and the item list.

  • Accepting records your username and the time against the installed application. It is shown on the application's card and in its detail panel, and the agreement itself is kept on that panel so what was accepted can be read back later.
  • The terms are part of the package's signed content. If the package is signed, its terms cannot be altered on the way to you without the signature failing.
  • An upgrade carrying the same agreement does not ask again — you already accepted that text.
  • An upgrade carrying a changed agreement says so and asks again. Accepting the old version does not carry over.

A package may also carry terms marked as not requiring acceptance. Those are shown for information and never block the install.

Packages that run code

If a package contains any of the following, GEM lists each one and requires you to confirm you trust where the package came from before it will install:

  • a custom driver or a web service — both execute on the controller
  • a device script — command and response scripts run every time that device is talked to
  • a macro with script steps
  • a custom widget carrying its own source — compiled on install and then loaded by every operator browser, including the admin session that ran the install. A widget composed in the visual designer carries a layout, not source, and does not count.

The judgement is made on what each artifact actually contains, not on its type, so a widget bundled inside a UI or a page is found the same way a standalone one is. It is also made after the package's settings have been applied, since a setting can decide what a macro step turns out to be.

Treat this the way you would treat running an installer from the internet: a package from an unknown source can do anything your controller can do.

Settings

A package can ask questions at install time instead of hard-coding answers. A well-built package for a conference room asks which amplifier drives this room rather than shipping a device ID that only means something on the machine it was authored on.

Settings render as normal form fields, including catalog-driven dropdowns that list the actual devices, zones or pages on your system. See Building a package for how they are declared.

Secrets — API keys, passwords — are handled separately. They are never stored in the package or on the application record; they are written straight to a secure attribute on this installation, encrypted with this installation's own key. A package can therefore be handed to someone else without handing them your credentials.

A secret can only be written onto a device or zone the package itself created, or onto the application record. A package that asks to put a secret on a row that was already here — an access-control panel, a camera, an alarm transceiver — is refused and the skip is logged, because the install wizard shows a setting by its label and never says which record its answer lands on. Overriding that is a deliberate, separately-granted choice, and the write is recorded when it happens.

Name prefix — installing the same package twice

Packages built by GEM declare a Name prefix setting, and everything the package creates is named under it.

That is what lets the same package be installed more than once on one controller. Install Conference Room AV with the prefix room_a, then install it again with room_b, and you get two complete, independent sets of devices, zones and UI pages that don't collide.

Each copy is tracked separately: it has its own version, its own settings and its own ledger, and can be upgraded or removed on its own.

Upgrading

Install a newer .gemapp with the same package ID. GEM matches the new version's items against what the old one installed and:

  • updates items that exist in both
  • creates items the new version adds
  • removes items the new version no longer ships
  • leaves alone anything you have edited since install, and tells you it did

That last point matters. If you renamed a zone or retuned a macro after installing, an upgrade will not quietly revert your work — it reports the item as changed and skips it. Tick Let the package's version win only when you want the package to take those rows over.

An upgrade also skips anything the application does not own. A row it only referenced — or one that merely happens to share a name with something the new version ships — is reported as not owned by this application and left exactly as it is. That is the same rule uninstall follows, applied to the other direction: a package can only overwrite what it created. Force overrides it when you genuinely want the package's version to take the row over.

Choosing which copy to upgrade

A package installed more than once has one copy per name prefix. When you upload a newer version, GEM lists every copy already installed and you pick the one to upgrade — you do not have to remember the prefix it went on under. Selecting a copy re-reads the settings it was installed with, so its name prefix carries forward and the new version lands on that copy rather than beside it.

If you meant to add another copy instead, choose Install as a new copy and give it a prefix of its own.

If an upgrade fails partway, it is reported precisely rather than rolled back: the previous version's rows are still in place and some of the new ones have landed. Read the result, fix the cause, and run it again.

Removing

Uninstall removes the configuration the application created:

  • items it owns are deleted, children first
  • items it only referenced are left in place
  • items you have edited since install are kept and listed, unless you tick Also remove items I have edited
  • history is never touched — attribute history, monitor history and activity records outlive the configuration that produced them

Any secret the application was given that wasn't aimed at a specific device or zone is stored against the application itself, and goes when the application does — a credential is not left behind attached to nothing. A secret written onto a device or zone follows that item's fate: it is removed with an item the application created, and left in place on one it only referenced.

The retained package file

Installing keeps a copy of the .gemapp alongside the installation. That copy is what the Package button on an application's card downloads, and what lets the application be re-installed or handed on without the original file.

Uninstalling leaves it in place unless you tick Delete the retained package file. Another copy of the same package installed under a different name prefix shares that one file, so it is only removed once no copy is using it.

Forget, keep configuration removes GEM's record of the application but leaves everything it built. Use this when you want to take a package's output over as your own configuration.

Building a package

The Create tab builds a .gemapp from configuration already on this system, in four steps.

1 · Package details

The package ID (reverse-DNS, e.g. com.yourcompany.conference_av), version, name and author. Optionally a minimum GEM version — installs on older systems are then refused up front with a clear message rather than failing partway — a licence label, a description of what installing the package gives you, and an icon (png, jpeg, gif or webp under 180KB) that identifies the application wherever it is installed.

The name, author and description are what the installer sees on the package before deciding to install it.

2 · Contents

Select the items to include. Each row carries an open link — inspect a record before deciding whether it belongs in the package, without losing the selections already made across every other section.

The filter narrows every section at once, and a section's Select all takes only the rows the filter is currently showing. Sections with nothing in them are not listed.

Everything a selected item depends on travels with it: a macro brings its steps, a UI its pages, widgets, controls and macro buttons, a device its attributes and command/response scripts.

3 · Settings the package asks for

This is the step that decides whether you have built a package or a snapshot of this site.

Press Scan selection. GEM reads the artifacts you selected and reports two things:

  • Points outside the package — every reference to configuration that is not included. A zone pointing at main_amp will look for a device called main_amp on the target system and fail if there isn't one.
  • Attribute values — the addresses, ids and credentials travelling with your devices and zones.

Tick any of them to turn it into a question. A reference becomes a dropdown listing the target system's own records of that type; an attribute becomes a text field. Each gets a setting key and a question you can edit.

Both ends of a reference row, and the artifact an attribute sits on, are links into the reference modal — the scan and everything you have already ticked stay behind it. Deciding whether an address or a credential is specific to this site is a question about the whole row it belongs to, not about the one value the scan printed. Composite references (rendered as name (in subsystem)) name no single row and stay plain text.

Tick Secret on an attribute — GEM pre-ticks it for anything that looks like a credential — and the value is removed from the package entirely. The installer is asked for it, and the answer is written straight to a secure attribute on the target, encrypted with their key. That is what lets you hand a package to someone else without handing over your credentials.

Other questions declares a setting that isn't a reference or an attribute. Reference it from an artifact as {{param.your_key}}.

Re-scan whenever you change the contents. If you build against a stale scan, any setting whose target is gone is reported as not applied rather than silently dropped — the package builds, but those values are still hard-coded.

4 · Licence agreement

Paste an agreement to be shown to whoever installs the package. With Require the installer to accept ticked (the default when there is any text) they must tick to continue, and their username and the time are recorded against the installed application.

The text lives in the manifest, which is covered by the package signature — a signed package's terms cannot be altered in transit without the signature failing. Leave it empty for no agreement.

Then build

Click Build Package, then Download. GEM automatically:

  • generates the artifact index from what's actually in the package, so the manifest can never disagree with its contents
  • rewrites the names of everything included to use the Name prefix setting, and rewrites the references between them to match — references to things outside the package are left alone
  • writes the correct dropdown definition for every reference setting, so the installer picks a real record rather than typing a name
  • records which macro step types the package uses, so an older target refuses it up front
  • stamps a content digest over the whole package and signs it

Building from a script

For rebuilding a settled package from CI rather than authoring one, scripts/build_app.js takes the same specification as a JSON file:

# what in this selection is welded to this site, and the bindings to write
node scripts/build_app.js package.json --analyze

# build it
node scripts/build_app.js package.json --out conference_av-1.4.0.gemapp

The spec holds manifest, items and param_bindings — run --analyze first, paste the binding lines it prints, then build. It exits non-zero if any setting could not be applied, so a CI job cannot ship a package that quietly kept your site's values. It connects to the configured database (a package is built from configuration) but does not start a server or load drivers.

What can go in a package

GroupTypes
DevicesCustom Drivers, Command Sets, Device Types, Devices (with attributes and command/response scripts), Subsystems, Zones
AutomationMacros (with steps), Schedules, Triggers, Variables
MonitoringAlarms, Monitors, Monitor Tags, Reports, Notification Profiles
InterfaceUIs (with pages, widgets, controls, zones and macro buttons), UI Pages, UI Widgets, UI Themes
OtherAV Sources, Channel Providers, Web Services, Holiday Calendars, Site Modes, Site Spaces

Custom widget source travels with the widget and is compiled automatically after install. Theme fonts and images travel as package assets.

Versions and identity

  • Package ID (app_id) is the identity used for upgrades. Keep it stable across versions; changing it makes a different application.
  • Version is dotted-numeric (1.4.0). Installing a lower version than the one present is refused; when the wizard detects one it offers an explicit Install this older version option.
  • Item keys are derived from each item's type and its name as authored, before the name prefix is applied. Keeping names stable across versions is what lets an upgrade match old to new. If you rename something between versions, the upgrade removes the old row and creates a new one.

Signing and publisher trust

A package can carry code that runs on your controller with full server privileges. A signature is how you tell where a package came from and whether anyone changed it on the way.

Packages built by GEM are signed automatically. The Publishers tab is where you manage the rest.

Trust levels

Every package is judged when you open it:

LevelMeaning
Published by GEMSigned with the key built into this release.
Verified publisherSigned by a publisher GEM has vouched for.
Trusted publisherSigned by a key you added on this install.
Signed, publisher not trustedThe signature is valid and the package is unmodified — but you have not said you trust whoever made it.
UnsignedNothing proves who made it or that it is unchanged.
Revoked keySigned with a key marked compromised here. Always refused.
Invalid signatureThe signature does not match the contents. Always refused.

The first three are trusted: their packages install their code without asking you to vouch for it. That is the practical reason to sign and to pin.

What a signature actually protects

The signature covers a digest of the manifest, every artifact and every asset. Change one character of one artifact and it stops verifying. The package can be re-compressed or re-packed freely — that does not break it — but its contents cannot be altered without detection.

Two attacks are specifically closed:

  • A signature cannot be lifted off a package you trust and attached to a different one: the package id and version are part of what gets signed.
  • A package cannot carry its own key while claiming a trusted publisher's fingerprint: the fingerprint is recomputed from the key in the package and compared, never taken at face value.

Trusting a publisher

  1. Get the publisher's public key and its fingerprint.
  2. Confirm the fingerprint through a different channel — a phone call, an in-person handover, an existing trusted email thread. This comparison is what the whole thing rests on; a key and a fingerprint that arrive together prove nothing.
  3. Paste the key under Publishers → Trust a Publisher, record how you verified it in the notes, and save.

Their packages then install without the code prompt.

Your own signing identity

The first package you build generates a signing key for this install. Its public half is shown under Publishers → Your Signing Identity; hand it to your customers so their controllers can trust your packages.

The private key lives in .package_signing_key at the install root, readable only by the GEM user, and never in the database or in any backup or export. Treat it the way you would treat a code-signing certificate:

  • Anyone with that file can sign packages in your name.
  • If you lose it, you cannot sign updates to your existing packages — customers will see a new, untrusted key and must pin it again.
  • If it leaks, tell your customers to revoke the fingerprint.

Revoking

Revoke marks a key compromised. Packages signed with it are refused from then on, and the refusal cannot be overridden by acknowledging them — that is the point.

Applications already installed from that key are left running and listed for you. Pulling a site's lighting or HVAC configuration because a signing key leaked would be an outage of your own making; deciding what to do about them is yours.

You do not need to have pinned a key to revoke it. Revoking a fingerprint you have only been warned about pre-empts the package before it ever arrives.

Remove is the milder action — it simply stops trusting a key, without declaring it compromised. Packages from it go back to being installable with a confirmation.

Code policy

Under Publishers → Code From Untrusted Publishers:

  • Ask me (default) — a package carrying drivers, web services or script steps installs if you confirm you trust its origin.
  • Trusted publishers only — code installs only when signed by a publisher on your list. Confirming is not enough.

Switch to Trusted publishers only once your publishers are set up. It is the setting that makes "someone talked an operator into ticking a box" stop being a way onto your controller.

Either way, an invalid signature or a revoked key is always refused.

A note on what signing does not tell you

A signature proves origin and integrity. It does not prove the package is good. A publisher you trust can still ship a package that misconfigures your site — trust means "I know who to call", not "this cannot hurt me". Read the install preview.

See also