StreamNook
StreamNook

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:

Transport

  • The host spawns the plugin executable (manifest runtime.entry) with runtime.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 id and expect exactly one response. Notifications carry no id and 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.

Tip

See Hooks for what each hook does, and Manifest for declaring requested capabilities.

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 ping request 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:

CodeNameMeaning
-32000capability_deniedMethod or credential kind not granted
-32001consent_deniedUser declined the consent prompt, or revoked the grant
-32002unknown_streamstream_id does not match an active relay session
-32003rate_limitedToo many calls; retry later
-32004shutting_downHost is shutting down; the call was not performed
-32005credential_unavailableNo 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_version is 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_min gates installation against the host application version. protocol_version gates the wire contract at the handshake. A host that cannot satisfy the plugin's protocol version fails initialize with -32600 and 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_change payloads beyond an empty reserved shape.

Note

New to plugins? Start with the Quickstart.