diff --git a/apps/website/content/docs/chat/getting-started/installation.mdx b/apps/website/content/docs/chat/getting-started/installation.mdx
index 1df1a645e..79b1e9164 100644
--- a/apps/website/content/docs/chat/getting-started/installation.mdx
+++ b/apps/website/content/docs/chat/getting-started/installation.mdx
@@ -1,110 +1,239 @@
# Installation
-Detailed setup guide for `@ngaf/chat`.
+A complete walkthrough for installing `@ngaf/chat` in an Angular 20+ application, activating a commercial license, and rendering your first chat in under 30 minutes.
-## Requirements
+
+This guide is written for customers who purchased a Developer Seat, Team, or Enterprise plan and received a `THREADPLANE_LICENSE` token by email. If you're evaluating `@ngaf/chat` for noncommercial use, you can skip the license steps — the library runs without a token (with a one-time advisory warning).
+
+
+## Prerequisites
-
-`@ngaf/chat` uses Angular Signals, the `input()` function, and `contentChildren()`. Angular 20 or later is required.
+
+`@ngaf/chat` uses Angular Signals, `input()`, and `contentChildren()`. Run `ng version` to confirm. Upgrade with `ng update @angular/core @angular/cli` if you're below 20.
-Required for the build toolchain and package installation.
+Required for the Angular build toolchain. `node --version` should report `v18` or newer.
+
+
+You need something for the chat UI to talk to. Two officially supported adapters cover virtually every backend:
+
+- **`@ngaf/langgraph`** — pick this if your backend is LangGraph or LangGraph Platform.
+- **`@ngaf/ag-ui`** — pick this for any AG-UI compatible backend (CrewAI, Mastra, Microsoft Agent Framework, AG2, Pydantic AI, AWS Strands, CopilotKit runtime).
+
+Both adapters expose the same `Agent` contract to `@ngaf/chat`, so swapping later is a one-line change. If you don't have a backend yet, use `mockAgent()` from `@ngaf/chat` to wire up the UI first.
-## Install the package
+## 1. Install the packages
+
+Install `@ngaf/chat`, your chosen runtime adapter, and the `marked` markdown parser:
```bash
-npm install @ngaf/chat marked
+# LangGraph backends
+npm install @ngaf/chat @ngaf/langgraph marked
+
+# AG-UI compatible backends
+npm install @ngaf/chat @ngaf/ag-ui marked
```
-`marked` is required for parsing assistant markdown. Beyond that: the chat components ship with their own design tokens and component-encapsulated styles. **No PostCSS config, no global stylesheet import, no Tailwind required.**
+`marked` is a required peer dependency used to render assistant message markdown (code blocks, tables, headings). The chat components ship with their own design tokens and component-scoped styles — no Tailwind, PostCSS, or global stylesheet import is required.
-## Peer Dependencies
+
+`@ngaf/chat` declares peers on `@angular/core`, `@angular/common`, `@angular/forms`, `@angular/platform-browser` (all `^20.0.0 || ^21.0.0`), plus `@ngaf/licensing`, `@ngaf/render`, `@ngaf/a2ui`, `@json-render/core` (`^0.16.0`), `@langchain/core` (`^1.1.33`), `rxjs` (`~7.8.0`), and `marked` (`^15 || ^16`). npm 7+ installs all of these automatically.
+
-`@ngaf/chat` declares the following peer dependencies:
+## 2. Add your license token
-| Package | Version | Required |
-|---------|---------|----------|
-| `@angular/core` | `^20.0.0 \|\| ^21.0.0` | Yes |
-| `@angular/common` | `^20.0.0 \|\| ^21.0.0` | Yes |
-| `@angular/forms` | `^20.0.0 \|\| ^21.0.0` | Yes |
-| `@angular/platform-browser` | `^20.0.0 \|\| ^21.0.0` | Yes |
-| `@ngaf/licensing` | `*` | Yes |
-| `@ngaf/render` | `*` | Yes |
-| `@ngaf/a2ui` | `*` | Yes |
-| `@json-render/core` | `^0.16.0` | Yes |
-| `@langchain/core` | `^1.1.33` | Yes |
-| `rxjs` | `~7.8.0` | Yes |
-| `marked` | `^15.0.0 \|\| ^16.0.0` | Yes |
+After purchase, ThreadPlane emails a signed token that looks like:
-`@cacheplane/partial-json` is installed by `@ngaf/chat` for streaming JSON parsing.
+```
+eyJzdWIiOiJjdXN0QGV4YW1wbGUuY29tIiwidGllciI6ImRldmVsb3Blci1zZWF0IiwiaWF0IjoxNzM…
+```
-
-`marked` parses AI message content into HTML (headings, code blocks, tables, lists). It is a required peer; the library ships a defensive plain-text fallback for resilience, but the rendered output is unusable without `marked` installed.
-
+The token is signed with Ed25519. Verification is **offline** and **advisory** — a missing or expired token logs one `console.warn` line on first boot and the chat keeps working. There is no kill switch, no network call, no telemetry.
+
+That makes how you store the token a matter of secret-management preference rather than runtime correctness. Pick whichever flow fits your team.
-## Configure provideChat() (optional)
+### Option A: `.env` file (recommended for local dev)
-Add `provideChat()` alongside your agent provider to register `CHAT_CONFIG` for global chat configuration:
+Create `.env` at the project root (add it to `.gitignore`):
+
+```bash
+# .env
+THREADPLANE_LICENSE=eyJzdWIi…
+```
+
+Wire the variable into your Angular environment file or read it directly in `app.config.ts` via your build's env-var mechanism (Vite/esbuild `define`, Angular CLI `fileReplacements`, etc.). For a typical Angular CLI setup:
+
+```ts
+// src/environments/environment.ts
+export const environment = {
+ production: false,
+ threadplaneLicense: process.env['THREADPLANE_LICENSE'] ?? '',
+};
+```
+
+### Option B: CI secret / secret manager (recommended for production)
+
+Set `THREADPLANE_LICENSE` as a build-time secret in GitHub Actions, Vercel, Netlify, CircleCI, AWS Secrets Manager, Doppler, or whatever you already use. Reference it the same way as Option A — the token is baked into the bundle at build time.
+
+```yaml
+# .github/workflows/deploy.yml
+- run: npm run build
+ env:
+ THREADPLANE_LICENSE: ${{ secrets.THREADPLANE_LICENSE }}
+```
+
+### Option C: Commit to a private repo
+
+The token is signed — it cannot be forged. If your repository is private and you accept distributing the token to everyone with repo access, it's safe to commit. Paste the literal string into `app.config.ts`:
```ts
-// app.config.ts
-import { ApplicationConfig } from '@angular/core';
+provideChat({
+ license: 'eyJzdWIi…',
+});
+```
+
+This is the lowest-friction path for small teams. Do **not** commit the token to a public repository — anyone with the token can use the seats it grants.
+
+## 3. Wire `provideChat()` and `provideAgent()`
+
+Register both providers in your application config. Below is a minimal `app.config.ts` for a LangGraph backend (swap `@ngaf/langgraph` for `@ngaf/ag-ui` if you picked that adapter — the API surface is identical).
+
+```ts
+// src/app/app.config.ts
+import { ApplicationConfig, provideZonelessChangeDetection } from '@angular/core';
+import { provideAgent } from '@ngaf/langgraph';
import { provideChat } from '@ngaf/chat';
+import { environment } from '../environments/environment';
export const appConfig: ApplicationConfig = {
providers: [
- provideChat({ assistantName: 'Assistant' }),
+ provideZonelessChangeDetection(),
+ provideAgent({
+ apiUrl: environment.langgraphApiUrl, // e.g. 'http://localhost:2024'
+ }),
+ provideChat({
+ license: environment.threadplaneLicense,
+ assistantName: 'Assistant',
+ }),
],
};
```
-`provideChat()` is optional - chat components fall back to sensible defaults.
+`provideChat()` accepts the license as a plain string — you can also inline a `typeof` guard if your build defines the token as a global:
+
+```ts
+declare const THREADPLANE_LICENSE: string | undefined;
+
+provideChat({
+ license: typeof THREADPLANE_LICENSE === 'string' ? THREADPLANE_LICENSE : undefined,
+});
+```
-## Theming
+`provideChat()` itself is optional — chat components fall back to sensible defaults — but you'll want it once you start passing a license, an `assistantName`, or other global config.
-The chat ships with a complete light/dark token system. Three ways to customize:
+## 4. Render your first chat
-### 1. Override a single token at app root
+Create a component, import `ChatComponent`, and bind it to an `agent()` instance. The full working example:
-```css
-/* src/styles.css */
-:root {
- --ngaf-chat-primary: oklch(0.55 0.22 264);
+```ts
+// src/app/chat-page.component.ts
+import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
+import { agent } from '@ngaf/langgraph';
+import { ChatComponent } from '@ngaf/chat';
+
+@Component({
+ selector: 'app-chat-page',
+ standalone: true,
+ imports: [ChatComponent],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ template: `
+
+
+
+ `,
+})
+export class ChatPageComponent {
+ protected readonly chatAgent = agent({
+ assistantId: 'chat_agent', // The graph/agent ID exposed by your backend
+ threadId: signal(null), // null = new thread on first send
+ });
}
```
-### 2. Force a theme via attribute
+Add the route, run `ng serve`, and open the page. You should see the chat surface mount, an input at the bottom, and streaming responses as the agent replies.
-```html
-
-```
+## 5. Verify the license activated
-### 3. Deep override via the optional global stylesheet
+Open the browser DevTools console and look for messages prefixed with `[threadplane]`.
-```css
-/* src/styles.css */
-@import '@ngaf/chat/chat.css';
+| What you see | What it means |
+|--------------|---------------|
+| (no `[threadplane]` warnings) | Token verified successfully. You're licensed. |
+| `[threadplane] @ngaf/chat: license missing.` | No token was passed. Chat still works, but you're in advisory mode. |
+| `[threadplane] @ngaf/chat: license expired.` | Token is past `exp`. Renew at [threadplane.ai](https://threadplane.ai/pricing). |
+| `[threadplane] @ngaf/chat: license tampered.` | Token failed signature verification. Re-copy from the purchase email. |
+| `[threadplane] @ngaf/chat: license in grace period.` | Token expired recently but is still inside the 14-day grace window. |
-:root {
- --ngaf-chat-primary: oklch(0.55 0.22 264);
-}
+Each warning fires at most once per package per status, so the console stays quiet on subsequent renders. There is no UI badge, no banner, and no rate limit — verification is purely a one-time advisory.
+
+
+A successful boot is silent. If you see `[threadplane]` lines in production, fix them before shipping — but the app will continue to function either way.
+
+
+## Troubleshooting
+
+
+
+You shipped without `THREADPLANE_LICENSE` defined at build time. Confirm the build secret is set in your CI environment, then verify the value actually reaches the bundle. A quick check:
+
+```ts
+console.log('license length:', environment.threadplaneLicense?.length ?? 0);
```
-See [Theming](/docs/chat/guides/theming) for the full token reference.
+It should print roughly 200+ characters. Zero means the env var didn't get inlined.
+
+
+The token failed Ed25519 verification. Common causes:
+
+- The string was truncated when copied from email (some clients break long lines).
+- A `.env` parser stripped a trailing character.
+- You pasted the token with a leading or trailing whitespace.
+
+Re-copy the full token from the original purchase email and try again. Tokens never expire silently — a tampered status always means string corruption.
+
+
+Your 12-month term has lapsed. Renew at [threadplane.ai/pricing](https://threadplane.ai/pricing); you'll receive a new token by email. There's a 14-day grace window after `exp` (during which the status reports `grace` rather than `expired`) to give you time to renew without disruption.
+
+
+Verify `apiUrl` in `provideAgent()` points to a reachable LangGraph or AG-UI endpoint, and `assistantId` matches a deployed graph on that server. For LangGraph, `langgraph dev` defaults to `http://localhost:2024`.
+
+
+Double-check the install completed and your `tsconfig.json` `paths` does not shadow node_modules. The package ships ESM and CJS — both Angular CLI and Vite-based builds work out of the box.
+
+
-## What's Next
+## What's next
- Build a working chat in 5 minutes.
+ The 5-minute version of this guide.
+
+
+ Tiers, grace periods, status semantics.
- Embedded, popup, or sidebar?
+ Embedded, popup, or sidebar.
- Customize the visual design.
+ Override design tokens for your brand.
+
+
+ Tool calls, human-in-the-loop, durable threads.
+
+
+ Full primitive and composition reference.