Addon API
Everything on the gryt object a client plugin runs against, generated from the source
Generated from the source and regenerated by CI, so it cannot fall behind the code. Editing this page by hand gets the edit wiped on the next run — change what the generator reads instead.
This is the reference. Addons is the page that teaches the shape, and plugin pairs covers the server half.
A plugin runs in a worker of its own, and gryt is a global in it. There is no
window.gryt and no addon id on any call — Gryt already knows which plugin is
asking.
What is not there
A worker has no page, and the rest is taken away before your module is imported:
window // a worker has none
document
localStorage
indexedDB // deleted off the prototype chain, not just off globalThis
caches
Worker // no nesting out of itYour network is not. Whatever you are granted, you can send anywhere, and that is the part worth telling people who install your plugin.
Capabilities
Declared in the manifest and agreed to per addon. Both, or the call rejects and says which is missing.
| Capability | What the person reads |
|---|---|
status | Set what you are doing, on every server you are on |
messaging | Exchange its own messages with the servers you are on |
display | Show its own panel beside the member list |
processes | See which of your listed programs are running |
media | See what your computer's media controls say is playing |
activity | Put a card on your profile, like "Listening to", on every server you are on |
The manifest
manifest.json, in your addon's folder.
| Field | Type | What it is |
|---|---|---|
id | string | |
name | string | |
version | string | |
type | "plugin" | "theme" | |
description? | string | |
author? | string | |
banner? | string | |
styles? | string[] | Theme-only: CSS files to inject |
main? | string | Plugin-only: JS entry point |
requiresReloadOnDisable? | boolean | Plugin-only: if true, disabling the addon reloads the client |
capabilities? | string[] | Plugin-only: what it says it needs to do. Agreed to per addon before window.gryt will answer; unknown names are dropped, not refused (GRYT-928). |
repository? | string | Where the addon is published, as owner/repo on GitHub. Optional, and not free-form: anything but two plain path segments is rejected when it is read. |
gryt
version
version: stringtheme
theme: ThemeInfoon()
on(event: "themeChange" | "cleanup", handler: (payload: ThemeInfo | undefined) => void): () => voidHear about something. themeChange when appearance changes, cleanup when
this plugin is turned off — the worker is terminated shortly after.
setActivity()
setActivity(activity: string): Promise<unknown>Needs status.
Say what the person running this is doing. An empty string clears it, and it rejects rather than resolving quietly when not granted.
gryt.messaging
send()
send(topic: string, data: unknown, host?: string): Promise<unknown>Needs messaging.
Send to the copy of this plugin on the server.
on()
on(topic: string, handler: (message: unknown) => void): () => voidHear from it. Needs messaging.
servers()
servers(): Promise<string[]>Needs messaging.
Which servers run the other half. A round trip, so a promise.
gryt.processes
running()
running(): Promise<string[]>Needs processes.
Which of the programs the person listed are running. Their list, not their machine. Empty in a browser and until one is listed.
on()
on(handler: (running: string[]) => void): () => voidHear when that answer changes. Needs processes.
gryt.media
current()
current(): Promise<unknown>Needs media.
What the media controls say is playing, or null. Desktop only.
on()
on(handler: (playing: unknown) => void): () => voidHear when it changes, checked every fifteen seconds. Needs media.
gryt.activity
set()
set(card: { type?: string; name: string; details?: string; state?: string; startedAt?: number }): Promise<unknown>Needs activity.
Put a card on your profile: { type: "listening", name, details, state, startedAt }.
clear()
clear(): Promise<unknown>Needs activity.
Take the card down.
gryt.ui
panel()
panel(panel: { title: string; rows: { label: string; value?: string }[] }): Promise<unknown>Needs display.
Draw a panel beside the member list. A title and rows of text, nothing else; calling it again replaces the one panel per plugin.
clear()
clear(): Promise<unknown>Needs display.
Take it down.
gryt.log
info()
info(message: string)warn()
warn(message: string)error()
error(message: string)