This folder is the catalog: the list of apps OpenPortal can install on a Meta Portal. It is data, not code, so you can add an app with a pull request and no code change. The app reads this folder at build time.
catalog/
index.json display order + featured pins
_template/app.json copy this to start a new app
apps/
<app-id>/
app.json the app's entry (required)
openportal.js a bundled setup program (only for kind: "sandboxed")
upstream/ vendored snapshot for a first-party program (rare)
- Copy
_template/app.jsontoapps/<your-app-id>/app.jsonand fill it in. - Add your
<your-app-id>toindex.jsonorderwhere you want it to appear. - Open a PR. Run
pnpm lintandpnpm buildfirst.
id is the folder name (kebab-case, unique). Prefer open-source apps and
official download sources. OpenPortal only uses public ADB commands, so do not
submit apps that need root, exploits, or that violate the device owner's terms.
| Field | Required | Notes |
|---|---|---|
id |
yes | Matches the folder name. |
name, packageName, description |
yes | packageName is the exact Android package. |
category |
yes | launcher, store, media, photo, smartHome, assistant, utility. |
version |
yes | Display version; "latest" if resolved at install time. |
source |
no | Where the APK comes from: github, fdroid, url, morphe, external. Omit it when a program drives the install (e.g. a launcher). |
repo |
for github |
owner/repo. Required for github (APK from its releases); for any source it also renders that repo's README on the detail page. |
assetPattern |
no | github only: case-insensitive regex to pick the right APK when a release ships several. |
apkUrl |
for url |
Direct APK URL. |
iconUrl / iconFile |
no | Remote icon URL, or a bundled public/app-icons/<packageName>.png ("iconFile": true). |
advancedOnly |
no | true restricts the app to Advanced mode. |
skipUpdateCheck |
no | true suppresses the update check when upstream versioning is unreliable. |
requires |
no | Package names this app depends on. |
program |
no | Setup beyond a plain install. See below. |
Curation lives in index.json, not the app files: order is the display order
and featured lists the ids pinned to the "Made for Portal" section.
A program is the escape hatch for anything an app needs past a plain install,
and it is data (a JSON block plus, for the sandboxed kind, an openportal.js). Two
kinds:
{ "kind": "commands", "commands": [...], "auto"?: bool, "labelKey"?: "..." }— declarative shell.auto: trueruns them silently right after install. The kind most apps should use; needs no code.{ "kind": "sandboxed", "repo"?: "owner/repo", "trust": "first-party" | "verified", "handlesInstall"?: bool, "revertOnUninstall"?: bool }— a JavaScript program run in a sandboxed worker that declares its own UI (a manifest form, presentation, a result view). A first-party program is bundled asopenportal.jsin this app's folder (omitrepo); a partner ships one in their own repo (a bundledopenportal.jsis the offline fallback). Seedocs/programs.mdandsdk/.trust(first-party/verified) is enforced at review time, do not claimverifiedfor an unvetted repo.