# WolOS plugins

> What a WolOS shell plugin is, the plugin.toml manifest, its permissions, and how an agent writes and tests one in five steps.

Source: https://wolos.pages.dev/plugins

A plugin is a folder named after its id with a `plugin.toml` and the Lua and image files it names: no install scripts, no binaries, at most 1 MiB, run in WolOS's Lua sandbox. Full reference: https://wolos.pages.dev/manual/plugins.md

## Manifest

```toml
schema = 1
id = "alice.stats"
name = "Stats"
version = "1.0"
author = "Alice"
license = "MIT"
description = "CPU and memory in the menu bar, with a desktop card."
min_wolos = "0.12"
permissions = ["run"]

[[menubar]]
id = "bar"
script = "bar.lua"
side = "right"

[[widget]]
id = "card"
script = "card.lua"
sizes = ["small", "medium"]

[[hotkey]]
id = "top"
default = "super+shift+t"
exec = ["foot", "-e", "btop"]
group = "Stats"
```

## Sections

- `[[menubar]]` (script, side): A bar item. `side` is `left`, `centre` or `right` (default). The script returns `wol.menubar`.
- `[[dock]]` (name, icon, exec): A Dock tile that runs `exec` (argv, never a shell line).
- `[[widget]]` (script, sizes): A desktop card (today's `lua:<id>`). `sizes`: any of `small`, `medium`, `large` (default all).
- `[[panel]]` (script, anchor): A sheet the shell shows on `wol.show("<id>")` or a hotkey. `anchor`: `top` (default), `bottom`, `left`, `right`, `centre`.
- `[[search]]` (script, kind, prefix): Search rows. `kind = "results"` (default) sees every query; `kind = "command"` sees queries starting with `prefix` (1 to 8 characters, no spaces).
- `[[tile]]` (icon, label, toggle): A Control Center tile bound to a `[[toggle]]` of this plugin.
- `[[toggle]]` (on, off): Two argv commands; the state is a flag file in `$XDG_STATE_HOME/wolos/toggles/<plugin>.<id>`.
- `[[hotkey]]` (default, exec, group): A user-rebindable shortcut (`shortcuts::Custom`). `default`: modifiers from `super`, `ctrl`, `alt`, `shift`, then a key (`super+shift+t`, `super+f5`, `super+space`). `group` is the heading in Settings (default: the plugin name).
- `[[webapp]]` (name, url, icon, profile): A frameless browser window for an `https://` URL, in Search and the Dock. `profile`: `shared` (default) or `own` (isolated cookies).
- `[[theme]]` (file): A `theme.json` (`shared::theme` tokens, optional `extends`); checked for contrast.
- `[[look]]` (file): A Looks preset JSON (`wol_core::looks`).
- `[[hypr]]` (file): `keyword = value` lines; only `windowrule`, `layerrule`, `bezier`, `animation`. Never `bind`, `exec`, `env`, `source`, `plugin`, `$variables` or `{ }` blocks. Parsed into `hyprprefs` keywords, never sourced raw.

## Permissions

- `notifications`: `wol.notify`
- `run`: `wol.run`
- `http`: `wol.http_get`
- `clipboard`: `wol.clipboard.text`
- `open`: `wol.open`
- `toggles`: `wol.toggle_set`

## How an agent writes one, in five steps

1. `wol plugin new alice.weather menubar,widget` makes a folder that already passes check. Read `/usr/share/wolos/plugins.schema.json` (the manifest schema) and this page.
2. Edit `plugin.toml` (name, description, permissions, entries) and the `.lua` files. Keep scripts small: one `read()` that fetches data, one `render()` that returns parts.
3. `wol plugin check alice.weather --json` until `"valid": true`. Every problem is one sentence naming the file or `[[section]] n` and what to change.
4. `wol plugin run alice.weather menubar --json` prints the view tree; `wol plugin run alice.weather widget card 1 --json` clicks part 1 first and shows the new tree and the `events` the handler caused. Use `XDG_STATE_HOME=$(mktemp -d)` for a clean state and `WOL_PLUGIN_HOSTS=api.example.com` when the plugin reads the web.
5. `wol plugin enable alice.weather` to see it on the desktop; `wol plugin pack alice.weather` to make the `.wolplug` to share.
