Umbrel packaging
September 17, 2026 ยท View on GitHub
Skillbox includes a release-gated package generator for the official Umbrel App Store and optional community stores. It does not install anything on an Umbrel device or submit a PR automatically.
Current release gates
Before other people can install a store package, the release needs:
- Reviewed public source/support URLs and MIT license. Do not publish old private operational history or library data with the application.
- A publicly pullable, version-tagged Skillbox image with a multi-architecture index digest, containing both
linux/amd64andlinux/arm64. - Successful native/runtime testing for both architectures. Multi-arch base images alone do not prove the application runs on both.
- Official repository lint, fresh install, restart, upgrade/persistence and browser/API testing through Umbrel's lifecycle, not merely raw Docker Compose.
- Store review assets: screenshots with synthetic/demo data and the logo source (
public/app-icon.svg). Official Umbrel maintainers host final gallery/icon assets; attach them to the PR rather than committing them into an official app package. - A reviewed submission PR or separately published community-store repository. Store acceptance is a separate maintainer decision.
No image URL or digest is guessed. The generator refuses moving/unpinned image references, images that cannot be inspected without registry credentials, images lacking either required architecture, a non-public project URL, or an existing output directory.
Generate an official-store package
After publishing and testing the image, use its actual multi-arch digest:
bun scripts/package-umbrel.ts \
--image registry/owner/skillbox:VERSION@sha256:INDEX_DIGEST \
--source-url https://public-source.example/project \
--support-url https://public-source.example/project/issues \
--version VERSION \
--out /path/to/new-submission-directory
Requires Bun and Docker Buildx on the packaging machine. Image inspection uses an empty temporary Docker auth config, not the maintainer's registry login. The output contains skillbox/umbrel-app.yml, docker-compose.yml, exports.sh, and empty persistent-data directories. Copy the skillbox directory into a working copy of the official getumbrel/umbrel-apps repository, then:
npm run lint:apps -- skillbox --check-images
The chosen default host port is 4791. Check it against the current store's port inventory; pass --port if reviewers assign another port. The container still listens internally on 4791.
Do not interpret successful generation or lint as a passing Umbrel install. The official test guide explicitly requires actual lifecycle verification. Describe any missing device/architecture test honestly in submission notes.
Community store
Add a unique store prefix and a real publicly hosted icon URL:
bun scripts/package-umbrel.ts \
--image registry/owner/skillbox:VERSION@sha256:INDEX_DIGEST \
--source-url https://public-source.example/project \
--version VERSION \
--store-id example \
--icon-url https://assets.example.com/skillbox.svg \
--out /path/to/new-community-store
This produces root umbrel-app-store.yml and the consistently prefixed example-skillbox/ app. Publish only this generated package tree to the intended public community-store repository. In Umbrel, add that repository URL through Community App Stores. Community distribution is independent of acceptance into the official store.
Publish the actual public/app-icon.svg as an accessible asset. Gallery screenshots can be added after capturing the tested app; do not use placeholder artwork or private user content.
Runtime behavior
app_proxystays enabled for the UI. Only/api/*,/mcp,/cli/*and/bootstrap/*bypass Umbrel proxy auth so bearer-token clients and installers work. Skillbox still enforces its own authentication on protected API/MCP routes; login and static bootstrap/CLI files remain intentionally public.APP_PASSWORDbecomes the Skillbox owner login key, surfaced by Umbrel's app-password UI throughdeterministicPassword: true. It is not logged, hardcoded or used as a provider API key.- PostgreSQL gets a separate deterministic, purpose-specific secret from
derive_entropy, scoped usingEXPORTS_APP_ID. It is not regenerated on restart/update. - No provider key is supplied by the package. Select TypeSafe AI or Vercel AI Gateway and add its own key in Skillbox Settings if you want Jev.
- Canonical browser origin uses
http://${DEVICE_DOMAIN_NAME}:${APP_PROXY_PORT}. Use the Umbrel launch hostname. Custom IP, Tor or HTTPS ingress origins require deliberate app configuration; the package does not wildcard CSRF origins. - App state and PostgreSQL live under
${APP_DATA_DIR}/data/.... No database port, Docker socket, host network or special Umbrel permissions are exposed. - Internal service hostnames include the app ID so a shared Umbrel network cannot accidentally resolve another app's database alias.
- The app runs as UID/GID 1000, read-only outside mounted state and
/tmp. The official Postgres entrypoint initializes/owns its bind mount and drops privileges.
Umbrel LAN URLs are commonly HTTP. Prefer HTTPS or a trusted SSH tunnel for agent access. For a deliberately trusted LAN, the CLI supports explicit allowInsecureHttp: true in its protected config or SKILLBOX_ALLOW_INSECURE_HTTP=1. HTTP sends credentials and content unencrypted; never enable that for an untrusted/public network.
Test checklist
Use a dedicated test Umbrel, or explicit owner approval for installing the isolated app on an existing device. Never overwrite someone else's app data or change network/proxy services to make a packaging test pass.
- Install from the actual store source; open through the Umbrel launcher.
- Log in with the displayed app password; verify the library and optional integrations start empty/unconfigured.
- Create a demo skill/profile/client; exercise unqueried browse, load, pinned file fetch and recommendations without a Gateway key.
- Verify API/MCP requests without Skillbox credentials fail, and a scoped bearer client works through the proxy whitelist.
- Save/remove a synthetic Gateway key in Settings; verify no secret is returned by status APIs. Do not send a synthetic key to the provider.
- Restart and perform a real version upgrade; verify revisions, clients and encrypted settings persist.
- Test backup/restore without changing the matching instance secrets. Moving a database to another device without its matching owner/encryption material can make saved integration credentials unreadable.
- Inspect logs for errors or secrets and confirm the API's exact published URL/certificate behavior.
- Report each tested architecture/device/version. Do not claim arm64, upgrade, Tor or store acceptance from an amd64 Compose smoke test.
Official references
Requirements checked against the current official guides on 2026-09-17; re-check before submission:
- https://github.com/getumbrel/umbrel-apps
- https://github.com/getumbrel/umbrel-apps/blob/master/.claude/skills/umbrel-package-app/SKILL.md
- https://github.com/getumbrel/umbrel-apps/blob/master/.claude/skills/umbrel-test-app/SKILL.md
- https://github.com/getumbrel/umbrel-apps/blob/master/.claude/skills/umbrel-develop-app/SKILL.md
- https://github.com/getumbrel/umbrel-community-app-store