Skip to content
ForgeCastDocs

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

FieldRequiredWhat it is
idyesThe 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.
nameyesThe name people see, up to 60 characters.
versionyesLike 1.0.0. Change it when you change the plugin.
authornoWho made it.
descriptionnoWhat it does, in a sentence or two (up to 500 characters). Shown on the plugin's card.
homepagenoWhere to read more.
mainnoThe Lua file that starts the plugin, inside the folder. Default main.lua.
apinoThe plugin API version it was written for. Today that is 1, and it is the default.
permissionsnoWhat 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.

PermissionLets the pluginFunctions
chat.readSee 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.middlewareLook at every message before it is shown, and block or change it.chats.use, chats.unuse
stream.readSee 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.notifyPop up notifications inside ForgeCast.ui.notify
ui.modalOpen dialog boxes over the app.ui.modal, ui.alert, ui.confirm, ui.prompt, ui.close
ui.windowOpen windows of its own.window.create, window.close, window.focus, window.set_title
ui.dashboardAdd its own sections to the Dashboard, and a settings panel to its card.dashboard.section, dashboard.remove, plugin.settings, plugin.config
storageSave 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
soundsPlay sounds from your Sound Library.sounds.play
alertsTrigger your alerts, as if the event had happened on your stream.alerts.show
busSend and receive messages with your other plugins.bus.emit, bus.on, bus.off, bus.handle, bus.call
networkSend 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_urlOpen web links in your browser.app.open_url
overlayPut 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
obsSee 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
aiAsk ForgeCast's AI. Each request is paid with your AI credits and shows under AI workers.ai.ask, ai.classify, ai.translate, ai.session
historySee the streams recorded on this PC: when, how long, viewers, chat and support.history.streams, history.stream, history.week, history.on, history.off
systemSee 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
activitySee 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
mediaSee what music is playing on the PC.media.now_playing, media.on
ttsRead text aloud with the PC's voices.tts.say, tts.stop, tts.voices
clipboardPut text on the clipboard (never read it).clipboard.copy
ui.appAdd 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
pointsSee, 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
viewersSee who has chatted across streams: since when, how often, how many streams.viewers.get, viewers.top, viewers.count
youtube.chatSend messages and run polls in the live chat as the channelyoutube.send_chat, youtube.poll, youtube.end_poll
youtube.moderateDelete messages and time out or ban viewers in the live chatyoutube.delete_message, youtube.timeout, youtube.ban, youtube.unban
youtube.manageChange the live stream's title and descriptionyoutube.set_title, youtube.set_description
hotkeysRegister global hotkeys that work while a game has the focushotkeys.on, hotkeys.off, hotkeys.list
lightsChange, flash or turn off the smart lights added in Deviceslights.list, lights.set, lights.flash, lights.off
homeassistantCall Home Assistant services and read states (never locks, alarms, garage doors or cameras)homeassistant.call, homeassistant.state, homeassistant.states
midiRead MIDI controllers and light their padsmidi.devices, midi.on, midi.off, midi.send
microphoneListen for voice commands or make live captions (Windows speech recognition)speech.listen, speech.stop, captions.on, captions.off
donationsSee tips from Ko-fi, Streamlabs and StreamElementsdonations.on, donations.off, donations.recent
oauthUse the Spotify or Google account the streamer connected, after they say yesoauth.connect, oauth.status, oauth.request
discordPost in the streamer's Discord server through ForgeCast's botdiscord.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 network gets 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.json or 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) end

The 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 settings

require("name") loads another .lua file from the plugin's folder (lib.format is lib/format.lua). It can't reach outside the folder.

On this page