Files
2026-08-08 23:39:27 -04:00

185 lines
9.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Community plugins
<p align="center">
<img src="https://assets.noctalia.dev/noctalia-logo.svg?v=2" alt="Noctalia Logo" style="width: 192px" />
</p>
---
This repo is the **community** plugin source for [Noctalia](https://github.com/noctalia-dev/noctalia). Every
plugin merged here is listed in the shell's plugin store and on
[noctalia.dev/plugins](https://noctalia.dev/plugins), and users can install it without adding a source of their own.
Plugins maintained by the core team live in
[official-plugins](https://github.com/noctalia-dev/official-plugins), which does not accept third-party plugins.
This one does. **PRs are welcome.**
> The plugin system is in **beta**. The manifest format and the plugin API may still change before v5 is stable.
> Expect to bump your plugin when they do.
## Layout
Each plugin is **one top-level directory**, named after the part of its id that follows the `/`, so `me/hello` lives
in `hello/`:
```
hello/
plugin.toml # manifest: id ("me/hello"), metadata, entries, settings
hello.luau # your entry scripts
README.md # rendered as the plugin's page on noctalia.dev
thumbnail.webp # the plugin's card image
translations/
en.json # every label_key / description_key the manifest references
```
`catalog.toml` at the repo root indexes every plugin. **It is generated by CI, so never edit it or include it in a
commit.**
A plugin id is `<author>/<plugin>`. The author part is yours (your GitHub handle is the obvious choice) and keeps your
id distinct from everyone else's, but the **directory name is first-come within this repo**. If `weather/` is already
taken, pick another name; the official repo is a separate source, so a name used there is not taken here. Both id
segments must be lowercase and match `[a-z0-9][a-z0-9._-]*`.
## What a plugin is allowed to be
Noctalia plugins are **trusted, unsandboxed Luau**. There is no permission broker and no capability sandbox:
installing a plugin is equivalent to running a script the user owns. It can read and write files, spawn processes, and
talk to the network as the user.
That is a deliberate design choice, and it puts the burden on review. So:
- **No obfuscated, minified, or generated code.** A reviewer must be able to read every line you ship.
- **No downloading and executing remote code.** Ship your logic in the repo, at a version people reviewed.
- **Declare what you shell out to.** External commands go in `dependencies` in `plugin.toml` and get a mention in your
README.
- **Account for every network call, filesystem write, and spawned process** in your PR description.
Anything that looks like it is hiding what it does will be rejected, regardless of intent.
## Writing a plugin
The [plugin development docs](https://docs.noctalia.dev/noctalia/plugins/development/) are the reference: the
[manifest](https://docs.noctalia.dev/noctalia/plugins/development/manifest/), the
[entry types](https://docs.noctalia.dev/noctalia/plugins/development/entries/) (`[[widget]]`, `[[panel]]`, `[[shortcut]]`,
`[[service]]`, `[[desktop_widget]]`, `[[launcher_provider]]`), the
[declarative UI](https://docs.noctalia.dev/noctalia/plugins/development/declarative-ui/) vocabulary, the
[runtime API](https://docs.noctalia.dev/noctalia/plugins/development/runtime-api/), and the
[workflow](https://docs.noctalia.dev/noctalia/plugins/development/workflow/) for developing and testing locally.
The fastest start is to read
[`noctalia/example`](https://github.com/noctalia-dev/official-plugins/tree/main/example) in the official repo. It
exercises a bar widget, a declarative widget, a service, a shortcut, a launcher provider, and a panel in one plugin.
To run your plugin while you work on it, add this checkout as a `path` source:
```sh
noctalia msg plugins source add dev path ~/dev/community-plugins
noctalia msg plugins enable me/hello
```
`.luau` edits hot-reload; manifest changes are picked up on the next config reload.
### Editor setup
`noctalia.d.luau` declares the whole plugin API, so luau-lsp gives you autocomplete and typo diagnostics. It lives in
official-plugins, which is its single source of truth; it is **not** vendored here, because a committed copy would be a
second one for everyone to trust and keep in sync. Fetch it into the repo root, where it is gitignored:
```sh
curl -O https://raw.githubusercontent.com/noctalia-dev/official-plugins/main/noctalia.d.luau
```
Re-run that whenever the plugin API changes; your local copy is a snapshot, not a subscription.
The committed `.vscode/settings.json` already points luau-lsp at it; for another editor, add it to luau-lsp's
`types.definitionFiles`. `.luaurc` sets `nonstrict` mode, matching the `--!nonstrict` directive every plugin file
starts with.
### Thumbnail
Every plugin ships a `thumbnail.webp`. It is the card image in the plugin store and on the website. Generate one with
the **[thumbnail generator](https://assets.noctalia.dev/plugins/thumbnail-generator.html)**: drop in a screenshot of
your plugin, set the title, category tag and accent color, then export the 960×540 WebP and commit it as
`<plugin>/thumbnail.webp`.
### README
`README.md` is the plugin's public page, so it must tell a user how to access every entry instead of only describing
the implementation. Follow [`README_TEMPLATE.md`](README_TEMPLATE.md), which mirrors the structure used by the
official plugins:
- Start with a title, a short explanation, a `Plugin` table, and practical `Usage` instructions.
- Copy the plugin id and every entry id exactly from `plugin.toml`.
- If the plugin declares a panel, include the exact command
`noctalia msg panel-toggle <author>/<plugin>:<panel-id>`.
- If it declares a launcher provider, document its `/<prefix>` and give an example query.
- Mention every manifest dependency under `Requirements`, using the exact dependency name.
- Document declared settings, including units or non-obvious effects.
- Use `IPC` and `Notes` when the plugin exposes extra events or has important filesystem, network, process, privacy,
hardware, or compositor behavior.
CI derives ids, panel commands, launcher prefixes, dependencies, and whether settings exist from `plugin.toml`. Its
error messages show the exact missing value, while maintainers review the usefulness and accuracy of the prose.
### Translations
Write `translations/en.json` only. Every `label_key` and `description_key` in your manifest must resolve to a key in
it, and CI checks this. Do not add machine-translated locales; other languages are handled separately.
To test the latest translated locales from [Noctalia Translate](https://i18n.noctalia.dev) in a working checkout, run:
```sh
./.tools/i18n-pull.sh
```
The command asks for confirmation and overwrites the locale files returned by the translation service. It does not
delete local locale files that are absent from the export. Review the resulting diff before committing anything.
### Tags
The `tags` in `plugin.toml` are used for catalog search. Tags must be lowercase and selected from this list:
- Surfaces: `bar`, `desktop`, `launcher`, `panel`, `service`, `shortcut`
- Purpose: `ai`, `animation`, `audio`, `clock`, `countdown`, `demo`, `development`, `emoticon`, `fun`, `gaming`,
`hardware`, `indicator`, `language`, `media`, `music`, `network`, `privacy`, `productivity`, `recording`, `system`,
`theming`, `time`, `utility`, `video`, `wallpaper`
- Compositors: `hyprland`, `labwc`, `mangowc`, `niri`, `sway`
- Distributions: `arch`, `debian`, `fedora`, `gentoo`, `nixos`, `opensuse`, `void`
If your plugin does not fit any existing tag, propose a new one in your pull request rather than inventing a tag in
the manifest.
## Submitting
Open a PR against `main`. CI validates your manifest, entry scripts, required files, and thumbnail on every push.
- **One plugin per PR.**
- The directory name matches the part of `id` after the `/` in `plugin.toml` **exactly**.
- `version` is semver and gets bumped on every change to the plugin.
- `plugin_api` is the oldest Noctalia plugin API level the plugin requires. Use the current documented level for a new
plugin, and increase it only when the plugin adopts a capability from a newer API level.
- `description` is concise catalog copy, limited to 120 characters. Put feature details in the plugin's README.
- `license` is set in `plugin.toml`. You keep the copyright on your plugin; if it is not MIT, put a `LICENSE` file in
your plugin directory. There is no repo-wide license covering contributed plugins.
- Screenshots or a short video for anything with a visual surface.
Maintainers read the code before merging. Expect review comments about clarity, and about anything the plugin does
that is not obvious from its description.
## Maintaining your plugin
The plugin directory is yours. Someone else's PR changing your plugin is not merged without your sign-off, unless it
fixes something that is broken or is a mechanical change applied across the whole repo. Maintainers will @-mention you
on PRs and issues that touch it.
If you stop maintaining a plugin, set `deprecated = true` in its `plugin.toml` rather than deleting the directory. The
store keeps working for people who already installed it, but it stops being offered to new users. Plugins that are
broken and unmaintained across a Noctalia release may be deprecated by maintainers.
## Help
- [Documentation](https://docs.noctalia.dev)
- [Discord](https://discord.noctalia.dev)
- Bugs in Noctalia itself (not in a plugin) belong in
[noctalia](https://github.com/noctalia-dev/noctalia/issues).