---
title: System
description: Browse files, read and change settings, set up Discord, run commands and exit the backend over the WebSocket API.
---

Browse the filesystem, read and update settings, run allowlisted commands, and shut down the backend.

## Files & directories

These events let you browse the base directories System Bridge exposes, list and inspect files within them, and validate paths.

The available base directory keys are `documents`, `downloads`, `home`, `music`, `pictures` and `videos`, plus any custom directories configured in `media.directories` in your [settings](#settings).

### List directories

Send the `GET_DIRECTORIES` event to list the available base directories. It takes no data and responds with the `DIRECTORIES` type.

```json title="Request"
{
    "id": "abc123",
    "token": "abc123",
    "event": "GET_DIRECTORIES",
    "data": {}
}
```

### Get a directory

Send the `GET_DIRECTORY` event with the base directory key to look up a single directory. It responds with the `DIRECTORY` type.

```json title="Request"
{
    "id": "abc123",
    "token": "abc123",
    "event": "GET_DIRECTORY",
    "data": {
        "base": "documents"
    }
}
```

### List files

Send the `GET_FILES` event with a base directory, and optionally a relative `path` within it, to list files. It responds with the `FILES` type.

```json title="Request"
{
    "id": "abc123",
    "token": "abc123",
    "event": "GET_FILES",
    "data": {
        "base": "documents",
        "path": "subfolder"
    }
}
```

### Get a file

Send the `GET_FILE` event with the absolute `path` to a file to get its information. It responds with the `FILE` type.

```json title="Request"
{
    "id": "abc123",
    "token": "abc123",
    "event": "GET_FILE",
    "data": {
        "path": "/home/user/Documents/example.txt"
    }
}
```

To read the contents of a media file, use the [Media File Data](/api/media-file-data/) HTTP endpoint instead.

### Validate a directory

Send the `VALIDATE_DIRECTORY` event with a `path` to check whether it exists and is a directory. It responds with the `DIRECTORY_VALIDATED` type and a `data.valid` boolean.

```json title="Request"
{
    "id": "abc123",
    "token": "abc123",
    "event": "VALIDATE_DIRECTORY",
    "data": {
        "path": "/home/user/Music"
    }
}
```

### Get disk mounts

Send the `GET_DISK_MOUNTS` event to list mounted disks, categorised into primary and secondary (bind and squashfs) mounts. It takes no data and responds with the `DISK_MOUNTS` type.

```json title="Request"
{
    "id": "abc123",
    "token": "abc123",
    "event": "GET_DISK_MOUNTS",
    "data": {}
}
```

## Settings

Read and update the backend settings over the WebSocket connection.

### Get settings

Send the `GET_SETTINGS` event to retrieve the current settings. It takes no data and responds with the `SETTINGS_RESULT` type.

```json title="Request"
{
    "id": "abc123",
    "token": "abc123",
    "event": "GET_SETTINGS",
    "data": {}
}
```

### Update settings

Send the `UPDATE_SETTINGS` event with the settings object to update. It responds with the `SETTINGS_UPDATED` type and the updated settings.

```json title="Request"
{
    "id": "abc123",
    "token": "abc123",
    "event": "UPDATE_SETTINGS",
    "data": {
        "autostart": true,
        "logLevel": "INFO"
    }
}
```

`UPDATE_SETTINGS` replaces the whole `commands.allowlist`, so two clients saving at once can undo each other's commands. To change one command, use the events below.

### Add, change or remove a command

Each of these changes one command in `commands.allowlist` and leaves the rest as they're saved, then responds with the updated settings.

| Event | Data | Response type |
| --- | --- | --- |
| `COMMAND_ADD` | The command, as in [`commands.allowlist`](#settings-keys) | `COMMAND_ADDED` |
| `COMMAND_UPDATE` | The command with its new values, matched by `id` | `COMMAND_UPDATED` |
| `COMMAND_REMOVE` | `{ "id": "..." }` | `COMMAND_REMOVED` |

```json title="Request"
{
    "id": "abc123",
    "token": "abc123",
    "event": "COMMAND_UPDATE",
    "data": {
        "id": "9ef69bc3-62f8-4d86-952d-5f498bbddf0f",
        "name": "Say hi",
        "command": "/usr/bin/echo",
        "arguments": ["hi"],
        "workingDir": "",
        "prefab": ""
    }
}
```

Adding a command whose ID is already on the list, or changing one that isn't (such as one another client removed), returns an `ERROR` response. Removing a command that isn't on the list does nothing. A command is checked the same way as through `UPDATE_SETTINGS`.

### Settings changes

Whenever the settings are saved, through any of the events above, every connected client gets a `SETTINGS_CHANGED` message with the `id` `system` and the new settings as its data, so it can show them without asking again.

### Settings keys

| Key | Type | Description |
| --- | --- | --- |
| `autostart` | boolean | Start the backend automatically when you log in. |
| `logLevel` | string | One of `DEBUG`, `INFO`, `WARN`, `ERROR`. Defaults to `WARN`. |
| `hotkeys` | array | List of `{ name, key }` hotkey bindings. |
| `commands.allowlist` | array | Commands that can be run via [Execute Command](#execute-command). Each entry is `{ id, name, command, workingDir, arguments, prefab }`. `prefab` is a [prefab](#list-command-prefabs)'s ID, or empty. With a prefab and an empty `command`, the prefab's program runs. |
| `disks.allowedSecondaryMountPoints` | array | Secondary mount points to include in disk data. |
| `media.directories` | array | Custom media directories as `{ name, path }`, exposed as [base directories](#files--directories). |
| `theme` | string | The web client's own theme, as a Groundwork theme document's JSON text, so every client of this host gets it. Empty when there's none. |

:::note
Changing `autostart` or `logLevel` is applied immediately by the backend.
:::

## Discord setup

Read and save the Discord application System Bridge signs in with. See [Discord](/features/discord/) for creating the application.

### Get the Discord setup

Send the `GET_DISCORD_SETUP` event to see how far Discord is set up. It takes no data and responds with the `DISCORD_SETUP` type. The client secret is never sent back.

```json title="Request"
{
    "id": "abc123",
    "token": "abc123",
    "event": "GET_DISCORD_SETUP",
    "data": {}
}
```

```json title="Response data"
{
    "configured": true,
    "clientId": "123456789012345678",
    "redirectUri": "http://localhost",
    "running": true,
    "connected": true,
    "authenticated": false,
    "error": ""
}
```

| Key | Description |
| --- | --- |
| `configured` | Valid credentials are saved. |
| `clientId` | The saved client ID, or empty. |
| `redirectUri` | The redirect to add on the application's **OAuth2** page. |
| `running` | The Discord desktop app can be reached. |
| `connected` | System Bridge is connected to Discord. |
| `authenticated` | You've approved System Bridge in Discord. |
| `error` | Why the last attempt to connect or sign in failed, or empty. |

### Update the Discord setup

Send the `UPDATE_DISCORD_SETUP` event with the application's `clientId` and `clientSecret`. System Bridge saves them to `discord.json`, readable only by your user, then connects to Discord straight away. Changing the application drops the saved Discord token, so Discord asks you to approve it again. It responds with the `DISCORD_SETUP_UPDATED` type and the [setup](#get-the-discord-setup).

```json title="Request"
{
    "id": "abc123",
    "token": "abc123",
    "event": "UPDATE_DISCORD_SETUP",
    "data": {
        "clientId": "123456789012345678",
        "clientSecret": "YOUR_CLIENT_SECRET"
    }
}
```

A client ID that isn't the long number from the **OAuth2** page, or a missing secret, returns an `ERROR` response with the `BAD_REQUEST` subtype.

## Execute command

Run a command from the allowlist defined in your [settings](#settings).

Send the `COMMAND_EXECUTE` event with the `commandID` of an allowlisted command:

```json title="Request"
{
    "id": "abc123",
    "token": "abc123",
    "event": "COMMAND_EXECUTE",
    "data": {
        "commandID": "my-command"
    }
}
```

The command runs asynchronously. You receive a `COMMAND_EXECUTING` response immediately, followed by a `COMMAND_COMPLETED` response once it finishes.

:::caution
Only commands present in `commands.allowlist` can be executed. Requesting an unknown command returns an `ERROR` response with the `COMMAND_NOT_FOUND` subtype.
:::

### List command prefabs

Send the `GET_COMMAND_PREFABS` event to list the [prefab commands](/features/commands/#prefab-commands) and whether each can run on this system. It takes no data and responds with the `COMMAND_PREFABS` type. A prefab only runs once it's added to `commands.allowlist`.

```json title="Request"
{
    "id": "abc123",
    "token": "abc123",
    "event": "GET_COMMAND_PREFABS",
    "data": {}
}
```

```json title="Response data"
[
    {
        "id": "lock",
        "name": "Lock screen",
        "description": "Lock the screen",
        "available": true,
        "command": "/usr/bin/loginctl",
        "arguments": ["lock-session"],
        "reason": ""
    }
]
```

| Key | Description |
| --- | --- |
| `available` | A program for it was found on this system. |
| `command`, `arguments` | What it would run, or empty when it isn't available. |
| `reason` | Why it isn't available, such as which tool to install, or empty. |

## Exit application

Send the `EXIT_APPLICATION` event to shut down the backend. It takes empty `data`.

```json title="Request"
{
    "id": "abc123",
    "token": "abc123",
    "event": "EXIT_APPLICATION",
    "data": {}
}
```
