StreamNook
StreamNook

Plugin Development

Manifest Reference

Every field of plugin.toml, the permission contract, the capability tiers, and install validation.

Every plugin ships a plugin.toml at the root of its artifact. The manifest is the complete, machine-readable statement of what the plugin is and what it may ask the host for. Anything not declared here is denied at runtime.

Example

id          = "community.drops-farmer"
name        = "Drops and Points Farmer"
version     = "1.2.0"
author      = "communityhandle"
tier        = "C"
description = "Background drops and channel-points farming."
homepage    = "https://example.org/drops-farmer"
host_min    = "8.0.0"

[runtime]
kind      = "process"
entry     = "drops-farmer.exe"
args      = []
transport = "stdio"

[capabilities]
events       = ["on_watch_tick", "on_followed_live", "on_channel_change"]
host_methods = ["get_followed_live", "notify", "log", "register_panel", "get_panel_values"]
credentials  = ["twitch.android"]
network      = "external"
ui           = ["panel"]

Top-level fields

FieldTypeConstraints
idstringReverse-DNS, globally unique, must match ^[a-z0-9]+(\.[a-z0-9-]+)+$, max 64 chars. Never changes across versions
namestringDisplay name, max 40 chars
versionstringSemver (MAJOR.MINOR.PATCH)
authorstringAuthor handle as listed in the index
tierstring"A", "B", or "C". See tier definitions below. Declared by the author, verified by the index curator. A plugin may not self-certify into a lower tier
descriptionstringPlain-language summary, max 200 chars, shown in the install dialog
homepagestringOptional, https URL
host_minstringMinimum StreamNook version (semver). Install is blocked on older hosts

[runtime]

FieldTypeConstraints
kindstring"process" (a separate executable) or "ui" (an in-app interface module, see Plugin UI). "wasm" is reserved and rejected
entrystringPath of the executable (process) or bundled JavaScript module (ui), relative to the plugin directory. Must not contain .. or be absolute
argsstring arrayprocess only: arguments passed at spawn. Optional, default empty
transportstringprocess only: "stdio" in v1. "socket" is reserved and rejected by the v1 host
ui_entrystringOptional, process only: path of an in-app UI module the sidecar ships alongside itself (a hybrid plugin). Same path rules as entry. See Plugin UI

Note

For kind = "ui" the [capabilities] and [contributes] blocks stay empty. The module contract in Plugin UI is the complete surface. A hybrid process plugin that sets ui_entry keeps its capabilities and contributions for the sidecar. The ui kind and ui_entry were added after protocol v1 froze. Both are additive (the plugin's host_min must be a version that knows them, and older hosts fail closed on the unknown value or field).

[capabilities]

The whole permission contract. The consent dialog renders exactly this block in plain language (see Plugin Capabilities for the vocabulary and the rendered strings).

FieldTypeMeaning
eventsstring arrayEvents the plugin may subscribe to. Subset of the event list in Protocol
host_methodsstring arrayHost methods the plugin may call. Note get_credential is governed by credentials, not by this list
credentialsstring arrayCredential kinds the broker may hand over, each requiring separate first-use consent. v1 vocabulary: "twitch.android"
networkstring"none" or "external". Informational and surfaced in consent: the host cannot prevent a separate process from using the network, so this field exists to make the plugin's behavior explicit to the user. A plugin observed doing networking it declared it does not do is grounds for index removal
uistring arrayUI contributions. v1 vocabulary: "panel"

Warning

Unknown capability strings cause install rejection in v1 hosts (fail closed), with one exception: index metadata may carry forward-looking strings for newer hosts, and the install dialog of an older host shows them as "requires a newer StreamNook".

[contributes]

Optional. The named hooks the plugin fills so the native UI can delegate to it. See Hooks for the full mechanism.

[contributes]
actions  = ["drops.mine", "drops.stop"]   # actions the plugin handles when the UI invokes them
status   = ["drops.status"]               # status slots the plugin pushes into for the UI to show
provides = ["drops.mining"]               # feature flags the host uses to light up matching controls

Each entry is a namespaced id (feature.name), defined by the host feature that exposes the hook. Non-namespaced ids are rejected at install.

Signing fields

The manifest itself carries no signature block. Signatures are detached and live alongside the artifact. The author's public key is pinned through the index and the first-install flow. This avoids a self-referential artifact (the manifest travels inside the signed artifact) and keeps one verification path. See Plugin Signing.

Tiers

A neutral capability-scope label and curation metadata. It is not a risk rating.

TierLabelScopeExamplesDistribution
AStandardOfficial APIs, local-only features, read-only integrations, ordinary user actionsTheme packs, layout tools, local statsOfficial index
BExtendedAdditional Twitch and third-party interfaces; user-initiated actions with no official equivalentAlternate emote providers, community badge sourcesOfficial index
CAdvancedPower-user add-ons that run their own background work and may use the user's loginDrops or points farming, ad bypassCommunity sources

Info

The tier is curation metadata: it determines where a plugin may be listed (see Plugin Signing). Its user-facing presentation is a neutral badge. The consent flow (Plugin Capabilities) is the same calm, capability-focused dialog for every tier. The official index lists the curated A and B tiers; heavier or specialized add-ons live in community sources.

Validation order at install

Artifact hash

Artifact hash matches the index entry.

Signature

Detached signature verifies against the author key (pinned via the index and trust-on-first-use).

Manifest parse

Manifest parses, all constraints above hold.

Index match

Manifest id, version, and tier exactly match the index entry. Any mismatch blocks install.

Host support

host_min is satisfied and runtime.kind plus runtime.transport are supported.

Consent

The consent dialog is shown. The user grants capabilities (possibly a subset).

Register

The plugin is unpacked into its own directory and registered.

A failure at any step blocks install with a specific reason. There is no partial install.