Skip to main content

serverbox-webapp

Adapt a self-hosted web service (Immich, Jellyfin, Paperless-ngx, Vaultwarden, …) into a ServerBox Monitor web app — a folder in `store/apps/<publisher>.<name>/` with a `manifest.toml` and the Docker Compose files the Monitor deploys — then validate it and propose it for the catalog. Use this whenever someone wants to add, port, update, fix or validate an app for the Monitor's app catalog, including requests that never say "manifest", such as "add Jellyfin to the monitor", "make the monitor able to install Nextcloud", "bump Immich to the new release", "why does my web app fail validation", or "turn this docker-compose.yml into a monitor app".

Source facts

Repository
lollipopkit/flutter_server_box
Last source activity
November 2, 2026 at 09:36
Detected SKILL.md language
English
Stars
8,957
Forks
578

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
4 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
serverbox-webapp
description
Adapt a self-hosted web service (Immich, Jellyfin, Paperless-ngx, Vaultwarden, …) into a ServerBox Monitor web app — a folder in `store/apps/<publisher>.<name>/` with a `manifest.toml` and the Docker Compose files the Monitor deploys — then validate it and propose it for the catalog. Use this whenever someone wants to add, port, update, fix or validate an app for the Monitor's app catalog, including requests that never say "manifest", such as "add Jellyfin to the monitor", "make the monitor able to install Nextcloud", "bump Immich to the new release", "why does my web app fail validation", or "turn this docker-compose.yml into a monitor app".
# ServerBox Monitor web apps A web app is a web service the Monitor deploys with Docker Compose and the panel's desk shows in a window. Its source is one folder: ``` store/apps/<publisher>.<name>/ manifest.toml what it is, its licence, and the env file it needs compose.yaml the compose files the manifest names … any other file they use (extends) ``` The Monitor copies the folder (minus the manifest) into the stack's directory, writes `.env` from the manifest and the deploy dialog's answers, and runs `docker compose -p sbm-<publisher>-<name> --env-file .env -f …`. The window reaches the service on loopback at the port setting `[web] port` names. `store/apps/futo.immich` is the worked example: Immich's release compose file, adjusted as below, with GPU acceleration choices. ## Workflow ### 1. Start from upstream's compose file Take the compose file the project publishes **for the release you pin** (release assets beat `main`). Write down its version, licence and homepage. If the licence is copyleft or has terms worth reading, set `[license] accept = true` so the admin accepts it before deploying. Copying upstream files is fine when their licence allows it (most do); keep a header comment saying where each file came from, which release, and what was changed. Files copied unchanged say so. ### 2. Adjust the compose file - Remove `name:` and every `container_name:` — the Monitor names the project, and fixed names collide with a copy the user already runs. - Pin images to the release (`image: org/app:${APP_VERSION}` with `APP_VERSION` in `[env]`), or by digest for supporting images. - Prefer upstream's image. Build one (`build:`, see "Building an image" in `references/manifest.md`) only when none is maintained. - Turn every value the user should choose into a `${VARIABLE}`: data paths, the published port, hardware acceleration. Publish the web port as `'${BIND}:${PORT}:<container port>'` so it can stay on loopback. - Keep upstream's structure otherwise (`extends`, healthchecks, `env_file: [.env]`): a later release is then a small diff. - Run as the shared folder's owner (`PUID=${SBM_UID}`, `PGID=${SBM_GID}`, or `user: "${SBM_UID}:${SBM_GID}"`) and set `TZ: ${SBM_TZ}`; the Monitor writes those three for every app. - Downloads, media, music, books, comics and documents go in the shared folder (`{shared}/downloads`, `{shared}/media/movies`, …), not the stack's own: another app reads them. Ports other machines need (DNS, BitTorrent, sync) are their own `port` settings with `protocol`. ### 3. Write the manifest Copy `assets/manifest.template.toml` to `store/apps/<publisher>.<name>/manifest.toml`. Its first line is a schema directive, so editors with Taplo/Even Better TOML/Tombi check it as you type. Every field is in `references/manifest.md`. - One `[[settings]]` per thing the deploy dialog should ask, each writing env values: `path` (data directories, `default = "{stack}/…"`, `data = true` for data), `port`, `bool` (`on`/`off` values), `choice` (options with env values and `suggest` for GPUs), `text` (with a `pattern`). - `[[secrets]]` for passwords the service needs: generated once, never shown. - `[login]` for the first sign-in: seed the admin from a secret where the service allows it, and name it there; the admin can then read it in the app's details. - `[env]` for fixed values. - `[[mcp]]` when the service has an MCP server, or a maintained one exists to run beside it as a sidecar: Agent mode connects to it once deployed. - Every env name comes from exactly one of those, and every `${VARIABLE}` a compose file needs must be one of them. - `notices`: what the compose files do that an admin should know (bind mounts, devices, published ports, `privileged`, host network, the Docker socket). They are shown, never refused — say what is there. - `title` names the window: the upstream project's own name ("Immich"), `en` only, never a generic word ("Photos"). Don't use upstream logos; `glyph` is a Material Symbols name. ### 4. Validate ```sh python3 <skill>/scripts/validate.py store/apps/<publisher>.<name> --compose ``` It checks the manifest against the published JSON Schema (via `uvx`/`pipx` `check-jsonschema`; pass `--schema docs/schemas/monitor-app.schema.json` inside the repository to use the local copy), then the rules only the Monitor knows (files, env names, defaults, compose variables), and with `--compose` runs `docker compose config` over the stack with the defaults' env file. Fix every error; read the warnings. Inside the repository also run: ```sh cargo test -p server_box_monitor --lib stacks:: ``` which reads every folder in `store/apps/` with the Monitor's own reader. Then deploy it on a machine with Docker through the Monitor, as a desk window reaches it (HTTPS, through the Monitor's proxy, signed in with what `[login]` shows): ```sh SBM_E2E_DOCKER=1 SBM_E2E_CATALOG_APPS=<publisher>.<name> cargo test -p server_box_monitor --test stacks_catalog_e2e -- --ignored --nocapture ``` and add the app's sign-in to that test's `sign_in`. ### 5. Try it The quickest way is a Monitor itself: put the folder in a directory the Monitor's `config.toml` names as `[stacks] local_apps` and restart it. The app shows in the App Store marked Local, and installs, opens, takes new settings and uninstalls as a catalog app does. `monitor/tests/apps/` holds a small one (`serverbox.testweb`) the Monitor's Docker e2e test deploys. Without a Monitor, on a Linux machine with Docker: copy the folder (without the manifest), write a `.env` like the validator's (`--compose` builds one from the defaults), `docker compose -p sbm-<publisher>-<name> --env-file .env -f compose.yaml up -d`, and open the port. Check first-run steps (an admin account to create, a setup wizard) and mention them in `description` if the window would otherwise look broken. `docker compose … down` when done. ### 6. Propose it Open a pull request against `lollipopkit/flutter_server_box` adding the folder. Say in the description which release it pins, where each file came from, and that you deployed it (step 5). An update to a new upstream release changes `version`, the pinned images and whatever the release's compose file changed.
View on GitHub