# Shappy Backend

Shappy Backend is the control plane for all the chats that you run. It keeps the model settings, the app tools and the access settings of each connected app. It runs each conversation in celld. Clients are the embedded chats in your apps and the Chrome extension.

> **Note:** To run the backend with Docker, follow [Self-host](/docs/self-host). This page describes the parts of the backend and how to run it from the source checkout.

## How a request travels

![A message goes from the page to your app server, which adds the app credential; Shappy Backend checks the origin, the conversation scope and the tool grants; a celld cell runs the turn, calls the model server and your MCP tools, and streams events back](/docs/diagrams/request-flow.svg)

1. The chat in your page sends the message to your own server.
2. Your server forwards `/shappy/*` to the backend with the app credential. The browser never holds the credential.
3. The backend checks the origin, the conversation scope of the app and the tools that the app may use.
4. A celld cell runs the turn. It asks the backend for the model key at each model request.
5. The model answers. MCP tool calls go to the tools that you connected.
6. Text, tool results and status stream back to the page as server-sent events.
7. The conversation stays in celld.

## Start the backend

Requirements: Node.js 22.19 or newer, the installed dependencies of the checkout, and Docker. The backend keeps conversations in celld, which runs in Docker.

```bash
./app.sh build
```

```bash
./app.sh celld
```

```bash
./app.sh start
```

`./app.sh celld` makes the service tokens, writes them to `celld.json` in the data folder and to the cell project, and starts celld 0.6.1 on `http://127.0.0.1:4610`. Run it again after you change `SHAPPYCHAT_PORT`. `./app.sh start` stops with a message if celld is not prepared.

The backend listens on `http://127.0.0.1:8849`. To use another port, set `SHAPPYCHAT_PORT`.

## Sign in as the operator

When the backend starts, it opens a private, single-use operator link in your browser. The link signs you in to the backend pages.

- To get a new link, run `shappy login` on the same machine. In Docker: `docker compose exec backend shappy login`. From the source checkout: `node server-dist/cli.js login`.
- If the browser does not open, open the URL in the `launch-url` file in the backend data folder.
- The link expires after 10 minutes.
- An operator session lasts 12 hours. It ends when you sign out or restart the backend.

## Backend pages

| Page | Use it to |
| --- | --- |
| **Setup** | Follow the seven setup steps. A new installation opens here until setup is complete. |
| **Playground** | Chat as the operator with every connected tool |
| **History** | Read the Playground conversations and, under **All apps**, the conversations of every connected app |
| **Models** | Set the model endpoint and choose models |
| **Connected apps** | Add an app or the extension, set its origin and tools, copy or revoke its credential |
| **Tools / MCP** | Add and refresh MCP connections |
| **Storage** | See what the data folder holds |
| **Operator access** | See the operator session and sign out |
| **Preferences** | Other backend settings |

## Setup steps

1. **Check this server:** celld and storage.
2. **Model:** where answers come from. Presets for LM Studio, Ollama and other endpoints.
3. **Tools:** turn on the MCP connections that you added under **Tools / MCP**.
4. **Connect an app:** the credential and the allowed origin.
5. **Test message:** a message through the whole path.
6. **Add to your app:** the code, or a prompt for your coding agent. See [Set up with your agent](/docs/agents).
7. **Ready:** a summary.

> **Warning:** Keep the `launch-url` file private. Anyone with the link can operate the backend.

## Configure a model

Open **Models** and set the inference endpoint. The backend works with servers that supply an OpenAI-compatible API, for example a local LM Studio server at `http://127.0.0.1:1234/v1`.

The backend finds the available models. It does not show embedding models. Each conversation keeps its model until you select a different one.

## Connect app tools

Open **Tools / MCP** and add the MCP URL and key of your app. For local processes, use a configuration file. See [App tools (MCP)](/docs/mcp).

## Add a client

Each app and each Chrome extension that uses the backend needs its own credential.

1. Open **Connected apps**.
2. Add a client. Enter its exact origin, for example `https://app.example.com` or `chrome-extension://<extension-id>`.
3. Select the MCP connections that the client can use.
4. If the client must act on its pages, grant host UI permission.
5. Copy the credential. The backend shows it one time only. It stores only a hash of the credential.

Other clients and the Playground cannot see the conversations of a client. To remove access, revoke the client. Revoking also cancels its running replies.

## Allow your app origin

The backend accepts browser requests only from origins that you allow. Set the list in the environment or in the configuration file:

```bash
SHAPPYCHAT_ALLOWED_ORIGINS=https://app.example.com,https://admin.example.com ./app.sh start
```

```json
{
  "allowedOrigins": ["https://app.example.com"]
}
```

Requests also need a valid credential.

## Conversations API

All requests need the app credential as a bearer token.

| Request | Result |
| --- | --- |
| `POST /api/conversations` with `{}` | Creates a conversation. The response contains `conversationId`. |
| `GET /api/conversations` | Lists the conversations of the client |
| `GET /api/conversations/<id>/events` | Server-sent events: the conversation state at connect, then each change. The event ID is the state revision. Send `Last-Event-ID` to receive only newer state. |
| `GET /api/conversations/events` | Server-sent events for the list of conversations of the client |
| `GET /api/models` | The models that the client can choose |
| `GET /sdk/shappychat.tgz` | The SDK package file. No credential is needed. |

The account and workspace scope comes from the trusted configuration. It does not come from the request body.

## Configuration reference

| Variable | Description |
| --- | --- |
| `SHAPPYCHAT_PORT` | The port. Default `8849`. |
| `SHAPPYCHAT_HOST` | The listen address. Default `127.0.0.1`. |
| `SHAPPYCHAT_PUBLIC_URL` | The address that users reach, for example `https://chat.example.com` |
| `SHAPPYCHAT_ALLOWED_HOSTS` | Extra allowed `Host` header values, comma-separated |
| `SHAPPYCHAT_DATA_DIR` | The data folder. Default: `~/Library/Application Support/ShappyChat` on macOS, `%APPDATA%\ShappyChat` on Windows, `$XDG_DATA_HOME/shappychat` or `~/.local/share/shappychat` on Linux |
| `SHAPPYCHAT_CONFIG` | Path to a JSON configuration file |
| `SHAPPYCHAT_ALLOWED_ORIGINS` | Comma-separated list of allowed browser origins |
| `SHAPPYCHAT_MODEL_URL` | The model endpoint. Default `http://127.0.0.1:1234/v1`. |
| `SHAPPYCHAT_MODEL_API_KEY` | The key for the model endpoint. Secret. |
| `SHAPPYCHAT_MASTER_KEY` | Base64 32-byte key that encrypts stored secrets. Default: `master.key` in the data folder. |
| `SHAPPYCHAT_SDK_TARBALL` | Path of the SDK package file that `/sdk/shappychat.tgz` serves |

## Data folder

| File | Contents |
| --- | --- |
| `celld.json` | The celld address, service token and callback token |
| `launch-url` | The private operator link |
| `clients.json` | Client records with hashed credentials |
| `connections-<scope>.json` | Provider and MCP settings for one scope. Keys are encrypted. |
| `master.key` | The key that encrypts provider and MCP keys. Back it up. |
| `admin-secret` | The secret that `shappy login` uses to ask for a new operator link |
| `data-version.json` | The format of the data folder |

celld keeps the conversations and the request receipts. It has one cell for each conversation and one directory cell for each scope. It also has one ledger cell that lists the conversations of all scopes.

**History** shows the conversations of the Playground. Under **All apps**, it shows the conversations of each connected app. Both lists change immediately when a conversation changes. celld keeps its data in `cells/shappy-backend/.celld` in the checkout.

> **Warning:** The backend keeps the provider keys and MCP keys that you enter in the data folder. It encrypts them with AES-256-GCM and `master.key` or `SHAPPYCHAT_MASTER_KEY`. Cells do not keep these keys. A cell gets the key from the backend for each model request. Make a backup of `master.key` with the data folder. Without `master.key`, the backend cannot read the keys.
