> ## Documentation Index
> Fetch the complete documentation index at: https://ttrpg-gm.docs.kitefrost.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Foundry VTT

> Use KiteFrost inside Foundry Virtual Tabletop - from the right-click menu, from macros and modules, or by calling the API directly.

KiteFrost gives your Foundry NPCs a voice: right-click an Actor, type what the players
say, and the NPC answers in character in chat. There are three ways to wire it up.
Most GMs only need the first; module and macro authors will want the second.

|                  | 1. Module - point and click                                                    | 2. Module - scripting API                                              | 3. Direct REST / SDK                                                                                    |
| ---------------- | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| **Who it's for** | GMs                                                                            | Macro and module authors                                               | Developers with their own tooling                                                                       |
| **Setup**        | Install the module, paste 3 settings                                           | Same as 1                                                              | None in Foundry; your own code                                                                          |
| **Code needed**  | None                                                                           | A few lines of JavaScript                                              | Your own HTTP / SDK code                                                                                |
| **Runs where**   | Foundry (GM's browser)                                                         | Foundry (GM's browser)                                                 | Dialogue: a Foundry macro. Everything else: Node.js / a server, outside the browser                     |
| **Reaches**      | NPC dialogue, issue reports                                                    | NPC dialogue, issue reports, a hook on every reply                     | The whole KiteFrost API (from Node / a server)                                                          |
| **Pros**         | Nothing to write; posts to chat as the NPC; uses the Actor's sheet for context | Automate: triggers, batch lines, custom UI; same behaviour as the menu | Full API; your own error handling, storage and UI                                                       |
| **Cons**         | Manual, one NPC at a time                                                      | Only what the module exposes                                           | You build request bodies and chat output yourself; in a browser only the dialogue endpoints are allowed |

<Warning>
  **Alpha access runs on staging.** Use `https://api-staging.kitefrost.ai` as the API URL
  until your invite says otherwise. The module is a **testing build** during the alpha.
</Warning>

## Before you start: an API key and your project

1. Sign in to your KiteFrost dashboard and open your project (or create one:
   **Projects -> New Project**).
2. Copy the **project ID** from the address bar - the part after `/projects/` (for
   example `https://.../projects/my-campaign` -> `my-campaign`).
3. Open the project's **API Keys** page -> **New API Key**. Choose **Secret (sk\_)** and
   **Full Access**, give it a name such as `foundry`, then **Create Key**.
4. Copy the key right away - it is shown only once. Treat it like a password.

The key is stored in your browser only (Foundry's client setting), never in the world
data your players can see. The project's **API Keys** page shows when each key was last
used - handy to confirm Foundry is really using the key you made.

## 1. The module, point and click

Foundry v13 or v14, logged in as the Gamemaster.

<Steps>
  <Step title="Install">
    Foundry setup screen -> **Add-on Modules** -> **Install Module**. Paste into
    **Manifest URL**:

    ```text theme={null}
    https://gitlab.com/kitefrost/foundry-vtt-sdk-testing/-/releases/permalink/latest/downloads/module.json
    ```

    Click **Install**. It appears as **KiteFrost (Testing)**. Foundry offers each new
    testing build as a normal module update.
  </Step>

  <Step title="Enable it in your world">
    Launch your world -> **Game Settings** (gear icon, right sidebar) ->
    **Manage Modules** -> tick **KiteFrost (Testing)** -> **Save Module Settings**.
  </Step>

  <Step title="Configure">
    **Game Settings -> Configure Settings -> KiteFrost**:

    * **API URL**: `https://api-staging.kitefrost.ai`
    * **API Key**: the `sk_...` key
    * **Project ID**: from the address bar (step 2 above)

    **Save Changes**.
  </Step>

  <Step title="Talk to an NPC">
    **Actors** tab -> right-click an Actor -> **AI: Generate Dialogue**. Type what the
    player says, optionally the situation and tone, and submit. The reply is posted to
    chat as that NPC, with its mood and suggested follow-ups. Use **Report Issue** on
    the message if a reply is off.
  </Step>
</Steps>

**Give an NPC a personality.** Anything stored on the Actor in the `kitefrost.personality`
flag is sent with every request (run once, as a macro):

```js theme={null}
await game.actors.getName("Grognard the Innkeeper").setFlag("kitefrost", "personality", {
  personality_traits: "Gruff exterior, secretly kind-hearted",
  motivation: "Protect the village from outsiders",
  secret: "Was once an adventurer before a bad injury",
});
```

## 2. The module's scripting API (macros and modules)

With the module installed and configured as above, everything the menu does is
available from code at `game.modules.get("kitefrost").api`.

```js theme={null}
const kf = game.modules.get("kitefrost").api;
try {
  const r = await kf.generateDialogue(game.actors.getName("Grognard the Innkeeper"), {
    playerMessage: "Any rooms free tonight?",
    situation: "late evening, the common room is packed", // optional
    tone: "friendly",                                      // optional
  });
  console.log(r.dialogue, r.mood, r.suggested_actions);   // also posted to chat
} catch (e) {
  ui.notifications.error(e.message);                       // bad key, missing setting, ...
}
```

| Member                                                                           | What it does                                                                                                                                                                             |
| -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `generateDialogue(actorOrId, { playerMessage, situation?, tone?, postToChat? })` | Generates a line (no dialog). Resolves `{ npc_name, dialogue, mood, stage_direction, suggested_actions, message }`; posts to chat unless `postToChat: false` (then `message` is `null`). |
| `extractActorContext(actorOrId)`                                                 | Shows exactly which NPC details are sent for an Actor.                                                                                                                                   |
| `reportIssue({ category, severity, description, npcName?, dialogue?, mood? })`   | Sends an issue report; resolves `{ feedback_id }`.                                                                                                                                       |
| `version`                                                                        | The installed module version.                                                                                                                                                            |

Every call **rejects** on a problem - wrap it in `try / catch`.

**React to every reply** - from the menu or the API:

```js theme={null}
Hooks.on("kitefrost.dialogueGenerated", ({ actor, result, message }) => {
  // e.g. speak it with your TTS module, or log it to a journal
});
```

**Example - a greeting for every selected token:**

```js theme={null}
const kf = game.modules.get("kitefrost").api;
for (const token of canvas.tokens.controlled) {
  await kf.generateDialogue(token.actor, { playerMessage: "The party walks in.", tone: "curious" });
}
```

## 3. Direct REST or the KiteFrost SDKs

Skip the module and call the API yourself.

**From a Foundry macro (browser)** - the NPC dialogue endpoint accepts calls from any
site, so plain `fetch` works:

```js theme={null}
const API = "https://api-staging.kitefrost.ai";
const KEY = "sk_...";          // better: read from a client setting, not the macro text
const PROJECT = "my-campaign";

const res = await fetch(`${API}/v1/projects/${PROJECT}/quick-dialogue`, {
  method: "POST",
  headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    npc_name: "Old Mara",
    player_message: "What do you know about the ruined tower?",
    tone: "mysterious",
    npc_context: { personality_traits: "cryptic, fond of riddles" },
  }),
});
if (!res.ok) throw new Error(`KiteFrost ${res.status}`);
const { dialogue, mood } = await res.json();
ChatMessage.create({ speaker: { alias: "Old Mara" }, content: `<p><em>[${mood}]</em> ${dialogue}</p>` });
```

<Note>
  In a browser only the NPC dialogue and issue-report endpoints can be called from
  another site. Everything else (projects, NPCs, quests, sessions, ...) is available from
  **Node.js or a server** - a companion script, a bot, or a build step - not from a
  Foundry page. A macro's text is visible to anyone who can open it: never paste a key
  into a macro you share.
</Note>

**From Node.js - the TypeScript SDK** (`npm install @kitefrost/ttrpg-gm@alpha`):

```ts theme={null}
import { TtrpgGmClient } from "@kitefrost/ttrpg-gm";

const kf = new TtrpgGmClient({ apiKey: process.env.KITEFROST_API_KEY, baseUrl: "https://api-staging.kitefrost.ai" });
const r = await kf.ttrpg.quick_dialogue("my-campaign", {
  npc_name: "Old Mara",
  player_message: "What do you know about the ruined tower?",
});
console.log(r.dialogue);
```

**From Python** (`pip install --pre kitefrost-ttrpg-gm`):

```python theme={null}
from kitefrost_core import KiteFrostCore
from kitefrost_ttrpg_gm import TtrpgGmClient

kf = TtrpgGmClient(KiteFrostCore(api_key="sk_...", base_url="https://api-staging.kitefrost.ai"))
r = kf.ttrpg.quick_dialogue("my-campaign", {"npc_name": "Old Mara", "player_message": "What do you know about the ruined tower?"})
print(r["dialogue"])
```

See [TypeScript SDK](/_shared/sdks/typescript) and [Python SDK](/_shared/sdks/python)
for the full client, and the [API reference](/api-reference) for every endpoint.

## Troubleshooting

| Symptom                                  | Fix                                                                                                                |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| No **AI: Generate Dialogue** in the menu | The menu item appears only when **API Key** and **Project ID** are set. Check **Configure Settings -> KiteFrost**. |
| `401` / "API key" error                  | The key is wrong or revoked - create a new one on the project's **API Keys** page.                                 |
| `404`                                    | The Project ID doesn't match a project of that key's account. Copy it again from the address bar.                  |
| Nothing happens                          | Press **F12 -> Console** and look for a red `[KiteFrost]` line.                                                    |
