Extension bundles — a single .tgz that ships many extensions at once. Install one pack and get all its members in a single operation, with no per-extension steps.
A pack is a single .tgz archive that contains multiple extensions of any type — plugins, providers, senders, themes, homepages, IdP connectors, login pages, webhooks and documentation. Every installable extension type can travel in a pack; the only thing a pack cannot contain is another pack. It is the recommended way to distribute a curated set: a "dark ops" pack that bundles the Post-Punk theme, the Matrix homepage and the Ops plugin, or a vendor pack that ships a plugin together with the login page that fronts it, the webhook that feeds it and its own user guide.
A pack is a fat .tgz with a package.json (pack metadata, extensionType: "pack"), a pack.json listing the member extensions, and one inner .tgz per member.
On install, Kwirth verifies that none of the members is already present (the whole pack is rejected otherwise), installs every member with the normal per-extension logic, records the pack in a dedicated ConfigMap (kwirth-packs), and tags each member with installedFrom: "pack:<id>".
installedFrom: "pack:<id>" — this drives the pack-ownership badge and the uninstall guard.Open ☰ → Manage extensions → Packs — the same card / list layout every extension family uses. Each pack card shows its name and version, a description, a source chip (local for a file upload, a URL chip, or a Kwirth chip for registry installs), a member summary (e.g. 1 theme, 1 homepage, 1 plugin) and a single 🗑 Uninstall that removes the pack and all its members at once.
Install from a URL, a local file, or the registry — the Available packs section lists curated packs when the public kwirthmagnify registry is reachable.
An extension installed via a pack shows a via pack badge in the manager of its own family, and its individual uninstall button is disabled — you remove the parent pack, never a single member. This prevents partial teardowns that would leave the pack metadata inconsistent.
Use the create-pack.mjs script at the repository root. Pass --include <type>:<name> to build an extension from source and embed a freshly built artifact (repeatable — types: plugin, provider, sender, theme, homepage, idp, login, webhook), or list pre-built .tgz files as positional arguments — which is how documentation travels, since it has no source folder of its own. Each run produces a distributable <id>-<version>.pack.tgz.
# Build from source and bundle in one command node packs/create-pack.mjs dark-ops \ --include theme:post-punk \ --include homepage:matrix \ --include plugin:ops \ --name "Dark Ops" --version "1.0.0" # Or use pre-built .tgz files directly node packs/create-pack.mjs my-pack \ ./dist/my-plugin-1.0.0.tgz \ ./dist/my-theme-1.0.0.tgz \ --name "My Pack"
The result contains the member tgzs plus a pack.json manifest and a package.json with extensionType: "pack". Upload it through ☰ → Manage extensions → Packs.
packs/manifest.json feeds the Available packs registry view — submit a PR to list your pack there.Self-contained docsify sites that Kwirth installs and serves itself — documentation hosted by the platform, with no external dependency.
A documentation package is a docsify site bundled as a .tgz that Kwirth serves directly from its own back end. Once installed it is reachable in the browser with no external host — the Kwirth server itself is the documentation host.
A documentation package always documents another extension, so it is identified by the pair that points at it: targetType is the type of the documented extension (plugin, provider, sender, theme, homepage, idp, login, or core for the Kwirth core itself) and id is that extension's own id — the Excubitor guide carries targetType: plugin and id: excubitor. The id alone would not be unique, since a plugin and a theme may share a name and each ship its own guide. Packages are served at /docs/<targetType>/<id>/, and Kwirth uses the same pair to point an extension's Help buttons at its guide. The core/kwirth package — the user & admin guide — documents the core itself and ships bundled with every Kwirth deployment.
Open ☰ → Manage extensions → Documentation. The left panel lists every installed package; each card shows its name, version, a short description, a source chip and two actions — 📖 Open docs (opens the site in a new tab) and, for non-bundled / non-dev packages, 🗑 Uninstall.
Install from a URL (paste the .tgz URL and click ⬇ Download), from a local file (Browse… and upload — extracted server-side), or from the registry (the Available documentation section, when the public kwirthmagnify registry is reachable).
A valid package is a .tgz with a root package.json carrying at least extensionType: "docs", the targetType / id pair of the extension it documents, plus name and version, and a docsify index.html with its Markdown content. targetType is exclusive to documentation packages: every other extension type declares only extensionType and its own id.
/tmp is ephemeral — URL-installed packages are re-downloaded automatically on each pod restart; bundled packages are always present; local (file-uploaded) packages must be re-uploaded after a restart.GET /docs) is public; installing, uploading and uninstalling require an admin API key.