Installation
A complete walkthrough for installing @threadplane/chat in an Angular 20+ application, activating a commercial license, and rendering your first chat in under 30 minutes.
This guide goes deeper than the Quick Start: license activation, peer dependencies, and the warnings you'll see in the console.
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 @threadplane/chat for noncommercial use, you can skip the license steps — the library runs without a token (with a one-time advisory warning).
#Prerequisites
@threadplane/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 Angular build toolchain. node --version should report v18 or newer.
The chat UI needs something to talk to. Two officially supported adapters cover virtually every backend:
@threadplane/langgraph— pick this if your backend is LangGraph or LangGraph Platform.@threadplane/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 @threadplane/chat, so swapping later is a one-line change. If you don't have a backend yet, use mockAgent() from @threadplane/chat to wire up the UI first.
#1. Install the packages
Install @threadplane/chat, your chosen runtime adapter, and the marked markdown parser:
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.
@threadplane/chat declares peers on @angular/core, @angular/common, @angular/forms, @angular/platform-browser (all ^20.0.0 || ^21.0.0), plus @threadplane/licensing, @threadplane/render, @threadplane/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.
#2. Add your license token
After purchase, Threadplane emails a signed token that looks like:
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.
So how you store the token is a matter of secret-management preference, not runtime correctness. Pick whichever flow fits your team.
#Option A: .env file (recommended for local dev)
Create .env at the project root (add it to .gitignore):
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:
#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.
#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:
For me, this is the lowest-friction path for a small team — the tradeoff is that everyone with repo access also gets the token. Do not commit it 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 @threadplane/langgraph for @threadplane/ag-ui if you picked that adapter — the API surface is identical).
provideChat() accepts the license as a plain string — you can also inline a typeof guard if your build defines the token as a global:
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 any other global config.
#4. Render your first chat
Add assistantId and threadId to the same root provideAgent({...}) from step 3, then bind <chat> to the result of injectAgent() in your component. Extend the config from step 3 rather than declaring a second provider:
The component just injects that agent — no second provider:
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.
Want several <chat> surfaces pointing at different graphs? Keep apiUrl (and license) on the root provider, then re-provide provideAgent({ assistantId, threadId }) in each component's providers: []. Angular's hierarchical DI merges the component-level config over the root, so each subtree gets its own assistantId while sharing the backend URL. injectAgent() resolves the nearest provider.
#5. Verify the license activated
Open the browser DevTools console and look for messages prefixed with [threadplane].
| What you see | What it means |
|---|---|
(no [threadplane] warnings) | Token verified successfully. You're licensed. |
[threadplane] @threadplane/chat: license missing. | No token was passed. Chat still works, but you're in advisory mode. |
[threadplane] @threadplane/chat: license expired. | Token is past exp. Renew at threadplane.ai. |
[threadplane] @threadplane/chat: license tampered. | Token failed signature verification. Re-copy from the purchase email. |
[threadplane] @threadplane/chat: license in grace period. | Token expired recently but is still inside the 14-day grace window. |
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:
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
.envparser 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; 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
The 5-minute version of this guide.
Tiers, grace periods, status semantics.
Embedded, popup, or sidebar.
Override design tokens for your brand.
Tool calls, human-in-the-loop, durable threads.
Full primitive and composition reference.