API Reference
Protocol
The JSON-RPC over stdio wire contract between StreamNook and process plugins.
JSON-RPC 2.0 between the host (StreamNook) and a plugin process, over the plugin's stdin and stdout. This document freezes protocol version 1.
Info
Protocol version 1 is frozen. The protocol_version integer bumps only on breaking changes (see Versioning rules).
This page covers the transport, lifecycle, errors, versioning, and reserved features. For the two message catalogs, see the dedicated pages:
Events
Notifications the host sends to the plugin.
Host methods
Requests and notifications the plugin sends to the host.
Transport
- The host spawns the plugin executable (manifest
runtime.entry) withruntime.args, working directory set to the plugin's install directory. - stdin and stdout carry protocol messages only. stderr is free-form: the host captures it to the plugin's log file.
- Each message is one JSON-RPC 2.0 envelope, framed with a byte-length header:
Content-Length: <byte count>\r\n
\r\n
<exactly that many bytes of UTF-8 JSON>- One envelope per frame. JSON-RPC batch arrays are not supported.
- Maximum frame size is 4 MiB. An oversized or malformed frame is a protocol violation. The host may terminate the plugin.
- Requests carry
idand expect exactly one response. Notifications carry noidand receive no response, including no error response.
Lifecycle
Handshake
Host sends initialize
Host spawns the process and sends the initialize request.
Plugin responds
Plugin responds within 10 seconds or the host terminates it.
Host sends initialized
Host sends the initialized notification. Event delivery begins only after this point.
initialize request, host to plugin:
{
"protocol_version": 1,
"host_version": "7.8.6",
"plugin_id": "community.example",
"granted": {
"events": ["on_watch_tick", "on_followed_live"],
"host_methods": ["get_followed_live", "notify", "log"],
"credentials": ["twitch.android"],
"ui": ["panel"]
},
"data_dir": "<absolute path the plugin may persist state in>",
"log_dir": "<absolute path of the directory holding the plugin's log file>"
}granted is the subset of the manifest's requested capabilities the user actually granted. A plugin must work with any subset (degrade or report via log, not crash).
initialize result, plugin to host:
{
"plugin_version": "1.2.0",
"hooks": ["on_watch_tick", "on_followed_live"]
}hooks is the list of events the plugin wants delivered. It must be a subset of granted.events. Names outside it are ignored. The host only emits events listed in hooks.
Shutdown
Host sends shutdown
Host sends the shutdown request. The plugin finishes in-flight work and responds with null.
Host sends exit
Host sends the exit notification. The plugin exits with code 0.
Host force-kills if needed
If the process is still alive 5 seconds after exit, the host kills it.
Health and restarts
- The host sends a
pingrequest every 30 seconds. The plugin responds with{}. Three consecutive missed responses count as unhealthy and the host restarts the plugin. - On process exit or unhealthy state, the host restarts with backoff: 1s, then 5s, then 25s. More than 3 restarts within 10 minutes disables the plugin and notifies the user.
- Events emitted while a plugin is down are not replayed. After any (re)start a plugin must rebuild its view of the world from host methods (for example
get_followed_live) instead of assuming it saw every event. - Event delivery order is preserved per plugin.
Warning
Do not assume you saw every event. A plugin can be restarted at any time, and events that fired while it was down are gone. Re-fetch current state on startup.
Errors
Standard JSON-RPC 2.0 codes apply (-32700 parse error, -32600 invalid request, -32601 method not found, -32602 invalid params, -32603 internal error). Host-defined codes:
| Code | Name | Meaning |
|---|---|---|
| -32000 | capability_denied | Method or credential kind not granted |
| -32001 | consent_denied | User declined the consent prompt, or revoked the grant |
| -32002 | unknown_stream | stream_id does not match an active relay session |
| -32003 | rate_limited | Too many calls; retry later |
| -32004 | shutting_down | Host is shutting down; the call was not performed |
| -32005 | credential_unavailable | No credential of that kind exists to hand over |
Error responses use the JSON-RPC error object. error.data may carry { "name": "<name above>", "retry_after_ms": <number|null> }.
Versioning rules
protocol_versionis an integer, currently 1. It bumps only on breaking changes.- Additive changes (new events, new methods, new optional fields, new panel field types, new error codes) do not bump it.
- Both sides must ignore unknown fields in any payload.
- A plugin must not call methods or rely on events outside its granted set, regardless of what this document defines.
- The manifest's
host_mingates installation against the host application version.protocol_versiongates the wire contract at the handshake. A host that cannot satisfy the plugin's protocol version failsinitializewith-32600and disables the plugin with a user notice.
Reserved, not in v1
runtime.kind = "wasm": in-process sandboxed extensions for safe extension points. Reserved in the manifest enum. The v1 host rejects it at install.runtime.transport = "socket": connecting to an independently running plugin instead of spawning it. Reserved. The v1 host rejects it at install.on_settings_changepayloads beyond an empty reserved shape.
Note
New to plugins? Start with the Quickstart.