---
name: velo-plugin-authoring
description: Author, review, pack, and publish Velo selection plugins (declarative plugin.json or a Rhai plugin.rhai). Use when writing 插件, creating .vplug/.vplugz, converting PopClip-like ideas, filling plugin.json, writing sandboxed scripts, attesting community submissions, or explaining how to extend the Velo selection bar. Not for generic JS runtimes, WASM guests, or in-app plugin stores.
---

# Velo Selection Plugin Authoring

> If the request is about themes, appearance palettes, or `targets: ["theme"]`, stop and load `../velo-theme-authoring/SKILL.md` instead. Theme Plugins are a separate contract, require Velo Desktop 0.2.0+, and never create selection actions.

Velo selection plugins are **signed capability packs** for the selection bar. They are not a JS/Shell runtime and cannot open windows, read the filesystem, spawn processes, inherit env, or call arbitrary URLs.

Requires **Velo Desktop 0.1.0+**.

Public URL: `https://velo.var.li/skills/velo-plugin-authoring/SKILL.md`
Catalog: `https://velo.var.li/skills/index.json`
Human guide: `https://velo.var.li/plugin-guide.html` (repo: `docs/PLUGIN_AUTHORING.md`)
Contract: `schemas/plugin-v2.schema.json`, `wit/selection.wit`, `docs/PLUGIN_DEVELOPMENT.md`.

Other developers: copy this whole folder (including `references/`) into `.agents/skills/velo-plugin-authoring/`.

## Load references as needed

- Unsure about permissions, actions, placeholders, or results → [references/contract.md](references/contract.md)
- Writing `plugin.json` / locales → [references/declarative.md](references/declarative.md)
- Writing a Rhai script → [references/script.md](references/script.md)
- Signing or community submit → [references/publish.md](references/publish.md)
- Reviewing a failing pack → [references/pitfalls.md](references/pitfalls.md)
- Mapping a PopClip extension → [references/popclip.md](references/popclip.md)

If a field is not in the schema, **do not invent it**. Unknown JSON keys fail validation.

## Workflow

1. Restate the user job as **one plugin pack, one selection-list row, optional submenu**.
2. Prefer **declarative** `plugin.json`. Use a Rhai `plugin.rhai` only when Host Actions cannot express the job (compute, BYOK HTTP, secrets). Never add JS or WASM.
3. Choose a reverse-DNS id (`com.example.foo`). Never use `velo` / `velo.*` unless the user is shipping an official pack with an out-of-repo official key.
4. Minimize `permissions`. Infer extra ones from placeholders (`{page}`/`{title}` → `browser_context`, `{app}`/`{bundle}` → `app_context`) and result dispositions (`paste` → `selection_replace`). `{url}`/`{email}` do not add permissions.
5. Author `plugin.json` (+ locales). Script actions must be `"handler": "script"` with `"action": { "type": "noop" }` and `entrypoint.kind` `script`.
6. Give the user these commands (do not run tests/builds unless they authorized this turn):

```bash
./scripts/install-plugin-cli.sh   # once; then velo-plugin is on PATH
velo-plugin validate ./the-plugin
velo-plugin pack ./the-plugin ./the-plugin.vplugz
```

Authors can also select a `#velo` snippet (or paste it in Selection) to preview-import without packing. PopClip URL/key/transform recipes: `docs/PLUGIN_POPCLIP.md`.

7. Secrets or Shell require `keygen` + `sign`. Never write the private key into the pack or git.
8. Community publish is license-portal challenge → `attest` → paste `submission.json`. Website `/plugins.html` is download-only.

## Hard no

- PopClip JS, AppleScript, free `eval`, WASI, Node, or a second plugin UI/window
- In-app catalog browse/install
- Unsigned `secrets` / `shell`
- Guest-owned HTML/WebView
- Reading host env except official `velo.*` `api_key` via Host (`$ENV_NAME` / `VELO_PLUGIN_KEY`)
- Expanding one pack into many selection rows

## Deliver

Return: plugin id, permission rationale, files to write, validate/pack/sign commands, and import steps (Velo → Selection → Import). If scripted, include the Rhai `prepare`/`execute` sketch and the Host result JSON shape. If publishing, list attest steps without uploading keys.
