plugin.json and permissions
What goes in a plugin's manifest, and what each permission lets the plugin do.
Every plugin folder has a plugin.json. It names the plugin and lists the permissions it needs. ForgeCast reads it before running any code, and shows the permissions to the person who turns the plugin on.
{
"id": "keyword-alerts",
"name": "Keyword alerts",
"version": "1.0.0",
"author": "Your name",
"description": "A notification when chat mentions words you care about.",
"homepage": "https://example.com/keyword-alerts",
"main": "main.lua",
"api": 1,
"permissions": ["chat.read", "ui.notify", "storage"]
}Fields
| Field | Required | What it is |
|---|---|---|
id | yes | The plugin's unique name: 3 to 40 characters, lowercase letters, digits and single hyphens (keyword-alerts). It must be the same as the folder's name. |
name | yes | The name people see, up to 60 characters. |
version | yes | Like 1.0.0. Change it when you change the plugin. |
author | no | Who made it. |
description | no | What it does, in a sentence or two (up to 500 characters). Shown on the plugin's card. |
homepage | no | Where to read more. |
main | no | The Lua file that starts the plugin, inside the folder. Default main.lua. |
api | no | The plugin API version it was written for. Today that is 1, and it is the default. |
permissions | no | What the plugin may do (below). Default: nothing. |
The easiest way to get the folder and the id right is Plugins → New plugin. A folder that doesn't have a valid manifest shows up under Folders that aren't plugins with the reason.
Editor help
A new plugin comes with the JSON schema for this file already wired up in VS Code, so you get completion for the fields and a description for each permission. You can also download the schema.
Permissions
A plugin can do nothing beyond plain Lua until it asks, and the person turning it on says yes. Add the permission to permissions the first time you use a function that needs it.
| Permission | Lets the plugin | Functions |
|---|---|---|
chat.read | See chat messages, Super Chats and members of the streams you watch. | chats.get, chats.count, chats.authors, chats.random, chats.on, chats.off, commands.add, chats.wait_for, chats.rate, chats.from, emotes.list, emotes.top, emotes.image |
chat.middleware | Look at every message before it is shown, and block or change it. | chats.use, chats.unuse |
stream.read | See viewers, likes and the state of the streams you watch. | stream.list, stream.state, stream.on, stream.off, events.recent, events.on, channel.info, channel.videos, channel.upcoming, youtube.health, youtube.stream_stats, youtube.quota, youtube.upcoming |
ui.notify | Pop up notifications inside ForgeCast. | ui.notify |
ui.modal | Open dialog boxes over the app. | ui.modal, ui.alert, ui.confirm, ui.prompt, ui.close |
ui.window | Open windows of its own. | window.create, window.close, window.focus, window.set_title |
ui.dashboard | Add its own sections to the Dashboard, and a settings panel to its card. | dashboard.section, dashboard.remove, plugin.settings, plugin.config |
storage | Save settings and data on this computer (only its own, up to 1 MB). | storage.get, storage.set, storage.delete, storage.keys, storage.clear, storage.table, storage.export_csv, storage.save_file, plugin.secret |
sounds | Play sounds from your Sound Library. | sounds.play |
alerts | Trigger your alerts, as if the event had happened on your stream. | alerts.show |
bus | Send and receive messages with your other plugins. | bus.emit, bus.on, bus.off, bus.handle, bus.call |
network | Send and receive data over https. It can send anything it can see, such as chat, to the sites it calls. | http.get, http.post, http.request |
app.open_url | Open web links in your browser. | app.open_url |
overlay | Put its own values (a timer, a score, a queue) into your overlays, where {{plugin.<its id>.<name>}} shows them. | overlay.set, overlay.get, overlay.clear, goals.list, goals.get, goals.set, goals.add, goals.on, overlay.press, overlay.confetti, overlay.rain, overlay.lower_third, overlay.spawn, overlay.draw, overlay.clear_draw, overlay.performance, overlay.canvas |
obs | See your OBS scenes and audio, switch scenes, mute audio and show or hide sources. What your viewers see can change. It can never start or stop your stream. | obs.state, obs.set_scene, obs.set_mute, obs.set_source_visible, obs.on, obs.off, obs.levels, obs.talking, obs.save_replay, obs.screenshot, obs.filters, obs.filter, obs.transform, obs.get_transform, obs.media, obs.set_text, obs.get_volume, obs.set_volume, obs.fade_volume |
ai | Ask ForgeCast's AI. Each request is paid with your AI credits and shows under AI workers. | ai.ask, ai.classify, ai.translate, ai.session |
history | See the streams recorded on this PC: when, how long, viewers, chat and support. | history.streams, history.stream, history.week, history.on, history.off |
system | See the PC's processor, memory, graphics card, network, disk, battery and temperature, and keep it awake. | system.specs, system.usage, system.app, system.battery, system.temps, system.keep_awake, system.ping, system.watch |
activity | See how long since the last key press (not what was typed) and which game is being played. It says what you are doing. | activity.idle_ms, activity.game, activity.on |
media | See what music is playing on the PC. | media.now_playing, media.on |
tts | Read text aloud with the PC's voices. | tts.say, tts.stop, tts.voices |
clipboard | Put text on the clipboard (never read it). | clipboard.copy |
ui.app | Add its own page to the sidebar, commands to Ctrl+K, items to the right-click menu and to a chat message's menu, and badges next to names. | ui.page, ui.remove_page, ui.command, ui.remove_command, ui.context_menu, ui.remove_context_menu, chats.menu, chats.remove_menu, chats.decorate, chats.undecorate, remote.button, remote.remove, deck.button, deck.remove, nav.page, nav.remove |
points | See, give and take the channel's points (games, giveaways, redeems, predictions). | points.name, points.get, points.account, points.add, points.take, points.set, points.transfer, points.top, points.on, redeems.add, predictions.start |
viewers | See who has chatted across streams: since when, how often, how many streams. | viewers.get, viewers.top, viewers.count |
youtube.chat | Send messages and run polls in the live chat as the channel | youtube.send_chat, youtube.poll, youtube.end_poll |
youtube.moderate | Delete messages and time out or ban viewers in the live chat | youtube.delete_message, youtube.timeout, youtube.ban, youtube.unban |
youtube.manage | Change the live stream's title and description | youtube.set_title, youtube.set_description |
hotkeys | Register global hotkeys that work while a game has the focus | hotkeys.on, hotkeys.off, hotkeys.list |
lights | Change, flash or turn off the smart lights added in Devices | lights.list, lights.set, lights.flash, lights.off |
homeassistant | Call Home Assistant services and read states (never locks, alarms, garage doors or cameras) | homeassistant.call, homeassistant.state, homeassistant.states |
midi | Read MIDI controllers and light their pads | midi.devices, midi.on, midi.off, midi.send |
microphone | Listen for voice commands or make live captions (Windows speech recognition) | speech.listen, speech.stop, captions.on, captions.off |
donations | See tips from Ko-fi, Streamlabs and StreamElements | donations.on, donations.off, donations.recent |
oauth | Use the Spotify or Google account the streamer connected, after they say yes | oauth.connect, oauth.status, oauth.request |
discord | Post in the streamer's Discord server through ForgeCast's bot | discord.send, discord.channels |
network, app.open_url, obs and ai are marked Be careful in the approval dialog and start unticked.
Everything else needs no permission: log, print, json, time, timer, util, plugin, app.info, require, the interface elements (ui.column, ui.text, ui.button and the rest), and plain Lua.
What the person sees
When someone turns a plugin on, ForgeCast lists the permissions it asked for with a plain-language line each, and lets them tick what to allow. They can change their mind later with the Permissions button on the plugin's card. So:
- Ask only for what you use. People read the list. A notifier that asks for
networkgets looked at twice. - A plugin must cope with a permission being refused. Calling a function it wasn't allowed gives an error that says which permission it needs (and whether it is missing from
plugin.jsonor only wasn't approved). The error goes to the console and the plugin carries on. - Asking for more later (in a new version) stops the plugin until the new permission is approved.
- What was approved is remembered on this computer, per plugin.
-- is this working? ask the console
local ok, err = pcall(function() return chats.get() end)
if not ok then log.warn("chat isn't allowed for this plugin:", err) endThe folder
keyword-alerts/
├─ plugin.json
├─ main.lua
├─ helpers.lua your own modules: require("helpers")
├─ lib/
│ └─ format.lua require("lib.format")
├─ .forgecast/ written by ForgeCast: the API for your editor
├─ .luarc.json Lua language server settings
└─ .vscode/ VS Code settingsrequire("name") loads another .lua file from the plugin's folder (lib.format is lib/format.lua). It can't reach outside the folder.

