> For the complete documentation index, see [llms.txt](https://docs.kouch.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kouch.dev/docs/adr/0022-discord-social-sdk.md).

# 0022: Discord as a second social backend, through the Discord Social SDK

* Status: accepted (owner request 2026-09-28)
* Plan: `docs/DISCORD_PLAN.md`

## Context

Kouch's social features (friends feed, lobby peek, invites, chat) run on Steam. Several of them (invites, rich presence, Workshop) need Kouch's own Steam app id, which hasn't arrived yet, and chat and invites need a second Steam account to test.

The owner's friends are on Discord. On 2026-09-28 they asked for Discord invites, friends, account sync, and a profile chooser for the Discord or Steam picture and banner. Chat is optional. They supplied the Discord Social SDK 1.10 (a C API with `discord_partner_sdk.dll` and `libdiscord_partner_sdk.so`).

## Decision

* **A new crate, `crates/kouch-discord`**, wraps the SDK's C API.
  * It loads the library at run time with `libloading`. Kouch never links against it, so a build or install without the SDK runs normally with Discord features off.
  * One "kouch-discord" thread owns the SDK client and pumps `Discord_RunCallbacks`. The rest of the app talks to it over channels, the same pattern as the input thread and Steam Input.
* **This crate becomes a documented `unsafe` island** (ground rule 4). It's the only place with Discord FFI, and every call site carries a `// SAFETY:` note.
* **Sign-in:** the public-client PKCE flow and, where Discord allows it, the device flow. The app holds only the Application ID; a client secret is never shipped. Tokens are kept in the OS keyring (the secrets store from ADR 0021's work, keyed per config dir).
* **Discord data:**
  * Friends and presence are held in memory only, never written to disk.
  * Unlinking wipes the token and everything derived from it.
  * Discord friends appear alongside Steam friends, not instead of them.
* **Distribution:**
  * **In the repo:** the SDK is never committed; the zip and tree are git-ignored under `vendor/`.
  * **In a release:** the library ships beside the binary once the owner confirms Discord's redistribution terms. Until then, dev builds find the library in `vendor/`.

## Consequences

* A second FFI surface and a second unsafe island. They're kept small and reviewed like `kouch-steam`.
* Linux support is "experimental" in Discord's matrix, and the Deck must be tested.
* The device sign-in flow is documented for consoles only. If Discord doesn't allow it for Kouch, controller-only sign-in on the Deck falls back to a browser or a phone link.
* Dev-tier rate limits (100 operations per 2 h for invites, lobbies and DMs) apply until Discord's Comms Access review passes. That review needs linking, presence, invites and friends working, plus a demo video.
* A Discord account link and a Steam account can show the same friend twice. The user merges them by choice; Kouch doesn't guess.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.kouch.dev/docs/adr/0022-discord-social-sdk.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
