Community plugins
Community plugins are JavaScript bundles Phials loads from disk: manifest.json, main.js, and optional styles.css. The host installs artifacts under the portable Phials data directory, resolves updates from a community index and GitHub Releases, and activates your code with import() of main.js. Your default export must be a function that returns a PhialsPlugin.
The host wraps PluginAPI with manifest-derived permission gates (scoped invoke, optional clipboard / fetch). This is trusted execution in the renderer with permission-gated Phials APIs — not a full sandbox. See Public API contract.
Companion: Plugin API · Getting started.
Community plugins safe mode
Safe mode is on by default for new profiles. While enabled:
- Browsing the community index, installing, enabling, updating (from the index), and refreshing the index are blocked.
- Already-enabled community plugins are disabled when safe mode is on (for example after the app restarts or when the user turns safe mode back on).
Users must open Settings → Plugins → Community plugins, turn safe mode off, and accept the warning before they can discover or install community plugins. Features that ship with Phials (not community bundles) are unaffected. For testers and supporters, see Community plugins in Phials.
Manifest (PluginManifest)
Parsing and validation helpers live in the example repo as sdk/manifest-schema.ts. Required fields:
id— pattern^[a-z][a-z0-9]*\.[a-z][a-z0-9-]*[a-z0-9]$(e.g.acme.preview-plugin). Cannot collide with reservedphials.*ids.name,version,minAppVersion,author,description— semver rules apply to plugin and minimum app versions.authorUrl,repository,icons,permissions,pluginApiVersionoptional (pluginApiVersiondefaults to1.0.0when omitted in compatibility checks).
permissions must be subsets of the supported union:
filesystem.read | filesystem.write |
clipboard.read | clipboard.write |
network.fetch
shell.execute is not a supported manifest permission in v1.
Use PERMISSION_DESCRIPTIONS / PERMISSION_RISK from sdk/manifest-schema.ts for UI copy or tooling.
Minimal manifest:
{
"id": "acme.hello-plugin",
"name": "Hello Plugin",
"version": "1.0.0",
"minAppVersion": "0.1.0",
"pluginApiVersion": "1.0.0",
"author": "You",
"description": "Example external plugin bundle.",
"permissions": ["filesystem.read", "network.fetch"]
}Compatibility
The host checks:
minAppVersionagainst the running Phials application version.pluginApiVersion(default1.0.0) against the host supported plugin API version.
Both must be satisfied before install or activation succeeds. See Public API contract.
Loader flow (behavioral)
Initialize
On startup the host loads installed plugin manifests, merges enabled flags from persisted state, applies safe mode (disabling community plugins when required), then activates each enabled plugin.
Install
Resolution from the community index → download manifest.json, main.js, optional styles.css → validate id, compatibility, and permissions shape → stage files on disk → finalize after successful activation or roll back on failure. New installs start disabled until the user enables them.
Enable / disable
Enable activates the plugin (blob import, register, onActivate). Disable tears down providers, injected styles, shortcuts, and event subscriptions for that plugin.
Updates
Updates reinstall files. If manifest permissions change compared to the last user-approved set, the host requires permission review before re-enabling; failed activation after an update can roll back to the previous on-disk version.
Activation
The host reads main.js, imports it, expects a default export function that yields a PhialsPlugin, checks plugin.id matches the install id, wires the permission-gated PluginAPI, then activates. Optional styles.css is injected with a plugin-scoped style element; it is removed on disable/uninstall.
Permission-gated PluginAPI
invoke
Allowed command names are derived from declared permissions plus a small always-allowed baseline (system paths, drives, thumbnails, platform probes). filesystem.read adds read-oriented file/directory commands; filesystem.write adds mutating file commands (and implies the read-side set for the API layer). Anything else throws a permission error.
clipboard
clipboard.read / clipboard.write gate the corresponding PluginAPI.clipboard helpers when present.
fetch
network.fetch gates PluginAPI.fetch when present. It does not prevent a malicious bundle from calling the browser’s global fetch directly — see the contract.
Trust model (v1)
Distribution assumes GitHub release trust plus registry review — not mandatory signatures or checksums in v1. See Public API contract.
Submitting to the community registry
The canonical index is the community-plugins.json file in github.com/EliWimmer/phials-plugins (served to Phials via raw GitHub). Maintainer checklist: SUBMISSION.md. Takedowns, broken releases, and ownership: POLICY.md.
Phials validates index shape at load time (unknown fields and invalid entries cause the index refresh to fail with a clear error).
Limits today
- Distribution is geared toward GitHub Releases (and the community index your Phials build uses). Other channels are not documented here.
- Plugins run in the same renderer as Phials; stronger isolation is not part of the current model (see the contract).