plugin.json
The manifest at the root of every plugin repository. The bridge validates it when a plugin is
installed or updated, and the host validates it again when it reads the compiled plugin table
at boot — through the same parser, parsePluginManifest from @vrcnext/plugin-api, so a
manifest that passes one passes the other. Parsing never throws: a bad manifest yields a list
of problems the UI shows verbatim.
{
"id": "friend-alerts", // [a-z0-9][a-z0-9-]{1,39}; equals plugin.id in main.ts
"name": "Friend alerts",
"version": "1.2.0", // semver
"apiVersion": "^0.2.0", // semver range against @vrcnext/plugin-api
"description": "…", // <= 200 characters
"author": "…", "homepage": "…", // optional
"tags": ["notifications"], // optional, <= 8
"permissions": ["host:events", "native"], // categories it may ever use
"optionalPermissions": ["network"], // asked for later via ctx.permissions.request
"actions": ["getFriends"], // VRCNext actions granted at enable (host:actions)
"events": ["friendOnline"], // host events granted at enable (host:events)
"hosts": ["api.example.com"] // hosts it means to reach (network); each still prompts once
}
Fields
| Field | Rules |
|---|---|
id |
Required. [a-z0-9][a-z0-9-]{1,39}. Must equal id in main.ts; also the clone directory name on the bridge. |
name |
Required. Shown in the manager and in every permission prompt. |
version |
Required. Plain MAJOR.MINOR.PATCH — no prerelease, no build metadata. Shown in the manager; updates are tracked by git commit, not by this field. |
apiVersion |
Required. A range of @vrcnext/plugin-api versions, checked before activation. Only four shapes are accepted: exact (0.2.0), caret (^0.2.0), tilde (~0.2.1) and space-separated comparator lists (>=0.2.0 <0.4.0). The parser is forty lines on purpose — the api package is compiled straight from source with no node_modules — so ||, x, * and hyphen ranges are not ranges here. |
description |
Optional (empty when absent); at most 200 characters. Shown in the manager and the enable modal. |
author, homepage |
Optional strings. |
tags |
Optional, at most 8. Any string is accepted; the manager filters by the suggested ones (PLUGIN_TAGS): accessibility, activity, audio, chat, customisation, developer, friends, fun, media, notifications, osc, privacy, ui, utility. |
permissions |
The categories the plugin may ever use. Granted when the user enables it. May be []. An undeclared category is refused outright at call time. |
optionalPermissions |
Categories the plugin may ask for later through ctx.permissions.request(p). |
actions |
Exact VRCNext action names ctx.bridge may send without a prompt. Needs host:actions. |
events |
Exact host event names ctx.events may subscribe to without a prompt. Needs host:events. openDeepLink here covers ctx.deepLinks. |
hosts |
Exact hosts ctx.http.fetch means to reach, shown to the user at enable. Each host still prompts before its first request. Bare host names, optionally with a port; no scheme, no path, no wildcards. Needs network. |
dependencies |
Optional: ids of plugins that must be enabled before this one activates. The host orders activation by these; a plugin cannot depend on itself. |
Lists are de-duplicated; empty or non-string entries are errors. An unknown permission name is an error, not a warning — the vocabulary is fixed.
The permission vocabulary
Exactly these, from PERMISSIONS in @vrcnext/plugin-api, each with the one-line description
and risk tone the consent modal shows:
| Permission | Tone | Description |
|---|---|---|
host:events |
low | Receive VRCNext events, limited to the event names listed in plugin.json. |
host:actions |
high | Send actions to VRCNext on your behalf, limited to the action names listed in plugin.json. Actions act on your real VRChat account. |
host:intercept |
high | Observe and drop every action VRCNext sends to its backend, including its own. |
network |
medium | Make HTTP requests. Each host is asked about before its first request, declared in plugin.json or not. |
notifications |
low | Show toasts, confirmation dialogs and desktop notifications. |
native |
medium | Send notifications through the VRCNext Bridge to your VR overlay and desktop. Only the bridge’s notification service is reachable. |
osc |
medium | Send and receive OSC avatar parameters through VRCNext. |
gamelog |
medium | Read the VRChat game log, live and its backlog. |
vrchat |
medium | Read VRChat data through VRCNext: your friends, favourites, groups and instance, and look up users, avatars, worlds and groups without opening their dialogs. |
context-menu |
low | Add entries to right-click menus. |
routes |
low | Serve in-page HTTP routes under /plugins/<id>/. |
clipboard |
medium | Read and write the clipboard. |
ui, settings, logger and disposables need no permission: they can only affect the
plugin’s own panels and its own stored values.
“Limited to the names listed” is what the declared lists buy at enable time. Names not listed are still reachable inside a declared category — the user is asked on first use. See Permissions for exactly when.
What the bridge checks beyond the parser
At install and update the bridge also refuses a manifest with unknown fields, and refuses the
repository if it has no plugin.json at the root (no_manifest), if the id is already installed
(already_installed), or if the sources fail the source policy. The error
message names the problem with a stable prefix (manifest_invalid: …, policy: file:line rule)
so it can be read straight off the panel.