APP_EXPERIMENTAL=plugins (see plugins).
The plugins
Brand marks: the manifest has no icon field yet, so the dashboard shows the monogram tile for these. A thesvg mark can be wired when the marketplace listing carries one.
Config fields
Config is plugin-wide and non-secret, given at install with--config <file>. Anything secret goes in the channel target instead.
allow_http is for a lab server on plain http. Without it, any non-https address is refused. An address with embedded credentials is always refused.
Use one
Build, sign and trust (for a package you built yourself), install, then add a channel:plugin:twilio-sms like any other channel, with the same delivery history.
DNS provider plugins
cloudflare-dns is the first plugin of kind dns_provider: it lists zones and creates, replaces, deletes and verifies records in Cloudflare. It needs no config and no credential of its own. The control plane hands it the Cloudflare DNS token you already stored under Settings on every call, and the plugin never keeps or logs it. Outbound host: api.cloudflare.com.
By default the built-in client writes DNS records. To use the plugin instead, build, install, approve and enable it, then:
- Plugins page: on the plugin’s row, press Test connection (it lists your zones with the stored token), then Use for DNS records.
- Domains page: pick the plugin under DNS record writer in the domain automation card.
- CLI:
levelrail-cli plugins test cloudflare-dns, thenlevelrail-cli plugins dns-provider cloudflare-dns.plugins dns-provider --offreturns to the built-in client, and with no argument it shows the current choice. - API:
POST /api/v1/plugins/{name}/testandGETorPUT /api/v1/settings/dns-provider-plugin(writes need root).
Self-hosted services
Zulip and Matrix run on your own server, so the shipped manifest lists a placeholder host (zulip.example.com, matrix.example.com). Hosts a plugin declares are shown at approval but are not yet enforced per host (see plugins), so the placeholder gives the plugin network access and the plugin itself only ever calls the base_url or homeserver you configure. To declare your real host, copy the manifest, change outbound_hosts, sign it with your own key and install that copy. The image digest stays the same.
Failure handling
Every plugin maps service answers the same way: 401 and 403 are permanent authentication failures, 429 waits out a short Retry-After and retries (a longer wait is reported as retryable), 5xx and network errors retry twice and then report retryable, and other 4xx are permanent with a short response excerpt. The credential is redacted from every message. Services that answer HTTP 200 with an error code in the body (DingTalk, WeCom) are treated as failures too.Building and signing
scripts/plugins-build.sh build|sign|all [name...] compiles each plugin for Linux, builds an image named <registry>/levelrail-plugin-<name>:local and writes dist/plugins/<name>/plugin.yaml (digest pinned) and plugin.sig. Without PLUGINS_KEY it signs with a throwaway key that exists for local tests only. It never pushes an image. Publishing is the maintainer’s step: push each image, set PLUGINS_DIGEST_<NAME> (or write dist/plugins/<name>/digest) to the registry digest, and run sign with PLUGINS_KEY pointing at the real publisher key.
Not yet
- Plugin icons and a marketplace listing for these plugins.
- DingTalk signature security and Matrix end-to-end encrypted rooms.