> ## Documentation Index
> Fetch the complete documentation index at: https://docs.evox.wraithesports.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Events and host-RPC reference

> The complete list of events a plugin receives and RPC calls it can send to the host.

This page is the complete surface of the evoX plugin protocol: **events** coming from the host to the plugin and **host-RPC** calls going from the plugin to the host. All names are the real contract in `@evox/plugin-protocol`; the renderer/plugin payload is not authoritative, identity and context are derived by the host.

## Contract rules

* Each binding instance is valid only for its own `bindingInstanceId` context. A display call after `action.willDisappear` is rejected with `CONTEXT_EXPIRED`.
* The host-assigned `session.plugin.pluginId` is the only authoritative identity; no other identity is selected through an event/RPC payload.
* RPC calls require a capability. A call that is not declared/granted returns `CAPABILITY_DENIED` (see [Capability APIs](/en/sdk/capabilities)).
* Error behavior is fail-closed; for codes see [Error codes](/en/sdk/errors).

## Received events (host → plugin)

Registered with `client.on(<event>, handler)`. Handlers must be registered before the `client.start()` handshake.

### Plugin lifecycle

| Event            | When                                                                               |
| ---------------- | ---------------------------------------------------------------------------------- |
| `plugin.start`   | The session was established and `host.hello` received; the plugin is ready to work |
| `plugin.stop`    | The session is closing; run handler cleanup and call `client.dispose()`            |
| `plugin.suspend` | The plugin was temporarily suspended; do not send new requests                     |
| `plugin.resume`  | Returned from suspension; continue normal processing                               |

### Device

| Event                 | When                                                                                 |
| --------------------- | ------------------------------------------------------------------------------------ |
| `device.connected`    | A device was connected; the payload carries the device identity and size information |
| `device.disconnected` | The device was removed                                                               |

### Action binding

| Event                    | When                                                                                                                                                                           |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `action.willAppear`      | An action instance became visible on a key/dial (app launch, profile/page switch, user assigned it)                                                                            |
| `action.willDisappear`   | The action instance is no longer visible (profile/page change, assignment deleted)                                                                                             |
| `action.keyDown`         | The user pressed the key                                                                                                                                                       |
| `action.keyUp`           | The user released the key                                                                                                                                                      |
| `action.dialDown`        | The user pressed the dial                                                                                                                                                      |
| `action.dialUp`          | The user released the pressed dial                                                                                                                                             |
| `action.dialRotate`      | The user rotated the dial; the payload carries `delta` (signed step, e.g. `+1`/`-1`) and/or `direction` (`'LEFT'`/`'RIGHT'`)                                                   |
| `action.settingsChanged` | The user changed this binding's settings in the interface; the current `settings` are in the payload. The plugin's own `client.patchSettings` call does not produce this event |

Every event carries `actionId` and `bindingInstanceId` in `event.context`. An `actionId` the plugin does not recognize must be ignored.

```js theme={}
client.on('action.keyDown', async (event) => {
  if (event.context?.actionId !== 'counter') return;
  await client.setTitle(event.context.bindingInstanceId, '1');
});

client.on('action.willDisappear', (event) => {
  counters.delete(event.context?.bindingInstanceId);
});
```

## Host-RPC calls (plugin → host)

Called through the SDK client; each returns a `Promise` and fails closed.

### Key/screen display — `key.display` capability

| SDK method                        | RPC               | Description                                                                               |
| --------------------------------- | ----------------- | ----------------------------------------------------------------------------------------- |
| `client.setTitle(context, title)` | `key.setTitle`    | Changes the binding title                                                                 |
| `client.setImage(context, image)` | `key.setImage`    | Changes the binding image (manifest-hash `assetId` or a bounded PNG/JPEG/WebP descriptor) |
| `client.setState(context, state)` | `key.setState`    | Changes the state of a multi-state action (starting at 0)                                 |
| `client.showSuccess(context)`     | `key.showSuccess` | Shows a temporary success indicator                                                       |
| `client.showError(context)`       | `key.showError`   | Shows a temporary error indicator                                                         |

```js theme={}
await client.setTitle(context.bindingInstanceId, 'Hazır');
await client.showSuccess(context.bindingInstanceId);
```

Raw file paths or external URLs are not accepted.

### Settings persistence

| SDK method                                 | RPC              | Description                                                                                                                                                                                                             |
| ------------------------------------------ | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `client.getSettings(context?)`             | `settings.get`   | Reads the persistent setting of the binding (or plugin-wide without a context)                                                                                                                                          |
| `client.patchSettings(settings, context?)` | `settings.patch` | Partially updates the setting and returns the current settings. The plugin's own write is not echoed back to it as `action.settingsChanged`; that event arrives only when the user changes the setting in the interface |

Every key you write must be declared in the manifest's settings schema: the action's `settingsSchema` for a call with a context, the plugin-wide `settingsSchema` for a call without one. A request containing a key that is not declared in the schema is rejected with `INVALID_REQUEST` (SDK 0.2.0 behavior change; the binding level now follows the same rule as plugin-wide settings). An attempt to write a `secret` or `oauth` field through this path returns `CAPABILITY_DENIED`.

<Warning>Do not write tokens/passwords/client secrets into normal settings. Use the secret/OAuth APIs for credentials.</Warning>

### Plugin-scoped storage — `storage.private` capability

| SDK method                      | RPC              | Description                                       |
| ------------------------------- | ---------------- | ------------------------------------------------- |
| `client.storageGet(key)`        | `storage.get`    | Reads a plugin-private value with a bounded quota |
| `client.storageSet(key, value)` | `storage.set`    | Writes the value                                  |
| `client.storageDelete(key)`     | `storage.delete` | Deletes the value                                 |

### Network and credentials — `network.fetch` / `secret.manage` / `oauth`

| SDK method                                 | RPC                           | Description                                                                                                                                                                            |
| ------------------------------------------ | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `client.networkFetch(input)`               | `network.fetch`               | A request within the declared HTTPS host/method/byte scope                                                                                                                             |
| `client.networkFetchWithCredential(input)` | `network.fetchWithCredential` | The host resolves the `{kind:'secret',name}` / `{kind:'oauth',provider}` reference from the vault and injects it into the permitted request; the raw token never returns to the plugin |
| `client.hasSecret(name)`                   | `secret.has`                  | Whether the secret exists (returns no bytes)                                                                                                                                           |
| `client.deleteSecret(name)`                | `secret.delete`               | Deletes the secret                                                                                                                                                                     |
| `client.beginOAuth(provider)`              | `oauth.begin`                 | Starts the OAuth flow                                                                                                                                                                  |
| `client.getOAuthStatus(provider)`          | `oauth.status`                | Reads the OAuth status (returns no token bytes)                                                                                                                                        |

### System and advanced surface

The following calls are defined in the protocol and capability-protected; without a separate SDK shortcut method, they are used through the generic `client.request(<rpc>, params)` path. Each requires the related permission to be declared in the manifest and a host/user grant.

| RPC                   | Capability            | Description                                        |
| --------------------- | --------------------- | -------------------------------------------------- |
| `system.openExternal` | `system.openExternal` | Opens an HTTPS URL in the default browser          |
| `system.openPath`     | `system.openPath`     | Opens a permitted path on the system               |
| `input.sendHotkey`    | `input.sendHotkey`    | Sends a shortcut key combination to the system     |
| `input.typeText`      | `input.typeText`      | Types bounded text to the system                   |
| `profile.activate`    | `profile.activate`    | Activates a permitted profile                      |
| `profile.write`       | `profile.write`       | Performs a host-validated profile write            |
| `clipboard.read`      | `clipboard.read`      | Reads bounded content from the clipboard           |
| `clipboard.write`     | `clipboard.write`     | Writes bounded content to the clipboard            |
| `action.invoke`       | `action.invoke`       | Triggers actions of plugins on the permission list |

<Warning>`input.*`, `clipboard.*` and `profile.*` are high-impact surfaces: they are default-deny, declare them with a narrow scope; in T2 they do not work without a user grant.</Warning>

## Notes

* This reference reflects the current protocol version; capability names and limits are normative on the [Capability APIs](/en/sdk/capabilities) page.
* For the public distribution boundary and T1/T2/T3 differences, see [Trust tiers](/en/sdk/trust-tiers) and [Distribution status](/en/sdk/distribution-status).
