diff --git a/.env.example b/.env.example
index 02a953dda..5f1462f64 100644
--- a/.env.example
+++ b/.env.example
@@ -6,8 +6,8 @@ POSTHOG_PERSONAL_API_KEY=
POSTHOG_HOST=https://us.i.posthog.com
POSTHOG_PROJECT_ID=
-# @ngaf/telemetry (libs/telemetry)
-# Default ingest URL points to the ThreadPlane website reverse proxy. Self-hosters
+# @threadplane/telemetry (libs/telemetry)
+# Default ingest URL points to the Threadplane website reverse proxy. Self-hosters
# can redirect to their own ingest. See libs/telemetry/README.md.
# NGAF_TELEMETRY_INGEST_URL=https://threadplane.ai/api/ingest
# NGAF_TELEMETRY_SAMPLE_RATE=1.0
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 2a0e61cb8..cd50db8aa 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -65,7 +65,7 @@ jobs:
# Trusted publishing is configured per-package on npm; no NPM_TOKEN needed.
# The OIDC token from id-token: write authenticates this workflow as a
- # trusted publisher for each @ngaf/* package. Provenance attestations are
+ # trusted publisher for each @threadplane/* package. Provenance attestations are
# generated automatically.
- name: Publish to npm
diff --git a/AGENTS.md b/AGENTS.md
index 65a104a5a..8c5a7d0d2 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -36,7 +36,7 @@ This file is for agents working in this repository. It is contributor-facing, no
## Repo Layout
-- `libs/langgraph`: main Angular library (`@ngaf/langgraph`).
+- `libs/langgraph`: main Angular library (`@threadplane/langgraph`).
- `apps/website`: docs and marketing site.
- `examples/chat/angular/e2e`: browser end-to-end coverage for the canonical chat example.
diff --git a/COMMERCIAL.md b/COMMERCIAL.md
index 421a62ff2..a58a28a25 100644
--- a/COMMERCIAL.md
+++ b/COMMERCIAL.md
@@ -1,19 +1,19 @@
# Licensing
-Most libraries in this repository — `@ngaf/render`, `@ngaf/agent`, `@ngaf/langgraph`, `@ngaf/ag-ui`, `@ngaf/a2ui`, `@ngaf/licensing`, `@ngaf/telemetry`, `@ngaf/design-tokens` — are released under the **MIT License**. Free for any use, commercial or noncommercial, with attribution. See [`LICENSE`](./LICENSE).
+Most published libraries in this repository — `@threadplane/render`, `@threadplane/langgraph`, `@threadplane/ag-ui`, `@threadplane/a2ui`, `@threadplane/licensing`, `@threadplane/telemetry` — are released under the **MIT License**. Free for any use, commercial or noncommercial, with attribution. See [`LICENSE`](./LICENSE).
-## `@ngaf/chat`
+## `@threadplane/chat`
-`@ngaf/chat` is dual-licensed:
+`@threadplane/chat` is dual-licensed:
- **PolyForm Noncommercial 1.0.0** for free noncommercial use (personal, hobby, student, academic, nonprofit, public demos, OSI-licensed open source, 30 calendar days of commercial evaluation from first commercial use).
-- **ThreadPlane Commercial license** for commercial production use. Sold via [threadplane.ai/pricing](https://threadplane.ai/pricing); see [/docs/licensing](https://threadplane.ai/docs/licensing) for installation.
+- **Threadplane Commercial license** for commercial production use. Sold via [threadplane.ai/pricing](https://threadplane.ai/pricing); see [/docs/licensing](https://threadplane.ai/docs/licensing) for installation.
See [`libs/chat/LICENSE.md`](./libs/chat/LICENSE.md), [`libs/chat/LICENSE-COMMERCIAL.md`](./libs/chat/LICENSE-COMMERCIAL.md), and [`libs/chat/COMMERCIAL-USE.md`](./libs/chat/COMMERCIAL-USE.md) for the full terms.
## Minting Service
-The ThreadPlane minting service (`apps/minting-service/`) is a proprietary internal service and is not covered by the MIT License. See `apps/minting-service/LICENSE` for its terms.
+The Threadplane minting service (`apps/minting-service/`) is a proprietary internal service and is not covered by the MIT License. See `apps/minting-service/LICENSE` for its terms.
## Questions
diff --git a/README.md b/README.md
index 0e4c078c1..031e8b608 100644
--- a/README.md
+++ b/README.md
@@ -1,18 +1,18 @@
- Agent UI for Angular — Production-ready chat, threads, and generative UI for AI agents.
+ Threadplane — Production-ready chat, threads, and generative UI for AI agents.
Paste the token below into your @threadplane/chat configuration. Your subscription renews automatically on ${escapeHtml(expiresIso.slice(0, 10))}; manage or cancel any time.
`;
return { subject, text, html };
@@ -130,23 +130,23 @@ export interface RevocationEmailVars {
}
export function renderRevocationEmail(vars: RevocationEmailVars): RenderedEmail {
- const subject = `Your ThreadPlane license has been revoked`;
+ const subject = `Your Threadplane license has been revoked`;
- const text = `Your ThreadPlane ${vars.tier} license has been revoked because the
+ const text = `Your Threadplane ${vars.tier} license has been revoked because the
underlying payment was refunded.
The token previously delivered will fail signature checks at boot and
-@ngaf/chat will fall back to a noncommercial-use warning.
+@threadplane/chat will fall back to a noncommercial-use warning.
If you believe this is in error, reply to this email.
--- The ThreadPlane team
+-- The Threadplane team
`;
- const html = `
Your ThreadPlane ${escapeHtml(vars.tier)} license has been revoked because the underlying payment was refunded.
-
The token previously delivered will fail signature checks at boot and @ngaf/chat will fall back to a noncommercial-use warning.
+ const html = `
Your Threadplane ${escapeHtml(vars.tier)} license has been revoked because the underlying payment was refunded.
+
The token previously delivered will fail signature checks at boot and @threadplane/chat will fall back to a noncommercial-use warning.
If you believe this is in error, reply to this email.
-
-- The ThreadPlane team
+
-- The Threadplane team
`;
return { subject, text, html };
diff --git a/apps/minting-service/src/lib/handlers.ts b/apps/minting-service/src/lib/handlers.ts
index 698dc146b..2fbe3ce94 100644
--- a/apps/minting-service/src/lib/handlers.ts
+++ b/apps/minting-service/src/lib/handlers.ts
@@ -4,7 +4,7 @@ import type {
Db,
License,
UpsertLicenseInput,
-} from '@ngaf/db';
+} from '@threadplane/db';
import type { MintInput } from './sign.js';
import type { LicenseEmailVars, RevocationEmailVars } from './email.js';
import { extractTier, computeSeats, type MintableTier } from './tier.js';
diff --git a/apps/minting-service/src/lib/sign.spec.ts b/apps/minting-service/src/lib/sign.spec.ts
index 21085f56f..3e825e60c 100644
--- a/apps/minting-service/src/lib/sign.spec.ts
+++ b/apps/minting-service/src/lib/sign.spec.ts
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
import * as ed from '@noble/ed25519';
-import { verifyLicense } from '@ngaf/licensing';
+import { verifyLicense } from '@threadplane/licensing';
import { mintToken } from './sign.js';
async function makeKeypair() {
diff --git a/apps/minting-service/src/lib/sign.ts b/apps/minting-service/src/lib/sign.ts
index 6f3390651..99aeb69da 100644
--- a/apps/minting-service/src/lib/sign.ts
+++ b/apps/minting-service/src/lib/sign.ts
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
-import { signLicense, type LicenseClaims } from '@ngaf/licensing';
+import { signLicense, type LicenseClaims } from '@threadplane/licensing';
import type { MintableTier } from './tier.js';
export interface MintInput {
diff --git a/apps/minting-service/src/lib/tier.ts b/apps/minting-service/src/lib/tier.ts
index c99a3e0c3..0785bf23a 100644
--- a/apps/minting-service/src/lib/tier.ts
+++ b/apps/minting-service/src/lib/tier.ts
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
-import type { LicenseTier } from '@ngaf/licensing';
+import type { LicenseTier } from '@threadplane/licensing';
export type MintableTier = Extract;
diff --git a/apps/website/.env.example b/apps/website/.env.example
index e73696366..39a0f5adf 100644
--- a/apps/website/.env.example
+++ b/apps/website/.env.example
@@ -15,7 +15,7 @@ ANTHROPIC_MODEL=claude-sonnet-4-6
# Resend (https://resend.com — free tier: 3,000 emails/month)
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
RESEND_AUDIENCE_ID=aud_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
-RESEND_FROM="Agent UI for Angular "
+RESEND_FROM="Threadplane "
RESEND_NOTIFY_TO=hello@cacheplane.ai
# Loops.so (https://loops.so — free tier: 1,000 contacts)
diff --git a/apps/website/content/AGENTS.md.template b/apps/website/content/AGENTS.md.template
index 9a1b12897..0cde15bcb 100644
--- a/apps/website/content/AGENTS.md.template
+++ b/apps/website/content/AGENTS.md.template
@@ -1,9 +1,9 @@
-# Agent UI for Angular v@VERSION@
+# Threadplane v@VERSION@
Production-ready chat, durable threads, interrupts, subagents, planning, memory, and generative UI for Angular agent apps.
## Install
-npm install @ngaf/chat @ngaf/langgraph
+npm install @threadplane/chat @threadplane/langgraph
## Key requirement
`agent()` MUST be called within an Angular injection context (component constructor or field initializer). Calling it in ngOnInit or any async context throws "NG0203: inject() must be called from an injection context".
@@ -12,18 +12,18 @@ npm install @ngaf/chat @ngaf/langgraph
```typescript
// app.config.ts
import type { ApplicationConfig } from '@angular/core';
-import { provideAgent } from '@ngaf/langgraph';
+import { provideAgent } from '@threadplane/langgraph';
export const appConfig: ApplicationConfig = {
providers: [provideAgent({ apiUrl: 'http://localhost:2024' })]
};
// chat.component.ts
import { Component } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatComponent as NgafChatComponent } from '@ngaf/chat';
+import { agent } from '@threadplane/langgraph';
+import { ChatComponent as ThreadplaneChatComponent } from '@threadplane/chat';
@Component({
- imports: [NgafChatComponent],
+ imports: [ThreadplaneChatComponent],
template: `
`,
diff --git a/apps/website/content/CLAUDE.md.template b/apps/website/content/CLAUDE.md.template
index 9a1b12897..0cde15bcb 100644
--- a/apps/website/content/CLAUDE.md.template
+++ b/apps/website/content/CLAUDE.md.template
@@ -1,9 +1,9 @@
-# Agent UI for Angular v@VERSION@
+# Threadplane v@VERSION@
Production-ready chat, durable threads, interrupts, subagents, planning, memory, and generative UI for Angular agent apps.
## Install
-npm install @ngaf/chat @ngaf/langgraph
+npm install @threadplane/chat @threadplane/langgraph
## Key requirement
`agent()` MUST be called within an Angular injection context (component constructor or field initializer). Calling it in ngOnInit or any async context throws "NG0203: inject() must be called from an injection context".
@@ -12,18 +12,18 @@ npm install @ngaf/chat @ngaf/langgraph
```typescript
// app.config.ts
import type { ApplicationConfig } from '@angular/core';
-import { provideAgent } from '@ngaf/langgraph';
+import { provideAgent } from '@threadplane/langgraph';
export const appConfig: ApplicationConfig = {
providers: [provideAgent({ apiUrl: 'http://localhost:2024' })]
};
// chat.component.ts
import { Component } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatComponent as NgafChatComponent } from '@ngaf/chat';
+import { agent } from '@threadplane/langgraph';
+import { ChatComponent as ThreadplaneChatComponent } from '@threadplane/chat';
@Component({
- imports: [NgafChatComponent],
+ imports: [ThreadplaneChatComponent],
template: `
`,
diff --git a/apps/website/content/blog/2026-05-17-build-a-streaming-chat-ui-in-angular-with-langgraph.mdx b/apps/website/content/blog/2026-05-17-build-a-streaming-chat-ui-in-angular-with-langgraph.mdx
index 5444d841b..dc0f9fc03 100644
--- a/apps/website/content/blog/2026-05-17-build-a-streaming-chat-ui-in-angular-with-langgraph.mdx
+++ b/apps/website/content/blog/2026-05-17-build-a-streaming-chat-ui-in-angular-with-langgraph.mdx
@@ -7,7 +7,7 @@ author: brian
featured: true
---
-Let's build a real streaming chat UI in Angular, wired to a LangGraph backend, using `@ngaf/chat` and `@ngaf/langgraph`.
+Let's build a real streaming chat UI in Angular, wired to a LangGraph backend, using `@threadplane/chat` and `@threadplane/langgraph`.
Most AI chat features still ship without streaming. They buffer the full response on the server, then drop it into the UI in one big paste. For me, that's the line between a demo and a production interface.
@@ -18,7 +18,7 @@ This is the tutorial I wish I had when I started shipping agentic chat in Angula
## Goals
- Understand *why* streaming is the production-vs-demo line for chat.
-- Scaffold a signal-native Angular chat with `@ngaf/chat` and `@ngaf/langgraph` in three files.
+- Scaffold a signal-native Angular chat with `@threadplane/chat` and `@threadplane/langgraph` in three files.
- Wire a real LangGraph backend to the UI without writing any transport code.
- Learn the three production patterns that matter once the scaffold is working: errors, threads, and generative UI.
- Have fun!
@@ -43,9 +43,9 @@ Let's look at the seams before we touch any code.
**LangGraph backend.** This is where your agent graph lives — nodes, edges, tools, interrupts. It exposes a streaming endpoint over SSE. You don't write the transport. LangGraph does.
-**`@ngaf/langgraph` adapter.** This is the Angular-side translator. It takes LangGraph's `ThreadState` and turns it into a signal-shaped `AgentCheckpoint` that the chat UI knows how to render. It also owns the run lifecycle — submit, cancel, retry — and the thread CRUD.
+**`@threadplane/langgraph` adapter.** This is the Angular-side translator. It takes LangGraph's `ThreadState` and turns it into a signal-shaped `AgentCheckpoint` that the chat UI knows how to render. It also owns the run lifecycle — submit, cancel, retry — and the thread CRUD.
-**`@ngaf/chat` UI.** This is the rendering layer. Message list, input, suggestions, interrupt panels, tool-call cards, reasoning blocks. Every piece is a signal, every signal flows through OnPush change detection, and everything is themeable through CSS custom properties.
+**`@threadplane/chat` UI.** This is the rendering layer. Message list, input, suggestions, interrupt panels, tool-call cards, reasoning blocks. Every piece is a signal, every signal flows through OnPush change detection, and everything is themeable through CSS custom properties.
The contract between the adapter and the UI is small on purpose. The chat doesn't know it's talking to LangGraph. The adapter doesn't know how messages get rendered. That separation is what lets you swap the backend, theme the UI, or replace a single component without touching the rest.
@@ -64,21 +64,21 @@ Let's start with a fresh Angular 20 app. Three commands and three files.
```bash
-npm install @ngaf/chat @ngaf/langgraph marked
+npm install @threadplane/chat @threadplane/langgraph marked
```
```bash
-pnpm add @ngaf/chat @ngaf/langgraph marked
+pnpm add @threadplane/chat @threadplane/langgraph marked
```
```bash
-yarn add @ngaf/chat @ngaf/langgraph marked
+yarn add @threadplane/chat @threadplane/langgraph marked
```
@@ -92,8 +92,8 @@ yarn add @ngaf/chat @ngaf/langgraph marked
```ts
// app.config.ts
import { ApplicationConfig } from '@angular/core';
-import { provideAgent } from '@ngaf/langgraph';
-import { provideChat } from '@ngaf/chat';
+import { provideAgent } from '@threadplane/langgraph';
+import { provideChat } from '@threadplane/chat';
export const appConfig: ApplicationConfig = {
providers: [
@@ -111,8 +111,8 @@ export const appConfig: ApplicationConfig = {
```ts
// chat-page.component.ts
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatComponent } from '@ngaf/chat';
+import { agent } from '@threadplane/langgraph';
+import { ChatComponent } from '@threadplane/chat';
@Component({
selector: 'app-chat-page',
@@ -246,12 +246,12 @@ Three places I'd look next:
- The [interrupts guide](/docs/chat/guides/streaming) — how to handle human-in-the-loop pauses without breaking the streaming model.
-If you're wiring `@ngaf/chat` into a regulated, multi-tenant, or design-system-heavy environment, we have a paid track for that. [Talk to us about the enterprise track →](/contact?source=blog_streaming_pillar&track=enterprise)
+If you're wiring `@threadplane/chat` into a regulated, multi-tenant, or design-system-heavy environment, we have a paid track for that. [Talk to us about the enterprise track →](/contact?source=blog_streaming_pillar&track=enterprise)
## Conclusion
-Streaming is the production-vs-demo line, and `@ngaf/chat` plus `@ngaf/langgraph` is the shortest path I've found to get an Angular app across it. Three files, signals all the way down, and a contract small enough that you can swap the backend without touching the UI.
+Streaming is the production-vs-demo line, and `@threadplane/chat` plus `@threadplane/langgraph` is the shortest path I've found to get an Angular app across it. Three files, signals all the way down, and a contract small enough that you can swap the backend without touching the UI.
The interesting work in agentic software isn't the chat itself. It's everything the chat lets you *stop* building so you can get back to the part that actually matters.
diff --git a/apps/website/content/blog/2026-05-21-build-fullstack-agentic-angular-apps-using-ag-ui.mdx b/apps/website/content/blog/2026-05-21-build-fullstack-agentic-angular-apps-using-ag-ui.mdx
index f3ba33a33..077f06898 100644
--- a/apps/website/content/blog/2026-05-21-build-fullstack-agentic-angular-apps-using-ag-ui.mdx
+++ b/apps/website/content/blog/2026-05-21-build-fullstack-agentic-angular-apps-using-ag-ui.mdx
@@ -20,7 +20,7 @@ Let's wire one up.
## Goals
- Understand what AG-UI is and why it matters for Angular devs.
-- Wire an AG-UI-compatible backend to an Angular 20+ app using `@ngaf/ag-ui` and `@ngaf/chat`.
+- Wire an AG-UI-compatible backend to an Angular 20+ app using `@threadplane/ag-ui` and `@threadplane/chat`.
- See how 17 protocol events become a handful of signals you can read from a template.
- Handle the parts that turn a demo into a product: tool calls, interrupts, threads, fallbacks.
- Have fun!
@@ -67,7 +67,7 @@ Three boxes. Two seams.
**The wire.** Server-Sent Events. Plain HTTP, no WebSocket gymnastics, no custom binary framing. Your firewall, load balancer, and reverse proxy already know what to do with it.
-**The Angular side.** This is what ThreadPlane provides. `@ngaf/ag-ui` is the adapter. It consumes the AG-UI event stream and exposes a runtime-neutral `Agent` contract built from signals. `@ngaf/chat` is the UI. It reads from that contract and renders. The two are decoupled on purpose. We'll get to why.
+**The Angular side.** This is what Threadplane provides. `@threadplane/ag-ui` is the adapter. It consumes the AG-UI event stream and exposes a runtime-neutral `Agent` contract built from signals. `@threadplane/chat` is the UI. It reads from that contract and renders. The two are decoupled on purpose. We'll get to why.
## Let's wire it up
@@ -79,21 +79,21 @@ We'll start with a fresh Angular 20+ app. I'll assume you already have one, or y
```bash
-npm install @ngaf/ag-ui @ngaf/chat marked
+npm install @threadplane/ag-ui @threadplane/chat marked
```
```bash
-pnpm add @ngaf/ag-ui @ngaf/chat marked
+pnpm add @threadplane/ag-ui @threadplane/chat marked
```
```bash
-yarn add @ngaf/ag-ui @ngaf/chat marked
+yarn add @threadplane/ag-ui @threadplane/chat marked
```
@@ -106,8 +106,8 @@ yarn add @ngaf/ag-ui @ngaf/chat marked
```ts
// app.config.ts
import { ApplicationConfig } from '@angular/core';
-import { provideAgUiAgent } from '@ngaf/ag-ui';
-import { provideChat } from '@ngaf/chat';
+import { provideAgUiAgent } from '@threadplane/ag-ui';
+import { provideChat } from '@threadplane/chat';
export const appConfig: ApplicationConfig = {
providers: [
@@ -119,15 +119,15 @@ export const appConfig: ApplicationConfig = {
That's the whole bootstrap. `provideAgUiAgent` is the AG-UI transport. It wraps the official `@ag-ui/client` `HttpAgent` and exposes the signal-shaped contract via DI. `provideChat` is the chat UI's configuration.
-Notice they're independent. `@ngaf/chat` doesn't know it's talking to an AG-UI backend. It just reads from the `Agent` contract. We'll lean on that boundary later.
+Notice they're independent. `@threadplane/chat` doesn't know it's talking to an AG-UI backend. It just reads from the `Agent` contract. We'll lean on that boundary later.
### Render the chat
```ts
// chat-page.component.ts
import { Component, ChangeDetectionStrategy, inject } from '@angular/core';
-import { AG_UI_AGENT } from '@ngaf/ag-ui';
-import { ChatComponent } from '@ngaf/chat';
+import { AG_UI_AGENT } from '@threadplane/ag-ui';
+import { ChatComponent } from '@threadplane/chat';
@Component({
selector: 'app-chat-page',
@@ -150,12 +150,12 @@ That's it. Three files, maybe twenty lines of code, and you have a working strea
- The AG-UI streaming demo running on @ngaf/chat with the @ngaf/ag-ui adapter — FakeAgent provides the events, but the same code drives real LangGraph/CrewAI/Mastra backends.
+ The AG-UI streaming demo running on @threadplane/chat with the @threadplane/ag-ui adapter — FakeAgent provides the events, but the same code drives real LangGraph/CrewAI/Mastra backends.
No `EventSource`. No reducer. No manual subscribe-and-render plumbing. No store.
@@ -176,7 +176,7 @@ The AG-UI protocol has seventeen event types, grouped into five families:
Having worked on the protocol from the inside, I'll tell you the families are doing real work. They're not arbitrary. Lifecycle is for "is something happening?" Text messages are the streaming triad you already know from chat UIs. Tool calls are deliberately incremental so you can render the *intent* before the arguments are fully formed. State sync uses RFC 6902 JSON Patch so the wire stays small even when the agent's state is large. Every event earns its keep.
-ThreadPlane's `@ngaf/ag-ui` runs each event through a small reducer that updates a handful of signals on the `Agent` contract:
+Threadplane's `@threadplane/ag-ui` runs each event through a small reducer that updates a handful of signals on the `Agent` contract:
- `messages()`: `Message[]`, the chat history. `TEXT_MESSAGE_CONTENT` appends a delta to the in-flight assistant message.
- `status()`: `'idle' | 'running' | 'error' | 'paused'`. Driven by the `RUN_*` events.
@@ -239,7 +239,7 @@ The slot pattern is intentional. The chat ships defaults so you can demo in a da
An interrupt is the agent saying *"I need a human before I do this thing."*
-You see them in production agents constantly: approve this database write, confirm this email send, choose between these three branches, fill in this missing field. AG-UI surfaces interrupts as state on the agent, and `@ngaf/chat` renders them inline in the message list with whatever resume affordance you give it.
+You see them in production agents constantly: approve this database write, confirm this email send, choose between these three branches, fill in this missing field. AG-UI surfaces interrupts as state on the agent, and `@threadplane/chat` renders them inline in the message list with whatever resume affordance you give it.
```html
@if (agent.interrupt(); as pause) {
@@ -279,7 +279,7 @@ constructor() {
What you *do* with that capability is a product decision, not a framework one. Scope threads per project, per task, per user session. There's no right answer. From my experience, the wrong answer is to ignore the question entirely and ship a chat where every refresh starts from zero.
-If you want a starting point, `@ngaf/chat` exposes a `` primitive that handles the layout without locking you into a persistence model.
+If you want a starting point, `@threadplane/chat` exposes a `` primitive that handles the layout without locking you into a persistence model.
## Swap the backend without changing the UI
@@ -297,7 +297,7 @@ provideAgUiAgent({ url: '/agents/mastra' }),
That's the diff.
-The same applies in reverse. If you're already on a LangGraph stack and want a slightly tighter coupling than AG-UI gives you, `@ngaf/langgraph` is a direct adapter for LangGraph's native streaming API. It speaks the same `Agent` contract to `@ngaf/chat`, so your UI doesn't change either way. Pick whichever fits your team.
+The same applies in reverse. If you're already on a LangGraph stack and want a slightly tighter coupling than AG-UI gives you, `@threadplane/langgraph` is a direct adapter for LangGraph's native streaming API. It speaks the same `Agent` contract to `@threadplane/chat`, so your UI doesn't change either way. Pick whichever fits your team.
For me, the durable bet is AG-UI. I'm biased (I helped grow the ecosystem around it at CopilotKit, and I'm a contributor to the spec), but the list of backends that already speak it covers most of what you'd reach for in 2026, and the protocol is small enough that I trust it not to drift into a multi-page spec that breaks every six months. The community around it is healthy, the maintainers are responsive, and the design choices have aged well.
@@ -308,9 +308,9 @@ The scaffold above is *short* on purpose. The framework intentionally hides the
The parts you'll want on day thirty:
- **Errors and retries.** Per-message retry, transport-level backoff for transient SSE drops, graceful degradation when streaming is unavailable. Some corporate proxies buffer SSE. You'll find out the hard way if you don't plan for it.
-- **Generative UI.** When the agent wants to render a richer surface than a tool-call card, `@ngaf/render` lets the backend stream a UI spec and the frontend resolves it against a registry of your approved Angular components. No arbitrary code, no `eval`, no design-system bypass. The agent picks from a menu you control.
-- **Observability.** `@ngaf/telemetry` ships a PostHog-shaped sink that is *off by default*. Turn it on per-environment, point it at your own analytics, never ship app content to a vendor you didn't pick.
-- **Testing.** Because the contract is signals all the way down, the testing story is "write a signal, the chat re-renders." `@ngaf/ag-ui` ships a `FakeAgent` you can hand-feed events to in a unit test. No SSE harness, no fixture loader, no test-only DI dance.
+- **Generative UI.** When the agent wants to render a richer surface than a tool-call card, `@threadplane/render` lets the backend stream a UI spec and the frontend resolves it against a registry of your approved Angular components. No arbitrary code, no `eval`, no design-system bypass. The agent picks from a menu you control.
+- **Observability.** `@threadplane/telemetry` ships a PostHog-shaped sink that is *off by default*. Turn it on per-environment, point it at your own analytics, never ship app content to a vendor you didn't pick.
+- **Testing.** Because the contract is signals all the way down, the testing story is "write a signal, the chat re-renders." `@threadplane/ag-ui` ships a `FakeAgent` you can hand-feed events to in a unit test. No SSE harness, no fixture loader, no test-only DI dance.
Each of those is its own post. The point here is just that the protocol-to-signal-to-template chain is the *spine*, and everything else hangs off it.
@@ -318,9 +318,9 @@ Each of those is its own post. The point here is just that the protocol-to-signa
AG-UI is the protocol Angular devs have been quietly waiting for, whether they knew it or not. It standardizes the wire between the agent and the UI, it's small enough to hold in your head, and the event model maps onto Angular signals so cleanly that the runtime almost writes itself. Markus and the CopilotKit crew deserve real credit for that. *Thank you* for designing something Angular could meet on its own terms.
-With ThreadPlane (`@ngaf/ag-ui` and `@ngaf/chat` on npm), the wiring is three lines: a provider, an inject, and a ``. The interesting work (your tool cards, your interrupt flows, your generative UI surfaces, your design system) is where you actually want to spend the day.
+With Threadplane (`@threadplane/ag-ui` and `@threadplane/chat` on npm), the wiring is three lines: a provider, an inject, and a ``. The interesting work (your tool cards, your interrupt flows, your generative UI surfaces, your design system) is where you actually want to spend the day.
-If you've been building agents in Angular by hand-rolling SSE parsing and gluing together React components in iframes, *stop*. The whole stack is here, it's open source (the adapters are MIT; `@ngaf/chat` is source-available with a free non-commercial tier), and the protocol underneath has real momentum from the community building it.
+If you've been building agents in Angular by hand-rolling SSE parsing and gluing together React components in iframes, *stop*. The whole stack is here, it's open source (the adapters are MIT; `@threadplane/chat` is source-available with a free non-commercial tier), and the protocol underneath has real momentum from the community building it.
I'd love to hear what you ship. If you wire this up and the docs come up short, [open an issue](https://github.com/threadplane/angular-agent-framework/issues) or come find us on Discord. And if you're building this inside an enterprise Angular app (design system, multi-tenant, regulated), [talk to us](/contact?source=blog_ag_ui_pillar&track=enterprise). We've helped a few teams through that gauntlet already.
diff --git a/apps/website/content/docs/a2ui/getting-started/introduction.mdx b/apps/website/content/docs/a2ui/getting-started/introduction.mdx
index 99fc405ff..ac74876d9 100644
--- a/apps/website/content/docs/a2ui/getting-started/introduction.mdx
+++ b/apps/website/content/docs/a2ui/getting-started/introduction.mdx
@@ -1,8 +1,8 @@
# Introduction
-`@ngaf/a2ui` is the protocol layer for A2UI messages. It gives the rest of the framework a shared TypeScript vocabulary for agent-built surfaces, streamed JSONL messages, dynamic values, and outbound action payloads.
+`@threadplane/a2ui` is the protocol layer for A2UI messages. It gives the rest of the framework a shared TypeScript vocabulary for agent-built surfaces, streamed JSONL messages, dynamic values, and outbound action payloads.
-It does not render Angular components. It does not register handler functions. It does not decide how an agent should respond to a button click. Those jobs sit in `@ngaf/chat` and `@ngaf/render`.
+It does not render Angular components. It does not register handler functions. It does not decide how an agent should respond to a button click. Those jobs sit in `@threadplane/chat` and `@threadplane/render`.
## What the package owns
@@ -15,7 +15,7 @@ The public entry point exports four groups of tools:
| Data access | `getByPointer()`, `setByPointer()`, `deleteByPointer()` |
| Dynamic values | `resolveDynamic()`, `A2uiScope`, literal/path guards |
-Use this package when you are building an adapter, validating an agent stream, testing A2UI payloads, or integrating a custom renderer with the same protocol surface that `@ngaf/chat` uses.
+Use this package when you are building an adapter, validating an agent stream, testing A2UI payloads, or integrating a custom renderer with the same protocol surface that `@threadplane/chat` uses.
## Message flow
@@ -31,7 +31,7 @@ deleteSurface
When a line parses and has one of those envelope keys, it is returned as an `A2uiMessage`. Unknown envelopes are ignored. Malformed lines are skipped. Incomplete JSON waits in the internal buffer until a newline arrives.
```ts
-import { createA2uiMessageParser } from '@ngaf/a2ui';
+import { createA2uiMessageParser } from '@threadplane/a2ui';
const parser = createA2uiMessageParser();
@@ -44,13 +44,13 @@ That posture is intentional. Agent streams are partial by nature. The low-level
## Relationship to chat and render
-`@ngaf/chat` detects A2UI content in assistant output, feeds the JSONL stream into `createA2uiMessageParser()`, applies messages to its surface store, and renders those surfaces through the A2UI render components.
+`@threadplane/chat` detects A2UI content in assistant output, feeds the JSONL stream into `createA2uiMessageParser()`, applies messages to its surface store, and renders those surfaces through the A2UI render components.
-`@ngaf/render` owns Angular component resolution, event dispatch, state updates, and handler execution. The A2UI package only describes protocol shapes and helper behavior.
+`@threadplane/render` owns Angular component resolution, event dispatch, state updates, and handler execution. The A2UI package only describes protocol shapes and helper behavior.
That separation matters when debugging:
-- If JSONL chunks are not becoming messages, inspect `@ngaf/a2ui`.
+- If JSONL chunks are not becoming messages, inspect `@threadplane/a2ui`.
- If messages are not becoming surfaces, inspect the chat A2UI surface store.
- If components render incorrectly or handlers do not run, inspect the render/chat integration.
@@ -68,7 +68,7 @@ This makes the protocol layer suitable for streaming, but it is not a full schem
## Install
```bash
-npm install @ngaf/a2ui
+npm install @threadplane/a2ui
```
The package has no peer dependencies.
diff --git a/apps/website/content/docs/a2ui/reference/parser-resolver-guards.mdx b/apps/website/content/docs/a2ui/reference/parser-resolver-guards.mdx
index 21359975f..d8883cc5f 100644
--- a/apps/website/content/docs/a2ui/reference/parser-resolver-guards.mdx
+++ b/apps/website/content/docs/a2ui/reference/parser-resolver-guards.mdx
@@ -1,11 +1,11 @@
# Parser, Resolver, and Guards
-`@ngaf/a2ui` exports small helpers that keep stream parsing and dynamic value resolution consistent across packages.
+`@threadplane/a2ui` exports small helpers that keep stream parsing and dynamic value resolution consistent across packages.
## createA2uiMessageParser()
```ts
-import { createA2uiMessageParser } from '@ngaf/a2ui';
+import { createA2uiMessageParser } from '@threadplane/a2ui';
const parser = createA2uiMessageParser();
const messages = parser.push(chunk);
@@ -28,7 +28,7 @@ The parser checks only for the known envelope key and a non-null object value. I
## resolveDynamic()
```ts
-import { resolveDynamic } from '@ngaf/a2ui';
+import { resolveDynamic } from '@threadplane/a2ui';
const model = {
customer: { name: 'Ada' },
@@ -69,7 +69,7 @@ resolveDynamic(
## Pointer helpers
```ts
-import { getByPointer, setByPointer, deleteByPointer } from '@ngaf/a2ui';
+import { getByPointer, setByPointer, deleteByPointer } from '@threadplane/a2ui';
```
The pointer helpers use slash-separated paths:
@@ -112,8 +112,8 @@ This package does not run validation rules, map actions to Angular handlers, or
A practical boundary is:
-- use `@ngaf/a2ui` to parse and inspect the protocol stream;
+- use `@threadplane/a2ui` to parse and inspect the protocol stream;
- use app or server validation to decide whether a message is trusted;
-- use `@ngaf/chat` and `@ngaf/render` to display surfaces and wire interactions.
+- use `@threadplane/chat` and `@threadplane/render` to display surfaces and wire interactions.
That split keeps protocol parsing deterministic and keeps privileged behavior in the host application.
diff --git a/apps/website/content/docs/a2ui/reference/schema.mdx b/apps/website/content/docs/a2ui/reference/schema.mdx
index ff0aa90d6..001495af6 100644
--- a/apps/website/content/docs/a2ui/reference/schema.mdx
+++ b/apps/website/content/docs/a2ui/reference/schema.mdx
@@ -1,6 +1,6 @@
# A2UI Schema
-The `@ngaf/a2ui` schema is a TypeScript model of the protocol shapes used by the framework. It is useful as a contract for agent output and custom integrations, but it is not a runtime validator.
+The `@threadplane/a2ui` schema is a TypeScript model of the protocol shapes used by the framework. It is useful as a contract for agent output and custom integrations, but it is not a runtime validator.
## Dynamic values
@@ -49,7 +49,7 @@ interface A2uiAction {
}
```
-`@ngaf/a2ui` does not execute actions. It only describes the payload that chat/render code can turn into an outbound `A2uiActionMessage`.
+`@threadplane/a2ui` does not execute actions. It only describes the payload that chat/render code can turn into an outbound `A2uiActionMessage`.
## Components
diff --git a/apps/website/content/docs/ag-ui/concepts/architecture.mdx b/apps/website/content/docs/ag-ui/concepts/architecture.mdx
index a712e6f5d..c38b7bb74 100644
--- a/apps/website/content/docs/ag-ui/concepts/architecture.mdx
+++ b/apps/website/content/docs/ag-ui/concepts/architecture.mdx
@@ -1,6 +1,6 @@
# Architecture
-`@ngaf/ag-ui` is an adapter. It does not replace `@ngaf/chat`, and it does not define a new chat runtime.
+`@threadplane/ag-ui` is an adapter. It does not replace `@threadplane/chat`, and it does not define a new chat runtime.
The package takes an AG-UI `AbstractAgent`, listens to its protocol events, and exposes the runtime-neutral `Agent` contract that the chat components already understand.
@@ -8,11 +8,11 @@ The package takes an AG-UI `AbstractAgent`, listens to its protocol events, and
Angular component
|
v
-@ngaf/chat Agent contract
+@threadplane/chat Agent contract
| messages, status, isLoading, error, toolCalls, state, events$
|
v
-@ngaf/ag-ui toAgent()
+@threadplane/ag-ui toAgent()
| reduces AG-UI events into Angular signals
|
v
@@ -24,14 +24,14 @@ AG-UI backend or in-process fake agent
## The boundary
-The important boundary is the `Agent` contract from `@ngaf/chat`.
+The important boundary is the `Agent` contract from `@threadplane/chat`.
Your components should depend on `Agent`, not on AG-UI transport details. That keeps the UI portable across AG-UI, LangGraph, and custom adapters.
`toAgent(source)` is the low-level boundary. It accepts any AG-UI `AbstractAgent` implementation:
```ts
-import { toAgent } from '@ngaf/ag-ui';
+import { toAgent } from '@threadplane/ag-ui';
import { HttpAgent } from '@ag-ui/client';
const source = new HttpAgent({ url: '/api/agent' });
@@ -42,7 +42,7 @@ Most Angular apps should use DI instead:
```ts
import { ApplicationConfig } from '@angular/core';
-import { provideAgUiAgent } from '@ngaf/ag-ui';
+import { provideAgUiAgent } from '@threadplane/ag-ui';
export const appConfig: ApplicationConfig = {
providers: [
@@ -55,8 +55,8 @@ export const appConfig: ApplicationConfig = {
```ts
import { Component } from '@angular/core';
-import { ChatComponent } from '@ngaf/chat';
-import { injectAgUiAgent } from '@ngaf/ag-ui';
+import { ChatComponent } from '@threadplane/chat';
+import { injectAgUiAgent } from '@threadplane/ag-ui';
@Component({
standalone: true,
@@ -72,7 +72,7 @@ You can also inject the token directly:
```ts
import { inject } from '@angular/core';
-import { AG_UI_AGENT } from '@ngaf/ag-ui';
+import { AG_UI_AGENT } from '@threadplane/ag-ui';
const agent = inject(AG_UI_AGENT);
```
@@ -111,12 +111,12 @@ The config maps directly to the AG-UI `HttpAgent` options currently exposed by t
`threadId` here is a plain string consumed once at construction — the provider does not accept an Angular Signal, and the adapter does not observe changes to it at runtime. The AG-UI protocol carries events, not snapshots, and defines no server-side endpoint for "fetch the messages of thread X". To move a user between threads with their prior conversation restored, you have two options:
- **Recreate the provider.** Inject `provideAgUiAgent({ ..., threadId: newId })` from a fresh injector when the active thread changes. Any prior message history must come from your own host service — pre-populate `setMessages()` on the source before the adapter boots, or render a "loading…" surface while you fetch it.
-- **Use the LangGraph adapter instead.** `@ngaf/langgraph` accepts `threadId: Signal` and hydrates messages from the latest checkpoint on every change. See its [Persistence guide](/docs/agent/guides/persistence). Use AG-UI when your runtime publishes events without checkpoint storage; use LangGraph when the server owns durable thread state.
+- **Use the LangGraph adapter instead.** `@threadplane/langgraph` accepts `threadId: Signal` and hydrates messages from the latest checkpoint on every change. See its [Persistence guide](/docs/agent/guides/persistence). Use AG-UI when your runtime publishes events without checkpoint storage; use LangGraph when the server owns durable thread state.
Use `provideFakeAgUiAgent()` when you need the UI to run without a backend:
```ts
-import { provideFakeAgUiAgent } from '@ngaf/ag-ui';
+import { provideFakeAgUiAgent } from '@threadplane/ag-ui';
providers: [
provideFakeAgUiAgent({
@@ -157,7 +157,7 @@ These features are intentionally out of scope for the AG-UI adapter today:
- Subagents.
- **History and time-travel.** AG-UI is an event-stream protocol — it doesn't define a server-side "fetch state of thread X" endpoint, so the adapter can't hydrate prior messages on a `threadId` change the way a checkpoint-aware runtime can. The [Provider choices](#provider-choices) section above describes the two patterns AG-UI consumers use to work around this.
-If those are central to your product, use the LangGraph adapter for that surface or build a custom adapter against the `@ngaf/chat` `Agent` contract. The [Writing an Adapter guide](/docs/chat/guides/writing-an-adapter#hydrating-from-a-server-stored-thread) walks through the thread-loading design choice in detail.
+If those are central to your product, use the LangGraph adapter for that surface or build a custom adapter against the `@threadplane/chat` `Agent` contract. The [Writing an Adapter guide](/docs/chat/guides/writing-an-adapter#hydrating-from-a-server-stored-thread) walks through the thread-loading design choice in detail.
## Next steps
diff --git a/apps/website/content/docs/ag-ui/getting-started/installation.mdx b/apps/website/content/docs/ag-ui/getting-started/installation.mdx
index 64796b026..5ae0928ac 100644
--- a/apps/website/content/docs/ag-ui/getting-started/installation.mdx
+++ b/apps/website/content/docs/ag-ui/getting-started/installation.mdx
@@ -9,19 +9,19 @@
## Install packages
```bash
-npm install @ngaf/chat @ngaf/ag-ui @ag-ui/client
+npm install @threadplane/chat @threadplane/ag-ui @ag-ui/client
```
-`@ngaf/chat` provides the chat UI primitives. `@ngaf/ag-ui` provides the adapter that wires an AG-UI backend into the `Agent` contract those primitives consume.
+`@threadplane/chat` provides the chat UI primitives. `@threadplane/ag-ui` provides the adapter that wires an AG-UI backend into the `Agent` contract those primitives consume.
## Peer Dependencies
-`@ngaf/ag-ui` declares the following peer dependencies:
+`@threadplane/ag-ui` declares the following peer dependencies:
| Package | Version |
|---|---|
-| `@ngaf/chat` | `*` |
-| `@ngaf/licensing` | `*` |
+| `@threadplane/chat` | `*` |
+| `@threadplane/licensing` | `*` |
| `@angular/core` | `^20.0.0 \|\| ^21.0.0` |
| `@ag-ui/client` | `*` |
| `rxjs` | `~7.8.0` |
@@ -32,7 +32,7 @@ In your app config:
```ts
import { ApplicationConfig } from '@angular/core';
-import { provideAgUiAgent } from '@ngaf/ag-ui';
+import { provideAgUiAgent } from '@threadplane/ag-ui';
export const appConfig: ApplicationConfig = {
providers: [
@@ -56,8 +56,8 @@ export const appConfig: ApplicationConfig = {
```ts
import { Component, inject } from '@angular/core';
-import { ChatComponent } from '@ngaf/chat';
-import { AG_UI_AGENT } from '@ngaf/ag-ui';
+import { ChatComponent } from '@threadplane/chat';
+import { AG_UI_AGENT } from '@threadplane/ag-ui';
@Component({
selector: 'app-streaming',
@@ -75,7 +75,7 @@ export class StreamingComponent {
Use the `FakeAgent` for offline demos:
```ts
-import { provideFakeAgUiAgent } from '@ngaf/ag-ui';
+import { provideFakeAgUiAgent } from '@threadplane/ag-ui';
export const appConfig: ApplicationConfig = {
providers: [
@@ -96,7 +96,7 @@ If you have a backend that speaks AG-UI but not over HTTP, subclass `AbstractAge
```ts
import { AbstractAgent, type RunAgentInput, type BaseEvent } from '@ag-ui/client';
import { Observable } from 'rxjs';
-import { toAgent } from '@ngaf/ag-ui';
+import { toAgent } from '@threadplane/ag-ui';
class MyCustomAgent extends AbstractAgent {
protected run(input: RunAgentInput): Observable {
diff --git a/apps/website/content/docs/ag-ui/getting-started/introduction.mdx b/apps/website/content/docs/ag-ui/getting-started/introduction.mdx
index 2ce83b8b1..eb470ae1b 100644
--- a/apps/website/content/docs/ag-ui/getting-started/introduction.mdx
+++ b/apps/website/content/docs/ag-ui/getting-started/introduction.mdx
@@ -1,6 +1,6 @@
# Introduction
-`@ngaf/ag-ui` is the runtime adapter that wraps an [AG-UI](https://github.com/ag-ui-protocol/ag-ui) `AbstractAgent` into the runtime-neutral `Agent` contract from `@ngaf/chat`. The chat UI primitives consume the Agent contract; the AG-UI adapter translates between the contract and the AG-UI event protocol.
+`@threadplane/ag-ui` is the runtime adapter that wraps an [AG-UI](https://github.com/ag-ui-protocol/ag-ui) `AbstractAgent` into the runtime-neutral `Agent` contract from `@threadplane/chat`. The chat UI primitives consume the Agent contract; the AG-UI adapter translates between the contract and the AG-UI event protocol.
AG-UI is the open agent-to-UI protocol from the CopilotKit ecosystem. It standardizes how agent runtimes stream events (messages, tool calls, state updates) to a frontend. Used by **CrewAI**, **Mastra**, **Microsoft Agent Framework**, **AG2**, **Pydantic AI**, **AWS Strands**, and the **CopilotKit runtime**. One adapter unlocks all of them.
@@ -9,16 +9,16 @@ AG-UI is the open agent-to-UI protocol from the CopilotKit ecosystem. It standar
## How it fits
```text
-@ngaf/chat
+@threadplane/chat
, ,
- @ngaf/chat/debug ->
+ @threadplane/chat/debug ->
|
| Agent contract (signals + events$)
|
- +--> @ngaf/langgraph
+ +--> @threadplane/langgraph
| LangGraphAgent -> LangGraph Platform
|
- +--> @ngaf/ag-ui
+ +--> @threadplane/ag-ui
toAgent(AbstractAgent) -> AG-UI backend
```
@@ -37,7 +37,7 @@ Scope of the first release:
- `state` (snapshots and JSON-Patch deltas)
- `events$` (custom events; discriminates `state_update`)
-Out of scope for now (use `@ngaf/langgraph` if you need these):
+Out of scope for now (use `@threadplane/langgraph` if you need these):
- Interrupts
- Subagents
- History / time-travel
diff --git a/apps/website/content/docs/ag-ui/getting-started/quickstart.mdx b/apps/website/content/docs/ag-ui/getting-started/quickstart.mdx
index afa780e69..720b4836c 100644
--- a/apps/website/content/docs/ag-ui/getting-started/quickstart.mdx
+++ b/apps/website/content/docs/ag-ui/getting-started/quickstart.mdx
@@ -1,6 +1,6 @@
# Quick Start
-Bind `` from `@ngaf/chat` to an AG-UI backend in 5 minutes.
+Bind `` from `@threadplane/chat` to an AG-UI backend in 5 minutes.
Angular 20+ project with Node.js 22+. If you need setup help, see the [Installation](/docs/ag-ui/getting-started/installation) guide.
@@ -10,7 +10,7 @@ Angular 20+ project with Node.js 22+. If you need setup help, see the [Installat
```bash
-npm install @ngaf/chat @ngaf/ag-ui @ag-ui/client
+npm install @threadplane/chat @threadplane/ag-ui @ag-ui/client
```
@@ -21,7 +21,7 @@ Add `provideAgUiAgent()` to your application config with your AG-UI backend URL.
```ts
// app.config.ts
import { ApplicationConfig } from '@angular/core';
-import { provideAgUiAgent } from '@ngaf/ag-ui';
+import { provideAgUiAgent } from '@threadplane/ag-ui';
export const appConfig: ApplicationConfig = {
providers: [
@@ -37,8 +37,8 @@ For offline development without a backend, swap to `provideFakeAgUiAgent({})` -
```ts
import { Component, inject } from '@angular/core';
-import { ChatComponent } from '@ngaf/chat';
-import { AG_UI_AGENT } from '@ngaf/ag-ui';
+import { ChatComponent } from '@threadplane/chat';
+import { AG_UI_AGENT } from '@threadplane/ag-ui';
@Component({
selector: 'app-streaming',
@@ -62,8 +62,8 @@ That's it. The `` composition handles streaming messages, tool calls, erro
- [Event Mapping](/docs/ag-ui/reference/event-mapping) is the backend compatibility checklist for emitted AG-UI events.
- [Fake Agent](/docs/ag-ui/guides/fake-agent) covers offline demos and frontend tests.
- [Troubleshooting](/docs/ag-ui/guides/troubleshooting) is the fastest place to start when a stream does not render.
-- The [`@ngaf/chat` Components](/docs/chat/components/chat) reference covers the primitives the `` composition uses internally - handy if you want to compose your own layout.
-- Looking for LangGraph instead of AG-UI? See [`@ngaf/langgraph`](/docs/agent/getting-started/quickstart).
+- The [`@threadplane/chat` Components](/docs/chat/components/chat) reference covers the primitives the `` composition uses internally - handy if you want to compose your own layout.
+- Looking for LangGraph instead of AG-UI? See [`@threadplane/langgraph`](/docs/agent/getting-started/quickstart).
## Switching backends without changing UI
diff --git a/apps/website/content/docs/ag-ui/guides/citations.mdx b/apps/website/content/docs/ag-ui/guides/citations.mdx
index 94988c0e8..18fc07002 100644
--- a/apps/website/content/docs/ag-ui/guides/citations.mdx
+++ b/apps/website/content/docs/ag-ui/guides/citations.mdx
@@ -1,6 +1,6 @@
# Citations
-`@ngaf/ag-ui` can copy citations from AG-UI state onto chat messages.
+`@threadplane/ag-ui` can copy citations from AG-UI state onto chat messages.
The bridge is intentionally simple: put citations under `state.citations`, keyed by message id. When a `STATE_SNAPSHOT` or `STATE_DELTA` arrives, the adapter merges matching citations onto `messages`.
@@ -109,7 +109,7 @@ If your backend sends citations before the matching message exists, send another
`bridgeCitationsState()` is exported for advanced adapters or custom reducers.
```ts
-import { bridgeCitationsState } from '@ngaf/ag-ui';
+import { bridgeCitationsState } from '@threadplane/ag-ui';
const nextMessages = bridgeCitationsState(
{ state: threadState },
diff --git a/apps/website/content/docs/ag-ui/guides/fake-agent.mdx b/apps/website/content/docs/ag-ui/guides/fake-agent.mdx
index 3f6dfb4ef..5d4f9ffad 100644
--- a/apps/website/content/docs/ag-ui/guides/fake-agent.mdx
+++ b/apps/website/content/docs/ag-ui/guides/fake-agent.mdx
@@ -19,7 +19,7 @@ For Angular apps, use `provideFakeAgUiAgent()`.
```ts
import { ApplicationConfig } from '@angular/core';
-import { provideFakeAgUiAgent } from '@ngaf/ag-ui';
+import { provideFakeAgUiAgent } from '@threadplane/ag-ui';
export const appConfig: ApplicationConfig = {
providers: [
@@ -35,8 +35,8 @@ Your component stays the same as the real backend version:
```ts
import { Component } from '@angular/core';
-import { ChatComponent } from '@ngaf/chat';
-import { injectAgUiAgent } from '@ngaf/ag-ui';
+import { ChatComponent } from '@threadplane/chat';
+import { injectAgUiAgent } from '@threadplane/ag-ui';
@Component({
standalone: true,
@@ -74,7 +74,7 @@ Reasoning events are emitted before text events and use the same message id, so
Use `FakeAgent` directly when a test needs an AG-UI source rather than Angular DI.
```ts
-import { FakeAgent, toAgent } from '@ngaf/ag-ui';
+import { FakeAgent, toAgent } from '@threadplane/ag-ui';
const source = new FakeAgent({
tokens: ['One', ' two', ' three.'],
diff --git a/apps/website/content/docs/ag-ui/guides/troubleshooting.mdx b/apps/website/content/docs/ag-ui/guides/troubleshooting.mdx
index 337b93be4..54e352a46 100644
--- a/apps/website/content/docs/ag-ui/guides/troubleshooting.mdx
+++ b/apps/website/content/docs/ag-ui/guides/troubleshooting.mdx
@@ -15,8 +15,8 @@ providers: [
Then make sure the component uses the provided agent:
```ts
-import { ChatComponent } from '@ngaf/chat';
-import { injectAgUiAgent } from '@ngaf/ag-ui';
+import { ChatComponent } from '@threadplane/chat';
+import { injectAgUiAgent } from '@threadplane/ag-ui';
@Component({
standalone: true,
@@ -138,14 +138,14 @@ Those flows are not implemented by the AG-UI adapter today.
Current scope is messages, status/loading/error, tool calls, state/custom events, reasoning messages, message snapshots, and citations from state.
-Use `@ngaf/langgraph` for the richer LangGraph-specific surface, or write a custom adapter against the `@ngaf/chat` `Agent` contract if you need AG-UI plus product-specific behavior.
+Use `@threadplane/langgraph` for the richer LangGraph-specific surface, or write a custom adapter against the `@threadplane/chat` `Agent` contract if you need AG-UI plus product-specific behavior.
## Isolate with FakeAgent
When you are unsure whether the issue is UI wiring or backend events, swap in the fake provider:
```ts
-import { provideFakeAgUiAgent } from '@ngaf/ag-ui';
+import { provideFakeAgUiAgent } from '@threadplane/ag-ui';
providers: [
provideFakeAgUiAgent({
diff --git a/apps/website/content/docs/ag-ui/reference/event-mapping.mdx b/apps/website/content/docs/ag-ui/reference/event-mapping.mdx
index a0ff40573..d6335a206 100644
--- a/apps/website/content/docs/ag-ui/reference/event-mapping.mdx
+++ b/apps/website/content/docs/ag-ui/reference/event-mapping.mdx
@@ -1,6 +1,6 @@
# Event Mapping
-`@ngaf/ag-ui` reduces AG-UI protocol events into the `Agent` contract from `@ngaf/chat`.
+`@threadplane/ag-ui` reduces AG-UI protocol events into the `Agent` contract from `@threadplane/chat`.
This page is the compatibility map. If your backend emits these events with the expected fields, the chat UI can render the run without knowing which runtime produced it.
diff --git a/apps/website/content/docs/agent/api/agent.mdx b/apps/website/content/docs/agent/api/agent.mdx
index 4bf7a64c5..433043138 100644
--- a/apps/website/content/docs/agent/api/agent.mdx
+++ b/apps/website/content/docs/agent/api/agent.mdx
@@ -1,11 +1,11 @@
# agent()
-`agent()` is the LangGraph adapter for Angular. It connects to a LangGraph Platform assistant, consumes the LangGraph SDK event stream, and projects the result into the runtime-neutral `Agent` contract used by `@ngaf/chat`.
+`agent()` is the LangGraph adapter for Angular. It connects to a LangGraph Platform assistant, consumes the LangGraph SDK event stream, and projects the result into the runtime-neutral `Agent` contract used by `@threadplane/chat`.
Call it in an Angular injection context, usually as a component field initializer. The returned object exposes Angular Signals for UI state and async methods for user actions.
```ts
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
readonly chat = agent({
apiUrl: 'http://localhost:2024',
diff --git a/apps/website/content/docs/agent/api/api-docs.json b/apps/website/content/docs/agent/api/api-docs.json
index 700b238b4..2f6d654dd 100644
--- a/apps/website/content/docs/agent/api/api-docs.json
+++ b/apps/website/content/docs/agent/api/api-docs.json
@@ -2,7 +2,7 @@
{
"name": "AgentLifecycleRegistry",
"kind": "class",
- "description": "Optional registry that collects per-instance agent lifecycles within\nan Angular injection context. External instrumentation packages\n(e.g. cockpit-telemetry) provide this token and read from it.\n\n`@ngaf/langgraph` does NOT provide this itself — `agent()` writes to\nthe registry only when an external consumer has provided it.",
+ "description": "Optional registry that collects per-instance agent lifecycles within\nan Angular injection context. External instrumentation packages\n(e.g. cockpit-telemetry) provide this token and read from it.\n\n`@threadplane/langgraph` does NOT provide this itself — `agent()` writes to\nthe registry only when an external consumer has provided it.",
"params": [],
"examples": [],
"properties": [
diff --git a/apps/website/content/docs/agent/api/fetch-stream-transport.mdx b/apps/website/content/docs/agent/api/fetch-stream-transport.mdx
index 52c418f60..53fa09eb9 100644
--- a/apps/website/content/docs/agent/api/fetch-stream-transport.mdx
+++ b/apps/website/content/docs/agent/api/fetch-stream-transport.mdx
@@ -9,7 +9,7 @@ In most apps you never instantiate `FetchStreamTransport` directly. When no cust
You reach for it explicitly when you want to share a transport instance, inspect behavior in tests, or implement a custom transport by matching the same `AgentTransport` interface.
```ts
-import { agent, FetchStreamTransport } from '@ngaf/langgraph';
+import { agent, FetchStreamTransport } from '@threadplane/langgraph';
const transport = new FetchStreamTransport(
'http://localhost:2024',
diff --git a/apps/website/content/docs/agent/api/mock-stream-transport.mdx b/apps/website/content/docs/agent/api/mock-stream-transport.mdx
index 078fb8da3..8629baef1 100644
--- a/apps/website/content/docs/agent/api/mock-stream-transport.mdx
+++ b/apps/website/content/docs/agent/api/mock-stream-transport.mdx
@@ -13,7 +13,7 @@ import {
provideAgent,
MockAgentTransport,
agent,
-} from '@ngaf/langgraph';
+} from '@threadplane/langgraph';
@Component({ template: '' })
class ChatComponent {
diff --git a/apps/website/content/docs/agent/api/provide-agent.mdx b/apps/website/content/docs/agent/api/provide-agent.mdx
index d5b16f953..213f73b50 100644
--- a/apps/website/content/docs/agent/api/provide-agent.mdx
+++ b/apps/website/content/docs/agent/api/provide-agent.mdx
@@ -9,7 +9,7 @@ import { bootstrapApplication } from '@angular/platform-browser';
import {
provideAgent,
MockAgentTransport,
-} from '@ngaf/langgraph';
+} from '@threadplane/langgraph';
import { AppComponent } from './app/app.component';
bootstrapApplication(AppComponent, {
diff --git a/apps/website/content/docs/agent/concepts/agent-architecture.mdx b/apps/website/content/docs/agent/concepts/agent-architecture.mdx
index 37e5a1746..2264f6f3f 100644
--- a/apps/website/content/docs/agent/concepts/agent-architecture.mdx
+++ b/apps/website/content/docs/agent/concepts/agent-architecture.mdx
@@ -1,6 +1,6 @@
# Agent Architecture
-How AI agents work — the planning, execution, and tool-calling lifecycle that agent() connects your Angular app to. This page shows you the Python patterns that power modern agents and exactly how each pattern surfaces in Angular through `@ngaf/langgraph`.
+How AI agents work — the planning, execution, and tool-calling lifecycle that agent() connects your Angular app to. This page shows you the Python patterns that power modern agents and exactly how each pattern surfaces in Angular through `@threadplane/langgraph`.
Every section below shows the Python backend code first, then the Angular frontend code that consumes it. You need both halves to build a production agent application — LangGraph handles the intelligence, agent() handles the reactivity.
@@ -149,7 +149,7 @@ graph = builder.compile()
```typescript
import { ChangeDetectionStrategy, Component, computed } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
interface AgentState {
messages: BaseMessage[];
@@ -404,7 +404,7 @@ graph = builder.compile()
```typescript
import { ChangeDetectionStrategy, Component, computed } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
interface OrchestratorState {
messages: BaseMessage[];
diff --git a/apps/website/content/docs/agent/concepts/agent-contract.mdx b/apps/website/content/docs/agent/concepts/agent-contract.mdx
index dedb54dd1..dc50c8f2e 100644
--- a/apps/website/content/docs/agent/concepts/agent-contract.mdx
+++ b/apps/website/content/docs/agent/concepts/agent-contract.mdx
@@ -2,24 +2,24 @@
The `Agent` contract is the spine between runtime adapters and chat UI.
-`@ngaf/chat` owns the contract. `@ngaf/langgraph` and `@ngaf/ag-ui` produce objects that satisfy it. Chat primitives and compositions consume it without knowing which runtime is behind the stream.
+`@threadplane/chat` owns the contract. `@threadplane/langgraph` and `@threadplane/ag-ui` produce objects that satisfy it. Chat primitives and compositions consume it without knowing which runtime is behind the stream.
This matters because the UI should not care whether a response came from LangGraph Platform, AG-UI, a local mock, or a custom HTTP service. The boundary is explicit: adapters translate runtime events into Angular signals and a small action surface.
```text
-LangGraph Platform -- @ngaf/langgraph --+
- +-- Agent -- @ngaf/chat
-AG-UI backend ------ @ngaf/ag-ui -------+
+LangGraph Platform -- @threadplane/langgraph --+
+ +-- Agent -- @threadplane/chat
+AG-UI backend ------ @threadplane/ag-ui -------+
custom backend ------ your adapter -----+
```
## The Contract Surface
-Import the contract from `@ngaf/chat`:
+Import the contract from `@threadplane/chat`:
```ts
-import type { Agent } from '@ngaf/chat';
+import type { Agent } from '@threadplane/chat';
```
An `Agent` has state signals, actions, optional runtime capabilities, and one event stream.
@@ -71,7 +71,7 @@ interface AgentSubmitOptions {
}
```
-Runtime-specific adapters may accept richer options. `@ngaf/langgraph` exports `LangGraphSubmitOptions` for LangGraph run configuration such as checkpointing, durability, multitask strategy, and stream mode. Keep app-level code on the neutral shape unless it is intentionally using LangGraph-only behavior.
+Runtime-specific adapters may accept richer options. `@threadplane/langgraph` exports `LangGraphSubmitOptions` for LangGraph run configuration such as checkpointing, durability, multitask strategy, and stream mode. Keep app-level code on the neutral shape unless it is intentionally using LangGraph-only behavior.
## Signals
@@ -96,7 +96,7 @@ The optional signals are important. A simple echo adapter should not fake interr
```ts
import { EMPTY } from 'rxjs';
-import type { AgentEvent } from '@ngaf/chat';
+import type { AgentEvent } from '@threadplane/chat';
const events$ = EMPTY as Observable;
```
@@ -112,13 +112,13 @@ Do not mirror `messages`, `status`, `toolCalls`, `interrupt`, or `subagents` thr
## Adapters And Transports
-`@ngaf/langgraph` exports `agent()`, `provideAgent()`, `FetchStreamTransport`, `MockAgentTransport`, and `AgentTransport`.
+`@threadplane/langgraph` exports `agent()`, `provideAgent()`, `FetchStreamTransport`, `MockAgentTransport`, and `AgentTransport`.
`agent()` is the Angular adapter. It connects to LangGraph, consumes stream events through a transport, and returns a `LangGraphAgent`. That object satisfies the neutral `Agent` contract and also exposes LangGraph-specific signals such as raw LangGraph messages, history, queue, branch state, and checkpoint helpers.
`AgentTransport` is lower level. Use it when the backend is LangGraph-compatible but the transport needs to change: custom fetch behavior, tests, local fixtures, or a nonstandard gateway.
-`@ngaf/ag-ui` exports `toAgent()`, `provideAgUiAgent()`, `injectAgUiAgent()`, `FakeAgent`, and `provideFakeAgUiAgent()`.
+`@threadplane/ag-ui` exports `toAgent()`, `provideAgUiAgent()`, `injectAgUiAgent()`, `FakeAgent`, and `provideFakeAgUiAgent()`.
`toAgent()` wraps an AG-UI `AbstractAgent` into the same neutral contract. The AG-UI adapter reduces AG-UI events into chat signals, appends user messages on submit, calls `runAgent()`, and maps stop to `abortRun()`.
@@ -133,16 +133,16 @@ The UI lifecycle is intentionally boring.
5. `stop()` aborts the active run when supported.
6. `regenerate(index)` rolls back from an assistant message and reruns from the preceding user message.
-LangGraph adds deeper lifecycle and history surfaces. `@ngaf/langgraph` exposes `agent().lifecycle` and exports `AgentLifecycle`, `AgentLifecycleRegistry`, and the low-level `AGENT_LIFECYCLE` token. Those are useful for telemetry, debugging, persistence, and time-travel UI. They are not required by `@ngaf/chat`.
+LangGraph adds deeper lifecycle and history surfaces. `@threadplane/langgraph` exposes `agent().lifecycle` and exports `AgentLifecycle`, `AgentLifecycleRegistry`, and the low-level `AGENT_LIFECYCLE` token. Those are useful for telemetry, debugging, persistence, and time-travel UI. They are not required by `@threadplane/chat`.
## Testing And Mocks
Use the closest mock to the boundary you are testing.
-For chat components, use `mockAgent()` from `@ngaf/chat`. It gives writable signals and records `submit()` calls.
+For chat components, use `mockAgent()` from `@threadplane/chat`. It gives writable signals and records `submit()` calls.
```ts
-import { mockAgent } from '@ngaf/chat';
+import { mockAgent } from '@threadplane/chat';
const agent = mockAgent({
messages: [{ id: 'm1', role: 'assistant', content: 'Ready' }],
@@ -150,9 +150,9 @@ const agent = mockAgent({
});
```
-For LangGraph-specific code, use `mockLangGraphAgent()` or `MockAgentTransport` from `@ngaf/langgraph`. That lets you test queue, checkpoint, raw SDK, and transport behavior without pretending those details exist on every adapter.
+For LangGraph-specific code, use `mockLangGraphAgent()` or `MockAgentTransport` from `@threadplane/langgraph`. That lets you test queue, checkpoint, raw SDK, and transport behavior without pretending those details exist on every adapter.
-For AG-UI integration, use `FakeAgent` or `provideFakeAgUiAgent()` from `@ngaf/ag-ui`.
+For AG-UI integration, use `FakeAgent` or `provideFakeAgUiAgent()` from `@threadplane/ag-ui`.
This matters because the contract is the seam you can test cheaply. Most component tests should not need a network, LangGraph server, or AG-UI runtime.
@@ -164,6 +164,6 @@ It is not a message database. Persistence belongs to the runtime or application
It is not a full orchestration API. LangGraph-specific operations such as branch selection, queued runs, checkpoint history, and raw SDK messages stay on `LangGraphAgent`.
-It is not a UI renderer. Rendering belongs to `@ngaf/chat`, `@ngaf/render`, and A2UI surfaces. The agent only exposes the state and events those renderers need.
+It is not a UI renderer. Rendering belongs to `@threadplane/chat`, `@threadplane/render`, and A2UI surfaces. The agent only exposes the state and events those renderers need.
Keep that boundary sharp. It makes adapters replaceable, tests smaller, and chat components more predictable.
diff --git a/apps/website/content/docs/agent/concepts/angular-signals.mdx b/apps/website/content/docs/agent/concepts/angular-signals.mdx
index 62b3aa65f..b32ec5d82 100644
--- a/apps/website/content/docs/agent/concepts/angular-signals.mdx
+++ b/apps/website/content/docs/agent/concepts/angular-signals.mdx
@@ -60,7 +60,7 @@ const status = toSignal(status$, { initialValue: 'idle' });
```typescript
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
// You never touch BehaviorSubjects or toSignal() yourself.
// agent() hands you clean Signals:
@@ -154,7 +154,7 @@ console.log(chat.isLoading()); // false
```typescript
import { computed } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
const chat = agent({
assistantId: 'chat_agent',
@@ -254,7 +254,7 @@ Angular's new control flow syntax (`@if`, `@for`, `@switch`) works naturally wit
```typescript
import { ChangeDetectionStrategy, Component, computed, effect, ElementRef, ViewChild } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
@Component({
selector: 'app-chat',
@@ -448,7 +448,7 @@ graph = builder.compile()
```typescript
import { ChangeDetectionStrategy, Component, computed, effect } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
@Component({
selector: 'app-chat',
diff --git a/apps/website/content/docs/agent/concepts/state-management.mdx b/apps/website/content/docs/agent/concepts/state-management.mdx
index f913becd8..4419a96a7 100644
--- a/apps/website/content/docs/agent/concepts/state-management.mdx
+++ b/apps/website/content/docs/agent/concepts/state-management.mdx
@@ -17,7 +17,7 @@ This inversion is intentional. Agent state can span multiple LLM calls, tool exe
Your Angular component calls `agent.submit({ message: text })`. No state is stored in the component.
-`@ngaf/langgraph` forwards the input to `FetchStreamTransport`, which opens an HTTP POST and SSE connection to LangGraph Platform.
+`@threadplane/langgraph` forwards the input to `FetchStreamTransport`, which opens an HTTP POST and SSE connection to LangGraph Platform.
The agent runs its nodes — calling the LLM, invoking tools, checking conditions — and streams SSE events back with incremental state updates.
@@ -424,7 +424,7 @@ def researcher_node(state: ResearchState) -> dict:
```typescript
import { BaseMessage } from '@langchain/core/messages';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
interface ResearchState {
messages: BaseMessage[];
diff --git a/apps/website/content/docs/agent/getting-started/installation.mdx b/apps/website/content/docs/agent/getting-started/installation.mdx
index 85b5fb79f..07c614d9a 100644
--- a/apps/website/content/docs/agent/getting-started/installation.mdx
+++ b/apps/website/content/docs/agent/getting-started/installation.mdx
@@ -19,18 +19,18 @@ A running LangGraph agent accessible via HTTP. Can be local (langgraph dev) or d
## Install the package
```bash
-npm install @ngaf/langgraph @ngaf/chat
+npm install @threadplane/langgraph @threadplane/chat
```
-`@ngaf/langgraph` provides `agent()` and `provideAgent()`. `@ngaf/chat` provides the runtime-neutral chat UI consumed by the LangGraph adapter.
+`@threadplane/langgraph` provides `agent()` and `provideAgent()`. `@threadplane/chat` provides the runtime-neutral chat UI consumed by the LangGraph adapter.
## Peer Dependencies
-`@ngaf/langgraph` declares the following peer dependencies:
+`@threadplane/langgraph` declares the following peer dependencies:
| Package | Version |
|---------|---------|
-| `@ngaf/chat` | `*` |
+| `@threadplane/chat` | `*` |
| `@angular/core` | `^20.0.0 \|\| ^21.0.0` |
| `@langchain/core` | `^1.1.33` |
| `@langchain/langgraph-sdk` | `^1.7.4` |
@@ -43,7 +43,7 @@ Add `provideAgent()` to your application configuration. This sets global default
```typescript
// app.config.ts
import { ApplicationConfig } from '@angular/core';
-import { provideAgent } from '@ngaf/langgraph';
+import { provideAgent } from '@threadplane/langgraph';
import { environment } from '../environments/environment';
export const appConfig: ApplicationConfig = {
diff --git a/apps/website/content/docs/agent/getting-started/introduction.mdx b/apps/website/content/docs/agent/getting-started/introduction.mdx
index 798fdf12a..7b5fa970e 100644
--- a/apps/website/content/docs/agent/getting-started/introduction.mdx
+++ b/apps/website/content/docs/agent/getting-started/introduction.mdx
@@ -128,7 +128,7 @@ Now connect your Angular app to the running agent using agent().
```bash
-npm install @ngaf/langgraph
+npm install @threadplane/langgraph
```
@@ -137,7 +137,7 @@ npm install @ngaf/langgraph
```typescript
// app.config.ts
import { ApplicationConfig } from '@angular/core';
-import { provideAgent } from '@ngaf/langgraph';
+import { provideAgent } from '@threadplane/langgraph';
export const appConfig: ApplicationConfig = {
providers: [
@@ -157,7 +157,7 @@ export const appConfig: ApplicationConfig = {
```typescript
// chat.component.ts
import { ChangeDetectionStrategy, Component, signal, computed } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
@Component({
selector: 'app-chat',
diff --git a/apps/website/content/docs/agent/getting-started/quickstart.mdx b/apps/website/content/docs/agent/getting-started/quickstart.mdx
index c449be131..5286e564d 100644
--- a/apps/website/content/docs/agent/getting-started/quickstart.mdx
+++ b/apps/website/content/docs/agent/getting-started/quickstart.mdx
@@ -10,7 +10,7 @@ Angular 20+ project with Node.js 18+. If you need setup help, see the [Installat
```bash
-npm install @ngaf/langgraph
+npm install @threadplane/langgraph
```
@@ -20,7 +20,7 @@ Add `provideAgent()` to your application config with your LangGraph Platform URL
```typescript
// app.config.ts
-import { provideAgent } from '@ngaf/langgraph';
+import { provideAgent } from '@threadplane/langgraph';
export const appConfig: ApplicationConfig = {
providers: [
@@ -42,7 +42,7 @@ Use `agent()` in a component field initializer. Every property on the returned r
```typescript
// chat.component.ts
import { Component, ChangeDetectionStrategy, signal, computed } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
@Component({
selector: 'app-chat',
diff --git a/apps/website/content/docs/agent/guides/deployment.mdx b/apps/website/content/docs/agent/guides/deployment.mdx
index 6e37d7483..3c4085a5e 100644
--- a/apps/website/content/docs/agent/guides/deployment.mdx
+++ b/apps/website/content/docs/agent/guides/deployment.mdx
@@ -106,7 +106,7 @@ export const environment = {
Wire the environment into `provideAgent()`:
```typescript
-import { provideAgent } from '@ngaf/langgraph';
+import { provideAgent } from '@threadplane/langgraph';
import { environment } from '../environments/environment';
export const appConfig: ApplicationConfig = {
@@ -188,7 +188,7 @@ Production apps need graceful error handling. Build a reactive error boundary us
```typescript
import { ChangeDetectionStrategy, Component, computed } from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
@Component({
selector: 'app-chat',
diff --git a/apps/website/content/docs/agent/guides/interrupts.mdx b/apps/website/content/docs/agent/guides/interrupts.mdx
index 34434c221..2c51b9d11 100644
--- a/apps/website/content/docs/agent/guides/interrupts.mdx
+++ b/apps/website/content/docs/agent/guides/interrupts.mdx
@@ -144,7 +144,7 @@ import {
signal,
ChangeDetectionStrategy,
} from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
import type { BaseMessage } from '@langchain/core/messages';
interface ApprovalPayload {
@@ -363,7 +363,7 @@ import {
computed,
ChangeDetectionStrategy,
} from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
import type { BaseMessage } from '@langchain/core/messages';
interface StepApproval {
@@ -465,7 +465,7 @@ By default, `interrupt()` returns an untyped value. The `BagTemplate` generic pa
`BagTemplate` is an SDK type with an `InterruptType` slot. When you specify that slot, the raw `langGraphInterrupts()` signal is typed. The normalized runtime-neutral `interrupt()` signal still exposes `value` as `unknown`, so cast that payload at the UI boundary if you use the neutral signal.
```typescript
-import { agent, BagTemplate } from '@ngaf/langgraph';
+import { agent, BagTemplate } from '@threadplane/langgraph';
// Define the exact shape of your interrupt payload
interface DeployApproval {
diff --git a/apps/website/content/docs/agent/guides/lifecycle.mdx b/apps/website/content/docs/agent/guides/lifecycle.mdx
index 36e5d3502..250d8d9e2 100644
--- a/apps/website/content/docs/agent/guides/lifecycle.mdx
+++ b/apps/website/content/docs/agent/guides/lifecycle.mdx
@@ -1,6 +1,6 @@
# Agent Lifecycle Signals
-The `@ngaf/langgraph` library exposes per-agent lifecycle signals on every `LangGraphAgent` returned by `agent()`. These are timestamps and classifications derived from the existing stream — useful for debugging, custom dashboards, or telemetry integrations.
+The `@threadplane/langgraph` library exposes per-agent lifecycle signals on every `LangGraphAgent` returned by `agent()`. These are timestamps and classifications derived from the existing stream — useful for debugging, custom dashboards, or telemetry integrations.
## Interface
@@ -53,7 +53,7 @@ Three signals require explicit hook points that the agent already invokes:
```typescript
import { Component, effect } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
@Component({ /* ... */ })
export class MyComponent {
@@ -76,7 +76,7 @@ For app-wide instrumentation, provide `AgentLifecycleRegistry` and read the life
```typescript
import { ApplicationConfig, inject } from '@angular/core';
-import { AgentLifecycleRegistry } from '@ngaf/langgraph';
+import { AgentLifecycleRegistry } from '@threadplane/langgraph';
export const appConfig: ApplicationConfig = {
providers: [AgentLifecycleRegistry],
diff --git a/apps/website/content/docs/agent/guides/memory.mdx b/apps/website/content/docs/agent/guides/memory.mdx
index 92c4989a2..a1fb31e9c 100644
--- a/apps/website/content/docs/agent/guides/memory.mdx
+++ b/apps/website/content/docs/agent/guides/memory.mdx
@@ -75,7 +75,7 @@ graph = builder.compile()
```typescript
import { Component, computed, ChangeDetectionStrategy } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
import type { BaseMessage } from '@langchain/core/messages';
interface AgentState {
@@ -266,7 +266,7 @@ graph = builder.compile()
```typescript
import { Component, computed, signal, ChangeDetectionStrategy } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
import type { BaseMessage } from '@langchain/core/messages';
@Component({
diff --git a/apps/website/content/docs/agent/guides/persistence.mdx b/apps/website/content/docs/agent/guides/persistence.mdx
index 35771959e..f4cffb1ed 100644
--- a/apps/website/content/docs/agent/guides/persistence.mdx
+++ b/apps/website/content/docs/agent/guides/persistence.mdx
@@ -7,7 +7,7 @@ LangGraph checkpoints agent state at every super-step. Each checkpoint is keyed
-"Restore a prior thread's messages when the user switches to it" is a behavior the `@ngaf/langgraph` adapter implements because the LangGraph protocol exposes per-thread checkpoint history. The runtime-neutral `Agent` contract in `@ngaf/chat` doesn't require this — adapters built on event-stream protocols (like `@ngaf/ag-ui`) typically can't offer it. If you're writing your own adapter, the [Writing an Adapter guide](/docs/chat/guides/writing-an-adapter#hydrating-from-a-server-stored-thread) covers the design choice.
+"Restore a prior thread's messages when the user switches to it" is a behavior the `@threadplane/langgraph` adapter implements because the LangGraph protocol exposes per-thread checkpoint history. The runtime-neutral `Agent` contract in `@threadplane/chat` doesn't require this — adapters built on event-stream protocols (like `@threadplane/ag-ui`) typically can't offer it. If you're writing your own adapter, the [Writing an Adapter guide](/docs/chat/guides/writing-an-adapter#hydrating-from-a-server-stored-thread) covers the design choice.
## Python: Checkpointer Setup
@@ -115,7 +115,7 @@ Save the thread ID to localStorage so conversations survive page refreshes. agen
```typescript
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { signal } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
@Component({
selector: 'app-chat',
@@ -165,7 +165,7 @@ A real chat application needs a sidebar showing all conversations. Here is a ful
```typescript
import { ChangeDetectionStrategy, Component, signal, computed } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
interface Thread {
id: string;
diff --git a/apps/website/content/docs/agent/guides/streaming.mdx b/apps/website/content/docs/agent/guides/streaming.mdx
index 823406891..44762dc5e 100644
--- a/apps/website/content/docs/agent/guides/streaming.mdx
+++ b/apps/website/content/docs/agent/guides/streaming.mdx
@@ -60,7 +60,7 @@ async for event in graph.astream_events(
```typescript
import { Component, computed, ChangeDetectionStrategy } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
@Component({
selector: 'app-chat',
@@ -188,7 +188,7 @@ If the SSE connection drops or the agent throws, `status()` transitions to `'err
```typescript
import { Component, computed, ChangeDetectionStrategy } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
@Component({
selector: 'app-chat',
diff --git a/apps/website/content/docs/agent/guides/subgraphs.mdx b/apps/website/content/docs/agent/guides/subgraphs.mdx
index 4eb095c55..61bb32a10 100644
--- a/apps/website/content/docs/agent/guides/subgraphs.mdx
+++ b/apps/website/content/docs/agent/guides/subgraphs.mdx
@@ -75,7 +75,7 @@ graph = builder.compile()
```typescript
import { Component, computed, inject, effect, ChangeDetectionStrategy } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
@Component({
selector: 'app-orchestrator',
diff --git a/apps/website/content/docs/agent/guides/testing.mdx b/apps/website/content/docs/agent/guides/testing.mdx
index 7ef013f95..c162b3bb9 100644
--- a/apps/website/content/docs/agent/guides/testing.mdx
+++ b/apps/website/content/docs/agent/guides/testing.mdx
@@ -48,7 +48,7 @@ On the Angular side, MockAgentTransport replaces the real HTTP transport. Create
```typescript
import { TestBed } from '@angular/core/testing';
-import { MockAgentTransport, agent } from '@ngaf/langgraph';
+import { MockAgentTransport, agent } from '@threadplane/langgraph';
describe('ChatComponent', () => {
it('should display agent messages', () => {
@@ -80,7 +80,7 @@ describe('ChatComponent', () => {
```typescript
import { ChangeDetectionStrategy, Component } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
@Component({
selector: 'app-chat',
@@ -139,7 +139,7 @@ The most common test pattern verifies the full submit-to-idle lifecycle: submit
```typescript
import { TestBed } from '@angular/core/testing';
-import { MockAgentTransport, agent } from '@ngaf/langgraph';
+import { MockAgentTransport, agent } from '@threadplane/langgraph';
describe('streaming lifecycle', () => {
it('should transition through running → values → idle', () => {
@@ -186,7 +186,7 @@ describe('streaming lifecycle', () => {
```typescript
import { ChangeDetectionStrategy, Component } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
@Component({
selector: 'app-chat',
@@ -223,7 +223,7 @@ Script an interrupt event to test human-in-the-loop flows. Verify the interrupt
```typescript
import { TestBed } from '@angular/core/testing';
-import { MockAgentTransport, agent } from '@ngaf/langgraph';
+import { MockAgentTransport, agent } from '@threadplane/langgraph';
describe('interrupt handling', () => {
it('should surface interrupt and resume on approval', () => {
@@ -271,7 +271,7 @@ describe('interrupt handling', () => {
```typescript
import { ChangeDetectionStrategy, Component } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
@Component({
selector: 'app-approval',
@@ -314,7 +314,7 @@ Inject errors with `emitError()` to verify your component handles failures grace
```typescript
import { TestBed } from '@angular/core/testing';
-import { MockAgentTransport, agent } from '@ngaf/langgraph';
+import { MockAgentTransport, agent } from '@threadplane/langgraph';
describe('error handling', () => {
it('should surface errors and set error status', () => {
@@ -373,7 +373,7 @@ describe('error handling', () => {
```typescript
import { ChangeDetectionStrategy, Component } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
@Component({
selector: 'app-chat',
@@ -477,7 +477,7 @@ describe('thread switching', () => {
-Make sure `@ngaf/langgraph` is available in your test environment. MockAgentTransport ships with the main package — no extra install needed.
+Make sure `@threadplane/langgraph` is available in your test environment. MockAgentTransport ships with the main package — no extra install needed.
Instantiate `MockAgentTransport` with optional pre-scripted batches for sequential playback, or leave it empty for imperative `emit()` calls.
diff --git a/apps/website/content/docs/agent/guides/time-travel.mdx b/apps/website/content/docs/agent/guides/time-travel.mdx
index 2b0d8d73e..e68f6659d 100644
--- a/apps/website/content/docs/agent/guides/time-travel.mdx
+++ b/apps/website/content/docs/agent/guides/time-travel.mdx
@@ -61,7 +61,7 @@ past_state = graph.get_state(past_config)
```typescript
import { Component, inject, computed, ChangeDetectionStrategy } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
import { AgentService } from './agent.service';
@Component({
@@ -175,7 +175,7 @@ Expose checkpoint history directly in your component to let users scrub through
```typescript
import { Component, inject, computed, ChangeDetectionStrategy } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
import { AgentService } from './agent.service';
@Component({
diff --git a/apps/website/content/docs/chat/api/api-docs.json b/apps/website/content/docs/chat/api/api-docs.json
index 324d4f9ce..1d98a8f1a 100644
--- a/apps/website/content/docs/chat/api/api-docs.json
+++ b/apps/website/content/docs/chat/api/api-docs.json
@@ -2729,7 +2729,7 @@
{
"name": "views",
"type": "InputSignal | RenderViewEntry>> | undefined>",
- "description": "A2UI component catalog forwarded to the inner . Without it,\nmessages classified as A2UI parse correctly but never mount a\nsurface. Pass `a2uiBasicCatalog()` from `@ngaf/chat`.",
+ "description": "A2UI component catalog forwarded to the inner . Without it,\nmessages classified as A2UI parse correctly but never mount a\nsurface. Pass `a2uiBasicCatalog()` from `@threadplane/chat`.",
"optional": false
}
],
@@ -3224,7 +3224,7 @@
{
"name": "views",
"type": "InputSignal | RenderViewEntry>> | undefined>",
- "description": "A2UI component catalog forwarded to the inner . Without it,\nmessages classified as A2UI parse correctly but never mount a\nsurface. Pass `a2uiBasicCatalog()` from `@ngaf/chat`.",
+ "description": "A2UI component catalog forwarded to the inner . Without it,\nmessages classified as A2UI parse correctly but never mount a\nsurface. Pass `a2uiBasicCatalog()` from `@threadplane/chat`.",
"optional": false
}
],
@@ -3436,7 +3436,7 @@
{
"name": "ChatStreamingMdComponent",
"kind": "class",
- "description": "Renders streaming markdown by walking a @cacheplane/partial-markdown AST\nthrough @ngaf/render's view registry.\n\nReactivity model: the live `parser.root` keeps a stable JS reference\nacross pushes (partial-markdown's identity guarantee). To make Angular\nsignals propagate downstream when the underlying tree changes, we surface\na materialized snapshot via `materialize()`. The snapshot shares\nstructurally — unchanged subtrees keep the SAME reference, and any\ndescendant change yields a NEW root reference. This lets Angular's\n`Object.is` equality check both detect changes (root reference differs)\nand short-circuit unchanged subtrees (per-node references stable).\n\nOverride per-node-type renderers via the `[viewRegistry]` input or by\nsupplying a different `MARKDOWN_VIEW_REGISTRY` provider in the injector\ntree.",
+ "description": "Renders streaming markdown by walking a @cacheplane/partial-markdown AST\nthrough @threadplane/render's view registry.\n\nReactivity model: the live `parser.root` keeps a stable JS reference\nacross pushes (partial-markdown's identity guarantee). To make Angular\nsignals propagate downstream when the underlying tree changes, we surface\na materialized snapshot via `materialize()`. The snapshot shares\nstructurally — unchanged subtrees keep the SAME reference, and any\ndescendant change yields a NEW root reference. This lets Angular's\n`Object.is` equality check both detect changes (root reference differs)\nand short-circuit unchanged subtrees (per-node references stable).\n\nOverride per-node-type renderers via the `[viewRegistry]` input or by\nsupplying a different `MARKDOWN_VIEW_REGISTRY` provider in the injector\ntree.",
"params": [],
"examples": [],
"properties": [
@@ -4972,7 +4972,7 @@
{
"name": "A2uiComponentView",
"kind": "interface",
- "description": "Chat-internal projection of an A2UI component, materialized by the\nsurface store. Distinct from the wire-format `A2uiComponent` in\n`@ngaf/a2ui` (which carries the raw `component: A2uiComponentDef`\npayload) — this type adds the per-component readiness fields the\nprogressive renderer consumes.",
+ "description": "Chat-internal projection of an A2UI component, materialized by the\nsurface store. Distinct from the wire-format `A2uiComponent` in\n`@threadplane/a2ui` (which carries the raw `component: A2uiComponentDef`\npayload) — this type adds the per-component readiness fields the\nprogressive renderer consumes.",
"properties": [
{
"name": "bindings",
@@ -6337,7 +6337,7 @@
{
"name": "A2uiViewEntry",
"kind": "type",
- "description": "Catalog entry for the A2UI surface renderer.\n\n`component` is mounted once all of the component's bindings (data\nmodel paths referenced in its prop expressions) have resolved. While\nany binding is unpopulated, the `fallback` is mounted instead. If\n`fallback` is omitted, the lib's default fallback\n(`A2uiDefaultFallbackComponent`) is mounted.\n\nThis is a chat-side alias for the shared `RenderViewEntry` shape so\nconsumers of `@ngaf/chat` don't have to import from `@ngaf/render`.",
+ "description": "Catalog entry for the A2UI surface renderer.\n\n`component` is mounted once all of the component's bindings (data\nmodel paths referenced in its prop expressions) have resolved. While\nany binding is unpopulated, the `fallback` is mounted instead. If\n`fallback` is omitted, the lib's default fallback\n(`A2uiDefaultFallbackComponent`) is mounted.\n\nThis is a chat-side alias for the shared `RenderViewEntry` shape so\nconsumers of `@threadplane/chat` don't have to import from `@threadplane/render`.",
"signature": "RenderViewEntry",
"examples": []
},
diff --git a/apps/website/content/docs/chat/api/chat-config.mdx b/apps/website/content/docs/chat/api/chat-config.mdx
index 4a7d04192..0eee6c8a5 100644
--- a/apps/website/content/docs/chat/api/chat-config.mdx
+++ b/apps/website/content/docs/chat/api/chat-config.mdx
@@ -5,8 +5,8 @@
**Import:**
```typescript
-import type { ChatConfig } from '@ngaf/chat';
-import type { AngularRegistry } from '@ngaf/render';
+import type { ChatConfig } from '@threadplane/chat';
+import type { AngularRegistry } from '@threadplane/render';
```
## Interface Definition
@@ -94,8 +94,8 @@ Inject `CHAT_CONFIG` to read configuration values in your own components:
```typescript
import { inject } from '@angular/core';
-import { CHAT_CONFIG } from '@ngaf/chat';
-import type { ChatConfig } from '@ngaf/chat';
+import { CHAT_CONFIG } from '@threadplane/chat';
+import type { ChatConfig } from '@threadplane/chat';
@Component({
selector: 'app-chat-header',
diff --git a/apps/website/content/docs/chat/api/content-classifier.mdx b/apps/website/content/docs/chat/api/content-classifier.mdx
index 0828b6fc4..450b73243 100644
--- a/apps/website/content/docs/chat/api/content-classifier.mdx
+++ b/apps/website/content/docs/chat/api/content-classifier.mdx
@@ -5,8 +5,8 @@ Factory function that creates a `ContentClassifier` — a stateful, per-message
**Import:**
```typescript
-import { createContentClassifier } from '@ngaf/chat';
-import type { ContentClassifier, ContentType } from '@ngaf/chat';
+import { createContentClassifier } from '@threadplane/chat';
+import type { ContentClassifier, ContentType } from '@threadplane/chat';
```
## Signature
diff --git a/apps/website/content/docs/chat/api/mock-agent.mdx b/apps/website/content/docs/chat/api/mock-agent.mdx
index 7fbced52f..fd41a6365 100644
--- a/apps/website/content/docs/chat/api/mock-agent.mdx
+++ b/apps/website/content/docs/chat/api/mock-agent.mdx
@@ -1,12 +1,12 @@
# mockAgent()
-`mockAgent()` creates a runtime-neutral `Agent` mock with writable signals for testing `@ngaf/chat` components. Use it when you are testing chat UI behavior and do not need LangGraph-specific fields.
+`mockAgent()` creates a runtime-neutral `Agent` mock with writable signals for testing `@threadplane/chat` components. Use it when you are testing chat UI behavior and do not need LangGraph-specific fields.
**Import:**
```typescript
-import { mockAgent } from '@ngaf/chat';
-import type { MockAgent } from '@ngaf/chat';
+import { mockAgent } from '@threadplane/chat';
+import type { MockAgent } from '@threadplane/chat';
```
## Signature
@@ -33,7 +33,7 @@ function mockAgent(options?: MockAgentOptions): MockAgent
```typescript
import { TestBed } from '@angular/core/testing';
-import { ChatComponent, mockAgent } from '@ngaf/chat';
+import { ChatComponent, mockAgent } from '@threadplane/chat';
it('renders messages from an agent', async () => {
const agent = mockAgent({
@@ -88,4 +88,4 @@ expect(agent.submitCalls[1]?.input).toEqual({
## LangGraph-Specific Tests
-Use `mockLangGraphAgent()` from `@ngaf/langgraph` only when the test needs LangGraph-specific signals such as raw LangGraph messages, checkpoint state, branches, queued runs, or transport metadata.
+Use `mockLangGraphAgent()` from `@threadplane/langgraph` only when the test needs LangGraph-specific signals such as raw LangGraph messages, checkpoint state, branches, queued runs, or transport metadata.
diff --git a/apps/website/content/docs/chat/api/parse-tree-store.mdx b/apps/website/content/docs/chat/api/parse-tree-store.mdx
index a631724f3..44a906335 100644
--- a/apps/website/content/docs/chat/api/parse-tree-store.mdx
+++ b/apps/website/content/docs/chat/api/parse-tree-store.mdx
@@ -5,8 +5,8 @@ Factory function that creates a `ParseTreeStore` — a bridge between the `@cach
**Import:**
```typescript
-import { createParseTreeStore } from '@ngaf/chat';
-import type { ParseTreeStore, ElementAccumulationState } from '@ngaf/chat';
+import { createParseTreeStore } from '@threadplane/chat';
+import type { ParseTreeStore, ElementAccumulationState } from '@threadplane/chat';
```
## Signature
@@ -51,7 +51,7 @@ interface ElementAccumulationState {
```typescript
import { createPartialJsonParser } from '@cacheplane/partial-json';
-import { createParseTreeStore } from '@ngaf/chat';
+import { createParseTreeStore } from '@threadplane/chat';
const parser = createPartialJsonParser();
const store = createParseTreeStore(parser);
diff --git a/apps/website/content/docs/chat/api/provide-chat.mdx b/apps/website/content/docs/chat/api/provide-chat.mdx
index 8b2867cdf..472c949c0 100644
--- a/apps/website/content/docs/chat/api/provide-chat.mdx
+++ b/apps/website/content/docs/chat/api/provide-chat.mdx
@@ -1,9 +1,9 @@
# provideChat()
-`provideChat` is the provider factory that registers `@ngaf/chat` configuration in Angular's dependency injection system and starts the package license check. Call it in your `ApplicationConfig` or at the route level when you need a shared `CHAT_CONFIG` value.
+`provideChat` is the provider factory that registers `@threadplane/chat` configuration in Angular's dependency injection system and starts the package license check. Call it in your `ApplicationConfig` or at the route level when you need a shared `CHAT_CONFIG` value.
```typescript
-import { provideChat } from '@ngaf/chat';
+import { provideChat } from '@threadplane/chat';
export const appConfig: ApplicationConfig = {
providers: [
@@ -40,7 +40,7 @@ This makes the `ChatConfig` object available throughout the application via the
## CHAT_CONFIG Injection Token
```typescript
-import { CHAT_CONFIG } from '@ngaf/chat';
+import { CHAT_CONFIG } from '@threadplane/chat';
const CHAT_CONFIG: InjectionToken;
```
@@ -49,7 +49,7 @@ The token is an `InjectionToken` that can be injected in any compone
```typescript
import { inject } from '@angular/core';
-import { CHAT_CONFIG } from '@ngaf/chat';
+import { CHAT_CONFIG } from '@threadplane/chat';
@Component({ /* ... */ })
export class MyComponent {
@@ -78,8 +78,8 @@ See the [ChatConfig API reference](/docs/chat/api/chat-config) for the full inte
```typescript
// app.config.ts
-import { provideAgent } from '@ngaf/langgraph';
-import { provideChat } from '@ngaf/chat';
+import { provideAgent } from '@threadplane/langgraph';
+import { provideChat } from '@threadplane/chat';
export const appConfig: ApplicationConfig = {
providers: [
diff --git a/apps/website/content/docs/chat/components/chat-debug.mdx b/apps/website/content/docs/chat/components/chat-debug.mdx
index 08ead9444..cbe01b4ab 100644
--- a/apps/website/content/docs/chat/components/chat-debug.mdx
+++ b/apps/website/content/docs/chat/components/chat-debug.mdx
@@ -7,15 +7,15 @@
**Import:**
```typescript
-import { ChatDebugComponent } from '@ngaf/chat/debug';
+import { ChatDebugComponent } from '@threadplane/chat/debug';
```
## Basic Usage
```typescript
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatDebugComponent } from '@ngaf/chat/debug';
+import { agent } from '@threadplane/langgraph';
+import { ChatDebugComponent } from '@threadplane/chat/debug';
@Component({
selector: 'app-debug-page',
@@ -93,6 +93,6 @@ The footer button is labelled in expanded and drawer modes. In collapsed mode it
## Production Bundles
-The debug implementation lives under `@ngaf/chat/debug`; the main `@ngaf/chat` entry point no longer exports it. In the canonical Angular demo, normal production builds set `NGAF_CHAT_DEBUG=false` and externalize `@ngaf/chat/debug`, so the debug implementation is absent from the emitted bundle. The `production-debug` build opts back in with `NGAF_CHAT_DEBUG=true`.
+The debug implementation lives under `@threadplane/chat/debug`; the main `@threadplane/chat` entry point no longer exports it. In the canonical Angular demo, normal production builds set `THREADPLANE_CHAT_DEBUG=false` and externalize `@threadplane/chat/debug`, so the debug implementation is absent from the emitted bundle. The `production-debug` build opts back in with `THREADPLANE_CHAT_DEBUG=true`.
Keep debug controls for your app outside the debug panel. The debug panel intentionally exposes a small fixed surface so consumers do not expect demo-specific controls to appear in their own applications.
diff --git a/apps/website/content/docs/chat/components/chat-input.mdx b/apps/website/content/docs/chat/components/chat-input.mdx
index b0aee06cd..11db06dd3 100644
--- a/apps/website/content/docs/chat/components/chat-input.mdx
+++ b/apps/website/content/docs/chat/components/chat-input.mdx
@@ -7,7 +7,7 @@
**Import:**
```typescript
-import { ChatInputComponent, submitMessage } from '@ngaf/chat';
+import { ChatInputComponent, submitMessage } from '@threadplane/chat';
```
## Basic Usage
@@ -70,8 +70,8 @@ The textarea uses `field-sizing: content` CSS, which allows it to grow with its
The `submitMessage()` function is exported as a standalone utility for programmatic message submission:
```typescript
-import { submitMessage } from '@ngaf/chat';
-import type { Agent } from '@ngaf/chat';
+import { submitMessage } from '@threadplane/chat';
+import type { Agent } from '@threadplane/chat';
function sendGreeting(agent: Agent) {
const result = submitMessage(agent, 'Hello!');
@@ -136,8 +136,8 @@ The component includes accessibility attributes:
```typescript
import { Component, signal, ChangeDetectionStrategy } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatInputComponent } from '@ngaf/chat';
+import { agent } from '@threadplane/langgraph';
+import { ChatInputComponent } from '@threadplane/chat';
@Component({
selector: 'app-input-demo',
diff --git a/apps/website/content/docs/chat/components/chat-interrupt-panel.mdx b/apps/website/content/docs/chat/components/chat-interrupt-panel.mdx
index fbc52e0d8..360fdaa98 100644
--- a/apps/website/content/docs/chat/components/chat-interrupt-panel.mdx
+++ b/apps/website/content/docs/chat/components/chat-interrupt-panel.mdx
@@ -7,8 +7,8 @@
**Import:**
```typescript
-import { ChatInterruptPanelComponent } from '@ngaf/chat';
-import type { InterruptAction } from '@ngaf/chat';
+import { ChatInterruptPanelComponent } from '@threadplane/chat';
+import type { InterruptAction } from '@threadplane/chat';
```
## How It Works
@@ -27,7 +27,7 @@ When no interrupt is active, the component renders nothing.
```
```typescript
-import type { InterruptAction } from '@ngaf/chat';
+import type { InterruptAction } from '@threadplane/chat';
handleInterrupt(action: InterruptAction) {
switch (action) {
@@ -113,7 +113,7 @@ If you need full control over the interrupt UI, use the lower-level `ChatInterru
The primitive also exports a `getInterrupt()` helper function:
```typescript
-import { getInterrupt } from '@ngaf/chat';
+import { getInterrupt } from '@threadplane/chat';
const interrupt = getInterrupt(chatRef); // Interrupt | undefined
```
@@ -122,9 +122,9 @@ const interrupt = getInterrupt(chatRef); // Interrupt | undefined
```typescript
import { Component, signal, ChangeDetectionStrategy } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatComponent, ChatInterruptPanelComponent } from '@ngaf/chat';
-import type { InterruptAction } from '@ngaf/chat';
+import { agent } from '@threadplane/langgraph';
+import { ChatComponent, ChatInterruptPanelComponent } from '@threadplane/chat';
+import type { InterruptAction } from '@threadplane/chat';
@Component({
selector: 'app-interrupt-demo',
diff --git a/apps/website/content/docs/chat/components/chat-message-list.mdx b/apps/website/content/docs/chat/components/chat-message-list.mdx
index a186cce46..c15545a87 100644
--- a/apps/website/content/docs/chat/components/chat-message-list.mdx
+++ b/apps/website/content/docs/chat/components/chat-message-list.mdx
@@ -11,7 +11,7 @@ import {
ChatMessageListComponent,
MessageTemplateDirective,
getMessageType,
-} from '@ngaf/chat';
+} from '@threadplane/chat';
```
## How It Works
@@ -77,7 +77,7 @@ The `MessageTemplateDirective` is a structural directive applied to `ng-template
**Selector:** `ng-template[chatMessageTemplate]`
```typescript
-import { MessageTemplateDirective } from '@ngaf/chat';
+import { MessageTemplateDirective } from '@threadplane/chat';
```
### Input
@@ -97,7 +97,7 @@ type MessageTemplateType = 'human' | 'ai' | 'tool' | 'system' | 'function';
The `getMessageType()` function maps a runtime-neutral `Message` role to a `MessageTemplateType`.
```typescript
-import { getMessageType } from '@ngaf/chat';
+import { getMessageType } from '@threadplane/chat';
const type = getMessageType(message); // 'human' | 'ai' | 'tool' | 'system' | 'function'
```
@@ -139,12 +139,12 @@ For custom templates, you can access `message.content` directly and handle the t
```typescript
import { Component, inject, ChangeDetectionStrategy, signal } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
import {
ChatMessageListComponent,
MessageTemplateDirective,
renderMarkdown,
-} from '@ngaf/chat';
+} from '@threadplane/chat';
@Component({
selector: 'app-messages-demo',
diff --git a/apps/website/content/docs/chat/components/chat-popup.mdx b/apps/website/content/docs/chat/components/chat-popup.mdx
index a3e0200da..f38af9049 100644
--- a/apps/website/content/docs/chat/components/chat-popup.mdx
+++ b/apps/website/content/docs/chat/components/chat-popup.mdx
@@ -7,7 +7,7 @@
**Import:**
```typescript
-import { ChatPopupComponent } from '@ngaf/chat';
+import { ChatPopupComponent } from '@threadplane/chat';
```
## When to Use It
@@ -20,8 +20,8 @@ If you need the chat to always be visible, use [``](/docs/chat/components/
```typescript
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatPopupComponent } from '@ngaf/chat';
+import { agent } from '@threadplane/langgraph';
+import { ChatPopupComponent } from '@threadplane/chat';
@Component({
selector: 'app-root',
diff --git a/apps/website/content/docs/chat/components/chat-reasoning.mdx b/apps/website/content/docs/chat/components/chat-reasoning.mdx
index 265318a18..ee77bee0b 100644
--- a/apps/website/content/docs/chat/components/chat-reasoning.mdx
+++ b/apps/website/content/docs/chat/components/chat-reasoning.mdx
@@ -7,7 +7,7 @@
**Import:**
```typescript
-import { ChatReasoningComponent, formatDuration } from '@ngaf/chat';
+import { ChatReasoningComponent, formatDuration } from '@threadplane/chat';
```
## Visual states
diff --git a/apps/website/content/docs/chat/components/chat-select.mdx b/apps/website/content/docs/chat/components/chat-select.mdx
index 5342c5e9f..2c207ab8e 100644
--- a/apps/website/content/docs/chat/components/chat-select.mdx
+++ b/apps/website/content/docs/chat/components/chat-select.mdx
@@ -7,7 +7,7 @@
**Import:**
```typescript
-import { ChatSelectComponent, type ChatSelectOption } from '@ngaf/chat';
+import { ChatSelectComponent, type ChatSelectOption } from '@threadplane/chat';
```
## Basic Usage
@@ -114,7 +114,7 @@ chat-select {
## Public API
```typescript
-import { ChatSelectComponent, type ChatSelectOption } from '@ngaf/chat';
+import { ChatSelectComponent, type ChatSelectOption } from '@threadplane/chat';
```
## See also
diff --git a/apps/website/content/docs/chat/components/chat-sidebar.mdx b/apps/website/content/docs/chat/components/chat-sidebar.mdx
index b97a385cb..404a58bbd 100644
--- a/apps/website/content/docs/chat/components/chat-sidebar.mdx
+++ b/apps/website/content/docs/chat/components/chat-sidebar.mdx
@@ -7,7 +7,7 @@
**Import:**
```typescript
-import { ChatSidebarComponent } from '@ngaf/chat';
+import { ChatSidebarComponent } from '@threadplane/chat';
```
## When to Use It
@@ -20,8 +20,8 @@ If you need a floating overlay that does not affect layout, use [``]
```typescript
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatSidebarComponent } from '@ngaf/chat';
+import { agent } from '@threadplane/langgraph';
+import { ChatSidebarComponent } from '@threadplane/chat';
@Component({
selector: 'app-shell',
diff --git a/apps/website/content/docs/chat/components/chat-subagent-card.mdx b/apps/website/content/docs/chat/components/chat-subagent-card.mdx
index 1f67b3e18..bcc9f1cdb 100644
--- a/apps/website/content/docs/chat/components/chat-subagent-card.mdx
+++ b/apps/website/content/docs/chat/components/chat-subagent-card.mdx
@@ -7,7 +7,7 @@
**Import:**
```typescript
-import { ChatSubagentCardComponent } from '@ngaf/chat';
+import { ChatSubagentCardComponent } from '@threadplane/chat';
```
## Basic Usage
@@ -26,7 +26,7 @@ import { ChatSubagentCardComponent } from '@ngaf/chat';
## Subagent
-The `Subagent` type comes from `@ngaf/chat`. It provides reactive state for a subagent:
+The `Subagent` type comes from `@threadplane/chat`. It provides reactive state for a subagent:
| Property | Type | Description |
|----------|------|-------------|
@@ -77,12 +77,12 @@ The `ChatSubagentsComponent` primitive iterates over active subagent streams fro
```typescript
import { Component, signal, ChangeDetectionStrategy } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
+import { agent } from '@threadplane/langgraph';
import {
ChatComponent,
ChatSubagentsComponent,
ChatSubagentCardComponent,
-} from '@ngaf/chat';
+} from '@threadplane/chat';
@Component({
selector: 'app-subagent-demo',
diff --git a/apps/website/content/docs/chat/components/chat-tool-call-card.mdx b/apps/website/content/docs/chat/components/chat-tool-call-card.mdx
index 0ff244148..4eda2daa1 100644
--- a/apps/website/content/docs/chat/components/chat-tool-call-card.mdx
+++ b/apps/website/content/docs/chat/components/chat-tool-call-card.mdx
@@ -7,7 +7,7 @@
**Import:**
```typescript
-import { ChatToolCallCardComponent, type ToolCallInfo } from '@ngaf/chat';
+import { ChatToolCallCardComponent, type ToolCallInfo } from '@threadplane/chat';
```
## Status pill
diff --git a/apps/website/content/docs/chat/components/chat-tool-call-template.mdx b/apps/website/content/docs/chat/components/chat-tool-call-template.mdx
index 70697129b..7abd664e7 100644
--- a/apps/website/content/docs/chat/components/chat-tool-call-template.mdx
+++ b/apps/website/content/docs/chat/components/chat-tool-call-template.mdx
@@ -7,7 +7,7 @@
**Import:**
```typescript
-import { ChatToolCallTemplateDirective, type ChatToolCallTemplateContext } from '@ngaf/chat';
+import { ChatToolCallTemplateDirective, type ChatToolCallTemplateContext } from '@threadplane/chat';
```
## Template context
diff --git a/apps/website/content/docs/chat/components/chat-tool-calls.mdx b/apps/website/content/docs/chat/components/chat-tool-calls.mdx
index e36704b49..e3beb87b8 100644
--- a/apps/website/content/docs/chat/components/chat-tool-calls.mdx
+++ b/apps/website/content/docs/chat/components/chat-tool-calls.mdx
@@ -7,7 +7,7 @@
**Import:**
```typescript
-import { ChatToolCallsComponent } from '@ngaf/chat';
+import { ChatToolCallsComponent } from '@threadplane/chat';
```
## Inputs
diff --git a/apps/website/content/docs/chat/components/chat-trace.mdx b/apps/website/content/docs/chat/components/chat-trace.mdx
index 4484b60dc..69375854c 100644
--- a/apps/website/content/docs/chat/components/chat-trace.mdx
+++ b/apps/website/content/docs/chat/components/chat-trace.mdx
@@ -7,7 +7,7 @@
**Import:**
```typescript
-import { ChatTraceComponent } from '@ngaf/chat';
+import { ChatTraceComponent } from '@threadplane/chat';
```
## When to Use It
@@ -90,8 +90,8 @@ When `state` transitions from any value to `'running'`, the trace automatically
```typescript
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatTraceComponent, ChatMessageListComponent } from '@ngaf/chat';
+import { agent } from '@threadplane/langgraph';
+import { ChatTraceComponent, ChatMessageListComponent } from '@threadplane/chat';
@Component({
selector: 'app-traced-chat',
diff --git a/apps/website/content/docs/chat/components/chat.mdx b/apps/website/content/docs/chat/components/chat.mdx
index 3a820d90e..187cf9f2f 100644
--- a/apps/website/content/docs/chat/components/chat.mdx
+++ b/apps/website/content/docs/chat/components/chat.mdx
@@ -11,7 +11,7 @@
**Import:**
```typescript
-import { ChatComponent } from '@ngaf/chat';
+import { ChatComponent } from '@threadplane/chat';
```
## When to Use It
@@ -33,8 +33,8 @@ If you need to customize the message layout, add components between sections, or
```typescript
import { Component, signal } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatComponent } from '@ngaf/chat';
+import { agent } from '@threadplane/langgraph';
+import { ChatComponent } from '@threadplane/chat';
@Component({
selector: 'app-chat-page',
@@ -65,8 +65,8 @@ export class ChatPageComponent {
| Input | Type | Default | Description |
|-------|------|---------|-------------|
-| `agent` | `Agent` | **Required** | The runtime-neutral agent providing streaming state. `agent()` from `@ngaf/langgraph` returns a compatible `LangGraphAgent`. |
-| `views` | `ViewRegistry \| undefined` | `undefined` | View registry for generative UI. Maps spec type names to Angular components. Created with `views()` from `@ngaf/chat`. |
+| `agent` | `Agent` | **Required** | The runtime-neutral agent providing streaming state. `agent()` from `@threadplane/langgraph` returns a compatible `LangGraphAgent`. |
+| `views` | `ViewRegistry \| undefined` | `undefined` | View registry for generative UI. Maps spec type names to Angular components. Created with `views()` from `@threadplane/chat`. |
| `store` | `StateStore \| undefined` | `undefined` | Optional state store for interactive generative UI specs. |
| `handlers` | `Record) => unknown \| Promise>` | `{}` | Event handlers for generative UI specs and A2UI `functionCall` actions. Handlers run in Angular injection context — `inject()` is available inside handler functions. |
| `threads` | `Thread[]` | `[]` | List of threads to display in the sidebar. Each thread must have an `id` property. |
@@ -141,7 +141,7 @@ When you pass a `[views]` registry, the component auto-detects JSON specs in AI
```
```typescript
-import { views } from '@ngaf/chat';
+import { views } from '@threadplane/chat';
import { WeatherCardComponent } from './weather-card.component';
const myViews = views({
@@ -156,7 +156,7 @@ AI messages containing JSON are parsed character-by-character as tokens stream.
When AI messages contain A2UI content (prefixed with `---a2ui_JSON---`), the component auto-detects A2UI mode. Pass `a2uiBasicCatalog()` to `[views]` to render the built-in catalog:
```typescript
-import { ChatComponent, a2uiBasicCatalog } from '@ngaf/chat';
+import { ChatComponent, a2uiBasicCatalog } from '@threadplane/chat';
views = a2uiBasicCatalog();
```
diff --git a/apps/website/content/docs/chat/concepts/message-model.mdx b/apps/website/content/docs/chat/concepts/message-model.mdx
index 74ace1888..9bea8fa04 100644
--- a/apps/website/content/docs/chat/concepts/message-model.mdx
+++ b/apps/website/content/docs/chat/concepts/message-model.mdx
@@ -1,6 +1,6 @@
# Message Model
-`@ngaf/chat` renders a runtime-neutral message model. Adapters translate backend-specific messages into this shape, then components render from it.
+`@threadplane/chat` renders a runtime-neutral message model. Adapters translate backend-specific messages into this shape, then components render from it.
This matters because provider message formats are not stable enough to build customer UI against directly. LangGraph, AG-UI, OpenAI, Anthropic, and custom backends all have different event and content shapes. The chat layer needs one model.
@@ -126,7 +126,7 @@ Messages can carry provider-agnostic citations:
message.citations;
```
-`@ngaf/langgraph` exports `extractCitations()` for advanced adapters that need to normalize nonstandard citation payloads. Chat markdown views can render citation markers against the message citation list.
+`@threadplane/langgraph` exports `extractCitations()` for advanced adapters that need to normalize nonstandard citation payloads. Chat markdown views can render citation markers against the message citation list.
Keep citation data on the message that owns the content. Avoid a separate global citation store unless your product has a cross-message source panel.
@@ -186,7 +186,7 @@ import {
isAssistantMessage,
isToolMessage,
isSystemMessage,
-} from '@ngaf/chat';
+} from '@threadplane/chat';
```
Put backend-specific fields in `extra`, and document them in your adapter. Portable UI should survive when `extra` is absent.
diff --git a/apps/website/content/docs/chat/concepts/primitives-vs-compositions.mdx b/apps/website/content/docs/chat/concepts/primitives-vs-compositions.mdx
index 7c81cf7b8..6012e69db 100644
--- a/apps/website/content/docs/chat/concepts/primitives-vs-compositions.mdx
+++ b/apps/website/content/docs/chat/concepts/primitives-vs-compositions.mdx
@@ -1,6 +1,6 @@
# Primitives vs Compositions
-`@ngaf/chat` gives you two levels of UI.
+`@threadplane/chat` gives you two levels of UI.
Use compositions when the default product shape is close to what you need. Use primitives when the layout, interaction model, or rendering policy is part of your application.
@@ -11,7 +11,7 @@ This matters because chat UI gets complicated quickly. Message streaming, input
The main composition is ``.
```ts
-import { ChatComponent } from '@ngaf/chat';
+import { ChatComponent } from '@threadplane/chat';
```
```html
@@ -46,7 +46,7 @@ Use `` when you want the library to own the chat shell.
`` is also a composition. It is built for development and inspection, not end-user chat layout, and ships from the debug-only secondary entry point.
```ts
-import { ChatDebugComponent } from '@ngaf/chat/debug';
+import { ChatDebugComponent } from '@threadplane/chat/debug';
```
```html
@@ -69,7 +69,7 @@ import {
ChatMessageListComponent,
MessageTemplateDirective,
ChatInputComponent,
-} from '@ngaf/chat';
+} from '@threadplane/chat';
```
```html
@@ -151,7 +151,7 @@ The mapping is:
Give `` a parent with height. The composition uses flex layout and `height: 100%`; without a constrained parent, it can collapse.
-Do not pass a raw backend client to chat primitives. They need the `Agent` contract from `@ngaf/chat`, not a LangGraph SDK client or AG-UI `AbstractAgent`.
+Do not pass a raw backend client to chat primitives. They need the `Agent` contract from `@threadplane/chat`, not a LangGraph SDK client or AG-UI `AbstractAgent`.
Do not mix two agents in one shell unless you mean it. `chat-message-list`, `chat-input`, tool-call UI, and debug UI should usually point at the same `Agent` instance.
diff --git a/apps/website/content/docs/chat/getting-started/changelog.mdx b/apps/website/content/docs/chat/getting-started/changelog.mdx
index 3ed584cec..b8926a9b6 100644
--- a/apps/website/content/docs/chat/getting-started/changelog.mdx
+++ b/apps/website/content/docs/chat/getting-started/changelog.mdx
@@ -5,7 +5,7 @@
### Reasoning
- New `` primitive renders model reasoning content as a "Thinking…" / "Thought for Ns" pill, default-collapsed once streaming completes. Auto-rendered by `` when `Message.reasoning` is populated.
-- New `Message.reasoning` and `Message.reasoningDurationMs` optional fields on the shared agent contract. Both adapters populate them: `@ngaf/langgraph` from `{type:'reasoning'}` / `{type:'thinking'}` content blocks, `@ngaf/ag-ui` from `REASONING_MESSAGE_*` events.
+- New `Message.reasoning` and `Message.reasoningDurationMs` optional fields on the shared agent contract. Both adapters populate them: `@threadplane/langgraph` from `{type:'reasoning'}` / `{type:'thinking'}` content blocks, `@threadplane/ag-ui` from `REASONING_MESSAGE_*` events.
### Tool-call templates
diff --git a/apps/website/content/docs/chat/getting-started/installation.mdx b/apps/website/content/docs/chat/getting-started/installation.mdx
index 79b1e9164..4cfb34c1e 100644
--- a/apps/website/content/docs/chat/getting-started/installation.mdx
+++ b/apps/website/content/docs/chat/getting-started/installation.mdx
@@ -1,16 +1,16 @@
# Installation
-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.
+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 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).
+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
-`@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.
+`@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.
@@ -18,34 +18,34 @@ Required for the Angular build toolchain. `node --version` should report `v18` o
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).
+- **`@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 `@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.
+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 `@ngaf/chat`, your chosen runtime adapter, and the `marked` markdown parser:
+Install `@threadplane/chat`, your chosen runtime adapter, and the `marked` markdown parser:
```bash
# LangGraph backends
-npm install @ngaf/chat @ngaf/langgraph marked
+npm install @threadplane/chat @threadplane/langgraph marked
# AG-UI compatible backends
-npm install @ngaf/chat @ngaf/ag-ui marked
+npm install @threadplane/chat @threadplane/ag-ui marked
```
`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.
-`@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.
+`@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:
+After purchase, Threadplane emails a signed token that looks like:
```
eyJzdWIiOiJjdXN0QGV4YW1wbGUuY29tIiwidGllciI6ImRldmVsb3Blci1zZWF0IiwiaWF0IjoxNzM…
@@ -99,13 +99,13 @@ This is the lowest-friction path for small teams. Do **not** commit the token to
## 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).
+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).
```ts
// src/app/app.config.ts
import { ApplicationConfig, provideZonelessChangeDetection } from '@angular/core';
-import { provideAgent } from '@ngaf/langgraph';
-import { provideChat } from '@ngaf/chat';
+import { provideAgent } from '@threadplane/langgraph';
+import { provideChat } from '@threadplane/chat';
import { environment } from '../environments/environment';
export const appConfig: ApplicationConfig = {
@@ -141,8 +141,8 @@ Create a component, import `ChatComponent`, and bind it to an `agent()` instance
```ts
// src/app/chat-page.component.ts
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatComponent } from '@ngaf/chat';
+import { agent } from '@threadplane/langgraph';
+import { ChatComponent } from '@threadplane/chat';
@Component({
selector: 'app-chat-page',
@@ -172,10 +172,10 @@ Open the browser DevTools console and look for messages prefixed with `[threadpl
| 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. |
+| `[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](https://threadplane.ai/pricing). |
+| `[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.
@@ -210,7 +210,7 @@ Your 12-month term has lapsed. Renew at [threadplane.ai/pricing](https://threadp
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.
diff --git a/apps/website/content/docs/chat/getting-started/introduction.mdx b/apps/website/content/docs/chat/getting-started/introduction.mdx
index ff0d83c4c..cd9fdeb34 100644
--- a/apps/website/content/docs/chat/getting-started/introduction.mdx
+++ b/apps/website/content/docs/chat/getting-started/introduction.mdx
@@ -1,9 +1,9 @@
# Introduction
-`@ngaf/chat` is the Angular UI component library for building chat interfaces on top of a runtime-neutral `Agent` contract. It provides a complete set of composable, Signal-driven components that render messages, handle user input, display tool calls, manage interrupts, and support generative UI -- all styled with CSS custom properties and built for Angular 20+.
+`@threadplane/chat` is the Angular UI component library for building chat interfaces on top of a runtime-neutral `Agent` contract. It provides a complete set of composable, Signal-driven components that render messages, handle user input, display tool calls, manage interrupts, and support generative UI -- all styled with CSS custom properties and built for Angular 20+.
-This guide explains the library's two-tier architecture, how it relates to the rest of the ThreadPlane stack, and when to reach for the all-in-one composition versus assembling primitives yourself.
+This guide explains the library's two-tier architecture, how it relates to the rest of the Threadplane stack, and when to reach for the all-in-one composition versus assembling primitives yourself.
## Two-Tier Architecture
@@ -37,30 +37,30 @@ Compositions are opinionated, styled components that combine primitives into rea
| `ChatInterruptPanelComponent` | `chat-interrupt-panel` | Styled interrupt card with accept/edit/respond/ignore actions |
| `ChatToolCallCardComponent` | `chat-tool-call-card` | Expandable card showing tool name, inputs, and output |
| `ChatSubagentCardComponent` | `chat-subagent-card` | Expandable card showing subagent status and messages |
-| `ChatDebugComponent` | `chat-debug` | Debug cockpit from `@ngaf/chat/debug` with timeline, state inspector, and diff viewer |
+| `ChatDebugComponent` | `chat-debug` | Debug cockpit from `@threadplane/chat/debug` with timeline, state inspector, and diff viewer |
| `ChatTimelineSliderComponent` | `chat-timeline-slider` | Slider-based timeline navigation |
## How the Stack Fits Together
-`@ngaf/chat` sits between your application and two other ThreadPlane libraries:
+`@threadplane/chat` sits between your application and two other Threadplane libraries:
```
Your App
|
v
-@ngaf/chat <-- UI components (this library)
+@threadplane/chat <-- UI components (this library)
| |
v v
-@ngaf/langgraph @ngaf/render
+@threadplane/langgraph @threadplane/render
(streaming state) (generative UI)
|
v
LangGraph Platform
```
-- **`@ngaf/langgraph`** provides the `agent()` function and returns a `LangGraphAgent`, which satisfies the `Agent` contract consumed by `@ngaf/chat`. It exposes reactive Signals for `messages()`, `isLoading()`, `error()`, `interrupt()`, `toolCalls()`, `history()`, and more.
+- **`@threadplane/langgraph`** provides the `agent()` function and returns a `LangGraphAgent`, which satisfies the `Agent` contract consumed by `@threadplane/chat`. It exposes reactive Signals for `messages()`, `isLoading()`, `error()`, `interrupt()`, `toolCalls()`, `history()`, and more.
-- **`@ngaf/render`** provides `RenderSpecComponent` and view registries for rendering JSON UI specs as Angular components. The `ChatComponent` auto-detects JSON specs in AI messages and renders them through `@ngaf/render` - pass a view registry via the `[views]` input. The same `[views]` input enables A2UI rendering with `a2uiBasicCatalog()`, which currently maps 18 component types.
+- **`@threadplane/render`** provides `RenderSpecComponent` and view registries for rendering JSON UI specs as Angular components. The `ChatComponent` auto-detects JSON specs in AI messages and renders them through `@threadplane/render` - pass a view registry via the `[views]` input. The same `[views]` input enables A2UI rendering with `a2uiBasicCatalog()`, which currently maps 18 component types.
## When to Use `ChatComponent` vs. Custom Assembly
diff --git a/apps/website/content/docs/chat/getting-started/quickstart.mdx b/apps/website/content/docs/chat/getting-started/quickstart.mdx
index 03519b69d..79f05aa2e 100644
--- a/apps/website/content/docs/chat/getting-started/quickstart.mdx
+++ b/apps/website/content/docs/chat/getting-started/quickstart.mdx
@@ -1,6 +1,6 @@
# Quick Start
-Build a streaming chat UI with `@ngaf/chat` in 5 minutes.
+Build a streaming chat UI with `@threadplane/chat` in 5 minutes.
Angular 20+ project with an agent provider configured. See [Agent Installation](/docs/agent/getting-started/installation) if you need help.
@@ -10,7 +10,7 @@ Angular 20+ project with an agent provider configured. See [Agent Installation](
```bash
-npm install @ngaf/chat marked
+npm install @threadplane/chat marked
```
`marked` is the markdown renderer used for assistant messages.
@@ -21,8 +21,8 @@ npm install @ngaf/chat marked
```ts
// app.config.ts
import { ApplicationConfig } from '@angular/core';
-import { provideAgent } from '@ngaf/langgraph';
-import { provideChat } from '@ngaf/chat';
+import { provideAgent } from '@threadplane/langgraph';
+import { provideChat } from '@threadplane/chat';
export const appConfig: ApplicationConfig = {
providers: [
@@ -38,8 +38,8 @@ export const appConfig: ApplicationConfig = {
```ts
// chat-page.component.ts
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatComponent } from '@ngaf/chat';
+import { agent } from '@threadplane/langgraph';
+import { ChatComponent } from '@threadplane/chat';
@Component({
selector: 'app-chat-page',
diff --git a/apps/website/content/docs/chat/guides/configuration.mdx b/apps/website/content/docs/chat/guides/configuration.mdx
index 834d0154d..930d624fd 100644
--- a/apps/website/content/docs/chat/guides/configuration.mdx
+++ b/apps/website/content/docs/chat/guides/configuration.mdx
@@ -1,6 +1,6 @@
# Configuration
-`@ngaf/chat` uses Angular's dependency injection system for shared configuration. The `provideChat()` function registers a `ChatConfig` object under the `CHAT_CONFIG` injection token and starts the package license check.
+`@threadplane/chat` uses Angular's dependency injection system for shared configuration. The `provideChat()` function registers a `ChatConfig` object under the `CHAT_CONFIG` injection token and starts the package license check.
## provideChat()
@@ -9,7 +9,7 @@ Call `provideChat()` in your application's provider array when your application
```typescript
// app.config.ts
import { ApplicationConfig } from '@angular/core';
-import { provideChat } from '@ngaf/chat';
+import { provideChat } from '@threadplane/chat';
export const appConfig: ApplicationConfig = {
providers: [
@@ -32,7 +32,7 @@ function provideChat(config: ChatConfig): EnvironmentProviders
## ChatConfig Interface
```typescript
-import type { AngularRegistry } from '@ngaf/render';
+import type { AngularRegistry } from '@threadplane/render';
interface ChatConfig {
/** Default render registry for consumers that read CHAT_CONFIG. */
@@ -64,8 +64,8 @@ The `CHAT_CONFIG` token is an `InjectionToken` that you can inject d
```typescript
import { inject } from '@angular/core';
-import { CHAT_CONFIG } from '@ngaf/chat';
-import type { ChatConfig } from '@ngaf/chat';
+import { CHAT_CONFIG } from '@threadplane/chat';
+import type { ChatConfig } from '@threadplane/chat';
@Component({ /* ... */ })
export class MyComponent {
@@ -87,7 +87,7 @@ Because `provideChat()` returns `EnvironmentProviders`, you can provide differen
```typescript
// app.routes.ts
-import { provideChat } from '@ngaf/chat';
+import { provideChat } from '@threadplane/chat';
export const routes: Routes = [
{
diff --git a/apps/website/content/docs/chat/guides/custom-catalogs.mdx b/apps/website/content/docs/chat/guides/custom-catalogs.mdx
index 06a2f151f..9e4580bd5 100644
--- a/apps/website/content/docs/chat/guides/custom-catalogs.mdx
+++ b/apps/website/content/docs/chat/guides/custom-catalogs.mdx
@@ -5,12 +5,12 @@ description: Compose custom component catalogs for generative UI using ViewRegis
# Custom Catalogs
-Both json-render specs and A2UI surfaces render through the same `ViewRegistry`. Compose catalogs using `views`, `withViews`, and `withoutViews` from `@ngaf/render`.
+Both json-render specs and A2UI surfaces render through the same `ViewRegistry`. Compose catalogs using `views`, `withViews`, and `withoutViews` from `@threadplane/render`.
## Using the Built-In A2UI Catalog
```typescript
-import { a2uiBasicCatalog } from '@ngaf/chat';
+import { a2uiBasicCatalog } from '@threadplane/chat';
```
@@ -18,8 +18,8 @@ import { a2uiBasicCatalog } from '@ngaf/chat';
## Adding Custom Components
```typescript
-import { withViews } from '@ngaf/render';
-import { a2uiBasicCatalog } from '@ngaf/chat';
+import { withViews } from '@threadplane/render';
+import { a2uiBasicCatalog } from '@threadplane/chat';
const catalog = withViews(a2uiBasicCatalog(), {
Chart: MyChartComponent,
@@ -32,8 +32,8 @@ const catalog = withViews(a2uiBasicCatalog(), {
## Overriding Built-In Components
```typescript
-import { views } from '@ngaf/render';
-import { a2uiBasicCatalog } from '@ngaf/chat';
+import { views } from '@threadplane/render';
+import { a2uiBasicCatalog } from '@threadplane/chat';
const catalog = views({
...a2uiBasicCatalog(),
@@ -44,8 +44,8 @@ const catalog = views({
## Removing Components
```typescript
-import { withoutViews } from '@ngaf/render';
-import { a2uiBasicCatalog } from '@ngaf/chat';
+import { withoutViews } from '@threadplane/render';
+import { a2uiBasicCatalog } from '@threadplane/chat';
const catalog = withoutViews(a2uiBasicCatalog(), 'Modal', 'Video');
```
@@ -53,7 +53,7 @@ const catalog = withoutViews(a2uiBasicCatalog(), 'Modal', 'Video');
## Custom-Only (No A2UI)
```typescript
-import { views } from '@ngaf/render';
+import { views } from '@threadplane/render';
const catalog = views({
Chart: MyChartComponent,
diff --git a/apps/website/content/docs/chat/guides/generative-ui.mdx b/apps/website/content/docs/chat/guides/generative-ui.mdx
index fc0067785..7a6066719 100644
--- a/apps/website/content/docs/chat/guides/generative-ui.mdx
+++ b/apps/website/content/docs/chat/guides/generative-ui.mdx
@@ -24,8 +24,8 @@ Pass a `ViewRegistry` via the `[views]` input on `ChatComponent`:
```typescript
import { Component, signal } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatComponent, views } from '@ngaf/chat';
+import { agent } from '@threadplane/langgraph';
+import { ChatComponent, views } from '@threadplane/chat';
import { WeatherCardComponent } from './weather-card.component';
import { ChartComponent } from './chart.component';
@@ -116,7 +116,7 @@ Because the JSON is parsed character-by-character as tokens arrive:
For interactive generative UI (forms, selections), pass a `StateStore` via the `[store]` input:
```typescript
-import { signalStateStore } from '@ngaf/render';
+import { signalStateStore } from '@threadplane/render';
@Component({
template: `
diff --git a/apps/website/content/docs/chat/guides/layout-modes.mdx b/apps/website/content/docs/chat/guides/layout-modes.mdx
index b984c99f0..593a61322 100644
--- a/apps/website/content/docs/chat/guides/layout-modes.mdx
+++ b/apps/website/content/docs/chat/guides/layout-modes.mdx
@@ -1,6 +1,6 @@
# Layout Modes
-`@ngaf/chat` ships three ready-made layout compositions. Pick the one that best fits how chat fits into your application.
+`@threadplane/chat` ships three ready-made layout compositions. Pick the one that best fits how chat fits into your application.
| Mode | Component | Best for |
|---|---|---|
@@ -19,8 +19,8 @@ The embedded composition fills its parent container using `height: 100%` and a f
```typescript
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatComponent } from '@ngaf/chat';
+import { agent } from '@threadplane/langgraph';
+import { ChatComponent } from '@threadplane/chat';
@Component({
selector: 'app-chat-page',
@@ -56,8 +56,8 @@ The popup composition renders a circular launcher button fixed to the bottom-rig
```typescript
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatPopupComponent } from '@ngaf/chat';
+import { agent } from '@threadplane/langgraph';
+import { ChatPopupComponent } from '@threadplane/chat';
@Component({
selector: 'app-root',
@@ -102,8 +102,8 @@ The sidebar composition renders a slide-in panel anchored to the right edge. It
```typescript
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatSidebarComponent } from '@ngaf/chat';
+import { agent } from '@threadplane/langgraph';
+import { ChatSidebarComponent } from '@threadplane/chat';
@Component({
selector: 'app-shell',
diff --git a/apps/website/content/docs/chat/guides/lifecycle.mdx b/apps/website/content/docs/chat/guides/lifecycle.mdx
index ea846f208..25ba81d66 100644
--- a/apps/website/content/docs/chat/guides/lifecycle.mdx
+++ b/apps/website/content/docs/chat/guides/lifecycle.mdx
@@ -1,6 +1,6 @@
# Chat Lifecycle Signals
-The `@ngaf/chat` library exposes per-instance lifecycle signals via the `CHAT_LIFECYCLE` injection token. Consumers can subscribe to these signals for debugging, custom dashboards, or telemetry integrations.
+The `@threadplane/chat` library exposes per-instance lifecycle signals via the `CHAT_LIFECYCLE` injection token. Consumers can subscribe to these signals for debugging, custom dashboards, or telemetry integrations.
## Interface
@@ -25,7 +25,7 @@ export const CHAT_LIFECYCLE = new InjectionToken('CHAT_LIFECYCLE'
```typescript
import { Component, inject, effect } from '@angular/core';
-import { CHAT_LIFECYCLE } from '@ngaf/chat';
+import { CHAT_LIFECYCLE } from '@threadplane/chat';
@Component({ /* ... */ })
export class MyComponent {
diff --git a/apps/website/content/docs/chat/guides/markdown.mdx b/apps/website/content/docs/chat/guides/markdown.mdx
index c314a7959..077268932 100644
--- a/apps/website/content/docs/chat/guides/markdown.mdx
+++ b/apps/website/content/docs/chat/guides/markdown.mdx
@@ -1,6 +1,6 @@
# Markdown Rendering
-AI messages in `@ngaf/chat` can render full markdown -- headings, code blocks, tables, lists, blockquotes, and inline formatting. This is powered by the `renderMarkdown()` utility and styled with `CHAT_MARKDOWN_STYLES`.
+AI messages in `@threadplane/chat` can render full markdown -- headings, code blocks, tables, lists, blockquotes, and inline formatting. This is powered by the `renderMarkdown()` utility and styled with `CHAT_MARKDOWN_STYLES`.
## How It Works
@@ -12,7 +12,7 @@ The markdown pipeline has two stages:
## The renderMarkdown() Function
```typescript
-import { renderMarkdown } from '@ngaf/chat';
+import { renderMarkdown } from '@threadplane/chat';
import { DomSanitizer } from '@angular/platform-browser';
// In a component:
@@ -49,7 +49,7 @@ The `marked` library is loaded via a dynamic `import('marked')` at module initia
The `CHAT_MARKDOWN_STYLES` constant provides CSS rules for all standard markdown elements. It targets the `.chat-md` class using `::ng-deep` for view encapsulation compatibility.
```typescript
-import { CHAT_MARKDOWN_STYLES } from '@ngaf/chat';
+import { CHAT_MARKDOWN_STYLES } from '@threadplane/chat';
@Component({
styles: [CHAT_MARKDOWN_STYLES],
@@ -94,7 +94,7 @@ import {
MessageTemplateDirective,
CHAT_MARKDOWN_STYLES,
renderMarkdown,
-} from '@ngaf/chat';
+} from '@threadplane/chat';
@Component({
selector: 'app-chat-view',
diff --git a/apps/website/content/docs/chat/guides/streaming.mdx b/apps/website/content/docs/chat/guides/streaming.mdx
index 4693b10c8..998691af5 100644
--- a/apps/website/content/docs/chat/guides/streaming.mdx
+++ b/apps/website/content/docs/chat/guides/streaming.mdx
@@ -34,7 +34,7 @@ Tokens arrive character-by-character
For custom message rendering outside of `ChatComponent`, use `createContentClassifier()`:
```typescript
-import { createContentClassifier } from '@ngaf/chat';
+import { createContentClassifier } from '@threadplane/chat';
// Create a classifier instance (must be in an Angular injection context)
const classifier = createContentClassifier();
@@ -75,7 +75,7 @@ For lower-level control over JSON-to-Spec materialization:
```typescript
import { createPartialJsonParser } from '@cacheplane/partial-json';
-import { createParseTreeStore } from '@ngaf/chat';
+import { createParseTreeStore } from '@threadplane/chat';
const parser = createPartialJsonParser();
const store = createParseTreeStore(parser);
diff --git a/apps/website/content/docs/chat/guides/theming.mdx b/apps/website/content/docs/chat/guides/theming.mdx
index 499b1546e..43e36f2ae 100644
--- a/apps/website/content/docs/chat/guides/theming.mdx
+++ b/apps/website/content/docs/chat/guides/theming.mdx
@@ -1,12 +1,12 @@
# Theming
-`@ngaf/chat` uses CSS custom properties (variables) for all visual styling. Every color, radius, font, and spacing value is controlled by a variable prefixed with `--ngaf-chat-`, making it straightforward to match your application's design system.
+`@threadplane/chat` uses CSS custom properties (variables) for all visual styling. Every color, radius, font, and spacing value is controlled by a variable prefixed with `--ngaf-chat-`, making it straightforward to match your application's design system.
## How Theming Works
-Chat components define all design tokens using CSS custom properties on the `:host` element. The token system supports automatic light/dark switching via `prefers-color-scheme` and explicit override via a `[data-ngaf-chat-theme]` attribute.
+Chat components define all design tokens using CSS custom properties on the `:host` element. The token system supports automatic light/dark switching via `prefers-color-scheme` and explicit override via a `[data-threadplane-chat-theme]` attribute.
-No imported stylesheet is needed - tokens are applied automatically by each component's encapsulated styles. An optional global stylesheet (`@ngaf/chat/chat.css`) is available if you want to customize tokens at the `:root` level.
+No imported stylesheet is needed - tokens are applied automatically by each component's encapsulated styles. An optional global stylesheet (`@threadplane/chat/chat.css`) is available if you want to customize tokens at the `:root` level.
## CSS Custom Properties Reference
@@ -54,13 +54,13 @@ No imported stylesheet is needed - tokens are applied automatically by each comp
## Light and Dark Mode
-Tokens default to light values. Dark mode activates automatically when the user's system preference is `prefers-color-scheme: dark`, unless the host element has `data-ngaf-chat-theme="light"` set.
+Tokens default to light values. Dark mode activates automatically when the user's system preference is `prefers-color-scheme: dark`, unless the host element has `data-threadplane-chat-theme="light"` set.
The switching logic is:
1. Light variables are applied by default on `:host`
-2. `@media (prefers-color-scheme: dark)` overrides with dark variables, unless `data-ngaf-chat-theme="light"` is set
-3. `[data-ngaf-chat-theme="dark"]` forces dark variables regardless of system preference
+2. `@media (prefers-color-scheme: dark)` overrides with dark variables, unless `data-threadplane-chat-theme="light"` is set
+3. `[data-threadplane-chat-theme="dark"]` forces dark variables regardless of system preference
## Customizing the Theme
@@ -77,19 +77,19 @@ The switching logic is:
```html
-
+
-
+
```
### Deep override via the optional global stylesheet
-Import `@ngaf/chat/chat.css` in your global styles to get a `:root`-level baseline you can override:
+Import `@threadplane/chat/chat.css` in your global styles to get a `:root`-level baseline you can override:
```css
/* src/styles.css */
-@import '@ngaf/chat/chat.css';
+@import '@threadplane/chat/chat.css';
:root {
--ngaf-chat-primary: oklch(0.55 0.22 264);
@@ -135,5 +135,5 @@ If you previously customized `--chat-*` tokens, rename them to `--ngaf-chat-*`.
| `--chat-success` | `--ngaf-chat-success` |
-The `CHAT_THEME_STYLES` named export no longer exists in `@ngaf/chat`. Remove imports of that constant - theme tokens are now applied automatically by each component. `CHAT_MARKDOWN_STYLES` remains available for custom markdown renderers.
+The `CHAT_THEME_STYLES` named export no longer exists in `@threadplane/chat`. Remove imports of that constant - theme tokens are now applied automatically by each component. `CHAT_MARKDOWN_STYLES` remains available for custom markdown renderers.
diff --git a/apps/website/content/docs/chat/guides/writing-an-adapter.mdx b/apps/website/content/docs/chat/guides/writing-an-adapter.mdx
index c8e31b70f..a2a3cc274 100644
--- a/apps/website/content/docs/chat/guides/writing-an-adapter.mdx
+++ b/apps/website/content/docs/chat/guides/writing-an-adapter.mdx
@@ -1,10 +1,10 @@
# Writing an Adapter
-Learn how to implement a custom `Agent` adapter so `@ngaf/chat` components work with any backend — whether that is a custom RPC service, an in-process mock, or an exotic streaming protocol.
+Learn how to implement a custom `Agent` adapter so `@threadplane/chat` components work with any backend — whether that is a custom RPC service, an in-process mock, or an exotic streaming protocol.
## When to Write Your Own Adapter
-`@ngaf/langgraph` covers LangGraph backends and `@ngaf/ag-ui` covers any [AG-UI-compatible](https://docs.ag-ui.com) backend. Everything else needs a hand-rolled adapter. Common scenarios:
+`@threadplane/langgraph` covers LangGraph backends and `@threadplane/ag-ui` covers any [AG-UI-compatible](https://docs.ag-ui.com) backend. Everything else needs a hand-rolled adapter. Common scenarios:
- **Custom RPC or HTTP API** — your backend speaks neither LangGraph Server nor the AG-UI protocol.
- **In-process logic** — you want the chat UI without any network call (demos, playgrounds, offline-first apps).
@@ -13,10 +13,10 @@ Learn how to implement a custom `Agent` adapter so `@ngaf/chat` components work
## The Contract
-Every `@ngaf/chat` primitive and composition accepts an `Agent` object. The type lives in `@ngaf/chat` and is intentionally runtime-neutral — it says nothing about HTTP, LangGraph, or any specific backend.
+Every `@threadplane/chat` primitive and composition accepts an `Agent` object. The type lives in `@threadplane/chat` and is intentionally runtime-neutral — it says nothing about HTTP, LangGraph, or any specific backend.
```typescript
-import type { Agent } from '@ngaf/chat';
+import type { Agent } from '@threadplane/chat';
```
An `Agent` is a set of Angular **signals** (reactive state) plus an RxJS **observable** of events, a `submit` method to send a message or resume an interrupted run, and a `stop` method to abort the in-flight run.
@@ -57,7 +57,7 @@ import { EMPTY, type Observable } from 'rxjs';
import type {
Agent, Message, AgentStatus, ToolCall,
AgentEvent, AgentSubmitInput, AgentSubmitOptions,
-} from '@ngaf/chat';
+} from '@threadplane/chat';
export interface EchoAgentOptions {
/** Delay before the echoed reply appears, in ms. Defaults to 400. */
@@ -133,7 +133,7 @@ The cleanest approach is to register your factory behind an Angular injection to
```typescript
// app.config.ts
import { ApplicationConfig, InjectionToken } from '@angular/core';
-import type { Agent } from '@ngaf/chat';
+import type { Agent } from '@threadplane/chat';
import { createEchoAgent } from './echo-agent';
export const ECHO_AGENT = new InjectionToken('ECHO_AGENT');
@@ -148,7 +148,7 @@ export const appConfig: ApplicationConfig = {
```typescript
// app.ts
import { Component, inject } from '@angular/core';
-import { ChatComponent } from '@ngaf/chat';
+import { ChatComponent } from '@threadplane/chat';
import { ECHO_AGENT } from './app.config';
@Component({
@@ -162,17 +162,17 @@ export class App {
}
```
-
+
`provideAgent()` and `agent()` are LangGraph-specific. When you bring your own adapter, skip them entirely — inject your token directly.
## Validating with the Conformance Suite
-`@ngaf/chat` ships a conformance helper that checks every contract field and a handful of semantic invariants (for example, `isLoading()` must only be `true` when `status() === 'running'`). Run it against your factory in a Vitest spec:
+`@threadplane/chat` ships a conformance helper that checks every contract field and a handful of semantic invariants (for example, `isLoading()` must only be `true` when `status() === 'running'`). Run it against your factory in a Vitest spec:
```typescript
// echo-agent.conformance.spec.ts
-import { runAgentConformance } from '@ngaf/chat/testing';
+import { runAgentConformance } from '@threadplane/chat/testing';
import { createEchoAgent } from './echo-agent';
runAgentConformance('createEchoAgent', () => createEchoAgent());
@@ -185,19 +185,19 @@ The conformance suite verifies:
- `events$` is a valid RxJS `Observable`.
- `submit` and `stop` return a `Promise`.
-There is no separate package to install — the testing entry point ships as part of `@ngaf/chat`.
+There is no separate package to install — the testing entry point ships as part of `@threadplane/chat`.
## AgentWithHistory (Optional)
If your backend supports checkpointing or thread history, extend the basic contract with `AgentWithHistory`:
```typescript
-import type { AgentWithHistory } from '@ngaf/chat';
+import type { AgentWithHistory } from '@threadplane/chat';
```
`AgentWithHistory` adds a `history: Signal` field. The implementation pattern is identical — add the signal to your factory return value.
-Use `runAgentWithHistoryConformance` from `@ngaf/chat/testing` in your spec instead of `runAgentConformance` to cover the additional field.
+Use `runAgentWithHistoryConformance` from `@threadplane/chat/testing` in your spec instead of `runAgentConformance` to cover the additional field.
### Hydrating from a server-stored thread
@@ -209,8 +209,8 @@ The chat UI assumes "yes" implicitly — clicking a thread in a sidebar list, or
How adapters in this repo answer the question:
-- **`@ngaf/langgraph`** answers *yes*. On every `threadId` change the bridge calls `transport.getHistory(id)` (LangGraph SDK `client.threads.getHistory`), takes the latest checkpoint, and seeds `messages$` and `values$` before any new user turn. The LangGraph protocol exposes a checkpoint endpoint per thread, so this is straightforward. See the [LangGraph persistence guide](/docs/agent/guides/persistence) for the consumer-side shape.
-- **`@ngaf/ag-ui`** answers *no, by design*. The AG-UI protocol is event-stream-only — it doesn't define a server-side "get the messages on this thread" endpoint. The adapter's `threadId` is therefore a plain string accepted once at construction, and switching threads means tearing down the provider and creating a new one (or pre-loading messages from the host service before the agent boots). See [AG-UI architecture › Provider choices](/docs/ag-ui/concepts/architecture#provider-choices).
+- **`@threadplane/langgraph`** answers *yes*. On every `threadId` change the bridge calls `transport.getHistory(id)` (LangGraph SDK `client.threads.getHistory`), takes the latest checkpoint, and seeds `messages$` and `values$` before any new user turn. The LangGraph protocol exposes a checkpoint endpoint per thread, so this is straightforward. See the [LangGraph persistence guide](/docs/agent/guides/persistence) for the consumer-side shape.
+- **`@threadplane/ag-ui`** answers *no, by design*. The AG-UI protocol is event-stream-only — it doesn't define a server-side "get the messages on this thread" endpoint. The adapter's `threadId` is therefore a plain string accepted once at construction, and switching threads means tearing down the provider and creating a new one (or pre-loading messages from the host service before the agent boots). See [AG-UI architecture › Provider choices](/docs/ag-ui/concepts/architecture#provider-choices).
If your protocol does store thread state, follow the LangGraph adapter's pattern: react to `threadId` changes, fetch the latest checkpoint, and surface a `isThreadLoading` signal so the UI can show a skeleton while the fetch runs. If it doesn't, follow AG-UI and be explicit in your docs that consumers own the load step.
@@ -224,22 +224,22 @@ If you want to distribute your adapter as an npm package, keep the following in
{
"peerDependencies": {
"@angular/core": "^20.0.0",
- "@ngaf/chat": "^0.0.2",
+ "@threadplane/chat": "^0.0.2",
"rxjs": "^7.0.0"
},
"devDependencies": {
- "@ngaf/chat": "^0.0.2"
+ "@threadplane/chat": "^0.0.2"
}
}
```
-The `@ngaf/chat/testing` entry point is part of the same package as the main entry point, so there is nothing extra to install for the conformance tests.
+The `@threadplane/chat/testing` entry point is part of the same package as the main entry point, so there is nothing extra to install for the conformance tests.
**Naming convention:** `@your-org/your-backend-agent` works well (e.g., `@acme/supabase-realtime-agent`). The `-agent` suffix signals that the package satisfies the `Agent` contract.
**Angular library setup:** Use Nx (`nx g @nx/angular:library`) or the Angular CLI (`ng g library`) to scaffold an Angular library with ng-packagr. Point your `package.json` exports at the compiled output. See the [Nx Angular library guide](https://nx.dev/recipes/angular/create-an-angular-library) for the full setup.
-**Optional: license-key gating.** If you want to restrict usage to paying customers, `@ngaf/licensing` provides a browser-safe license verification API. Declare it as an optional peer dependency.
+**Optional: license-key gating.** If you want to restrict usage to paying customers, `@threadplane/licensing` provides a browser-safe license verification API. Declare it as an optional peer dependency.
## What's Next
diff --git a/apps/website/content/docs/licensing/api/api-docs.json b/apps/website/content/docs/licensing/api/api-docs.json
index 5d8e42be8..367e161b4 100644
--- a/apps/website/content/docs/licensing/api/api-docs.json
+++ b/apps/website/content/docs/licensing/api/api-docs.json
@@ -7,7 +7,7 @@
{
"name": "package",
"type": "string",
- "description": "Fully-qualified npm package name, e.g. \"@ngaf/langgraph\".",
+ "description": "Fully-qualified npm package name, e.g. \"@threadplane/langgraph\".",
"optional": false
},
{
diff --git a/apps/website/content/docs/licensing/getting-started/introduction.mdx b/apps/website/content/docs/licensing/getting-started/introduction.mdx
index a378f2f66..adff924a9 100644
--- a/apps/website/content/docs/licensing/getting-started/introduction.mdx
+++ b/apps/website/content/docs/licensing/getting-started/introduction.mdx
@@ -1,6 +1,6 @@
# Introduction
-`@ngaf/licensing` is the shared license-check helper used by `@ngaf/chat` and by custom integrations that opt into the same warning behavior. It verifies compact Ed25519-signed tokens offline, evaluates the result into a small status set, and emits non-blocking warnings when appropriate.
+`@threadplane/licensing` is the shared license-check helper used by `@threadplane/chat` and by custom integrations that opt into the same warning behavior. It verifies compact Ed25519-signed tokens offline, evaluates the result into a small status set, and emits non-blocking warnings when appropriate.
The package itself is MIT licensed. `COMMERCIAL.md` states that the libraries in this repository are free to use, modify, and distribute in commercial and noncommercial projects. The proprietary part called out there is the internal minting service, not this package.
@@ -67,4 +67,4 @@ The higher-level check is designed not to block app startup:
- warning output goes through `console.warn` unless a custom `warn` function is supplied;
- no network request is made by the licensing check.
-The code returns statuses instead of throwing for normal license states. Consumers can choose what to do with the status, and `@ngaf/chat` uses it as a warning and visibility mechanism, not as an app kill switch.
+The code returns statuses instead of throwing for normal license states. Consumers can choose what to do with the status, and `@threadplane/chat` uses it as a warning and visibility mechanism, not as an app kill switch.
diff --git a/apps/website/content/docs/licensing/guides/ci-and-offline.mdx b/apps/website/content/docs/licensing/guides/ci-and-offline.mdx
index 0b528365d..9a41d20ae 100644
--- a/apps/website/content/docs/licensing/guides/ci-and-offline.mdx
+++ b/apps/website/content/docs/licensing/guides/ci-and-offline.mdx
@@ -22,7 +22,7 @@ If you call `runLicenseCheck()` directly, inject the current time only when you
```ts
await runLicenseCheck({
- package: '@ngaf/example',
+ package: '@threadplane/example',
token,
publicKey,
nowSec: 1_735_689_600,
@@ -34,7 +34,7 @@ await runLicenseCheck({
Use `verifyLicense()` and `evaluateLicense()` directly when network access is unavailable or unwanted.
```ts
-import { evaluateLicense, verifyLicense } from '@ngaf/licensing';
+import { evaluateLicense, verifyLicense } from '@threadplane/licensing';
const verified = await verifyLicense(token, publicKey);
const result = evaluateLicense(verified, {
@@ -49,7 +49,7 @@ This does not emit warnings. The higher-level `runLicenseCheck()` helper can emi
`signLicense()` is exported for token minting and tests:
```ts
-import { signLicense } from '@ngaf/licensing';
+import { signLicense } from '@threadplane/licensing';
const token = await signLicense(claims, privateKey);
```
diff --git a/apps/website/content/docs/licensing/guides/setup.mdx b/apps/website/content/docs/licensing/guides/setup.mdx
index dac281b52..29aaa75a0 100644
--- a/apps/website/content/docs/licensing/guides/setup.mdx
+++ b/apps/website/content/docs/licensing/guides/setup.mdx
@@ -1,11 +1,11 @@
# Setup
-Most applications do not import `@ngaf/licensing` directly. `@ngaf/chat` calls `runLicenseCheck()` from `provideChat()` when you pass a license token.
+Most applications do not import `@threadplane/licensing` directly. `@threadplane/chat` calls `runLicenseCheck()` from `provideChat()` when you pass a license token.
For example, chat exposes a `license` option:
```ts
-provideChat({ license: environment.ngafLicense });
+provideChat({ license: environment.threadplaneLicense });
```
When no token is supplied, the licensing helper can evaluate the environment as `noncommercial` when the caller passes `isNoncommercial: true`.
@@ -19,10 +19,10 @@ import {
LICENSE_PUBLIC_KEY,
inferNoncommercial,
runLicenseCheck,
-} from '@ngaf/licensing';
+} from '@threadplane/licensing';
const status = await runLicenseCheck({
- package: '@ngaf/example',
+ package: '@threadplane/example',
token: process.env.THREADPLANE_LICENSE,
publicKey: LICENSE_PUBLIC_KEY,
isNoncommercial: inferNoncommercial(),
@@ -51,7 +51,7 @@ You can inject a custom warning sink:
```ts
await runLicenseCheck({
- package: '@ngaf/example',
+ package: '@threadplane/example',
token,
publicKey,
warn: (message) => logger.warn(message),
diff --git a/apps/website/content/docs/licensing/reference/api.mdx b/apps/website/content/docs/licensing/reference/api.mdx
index 9932ff45b..607c65040 100644
--- a/apps/website/content/docs/licensing/reference/api.mdx
+++ b/apps/website/content/docs/licensing/reference/api.mdx
@@ -1,6 +1,6 @@
# Licensing API
-This page documents the public exports from `@ngaf/licensing`.
+This page documents the public exports from `@threadplane/licensing`.
## Types
diff --git a/apps/website/content/docs/render/a2ui/catalog.mdx b/apps/website/content/docs/render/a2ui/catalog.mdx
index d35972187..283caffe3 100644
--- a/apps/website/content/docs/render/a2ui/catalog.mdx
+++ b/apps/website/content/docs/render/a2ui/catalog.mdx
@@ -5,7 +5,7 @@ The built-in A2UI catalog provides 18 Angular components covering display, layou
**Import:**
```typescript
-import { a2uiBasicCatalog } from '@ngaf/chat';
+import { a2uiBasicCatalog } from '@threadplane/chat';
```
## Signature
diff --git a/apps/website/content/docs/render/a2ui/overview.mdx b/apps/website/content/docs/render/a2ui/overview.mdx
index 82076c2f3..4a828de10 100644
--- a/apps/website/content/docs/render/a2ui/overview.mdx
+++ b/apps/website/content/docs/render/a2ui/overview.mdx
@@ -2,7 +2,7 @@
A2UI is the structured UI path for agent-built surfaces in chat.
-The important boundary is simple: the agent streams declarative messages, the client owns rendering, and Angular handlers stay inside your application. The model does not ship code. It emits a constrained surface description that `@ngaf/chat`, `@ngaf/a2ui`, and `@ngaf/render` turn into Angular UI.
+The important boundary is simple: the agent streams declarative messages, the client owns rendering, and Angular handlers stay inside your application. The model does not ship code. It emits a constrained surface description that `@threadplane/chat`, `@threadplane/a2ui`, and `@threadplane/render` turn into Angular UI.
When an assistant message starts with `---a2ui_JSON---`, the chat streaming pipeline treats the rest of the content as newline-delimited A2UI JSON.
@@ -19,7 +19,7 @@ assistant text starts with ---a2ui_JSON---
This is why A2UI sits between chat and render. Chat owns message streaming. A2UI owns the protocol shapes. The normal chat path uses progressive surface state and `a2uiSlot` so components can appear as their required data arrives.
-There is also a compatibility path: when `A2uiSurfaceComponent` receives a `surface` without a `state`, it calls `surfaceToSpec()` and renders through `@ngaf/render`. That fallback is where render-spec handlers, render events, and json-render state bindings apply.
+There is also a compatibility path: when `A2uiSurfaceComponent` receives a `surface` without a `state`, it calls `surfaceToSpec()` and renders through `@threadplane/render`. That fallback is where render-spec handlers, render events, and json-render state bindings apply.
## Message Envelopes
@@ -166,7 +166,7 @@ A2UI component props can point at the surface data model.
In the render-spec compatibility path, `surfaceToSpec()` converts path references into json-render state bindings. Catalog input components can use `emitBinding()` to write back through the render event pipeline.
```ts
-import { emitBinding } from '@ngaf/chat';
+import { emitBinding } from '@threadplane/chat';
onInput(event: Event): void {
const value = (event.target as HTMLInputElement).value;
@@ -254,8 +254,8 @@ Pass the built-in A2UI catalog to chat:
```ts
import { Component } from '@angular/core';
-import { ChatComponent, a2uiBasicCatalog } from '@ngaf/chat';
-import { agent } from '@ngaf/langgraph';
+import { ChatComponent, a2uiBasicCatalog } from '@threadplane/chat';
+import { agent } from '@threadplane/langgraph';
@Component({
standalone: true,
@@ -272,7 +272,7 @@ export class SupportChatComponent {
}
```
-For custom component sets, build a catalog with the same view registry tools used by `@ngaf/render`.
+For custom component sets, build a catalog with the same view registry tools used by `@threadplane/render`.
## Gotchas
diff --git a/apps/website/content/docs/render/a2ui/surface-component.mdx b/apps/website/content/docs/render/a2ui/surface-component.mdx
index 1b4126fae..e5f707d42 100644
--- a/apps/website/content/docs/render/a2ui/surface-component.mdx
+++ b/apps/website/content/docs/render/a2ui/surface-component.mdx
@@ -5,7 +5,7 @@ Angular component that renders a single A2UI surface. It converts the surface's
**Import:**
```typescript
-import { A2uiSurfaceComponent } from '@ngaf/chat';
+import { A2uiSurfaceComponent } from '@threadplane/chat';
```
**Selector:** `a2ui-surface`
@@ -60,8 +60,8 @@ The final `Spec` is passed to `RenderSpecComponent` along with the `ViewRegistry
```typescript
import { Component, signal } from '@angular/core';
-import { A2uiSurfaceComponent, createA2uiSurfaceStore, a2uiBasicCatalog } from '@ngaf/chat';
-import { createA2uiMessageParser } from '@ngaf/a2ui';
+import { A2uiSurfaceComponent, createA2uiSurfaceStore, a2uiBasicCatalog } from '@threadplane/chat';
+import { createA2uiMessageParser } from '@threadplane/a2ui';
@Component({
selector: 'app-agent-panel',
@@ -97,7 +97,7 @@ The conversion function is exported for testing or custom rendering pipelines.
**Import:**
```typescript
-import { surfaceToSpec } from '@ngaf/chat';
+import { surfaceToSpec } from '@threadplane/chat';
```
**Signature:**
diff --git a/apps/website/content/docs/render/a2ui/surface-store.mdx b/apps/website/content/docs/render/a2ui/surface-store.mdx
index 04a4e9ff9..ed37d20dc 100644
--- a/apps/website/content/docs/render/a2ui/surface-store.mdx
+++ b/apps/website/content/docs/render/a2ui/surface-store.mdx
@@ -5,7 +5,7 @@ Factory function that creates an `A2uiSurfaceStore` — a reactive store that ac
**Import:**
```typescript
-import { createA2uiSurfaceStore } from '@ngaf/chat';
+import { createA2uiSurfaceStore } from '@threadplane/chat';
```
## Signature
@@ -87,8 +87,8 @@ The `updateDataModel` message uses JSON Pointer (RFC 6901) paths to address valu
The surface store is designed to work with `createA2uiMessageParser`, which parses raw JSONL chunks into typed `A2uiMessage` objects.
```typescript
-import { createA2uiSurfaceStore } from '@ngaf/chat';
-import { createA2uiMessageParser } from '@ngaf/a2ui';
+import { createA2uiSurfaceStore } from '@threadplane/chat';
+import { createA2uiMessageParser } from '@threadplane/a2ui';
import { effect } from '@angular/core';
const store = createA2uiSurfaceStore();
diff --git a/apps/website/content/docs/render/api/define-angular-registry.mdx b/apps/website/content/docs/render/api/define-angular-registry.mdx
index 65154507c..4d88be7de 100644
--- a/apps/website/content/docs/render/api/define-angular-registry.mdx
+++ b/apps/website/content/docs/render/api/define-angular-registry.mdx
@@ -5,7 +5,7 @@ Creates an `AngularRegistry` that maps element type names to Angular component c
## Import
```typescript
-import { defineAngularRegistry } from '@ngaf/render';
+import { defineAngularRegistry } from '@threadplane/render';
```
## Signature
@@ -45,7 +45,7 @@ interface AngularRegistry {
### Basic Registry
```typescript
-import { defineAngularRegistry } from '@ngaf/render';
+import { defineAngularRegistry } from '@threadplane/render';
import { TextComponent } from './text.component';
import { CardComponent } from './card.component';
@@ -63,7 +63,7 @@ registry.names(); // ['Text', 'Card']
### With provideRender()
```typescript
-import { provideRender, defineAngularRegistry } from '@ngaf/render';
+import { provideRender, defineAngularRegistry } from '@threadplane/render';
export const appConfig: ApplicationConfig = {
providers: [
diff --git a/apps/website/content/docs/render/api/provide-render.mdx b/apps/website/content/docs/render/api/provide-render.mdx
index aa8f1c17f..09815666a 100644
--- a/apps/website/content/docs/render/api/provide-render.mdx
+++ b/apps/website/content/docs/render/api/provide-render.mdx
@@ -1,11 +1,11 @@
# provideRender()
-Registers global default configuration for `@ngaf/render` via Angular's dependency injection system.
+Registers global default configuration for `@threadplane/render` via Angular's dependency injection system.
## Import
```typescript
-import { provideRender, RENDER_CONFIG } from '@ngaf/render';
+import { provideRender, RENDER_CONFIG } from '@threadplane/render';
```
## Signature
@@ -58,7 +58,7 @@ You can inject it directly if needed:
```typescript
import { inject } from '@angular/core';
-import { RENDER_CONFIG } from '@ngaf/render';
+import { RENDER_CONFIG } from '@threadplane/render';
const config = inject(RENDER_CONFIG, { optional: true });
// null if provideRender() was not called
@@ -71,7 +71,7 @@ const config = inject(RENDER_CONFIG, { optional: true });
```typescript
// app.config.ts
import { ApplicationConfig } from '@angular/core';
-import { provideRender, defineAngularRegistry } from '@ngaf/render';
+import { provideRender, defineAngularRegistry } from '@threadplane/render';
import { TextComponent } from './components/text.component';
import { CardComponent } from './components/card.component';
@@ -94,7 +94,7 @@ import {
provideRender,
defineAngularRegistry,
signalStateStore,
-} from '@ngaf/render';
+} from '@threadplane/render';
const globalStore = signalStateStore({ theme: 'light' });
diff --git a/apps/website/content/docs/render/api/render-spec-component.mdx b/apps/website/content/docs/render/api/render-spec-component.mdx
index 13d57d886..11323aef3 100644
--- a/apps/website/content/docs/render/api/render-spec-component.mdx
+++ b/apps/website/content/docs/render/api/render-spec-component.mdx
@@ -5,7 +5,7 @@ The top-level entry point for rendering a `@json-render/core` spec as an Angular
## Import
```typescript
-import { RenderSpecComponent } from '@ngaf/render';
+import { RenderSpecComponent } from '@threadplane/render';
```
## Selector
@@ -91,7 +91,7 @@ The context is a `computed` signal that updates when any input or config changes
```typescript
import { inject } from '@angular/core';
-import { RENDER_CONTEXT } from '@ngaf/render';
+import { RENDER_CONTEXT } from '@threadplane/render';
const ctx = inject(RENDER_CONTEXT);
ctx.store.get('/some/path');
@@ -142,7 +142,7 @@ import {
RenderSpecComponent,
defineAngularRegistry,
signalStateStore,
-} from '@ngaf/render';
+} from '@threadplane/render';
import type { Spec } from '@json-render/core';
import { TextComponent } from './text.component';
import { ButtonComponent } from './button.component';
diff --git a/apps/website/content/docs/render/api/signal-state-store.mdx b/apps/website/content/docs/render/api/signal-state-store.mdx
index ef4e6c5d3..f847fbb7a 100644
--- a/apps/website/content/docs/render/api/signal-state-store.mdx
+++ b/apps/website/content/docs/render/api/signal-state-store.mdx
@@ -5,7 +5,7 @@ Creates a reactive state store backed by Angular Signals that implements the `St
## Import
```typescript
-import { signalStateStore } from '@ngaf/render';
+import { signalStateStore } from '@threadplane/render';
```
## Signature
diff --git a/apps/website/content/docs/render/api/views.mdx b/apps/website/content/docs/render/api/views.mdx
index d7a641b59..42160d53b 100644
--- a/apps/website/content/docs/render/api/views.mdx
+++ b/apps/website/content/docs/render/api/views.mdx
@@ -10,7 +10,7 @@ Creates an immutable view registry mapping names to Angular components. Views ar
## Usage
```typescript
-import { views } from '@ngaf/render';
+import { views } from '@threadplane/render';
const ui = views({
'plan-checklist': PlanChecklistComponent,
@@ -28,7 +28,7 @@ Pass to the chat component:
Or provide globally via DI:
```typescript
-import { provideViews } from '@ngaf/render';
+import { provideViews } from '@threadplane/render';
// app.config.ts
providers: [provideViews(ui)]
diff --git a/apps/website/content/docs/render/concepts/json-render-vs-a2ui.mdx b/apps/website/content/docs/render/concepts/json-render-vs-a2ui.mdx
index 17d06ec27..2e4699af3 100644
--- a/apps/website/content/docs/render/concepts/json-render-vs-a2ui.mdx
+++ b/apps/website/content/docs/render/concepts/json-render-vs-a2ui.mdx
@@ -1,29 +1,29 @@
# json-render vs A2UI
-`@ngaf/render` and `@ngaf/a2ui` both render structured UI, but they solve different problems.
+`@threadplane/render` and `@threadplane/a2ui` both render structured UI, but they solve different problems.
-`@ngaf/render` renders a fixed json-render spec into Angular components.
+`@threadplane/render` renders a fixed json-render spec into Angular components.
-`@ngaf/a2ui` defines an agent-to-UI protocol: surfaces, components, dynamic values, data model updates, and actions. In `@ngaf/chat`, A2UI surfaces are rendered through the same render infrastructure where possible.
+`@threadplane/a2ui` defines an agent-to-UI protocol: surfaces, components, dynamic values, data model updates, and actions. In `@threadplane/chat`, A2UI surfaces are rendered through the same render infrastructure where possible.
This matters because the tradeoff is not "which renderer is better." The tradeoff is contract shape. A fixed spec is easier to validate and reason about. A2UI is better when the agent needs to update a UI over time or receive structured user actions back.
## The Layers
```text
-@ngaf/render
+@threadplane/render
renders a Spec using an Angular registry, state store, functions, and handlers
-@ngaf/a2ui
+@threadplane/a2ui
defines A2UI v0.9 message and component types
-@ngaf/chat
+@threadplane/chat
detects assistant content, manages streaming state, and mounts render or A2UI surfaces
```
-Use `@ngaf/render` directly when your application already has a spec.
+Use `@threadplane/render` directly when your application already has a spec.
-Use A2UI through `@ngaf/chat` when the agent is producing UI as part of a conversation.
+Use A2UI through `@threadplane/chat` when the agent is producing UI as part of a conversation.
## json-render
@@ -40,7 +40,7 @@ import {
RenderSpecComponent,
defineAngularRegistry,
signalStateStore,
-} from '@ngaf/render';
+} from '@threadplane/render';
```
Choose json-render when:
@@ -115,17 +115,17 @@ For A2UI, chat parses newline-delimited A2UI messages, applies them to an `A2uiS
The same `views` input is used by both paths. For A2UI, `a2uiBasicCatalog()` provides the built-in catalog:
```ts
-import { a2uiBasicCatalog } from '@ngaf/chat';
+import { a2uiBasicCatalog } from '@threadplane/chat';
catalog = a2uiBasicCatalog();
```
## Registries And Catalogs
-`@ngaf/render` uses a view registry:
+`@threadplane/render` uses a view registry:
```ts
-import { views, withViews } from '@ngaf/render';
+import { views, withViews } from '@threadplane/render';
const registry = views({
OrderSummary: OrderSummaryComponent,
@@ -185,7 +185,7 @@ This matters because rendering JSON should not mean executing arbitrary model in
## Fallbacks
-`@ngaf/render` has a default fallback for registered views that are not ready and supports per-view fallback entries.
+`@threadplane/render` has a default fallback for registered views that are not ready and supports per-view fallback entries.
A2UI uses the same idea at the catalog level. A catalog entry can be a component type or an object with a component and fallback. While data-bound props are unresolved, the fallback renders. Once the real component mounts, readiness is monotonic for that element.
diff --git a/apps/website/content/docs/render/getting-started/installation.mdx b/apps/website/content/docs/render/getting-started/installation.mdx
index eb295424c..90c020156 100644
--- a/apps/website/content/docs/render/getting-started/installation.mdx
+++ b/apps/website/content/docs/render/getting-started/installation.mdx
@@ -1,12 +1,12 @@
# Installation
-Detailed setup guide for `@ngaf/render` in your Angular application.
+Detailed setup guide for `@threadplane/render` in your Angular application.
## Requirements
-`@ngaf/render` uses Angular Signals, the `input()` function, and the `NgComponentOutlet` directive. Angular 20 or later is required.
+`@threadplane/render` uses Angular Signals, the `input()` function, and the `NgComponentOutlet` directive. Angular 20 or later is required.
Required for the build toolchain and package installation.
@@ -16,7 +16,7 @@ Required for the build toolchain and package installation.
## Install the Package
```bash
-npm install @ngaf/render @json-render/core
+npm install @threadplane/render @json-render/core
```
### Peer Dependencies
@@ -40,7 +40,7 @@ Add `provideRender()` to your application configuration. This sets global defaul
```typescript
// app.config.ts
import { ApplicationConfig } from '@angular/core';
-import { provideRender, defineAngularRegistry } from '@ngaf/render';
+import { provideRender, defineAngularRegistry } from '@threadplane/render';
import { TextComponent } from './components/text.component';
import { CardComponent } from './components/card.component';
@@ -69,7 +69,7 @@ Here is a complete minimal application setup:
```typescript
import { ApplicationConfig } from '@angular/core';
-import { provideRender, defineAngularRegistry } from '@ngaf/render';
+import { provideRender, defineAngularRegistry } from '@threadplane/render';
import { TextComponent } from './text.component';
export const appConfig: ApplicationConfig = {
@@ -107,7 +107,7 @@ export class TextComponent {
```typescript
import { Component, ChangeDetectionStrategy } from '@angular/core';
-import { RenderSpecComponent } from '@ngaf/render';
+import { RenderSpecComponent } from '@threadplane/render';
import type { Spec } from '@json-render/core';
@Component({
diff --git a/apps/website/content/docs/render/getting-started/introduction.mdx b/apps/website/content/docs/render/getting-started/introduction.mdx
index c4a3b6617..1bc5b6a5c 100644
--- a/apps/website/content/docs/render/getting-started/introduction.mdx
+++ b/apps/website/content/docs/render/getting-started/introduction.mdx
@@ -1,10 +1,10 @@
# Introduction
-`@ngaf/render` is the Angular rendering engine for [json-render](https://github.com/nicholasgriffintn/json-render) specs. It takes a declarative JSON specification and renders it into a live Angular component tree -- with reactive state, event handling, and conditional rendering built in.
+`@threadplane/render` is the Angular rendering engine for [json-render](https://github.com/nicholasgriffintn/json-render) specs. It takes a declarative JSON specification and renders it into a live Angular component tree -- with reactive state, event handling, and conditional rendering built in.
-## Why @ngaf/render?
+## Why @threadplane/render?
-Building dynamic UIs from server-driven specifications is a common pattern in AI applications, form builders, and CMS-powered frontends. `@ngaf/render` bridges the gap between `@json-render/core` (a framework-agnostic spec evaluation engine) and Angular's component model.
+Building dynamic UIs from server-driven specifications is a common pattern in AI applications, form builders, and CMS-powered frontends. `@threadplane/render` bridges the gap between `@json-render/core` (a framework-agnostic spec evaluation engine) and Angular's component model.
Instead of writing imperative rendering logic, you describe your UI as a JSON spec and let the library handle the rest:
@@ -31,7 +31,7 @@ The library resolves `Text` from your component registry, evaluates the `$state`
`@json-render/core` provides the spec format and the evaluation engine -- it resolves prop expressions (`$state`, `$item`, `$index`, `$bindState`, `$fn`), evaluates visibility conditions, and resolves bindings. It is framework-agnostic and has no Angular dependency.
-`@ngaf/render` is the Angular adapter layer. It provides:
+`@threadplane/render` is the Angular adapter layer. It provides:
- **Component registry** -- maps spec element types (like `"Text"` or `"Card"`) to Angular component classes
- **Signal-based state store** -- an Angular Signals-backed implementation of the `StateStore` interface from `@json-render/core`
diff --git a/apps/website/content/docs/render/getting-started/quickstart.mdx b/apps/website/content/docs/render/getting-started/quickstart.mdx
index 71211fdb5..72dc0ea95 100644
--- a/apps/website/content/docs/render/getting-started/quickstart.mdx
+++ b/apps/website/content/docs/render/getting-started/quickstart.mdx
@@ -3,7 +3,7 @@
Render a JSON spec as a live Angular component tree in 5 minutes.
-Angular 20+ project with `@ngaf/render` installed. See the [Installation](/docs/render/getting-started/installation) guide if you need setup help.
+Angular 20+ project with `@threadplane/render` installed. See the [Installation](/docs/render/getting-started/installation) guide if you need setup help.
@@ -35,7 +35,7 @@ Map element type names to Angular component classes using `defineAngularRegistry
```typescript
// ui-registry.ts
-import { defineAngularRegistry } from '@ngaf/render';
+import { defineAngularRegistry } from '@threadplane/render';
import { TextComponent } from './text.component';
export const uiRegistry = defineAngularRegistry({
@@ -51,7 +51,7 @@ A spec describes the UI tree as a flat map of elements. The `root` key points to
```typescript
// app.component.ts
import { Component, ChangeDetectionStrategy } from '@angular/core';
-import { RenderSpecComponent } from '@ngaf/render';
+import { RenderSpecComponent } from '@threadplane/render';
import type { Spec } from '@json-render/core';
import { uiRegistry } from './ui-registry';
@@ -72,7 +72,7 @@ export class AppComponent {
elements: {
greeting: {
type: 'Text',
- props: { label: 'Hello from @ngaf/render!' },
+ props: { label: 'Hello from @threadplane/render!' },
},
},
};
@@ -86,7 +86,7 @@ export class AppComponent {
ng serve
```
-Open `http://localhost:4200`. You should see "Hello from @ngaf/render!" rendered by your `TextComponent`.
+Open `http://localhost:4200`. You should see "Hello from @threadplane/render!" rendered by your `TextComponent`.
@@ -97,7 +97,7 @@ Specs become powerful when you connect them to a state store. Props with `$state
```typescript
import { Component, ChangeDetectionStrategy } from '@angular/core';
-import { RenderSpecComponent, signalStateStore } from '@ngaf/render';
+import { RenderSpecComponent, signalStateStore } from '@threadplane/render';
import type { Spec } from '@json-render/core';
import { uiRegistry } from './ui-registry';
diff --git a/apps/website/content/docs/render/guides/events.mdx b/apps/website/content/docs/render/guides/events.mdx
index 661d1d5dd..0e24915e6 100644
--- a/apps/website/content/docs/render/guides/events.mdx
+++ b/apps/website/content/docs/render/guides/events.mdx
@@ -125,7 +125,7 @@ export class AppComponent {
```typescript
// app.config.ts
-import { provideRender } from '@ngaf/render';
+import { provideRender } from '@threadplane/render';
export const appConfig: ApplicationConfig = {
providers: [
diff --git a/apps/website/content/docs/render/guides/lifecycle.mdx b/apps/website/content/docs/render/guides/lifecycle.mdx
index c442c9238..ca0239a47 100644
--- a/apps/website/content/docs/render/guides/lifecycle.mdx
+++ b/apps/website/content/docs/render/guides/lifecycle.mdx
@@ -1,6 +1,6 @@
# Render Lifecycle Signals
-The `@ngaf/render` library exposes per-context lifecycle signals via the `RENDER_LIFECYCLE` injection token. All five signals derive from the existing `RenderEvent` stream via `RenderLifecycleService.notify*` methods — no separate event source, no double-counting.
+The `@threadplane/render` library exposes per-context lifecycle signals via the `RENDER_LIFECYCLE` injection token. All five signals derive from the existing `RenderEvent` stream via `RenderLifecycleService.notify*` methods — no separate event source, no double-counting.
## Interface
@@ -39,7 +39,7 @@ All signals derive from `RenderEvent` (see [Events](/docs/render/guides/events))
```typescript
import { Component, inject, effect } from '@angular/core';
-import { RENDER_LIFECYCLE } from '@ngaf/render';
+import { RENDER_LIFECYCLE } from '@threadplane/render';
@Component({ /* ... */ })
export class MyComponent {
diff --git a/apps/website/content/docs/render/guides/registry.mdx b/apps/website/content/docs/render/guides/registry.mdx
index 7e50cdf6d..e478fb207 100644
--- a/apps/website/content/docs/render/guides/registry.mdx
+++ b/apps/website/content/docs/render/guides/registry.mdx
@@ -7,7 +7,7 @@ The component registry maps element type names from your spec to Angular compone
Use `defineAngularRegistry()` to create a registry from a plain object mapping type names to component classes:
```typescript
-import { defineAngularRegistry } from '@ngaf/render';
+import { defineAngularRegistry } from '@threadplane/render';
import { TextComponent } from './text.component';
import { CardComponent } from './card.component';
import { ButtonComponent } from './button.component';
@@ -34,7 +34,7 @@ uiRegistry.names(); // ['Text', 'Card', 'Button', 'Container']
## The Component Input Contract
-Every component rendered by `@ngaf/render` receives inputs conforming to the `AngularComponentInputs` interface. Your custom props from the spec are spread as additional inputs alongside the standard ones.
+Every component rendered by `@threadplane/render` receives inputs conforming to the `AngularComponentInputs` interface. Your custom props from the spec are spread as additional inputs alongside the standard ones.
### Standard Inputs
@@ -126,7 +126,7 @@ You can use the bindings map to write back to the store:
```typescript
import { Component, ChangeDetectionStrategy, input, inject } from '@angular/core';
-import { RENDER_CONTEXT } from '@ngaf/render';
+import { RENDER_CONTEXT } from '@threadplane/render';
@Component({
selector: 'app-input',
@@ -162,7 +162,7 @@ Container components can render their children by using the `childKeys` and `spe
```typescript
import { Component, ChangeDetectionStrategy, input } from '@angular/core';
-import { RenderElementComponent } from '@ngaf/render';
+import { RenderElementComponent } from '@threadplane/render';
import type { Spec } from '@json-render/core';
@Component({
@@ -198,7 +198,7 @@ You can provide the registry in two ways:
```typescript
// app.config.ts
-import { provideRender, defineAngularRegistry } from '@ngaf/render';
+import { provideRender, defineAngularRegistry } from '@threadplane/render';
export const appConfig: ApplicationConfig = {
providers: [
diff --git a/apps/website/content/docs/render/guides/specs.mdx b/apps/website/content/docs/render/guides/specs.mdx
index 2b30c0b51..0c16aaf71 100644
--- a/apps/website/content/docs/render/guides/specs.mdx
+++ b/apps/website/content/docs/render/guides/specs.mdx
@@ -1,6 +1,6 @@
# Specs
-A spec is the JSON object that describes your entire UI tree. It tells `@ngaf/render` what to render, how to wire state, and when to show or hide elements.
+A spec is the JSON object that describes your entire UI tree. It tells `@threadplane/render` what to render, how to wire state, and when to show or hide elements.
## Spec Format
diff --git a/apps/website/content/docs/render/guides/state-store.mdx b/apps/website/content/docs/render/guides/state-store.mdx
index 2c34d28af..7873b2498 100644
--- a/apps/website/content/docs/render/guides/state-store.mdx
+++ b/apps/website/content/docs/render/guides/state-store.mdx
@@ -1,11 +1,11 @@
# State Store
-The state store holds the reactive state that drives your rendered UI. `@ngaf/render` provides `signalStateStore()`, an Angular Signals-backed implementation of the `StateStore` interface from `@json-render/core`.
+The state store holds the reactive state that drives your rendered UI. `@threadplane/render` provides `signalStateStore()`, an Angular Signals-backed implementation of the `StateStore` interface from `@json-render/core`.
## Creating a State Store
```typescript
-import { signalStateStore } from '@ngaf/render';
+import { signalStateStore } from '@threadplane/render';
const store = signalStateStore({
user: { name: 'Alice', age: 30 },
diff --git a/apps/website/content/docs/telemetry/api/api-docs.json b/apps/website/content/docs/telemetry/api/api-docs.json
index c3af8655f..a0893a4a2 100644
--- a/apps/website/content/docs/telemetry/api/api-docs.json
+++ b/apps/website/content/docs/telemetry/api/api-docs.json
@@ -1,20 +1,20 @@
[
{
- "name": "NgafBrowserEvent",
+ "name": "ThreadplaneBrowserEvent",
"kind": "type",
"description": "",
"signature": "\"ngaf:browser_provided\" | \"ngaf:browser_chat_init\"",
"examples": []
},
{
- "name": "NgafEvent",
+ "name": "ThreadplaneEvent",
"kind": "type",
"description": "",
- "signature": "NgafNodeEvent | NgafBrowserEvent",
+ "signature": "ThreadplaneNodeEvent | ThreadplaneBrowserEvent",
"examples": []
},
{
- "name": "NgafNodeEvent",
+ "name": "ThreadplaneNodeEvent",
"kind": "type",
"description": "",
"signature": "\"ngaf:postinstall\" | \"ngaf:runtime_instance_created\" | \"ngaf:runtime_request_created\" | \"ngaf:stream_started\" | \"ngaf:stream_ended\" | \"ngaf:stream_errored\"",
@@ -221,11 +221,11 @@
"name": "captureEvent",
"kind": "function",
"description": "",
- "signature": "captureEvent(event: NgafNodeEvent, properties: Record): Promise",
+ "signature": "captureEvent(event: ThreadplaneNodeEvent, properties: Record): Promise",
"params": [
{
"name": "event",
- "type": "NgafNodeEvent",
+ "type": "ThreadplaneNodeEvent",
"description": "",
"optional": false
},
diff --git a/apps/website/content/docs/telemetry/getting-started/introduction.mdx b/apps/website/content/docs/telemetry/getting-started/introduction.mdx
index 0914bb760..65ad8b408 100644
--- a/apps/website/content/docs/telemetry/getting-started/introduction.mdx
+++ b/apps/website/content/docs/telemetry/getting-started/introduction.mdx
@@ -1,6 +1,6 @@
# Introduction
-`@ngaf/telemetry` is the shared telemetry package for the framework. It has separate surfaces for browser applications, Node adapters, and shared utilities.
+`@threadplane/telemetry` is the shared telemetry package for the framework. It has separate surfaces for browser applications, Node adapters, and shared utilities.
The important boundary is simple:
@@ -14,16 +14,16 @@ Do not treat the browser and Node entry points as interchangeable. They have dif
```ts
// Shared utilities
-import { isTelemetryDisabled, getDisableReason } from '@ngaf/telemetry';
+import { isTelemetryDisabled, getDisableReason } from '@threadplane/telemetry';
// Browser Angular provider and service
-import { provideNgafTelemetry } from '@ngaf/telemetry/browser';
+import { provideThreadplaneTelemetry } from '@threadplane/telemetry/browser';
// Node/server helpers
-import { disableTelemetry, capturePostinstall } from '@ngaf/telemetry/node';
+import { disableTelemetry, capturePostinstall } from '@threadplane/telemetry/node';
```
-The package also exports `@ngaf/telemetry/node/postinstall` for the package postinstall executable.
+The package also exports `@threadplane/telemetry/node/postinstall` for the package postinstall executable.
## Browser posture
diff --git a/apps/website/content/docs/telemetry/guides/browser.mdx b/apps/website/content/docs/telemetry/guides/browser.mdx
index 905b10109..89675bd96 100644
--- a/apps/website/content/docs/telemetry/guides/browser.mdx
+++ b/apps/website/content/docs/telemetry/guides/browser.mdx
@@ -1,16 +1,16 @@
# Browser Telemetry
-Browser telemetry is opt-in. If your Angular app never calls `provideNgafTelemetry()`, the service has no enabled config and `capture()` returns without sending.
+Browser telemetry is opt-in. If your Angular app never calls `provideThreadplaneTelemetry()`, the service has no enabled config and `capture()` returns without sending.
## Configure
```ts
import type { ApplicationConfig } from '@angular/core';
-import { provideNgafTelemetry } from '@ngaf/telemetry/browser';
+import { provideThreadplaneTelemetry } from '@threadplane/telemetry/browser';
export const appConfig: ApplicationConfig = {
providers: [
- provideNgafTelemetry({
+ provideThreadplaneTelemetry({
enabled: true,
endpoint: '/api/telemetry',
sampleRate: 1,
@@ -39,7 +39,7 @@ The browser distinct ID is generated per service instance. The source does not w
Use `sink` when your app already has an analytics boundary.
```ts
-provideNgafTelemetry({
+provideThreadplaneTelemetry({
enabled: true,
sink: async ({ event, properties }) => {
await analytics.track(event, properties);
diff --git a/apps/website/content/docs/telemetry/guides/node.mdx b/apps/website/content/docs/telemetry/guides/node.mdx
index 733ce4bda..5f0130e4e 100644
--- a/apps/website/content/docs/telemetry/guides/node.mdx
+++ b/apps/website/content/docs/telemetry/guides/node.mdx
@@ -1,6 +1,6 @@
# Node Telemetry
-Node telemetry lives under `@ngaf/telemetry/node`. It is intended for package lifecycle hooks and server-side adapters.
+Node telemetry lives under `@threadplane/telemetry/node`. It is intended for package lifecycle hooks and server-side adapters.
```ts
import {
@@ -9,7 +9,7 @@ import {
captureStreamEnded,
captureStreamErrored,
disableTelemetry,
-} from '@ngaf/telemetry/node';
+} from '@threadplane/telemetry/node';
```
## Opt out programmatically
@@ -17,7 +17,7 @@ import {
Call `disableTelemetry()` before capture helpers run.
```ts
-import { disableTelemetry } from '@ngaf/telemetry/node';
+import { disableTelemetry } from '@threadplane/telemetry/node';
disableTelemetry();
```
diff --git a/apps/website/content/docs/telemetry/guides/privacy-and-opt-out.mdx b/apps/website/content/docs/telemetry/guides/privacy-and-opt-out.mdx
index f6080cb14..2871461c4 100644
--- a/apps/website/content/docs/telemetry/guides/privacy-and-opt-out.mdx
+++ b/apps/website/content/docs/telemetry/guides/privacy-and-opt-out.mdx
@@ -25,7 +25,7 @@ The boolean parser treats `1`, `true`, `TRUE`, and `yes` as true values.
You can also disable telemetry in process:
```ts
-import { disableTelemetry } from '@ngaf/telemetry/node';
+import { disableTelemetry } from '@threadplane/telemetry/node';
disableTelemetry();
```
@@ -41,7 +41,7 @@ disableTelemetry();
Browser capture requires an enabled config:
```ts
-provideNgafTelemetry({ enabled: true, sink });
+provideThreadplaneTelemetry({ enabled: true, sink });
```
With `enabled: false` or no provider, browser capture no-ops.
diff --git a/apps/website/content/docs/telemetry/reference/events.mdx b/apps/website/content/docs/telemetry/reference/events.mdx
index 1f9642469..b9520f5fc 100644
--- a/apps/website/content/docs/telemetry/reference/events.mdx
+++ b/apps/website/content/docs/telemetry/reference/events.mdx
@@ -3,13 +3,13 @@
The shared event union is:
```ts
-type NgafEvent = NgafNodeEvent | NgafBrowserEvent;
+type ThreadplaneEvent = ThreadplaneNodeEvent | ThreadplaneBrowserEvent;
```
## Node events
```ts
-type NgafNodeEvent =
+type ThreadplaneNodeEvent =
| 'ngaf:postinstall'
| 'ngaf:runtime_instance_created'
| 'ngaf:stream_started'
@@ -32,13 +32,13 @@ type NgafNodeEvent =
The shared event file lists these browser-only events:
```ts
-type NgafBrowserEvent = 'ngaf:browser_provided' | 'ngaf:browser_chat_init';
+type ThreadplaneBrowserEvent = 'ngaf:browser_provided' | 'ngaf:browser_chat_init';
```
The browser Angular token broadens the local service event type to:
```ts
-type NgafTelemetryEvent =
+type ThreadplaneTelemetryEvent =
| 'ngaf:browser_provided'
| 'ngaf:browser_chat_init'
| 'ngaf:runtime_instance_created'
@@ -86,4 +86,4 @@ Node delivery sends:
}
```
-The public ingest key is a routing identifier accepted by the ThreadPlane ingest proxy. It is not a secret.
+The public ingest key is a routing identifier accepted by the Threadplane ingest proxy. It is not a secret.
diff --git a/apps/website/content/prompts/configuration.md b/apps/website/content/prompts/configuration.md
index f9fdb02ea..37a2283a9 100644
--- a/apps/website/content/prompts/configuration.md
+++ b/apps/website/content/prompts/configuration.md
@@ -1,13 +1,13 @@
Configure angular globally and per-component in my Angular application.
Global config (applies to all agent() calls in the app):
-In app.config.ts, provideAgent({ apiUrl: 'https://my-langgraph-server.com', }) — import provideAgent from '@ngaf/langgraph'.
+In app.config.ts, provideAgent({ apiUrl: 'https://my-langgraph-server.com', }) — import provideAgent from '@threadplane/langgraph'.
Per-call override (overrides global config for one component):
Pass apiUrl directly to agent({ apiUrl: 'https://other-server.com', assistantId: 'my-agent' }) — per-call options take precedence over global config.
Custom transport (for auth headers, logging, or testing):
-Implement the AgentTransport interface from @ngaf/langgraph. Its required method is stream(assistantId, threadId, payload, signal, options), and optional methods cover queued runs, cancellation, history, and updateState. Pass an AgentTransport instance as transport: myTransport to either provideAgent() or agent(). FetchStreamTransport is the default.
+Implement the AgentTransport interface from @threadplane/langgraph. Its required method is stream(assistantId, threadId, payload, signal, options), and optional methods cover queued runs, cancellation, history, and updateState. Pass an AgentTransport instance as transport: myTransport to either provideAgent() or agent(). FetchStreamTransport is the default.
To pass a system prompt to the LangGraph agent per-thread, use the config option:
agent({ config: { configurable: { system_prompt: 'You are a helpful assistant.' } } })
diff --git a/apps/website/content/prompts/getting-started.md b/apps/website/content/prompts/getting-started.md
index 0000c7498..7e66ab1e8 100644
--- a/apps/website/content/prompts/getting-started.md
+++ b/apps/website/content/prompts/getting-started.md
@@ -1,8 +1,8 @@
Add angular to my Angular 20+ application.
-Install: npm install @ngaf/langgraph@latest
+Install: npm install @threadplane/langgraph@latest
-1. In app.config.ts, add provideAgent({ apiUrl: 'http://localhost:2024' }) to the providers array. Import it from '@ngaf/langgraph'.
+1. In app.config.ts, add provideAgent({ apiUrl: 'http://localhost:2024' }) to the providers array. Import it from '@threadplane/langgraph'.
2. Create a ChatComponent that calls agent({ assistantId: 'chat' }) in the constructor or as a field initializer. agent() MUST be called inside an Angular injection context — constructor or field initializer is correct; ngOnInit is not.
diff --git a/apps/website/content/prompts/testing.md b/apps/website/content/prompts/testing.md
index 3a9a08307..a39018cec 100644
--- a/apps/website/content/prompts/testing.md
+++ b/apps/website/content/prompts/testing.md
@@ -1,6 +1,6 @@
Write unit tests for my Angular component that uses angular, without hitting a real LangGraph server.
-Use MockAgentTransport from '@ngaf/langgraph'. It implements AgentTransport and lets you script exactly what events the stream emits.
+Use MockAgentTransport from '@threadplane/langgraph'. It implements AgentTransport and lets you script exactly what events the stream emits.
Test setup:
const transport = new MockAgentTransport();
diff --git a/apps/website/e2e/solutions.spec.ts b/apps/website/e2e/solutions.spec.ts
index 17aac7089..8cfec1377 100644
--- a/apps/website/e2e/solutions.spec.ts
+++ b/apps/website/e2e/solutions.spec.ts
@@ -19,9 +19,9 @@ test.describe('Solutions detail pages', () => {
});
}
- test('/solutions/compliance shows the @ngaf/langgraph package pill', async ({ page }) => {
+ test('/solutions/compliance shows the @threadplane/langgraph package pill', async ({ page }) => {
await page.goto('/solutions/compliance');
- await expect(page.getByText('@ngaf/langgraph').first()).toBeVisible();
+ await expect(page.getByText('@threadplane/langgraph').first()).toBeVisible();
});
test('/solutions/unknown-slug returns 404', async ({ page }) => {
diff --git a/apps/website/e2e/website.spec.ts b/apps/website/e2e/website.spec.ts
index 8639a5c05..afcae810e 100644
--- a/apps/website/e2e/website.spec.ts
+++ b/apps/website/e2e/website.spec.ts
@@ -61,7 +61,7 @@ test('contact page submits a lead payload and renders success state', async ({ p
await contactForm.getByRole('textbox', { name: 'Email', exact: true }).fill('jane@acme.com');
await contactForm.getByRole('textbox', { name: 'Name' }).fill('Jane Smith');
await contactForm.getByRole('textbox', { name: 'Company' }).fill('Acme');
- await contactForm.getByRole('textbox', { name: 'Message' }).fill('We are evaluating Agent UI for Angular.');
+ await contactForm.getByRole('textbox', { name: 'Message' }).fill('We are evaluating Threadplane.');
await contactForm.getByRole('button', { name: 'Send' }).click();
await expect(page.getByText("Thanks. We'll be in touch within one business day.")).toBeVisible();
@@ -69,7 +69,7 @@ test('contact page submits a lead payload and renders success state', async ({ p
email: 'jane@acme.com',
name: 'Jane Smith',
company: 'Acme',
- message: 'We are evaluating Agent UI for Angular.',
+ message: 'We are evaluating Threadplane.',
source_page: 'e2e_contact',
track: 'enterprise',
});
@@ -176,8 +176,8 @@ test('/llms.txt returns plain text', async ({ page }) => {
const response = await page.goto('/llms.txt');
expect(response?.headers()['content-type']).toContain('text/plain');
const body = await page.locator('body').textContent();
- expect(body).toContain('@ngaf/a2ui');
- expect(body).toContain('@ngaf/telemetry');
+ expect(body).toContain('@threadplane/a2ui');
+ expect(body).toContain('@threadplane/telemetry');
expect(body).toContain('ChatMessageListComponent');
expect(body).not.toContain('ChatMessagesComponent');
});
@@ -226,7 +226,7 @@ test('docs pages render canonical and social metadata', async ({ page }) => {
);
await expect(page.locator('meta[property="og:title"]')).toHaveAttribute(
'content',
- 'Streaming - Agent Docs - Agent UI for Angular',
+ 'Streaming - Agent Docs - Threadplane',
);
await expect(page.locator('meta[property="og:url"]')).toHaveAttribute(
'content',
@@ -234,7 +234,7 @@ test('docs pages render canonical and social metadata', async ({ page }) => {
);
await expect(page.locator('meta[name="twitter:title"]')).toHaveAttribute(
'content',
- 'Streaming - Agent Docs - Agent UI for Angular',
+ 'Streaming - Agent Docs - Threadplane',
);
});
diff --git a/apps/website/emails/drip-angular-followup.ts b/apps/website/emails/drip-angular-followup.ts
index 145470dff..a2b47e05d 100644
--- a/apps/website/emails/drip-angular-followup.ts
+++ b/apps/website/emails/drip-angular-followup.ts
@@ -18,12 +18,12 @@ export function dripAngularFollowupHtml(day: number): { subject: string; html: s
if (day === 5) {
return {
- subject: 'LangGraph Angular SDK vs @ngaf/langgraph',
+ subject: 'LangGraph Angular SDK vs @threadplane/langgraph',
html: wrapEmail({
body: `
Comparison
-
LangGraph Angular SDK vs @ngaf/langgraph
-
The LangGraph JS SDK gives you a streaming client. @ngaf/langgraph gives you signal-native state, thread persistence, interrupt flows, and a full test harness — all wired together and optimized for Angular's change detection model. See the full comparison on our product page.
+
LangGraph Angular SDK vs @threadplane/langgraph
+
The LangGraph JS SDK gives you a streaming client. @threadplane/langgraph gives you signal-native state, thread persistence, interrupt flows, and a full test harness — all wired together and optimized for Angular's change detection model. See the full comparison on our product page.
See the Comparison →
`,
showUnsubscribe: true,
diff --git a/apps/website/emails/drip-chat-followup.ts b/apps/website/emails/drip-chat-followup.ts
index 63323afdf..e1bfcfbfc 100644
--- a/apps/website/emails/drip-chat-followup.ts
+++ b/apps/website/emails/drip-chat-followup.ts
@@ -23,7 +23,7 @@ export function dripChatFollowupHtml(day: number): { subject: string; html: stri
body: `
The Sprint Tax
The sprint tax: why every team rebuilds chat from scratch
-
Most teams spend 2–4 sprints building a chat UI before a single agent feature lands. Streaming state management, optimistic updates, thread history, error recovery — it's the same work every time. @ngaf/chat eliminates the sprint tax so your team ships features from day one.
+
Most teams spend 2–4 sprints building a chat UI before a single agent feature lands. Streaming state management, optimistic updates, thread history, error recovery — it's the same work every time. @threadplane/chat eliminates the sprint tax so your team ships features from day one.
See How It Works →
`,
showUnsubscribe: true,
diff --git a/apps/website/emails/drip-render-followup.ts b/apps/website/emails/drip-render-followup.ts
index d9989f64a..5581c0edf 100644
--- a/apps/website/emails/drip-render-followup.ts
+++ b/apps/website/emails/drip-render-followup.ts
@@ -23,7 +23,7 @@ export function dripRenderFollowupHtml(day: number): { subject: string; html: st
body: `
Architecture
Why tight coupling between agents and UI kills iteration speed
-
When an agent generates UI directly — raw HTML, string templates, hardcoded component names — every model change breaks the frontend and every UI change breaks the prompt. Decoupling via a declarative spec layer means agents and UI teams can iterate independently. See how @ngaf/render makes this the default.
+
When an agent generates UI directly — raw HTML, string templates, hardcoded component names — every model change breaks the frontend and every UI change breaks the prompt. Decoupling via a declarative spec layer means agents and UI teams can iterate independently. See how @threadplane/render makes this the default.
See How It Works →
`,
showUnsubscribe: true,
diff --git a/apps/website/emails/email-wrapper.ts b/apps/website/emails/email-wrapper.ts
index 014af7971..5103eba34 100644
--- a/apps/website/emails/email-wrapper.ts
+++ b/apps/website/emails/email-wrapper.ts
@@ -13,12 +13,12 @@ export function wrapEmail(opts: {
-
🛩️ Agent UI for Angular
+
🛩️ Threadplane
${opts.body}
-
Agent UI for Angular — Production-ready chat, threads, and generative UI for AI agents.
+
Threadplane — Production-ready chat, threads, and generative UI for AI agents.
You'll receive updates on new capabilities, production patterns, and Angular agent best practices. We keep it focused and infrequent — no spam.
Explore the Docs
`,
diff --git a/apps/website/instrumentation-client.ts b/apps/website/instrumentation-client.ts
index 0d2bf4c6f..13799d13e 100644
--- a/apps/website/instrumentation-client.ts
+++ b/apps/website/instrumentation-client.ts
@@ -1,5 +1,5 @@
import posthog from 'posthog-js';
-import { shouldCaptureAnalytics } from '@ngaf/telemetry/browser';
+import { shouldCaptureAnalytics } from '@threadplane/telemetry/browser';
const token = process.env.NEXT_PUBLIC_POSTHOG_TOKEN;
const captureLocal = process.env.NEXT_PUBLIC_POSTHOG_CAPTURE_LOCAL === 'true';
diff --git a/apps/website/lib/design-tokens.ts b/apps/website/lib/design-tokens.ts
index 80e940449..50822010e 100644
--- a/apps/website/lib/design-tokens.ts
+++ b/apps/website/lib/design-tokens.ts
@@ -3,7 +3,7 @@
*
* Kept as a barrel so existing imports of the form
* `import { tokens } from '../../lib/design-tokens'` keep working.
- * New code should import directly from `@ngaf/design-tokens`.
+ * New code should import directly from `@threadplane/design-tokens`.
*/
export {
tokens,
@@ -14,4 +14,4 @@ export {
shadows,
radius,
space,
-} from '@ngaf/design-tokens';
+} from '@threadplane/design-tokens';
diff --git a/apps/website/lib/resend.ts b/apps/website/lib/resend.ts
index f073b3fbc..f31e892ba 100644
--- a/apps/website/lib/resend.ts
+++ b/apps/website/lib/resend.ts
@@ -11,7 +11,7 @@ function getResend(): Resend | null {
}
export const AUDIENCE_ID = process.env.RESEND_AUDIENCE_ID || '';
-export const FROM = process.env.RESEND_FROM || 'Agent UI for Angular ';
+export const FROM = process.env.RESEND_FROM || 'Threadplane ';
export const NOTIFY_TO = process.env.RESEND_NOTIFY_TO || 'hello@cacheplane.ai';
/** Send an email via Resend. No-ops when API key is missing. */
diff --git a/apps/website/public/AGENTS.md b/apps/website/public/AGENTS.md
index 544b2463c..1d5b40477 100644
--- a/apps/website/public/AGENTS.md
+++ b/apps/website/public/AGENTS.md
@@ -1,9 +1,9 @@
-# Agent UI for Angular v0.0.40
+# Threadplane v0.0.46
Production-ready chat, durable threads, interrupts, subagents, planning, memory, and generative UI for Angular agent apps.
## Install
-npm install @ngaf/chat @ngaf/langgraph
+npm install @threadplane/chat @threadplane/langgraph
## Key requirement
`agent()` MUST be called within an Angular injection context (component constructor or field initializer). Calling it in ngOnInit or any async context throws "NG0203: inject() must be called from an injection context".
@@ -12,18 +12,18 @@ npm install @ngaf/chat @ngaf/langgraph
```typescript
// app.config.ts
import type { ApplicationConfig } from '@angular/core';
-import { provideAgent } from '@ngaf/langgraph';
+import { provideAgent } from '@threadplane/langgraph';
export const appConfig: ApplicationConfig = {
providers: [provideAgent({ apiUrl: 'http://localhost:2024' })]
};
// chat.component.ts
import { Component } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatComponent as NgafChatComponent } from '@ngaf/chat';
+import { agent } from '@threadplane/langgraph';
+import { ChatComponent as ThreadplaneChatComponent } from '@threadplane/chat';
@Component({
- imports: [NgafChatComponent],
+ imports: [ThreadplaneChatComponent],
template: `
`,
diff --git a/apps/website/public/CLAUDE.md b/apps/website/public/CLAUDE.md
index 544b2463c..1d5b40477 100644
--- a/apps/website/public/CLAUDE.md
+++ b/apps/website/public/CLAUDE.md
@@ -1,9 +1,9 @@
-# Agent UI for Angular v0.0.40
+# Threadplane v0.0.46
Production-ready chat, durable threads, interrupts, subagents, planning, memory, and generative UI for Angular agent apps.
## Install
-npm install @ngaf/chat @ngaf/langgraph
+npm install @threadplane/chat @threadplane/langgraph
## Key requirement
`agent()` MUST be called within an Angular injection context (component constructor or field initializer). Calling it in ngOnInit or any async context throws "NG0203: inject() must be called from an injection context".
@@ -12,18 +12,18 @@ npm install @ngaf/chat @ngaf/langgraph
```typescript
// app.config.ts
import type { ApplicationConfig } from '@angular/core';
-import { provideAgent } from '@ngaf/langgraph';
+import { provideAgent } from '@threadplane/langgraph';
export const appConfig: ApplicationConfig = {
providers: [provideAgent({ apiUrl: 'http://localhost:2024' })]
};
// chat.component.ts
import { Component } from '@angular/core';
-import { agent } from '@ngaf/langgraph';
-import { ChatComponent as NgafChatComponent } from '@ngaf/chat';
+import { agent } from '@threadplane/langgraph';
+import { ChatComponent as ThreadplaneChatComponent } from '@threadplane/chat';
@Component({
- imports: [NgafChatComponent],
+ imports: [ThreadplaneChatComponent],
template: `
`,
diff --git a/apps/website/public/assets/arch-diagram.svg b/apps/website/public/assets/arch-diagram.svg
index e4c923b09..40a0e0ce2 100644
--- a/apps/website/public/assets/arch-diagram.svg
+++ b/apps/website/public/assets/arch-diagram.svg
@@ -36,7 +36,7 @@
font-size="11" fill="#4A527A">Agent UI state
@ngaf/langgraph
+ font-size="11" fill="#4A527A">@threadplane/langgraph
diff --git a/apps/website/public/assets/hero.svg b/apps/website/public/assets/hero.svg
index 928409810..a8d053758 100644
--- a/apps/website/public/assets/hero.svg
+++ b/apps/website/public/assets/hero.svg
@@ -24,7 +24,7 @@
font-style="italic"
fill="#8B96C8"
opacity="0.9"
- >Agent UI for Angular — Production-ready agent UI
+ >Threadplane — Production-ready agent UI
diff --git a/apps/website/public/whitepaper-preview.html b/apps/website/public/whitepaper-preview.html
index df46dbebc..3cf4aa2d2 100644
--- a/apps/website/public/whitepaper-preview.html
+++ b/apps/website/public/whitepaper-preview.html
@@ -20,7 +20,7 @@
-
ThreadPlane · Enterprise Angular Agent UI
+
Threadplane · Enterprise Angular Agent UI
Agent UI for Angular
Production-ready chat, threads, and generative UI for AI agents
threadplane.ai · 2026
@@ -171,7 +171,7 @@
The Raw Stream Problem
Hand-parsing these events is fragile. You end up maintaining state machines to track which call is active, handling out-of-order delivery, and writing defensive code for malformed chunks. Testing becomes painful because you need to simulate realistic streaming sequences. Every edge case—interrupted calls, parallel tool execution, retry logic—adds branching complexity.
The framework solves this by exposing `toolCalls()` as a normalized signal on the agent surface. Each tool call object includes its current status, accumulated steps, and final result. The stream parsing happens once, correctly, inside the transport layer.
Headless and Prebuilt Options
-
`@ngaf/chat` provides two components for tool call rendering. `` is the headless primitive—it manages the structural rendering of multiple concurrent calls but leaves visual presentation to you. `` is the prebuilt option that handles common patterns: status indicators, step lists, collapsible sections, and error states.
+
`@threadplane/chat` provides two components for tool call rendering. `` is the headless primitive—it manages the structural rendering of multiple concurrent calls but leaves visual presentation to you. `` is the prebuilt option that handles common patterns: status indicators, step lists, collapsible sections, and error states.
For most production apps, start with the prebuilt card and customize from there:
@@ -215,7 +215,7 @@
The `interrupt()` Signal
When `interrupt()` returns a defined value, the agent is paused and awaiting human input. The `AgentInterrupt` object contains the action metadata emitted by the graph—typically a description of the pending operation and any parameters the user might modify. When `interrupt()` returns `undefined`, no approval is pending.
This signal-based approach eliminates the need for manual subscription management or imperative state tracking. Angular's reactivity system propagates interrupt state changes automatically, and the signal remains consistent across component re-renders.
UI Components for Interrupt Handling
-
The `@ngaf/chat` package provides two components for rendering interrupt flows. `` offers a prebuilt approval interface with sensible defaults. For custom designs, the headless `` component exposes the interrupt state and action handlers without imposing markup or styling.
+
The `@threadplane/chat` package provides two components for rendering interrupt flows. `` offers a prebuilt approval interface with sensible defaults. For custom designs, the headless `` component exposes the interrupt state and action handlers without imposing markup or styling.
Both components support three user actions that map directly to resume commands:
Approve: Resume execution with the original parameters
Edit: Resume execution with user-modified parameters
@@ -261,10 +261,10 @@
The Custom Event Pattern
"rows": rows_so_far
})
-
On the Angular side, `@ngaf/langgraph` surfaces these through the agent's event stream. The `@ngaf/render` package consumes these specs and resolves them to Angular components at runtime.
+
On the Angular side, `@threadplane/langgraph` surfaces these through the agent's event stream. The `@threadplane/render` package consumes these specs and resolves them to Angular components at runtime.
Registry-Based Resolution
The registry pattern decouples agent output from component implementation. Your agent emits a type identifier. Your frontend maps that identifier to a component. Neither side knows implementation details of the other.
-
import { defineAngularRegistry } from '@ngaf/render';
+
import { defineAngularRegistry } from '@threadplane/render';
import { DataTableComponent } from './components/data-table.component';
import { ReservationFormComponent } from './components/reservation-form.component';
import { ChartComponent } from './components/chart.component';
@@ -282,7 +282,7 @@
Registry-Based Resolution
Or configure the registry at the provider level with `provideRender({ registry: uiRegistry })` and omit it from individual templates.
Progressive Updates Through JSON Patch
Static specs work for complete data. Streaming scenarios require progressive updates. When your agent processes a large dataset, users shouldn't wait for completion before seeing results.
-
`@ngaf/render` supports JSON Patch streaming for incremental UI updates. The agent emits patches as data arrives:
+
`@threadplane/render` supports JSON Patch streaming for incremental UI updates. The agent emits patches as data arrives:
# Patches as rows arrive
diff --git a/apps/website/public/whitepapers/angular-preview.html b/apps/website/public/whitepapers/angular-preview.html
index 2aa78cbde..aa6c74be5 100644
--- a/apps/website/public/whitepapers/angular-preview.html
+++ b/apps/website/public/whitepapers/angular-preview.html
@@ -20,7 +20,7 @@
-
ThreadPlane · Angular Agent UI Guide
+
Threadplane · Angular Agent UI Guide
The Enterprise Guide to Agent UI in Angular
Ship LangGraph and AG-UI-compatible agents without building the plumbing
threadplane.ai · 2026
@@ -226,7 +226,7 @@
Production Considerations
Chapter 4
Interrupt & Approval Flows
# Interrupt & Approval Flows
-
Agents that modify external systems—sending emails, executing database writes, triggering deployments—require human oversight. Autonomous execution without checkpoints creates liability, compliance violations, and irreversible mistakes. LangGraph's `interrupt()` primitive solves this at the graph level, pausing execution mid-stream until a human provides explicit authorization. `@ngaf/langgraph` surfaces this as a reactive signal, making approval workflows native to Angular's change detection without polling, websockets, or custom resume endpoints.
+
Agents that modify external systems—sending emails, executing database writes, triggering deployments—require human oversight. Autonomous execution without checkpoints creates liability, compliance violations, and irreversible mistakes. LangGraph's `interrupt()` primitive solves this at the graph level, pausing execution mid-stream until a human provides explicit authorization. `@threadplane/langgraph` surfaces this as a reactive signal, making approval workflows native to Angular's change detection without polling, websockets, or custom resume endpoints.
How LangGraph Interrupt Works
When a LangGraph node calls `interrupt()`, the graph halts execution and persists its current state to the configured checkpointer. The interrupt payload—containing context about the pending action—is sent to the client as part of the stream. Execution remains suspended until the client sends a resume command with one of three directives: approve the action as-is, provide edited parameters, or cancel entirely.
The resume payload structure is straightforward:
@@ -246,7 +246,7 @@
The interrupt() Signal
This signal integrates directly with Angular's reactivity model. Components re-render automatically when an interrupt arrives—no subscription management, no manual change detection triggers. When the user responds and execution resumes, the signal returns to `undefined`.
Prebuilt Approval UI
-
`@ngaf/chat` provides ``, a ready-to-use approval interface:
+
`@threadplane/chat` provides ``, a ready-to-use approval interface:
Session expiration: Checkpointed state survives session boundaries. The interrupt signal repopulates on reconnection, though your application should handle re-authentication before allowing resume actions.
Cancel with partial state: Cancellation doesn't roll back prior node executions. If three nodes completed before the interrupt, those effects persist. Design graphs with compensation logic for actions that require atomicity, or structure interrupts to occur before side effects rather than after.
Multiple pending interrupts: LangGraph supports sequential interrupts within a single run. The `interrupt()` signal reflects the current pending interrupt; each resume advances to the next pause point or completion.
-
Human-in-the-loop isn't optional for production agents. `@ngaf/langgraph` makes it reactive, type-safe, and compatible with Angular's rendering model—approval flows become UI state, not infrastructure problems.
+
Human-in-the-loop isn't optional for production agents. `@threadplane/langgraph` makes it reactive, type-safe, and compatible with Angular's rendering model—approval flows become UI state, not infrastructure problems.
Chapter 5
Full LangGraph Feature Coverage
# Full LangGraph Feature Coverage
-
Most Angular LLM integrations handle the basics: send a message, stream tokens, render a response. The moment you need tool calls, subgraphs, or multi-agent coordination, you're writing raw SSE parsers and manually reconciling state. @ngaf/langgraph exists specifically to avoid that cliff—every LangGraph feature surfaces through the same reactive signals your components already consume.
+
Most Angular LLM integrations handle the basics: send a message, stream tokens, render a response. The moment you need tool calls, subgraphs, or multi-agent coordination, you're writing raw SSE parsers and manually reconciling state. @threadplane/langgraph exists specifically to avoid that cliff—every LangGraph feature surfaces through the same reactive signals your components already consume.
Tool Call Streaming
LangGraph emits tool invocations as structured events mid-stream. Rather than parsing `tool_call` chunks yourself, the agent ref exposes them directly:
readonly chat = agent({
@@ -300,7 +300,7 @@
Tool Call Streaming
The `toolCalls()` signal updates as invocations arrive, complete as the agent processes results, and clear when the turn ends. No manual event filtering. Tool call arguments stream incrementally—useful for showing users what data the agent is requesting before results return.
Subgraph Support
-
Nested graphs emit events with their own namespaces. @ngaf/langgraph flattens these into the primary stream while preserving hierarchy through the `subagents()` signal:
+
Nested graphs emit events with their own namespaces. @threadplane/langgraph flattens these into the primary stream while preserving hierarchy through the `subagents()` signal:
// Parent agent spawns child graphs for specialized tasks
const activeSubagents = this.chat.subagents();
// Returns SubagentInfo[] with id, name, status for each active subgraph
@@ -346,11 +346,11 @@
Why Full Coverage Matters
Deterministic Testing
# Deterministic Testing
Agent UIs are notoriously difficult to test. Real LLM calls introduce latency measured in seconds, non-deterministic outputs, rate limits, and network dependencies that make CI pipelines slow and flaky. A test that passes locally might fail in CI because the model returned a slightly different response, or the API throttled your request, or the stream took longer than your timeout.
-
The solution is deterministic mocking at the transport layer. NGAF provides two complementary approaches: `MockAgentTransport` for scripting realistic SSE event sequences, and `mockLangGraphAgent()` for direct signal manipulation when you need fine-grained control.
+
The solution is deterministic mocking at the transport layer. Threadplane provides two complementary approaches: `MockAgentTransport` for scripting realistic SSE event sequences, and `mockLangGraphAgent()` for direct signal manipulation when you need fine-grained control.
MockAgentTransport: Scripted Event Sequences
`MockAgentTransport` replaces `FetchStreamTransport` in tests, emitting a predetermined sequence of SSE events without any network calls. You script exactly what the agent receives—message chunks, tool calls, interrupts, errors—and the transport replays them synchronously or with configurable delays.
import { TestBed } from '@angular/core/testing';
-import { MockAgentTransport, provideAgent } from '@ngaf/langgraph';
+import { MockAgentTransport, provideAgent } from '@threadplane/langgraph';
describe('ChatComponent', () => {
let transport: MockAgentTransport;
The Enterprise Guide to Agent Chat Interfaces in Angular
Production agent chat UI in days, not sprints
threadplane.ai · 2026
@@ -80,8 +80,8 @@
"Good Enough for Demo" vs. Production
The Opportunity Cost
Here's the actual problem: you're paying senior Angular engineers to solve problems that have already been solved. Problems that have nothing to do with what makes your agent application valuable.
While your team is debugging auto-scroll edge cases, your agent backend is ready and waiting. While they're implementing tool call state machines, your differentiating features aren't getting built. While they're fixing accessibility audit failures, your competitors are shipping.
The thesis is simple: ship the chat UI on day one. Spend the sprints on what differentiates your product—the agent logic, the tool integrations, the domain-specific features that your competitors can't copy.
The sprint tax is optional. Stop paying it.
@@ -89,7 +89,7 @@
The @ngaf/chat Thesis
Chapter 2
Batteries-Included Components
# Batteries-Included Components
-
@ngaf/chat ships two component tiers: headless primitives that encapsulate behavior without styling opinions, and prebuilt compositions that deliver production-ready interfaces with minimal configuration. The separation lets teams adopt complete solutions immediately while preserving escape hatches for custom requirements.
+
@threadplane/chat ships two component tiers: headless primitives that encapsulate behavior without styling opinions, and prebuilt compositions that deliver production-ready interfaces with minimal configuration. The separation lets teams adopt complete solutions immediately while preserving escape hatches for custom requirements.
The Headless Tier
Headless components own behavior and state management but emit no styled markup. They expose content projection slots and structural directives for complete template control.
`` manages scroll position, virtualization hints, and message grouping logic. It consumes `Message[]` from the agent surface and handles the complexity of streaming message updates—partial content, role transitions, and optimistic UI states. Your templates define how each message renders.
@@ -116,8 +116,8 @@
Composing Tiers
The practical pattern: use prebuilt components for standard sections, drop to headless for custom requirements. A typical enterprise implementation might use the prebuilt message list and input while providing a custom tool call renderer that integrates with internal component libraries.
The `` component accepts content projection for this purpose. Override specific slots while retaining default behavior elsewhere. When projection proves insufficient, decompose to individual prebuilt components, then to headless primitives as customization needs escalate.
The Agent Contract
-
Both tiers consume the runtime-neutral `Agent` contract returned by `agent()` from @ngaf/langgraph. This contract exposes signals: `messages()` returns `Message[]` representing the conversation, `status()` indicates connection state, `isLoading()` reflects pending operations, `toolCalls()` surfaces invocations, and `state()` provides LangGraph checkpoint data.
-
Components bind directly to these signals. When the agent streams a response, `messages()` updates reactively. Components re-render affected sections without manual change detection. The `Message` type from @ngaf/chat provides the runtime-neutral representation—role, content, metadata—that components consume regardless of the underlying LangGraph message format.
+
Both tiers consume the runtime-neutral `Agent` contract returned by `agent()` from @threadplane/langgraph. This contract exposes signals: `messages()` returns `Message[]` representing the conversation, `status()` indicates connection state, `isLoading()` reflects pending operations, `toolCalls()` surfaces invocations, and `state()` provides LangGraph checkpoint data.
+
Components bind directly to these signals. When the agent streams a response, `messages()` updates reactively. Components re-render affected sections without manual change detection. The `Message` type from @threadplane/chat provides the runtime-neutral representation—role, content, metadata—that components consume regardless of the underlying LangGraph message format.
Choosing Your Tier
Start with ``. It covers the common case and establishes baseline functionality in minutes. Drop to prebuilt companions when you need to rearrange layout or inject custom sections between standard elements. Move to headless primitives when your design system requires specific DOM structures or when you're building novel interaction patterns.
Migration between tiers is mechanical: prebuilt components are compositions of headless primitives with styling applied. Extracting customization points means identifying which primitive to expose and which styling to preserve. The agent contract remains constant across tiers—your backend integration stays unchanged regardless of which component tier renders the interface.
@@ -127,9 +127,9 @@
Choosing Your Tier
Theming & Design System Integration
# Theming & Design System Integration
A chat interface that looks like a demo is a liability in production. Users notice when components don't match the rest of the application—inconsistent border radius, wrong font stack, off-brand colors. These details erode trust in the product and in the AI features you're shipping.
-
@ngaf/chat exposes its visual design decisions through CSS custom properties, giving you control over appearance without touching component internals or maintaining forks.
+
@threadplane/chat exposes its visual design decisions through CSS custom properties, giving you control over appearance without touching component internals or maintaining forks.
The CSS Custom Property API
-
Every visual decision in @ngaf/chat maps to a custom property. The components read these values at runtime, so overriding them in your stylesheet changes the rendered output immediately.
+
Every visual decision in @threadplane/chat maps to a custom property. The components read these values at runtime, so overriding them in your stylesheet changes the rendered output immediately.
The naming convention follows a predictable pattern: `--chat-{component}-{property}`. Component-level tokens reference global tokens, which reference your design system tokens. This layering lets you override at whatever granularity makes sense—change one button's border radius or change every border radius in the chat interface with a single line.
Design Token Mapping
If your team already maintains design tokens, integration is direct assignment. Map your existing tokens to the chat component tokens in a single stylesheet:
@@ -155,7 +155,7 @@
Design Token Mapping
This mapping becomes your single source of truth. When design updates the brand's border radius, the chat components update automatically because they reference your tokens, not hardcoded values.
Typography Integration
Chat interfaces are text-heavy. Typography consistency matters more here than in most UI contexts.
-
@ngaf/chat exposes tokens for font family, size scale (base, small, large), line height, and font weight. Message content, timestamps, tool call labels, and input placeholders all reference these tokens. Set them once, and the entire typographic hierarchy follows your design system.
+
@threadplane/chat exposes tokens for font family, size scale (base, small, large), line height, and font weight. Message content, timestamps, tool call labels, and input placeholders all reference these tokens. Set them once, and the entire typographic hierarchy follows your design system.
Color System Integration
Surface colors control backgrounds—the chat container, message bubbles, input field. Text colors handle primary content and secondary metadata. Accent colors drive interactive elements and visual emphasis. Semantic state colors handle error states, success confirmations, and loading indicators.
The token structure assumes you have these categories in your design system. If you don't, use literal values.
@@ -178,7 +178,7 @@
# Generative UI in Chat
Text is a bottleneck. When a financial agent needs to present quarterly results, streaming prose about revenue figures wastes cognitive load. When a scheduling agent confirms a booking, a wall of text obscures the actionable details. The most capable agent interfaces solve this by rendering structured UI directly in the message stream—tables, forms, approval cards—alongside conversational text.
Structured UI in the Message Stream
-
@ngaf/chat treats generative UI as a first-class message type. When an agent emits a UI specification instead of text, the chat renders it inline using @ngaf/render. From the user's perspective, the conversation flows naturally: the agent explains context in prose, then presents a rendered component for interaction.
+
@threadplane/chat treats generative UI as a first-class message type. When an agent emits a UI specification instead of text, the chat renders it inline using @threadplane/render. From the user's perspective, the conversation flows naturally: the agent explains context in prose, then presents a rendered component for interaction.
This works because the Agent contract exposes messages as a heterogeneous stream. Text messages render as text. UI messages resolve to Angular components through a registry. The chat component handles both transparently.
The json-render Spec
The json-render specification defines a minimal contract for declarative UI. An agent emits a JSON object with a `type` field identifying the component and a `props` field containing its inputs:
@@ -187,10 +187,10 @@
The json-render Spec
The renderer resolves `data-table` to an Angular component, binds `props` to its inputs, and inserts it into the DOM. No custom parsing, no message-type switches in templates. The specification stays minimal intentionally—agents describe *what* to render, not *how*.
A2UI: Agent-Specific Patterns
Google's A2UI specification extends json-render with patterns specific to agent interactions: approval workflows, structured actions, and rich data displays. Where json-render handles arbitrary components, A2UI codifies the common cases—confirmation dialogs, multi-step forms, action buttons with pending states.
-
@ngaf/render supports both specifications. You can mix A2UI's structured patterns with custom json-render components in the same message stream.
+
@threadplane/render supports both specifications. You can mix A2UI's structured patterns with custom json-render components in the same message stream.
Registry Integration
Component resolution flows through a registry. You define which component handles each type, then provide it to the chat context:
-
import { defineAngularRegistry, provideRender } from '@ngaf/render';
+
import { defineAngularRegistry, provideRender } from '@threadplane/render';
import { DataTableComponent } from './data-table.component';
import { BookingFormComponent } from './booking-form.component';
import { ApprovalCardComponent } from './approval-card.component';
@@ -204,7 +204,7 @@
Registry Integration
The chat component picks up the registry through dependency injection. When a message contains a render spec, it resolves and instantiates the component automatically.
Streaming Patches
-
Agents rarely emit complete UI specifications in one shot. A data table streams rows as they arrive. A form populates fields progressively. @ngaf/render handles this through JSON Patch streaming—the agent emits an initial skeleton, then streams RFC 6902 patches that mutate the specification incrementally.
+
Agents rarely emit complete UI specifications in one shot. A data table streams rows as they arrive. A form populates fields progressively. @threadplane/render handles this through JSON Patch streaming—the agent emits an initial skeleton, then streams RFC 6902 patches that mutate the specification incrementally.
In the chat context, this creates the live update effect users expect. A table appears with headers, then rows populate one by one. A summary card fills in as the agent processes. The render layer applies patches reactively; bound components update without re-instantiation.
This matters for perceived latency. Users see structure immediately, then watch it fill in—progress feels continuous rather than blocked on complete responses.
@@ -213,7 +213,7 @@
Streaming Patches
Debug Tooling
# Debug Tooling
Debugging agent chat is hard. The message stream is opaque, tool call state transitions happen in milliseconds, and interrupt flows have timing edge cases that only surface under load. You can't step through a streaming conversation the way you step through synchronous code.
-
`` is @ngaf/chat's built-in debug panel—a developer overlay that surfaces agent state, raw message events, tool call history, and interrupt state in real time. One component, zero configuration.
+
`` is @threadplane/chat's built-in debug panel—a developer overlay that surfaces agent state, raw message events, tool call history, and interrupt state in real time. One component, zero configuration.
What chat-debug Shows
The debug panel exposes four primary views:
Message State. The current `Message[]` array, rendered as expandable JSON. You see every message the agent has processed—user inputs, assistant responses, tool results—with full metadata intact.
@@ -222,7 +222,7 @@
What chat-debug Shows
Interrupt Payload. When the agent requests human intervention, the full interrupt payload appears in the panel—the interrupt type, the data the agent is requesting, and any context it provided. After user action, you see both the original payload and the response.
Adding chat-debug
Drop it into any chat interface:
-
import { ChatDebugComponent } from '@ngaf/chat';
+
import { ChatDebugComponent } from '@threadplane/chat';
Agents that render UI — without coupling to your frontend
threadplane.ai · 2026
@@ -174,11 +174,11 @@
Control Flow in the Spec
Computed properties use template expressions. The renderer evaluates these against a provided context object, keeping the spec declarative while supporting dynamic data binding.
Google's A2UI Extension
Google's Agent-to-UI (A2UI) specification extends json-render with agent-specific patterns. It adds constructs for streaming updates, tool call visualization, and interrupt handling—concepts that don't exist in static UI rendering but are fundamental to agent interactions.
-
A2UI defines how partial UI updates arrive during generation, how tool invocations surface to users, and how human-in-the-loop checkpoints integrate with component trees. The `@ngaf/render` package implements both specifications.
-
The @ngaf/render Implementation
+
A2UI defines how partial UI updates arrive during generation, how tool invocations surface to users, and how human-in-the-loop checkpoints integrate with component trees. The `@threadplane/render` package implements both specifications.
+
The @threadplane/render Implementation
The `` directive consumes json-render documents and instantiates Angular components:
import { Component, signal } from '@angular/core';
-import { RenderSpecComponent, defineAngularRegistry } from '@ngaf/render';
+import { RenderSpecComponent, defineAngularRegistry } from '@threadplane/render';
import { CardComponent, MetricComponent, SparklineComponent } from './components';
Generative UI collapses the moment you wait for complete responses. A data table with 50 rows, each containing nested product details, might produce 15KB of JSON. Sending the full document on every update—when a single cell changes—creates unnecessary latency and forces the UI to block until the entire payload arrives. Users stare at spinners while the agent has already produced usable content.
-
@ngaf/render solves this with JSON Patch (RFC 6902), streaming incremental operations that mutate the UI spec in place as the agent generates it.
+
@threadplane/render solves this with JSON Patch (RFC 6902), streaming incremental operations that mutate the UI spec in place as the agent generates it.
The Problem with Full-Document Streaming
Consider an agent building a dashboard. The initial render spec might be 8KB. Adding a chart adds 2KB. Traditional approaches either:
1. Wait for the complete spec before rendering anything
@@ -297,7 +297,7 @@
Patch-Based Agent Output
Each line is independently parseable. The render layer applies patches immediately, updating only the affected portion of the component tree.
Partial-JSON Parsing and Skeleton States
-
Real streams don't arrive in neat lines. TCP chunks split mid-token. @ngaf/render handles incomplete JSON by maintaining parse state across chunks, rendering valid portions while buffering incomplete fragments.
+
Real streams don't arrive in neat lines. TCP chunks split mid-token. @threadplane/render handles incomplete JSON by maintaining parse state across chunks, rendering valid portions while buffering incomplete fragments.
Skeleton states emerge naturally from this model. The agent can emit structural placeholders first—empty arrays, loading indicators—then fill them progressively:
@Component({
template: ``,
@@ -311,7 +311,7 @@
Partial-JSON Parsing and Skeleton States
}
}
-
The `signalStateStore` from @ngaf/render manages immutable state updates. Each `applyPatch` call triggers fine-grained Angular signals, re-rendering only components bound to changed paths.
+
The `signalStateStore` from @threadplane/render manages immutable state updates. Each `applyPatch` call triggers fine-grained Angular signals, re-rendering only components bound to changed paths.
Performance Characteristics
Patch-based updates are O(change), not O(spec size). Appending one row to a 500-row table touches one array slot. The differ doesn't walk the entire spec; it applies the operation directly to the target path.
This matters at scale. A real-time monitoring dashboard receiving 10 updates per second would choke on full-document replacement. With patches, each update carries only the delta—typically under 200 bytes—and applies in microseconds.
@@ -321,10 +321,10 @@
Performance Characteristics
Chapter 5
State Management & Computed Functions
# State Management & Computed Functions
-
Static UI specs hit a wall fast. The moment you need a total that updates when line items change, or a button that disables based on form state, you're beyond what static JSON can express. Production generative UI requires computed properties and collection rendering—capabilities that @ngaf/render delivers through `signalStateStore()` and spec-level computed functions.
+
Static UI specs hit a wall fast. The moment you need a total that updates when line items change, or a button that disables based on form state, you're beyond what static JSON can express. Production generative UI requires computed properties and collection rendering—capabilities that @threadplane/render delivers through `signalStateStore()` and spec-level computed functions.
Agent-Managed State with signalStateStore()
`signalStateStore()` creates a reactive state container that both agents and components can manipulate. The agent initializes state through the spec, components update it via user interaction, and computed properties derive new values automatically.
-
import { signalStateStore } from '@ngaf/render';
+
import { signalStateStore } from '@threadplane/render';
const store = signalStateStore({
items: [
{ name: 'Widget', price: 25, quantity: 2 },
diff --git a/apps/website/scripts/generate-narrative-docs.ts b/apps/website/scripts/generate-narrative-docs.ts
index 60be5c204..dd9e82f89 100644
--- a/apps/website/scripts/generate-narrative-docs.ts
+++ b/apps/website/scripts/generate-narrative-docs.ts
@@ -10,7 +10,7 @@ const API_DOCS_ROOT = 'apps/website/content/docs';
const TOPICS = [
{
slug: 'introduction',
- prompt: 'Write an introduction to the Agent UI for Angular library. Explain what it does, who it is for, and why it exists. Include a minimal getting-started example.',
+ prompt: 'Write an introduction to the Threadplane library. Explain what it does, who it is for, and why it exists. Include a minimal getting-started example.',
},
{
slug: 'streaming',
@@ -36,7 +36,7 @@ async function generateDoc(slug: string, prompt: string, apiDocsJson: string): P
max_tokens: 2048,
messages: [{
role: 'user',
- content: `You are writing documentation for the Agent UI for Angular library.
+ content: `You are writing documentation for the Threadplane library.
Here is the TypeDoc API reference JSON:\n\n${apiDocsJson}\n\n${prompt}
Write clean, developer-friendly MDX documentation. Use precise, no-fluff prose. Include code examples. Start with a single # heading.`,
diff --git a/apps/website/scripts/generate-whitepaper.ts b/apps/website/scripts/generate-whitepaper.ts
index 33ce91e79..61fcd3225 100644
--- a/apps/website/scripts/generate-whitepaper.ts
+++ b/apps/website/scripts/generate-whitepaper.ts
@@ -11,17 +11,17 @@ if (!process.env['ANTHROPIC_API_KEY'] && loadEnvFile && fs.existsSync('.env')) {
const client = new Anthropic();
const MODEL = process.env['ANTHROPIC_MODEL'] ?? 'claude-opus-4-5';
-const CURRENT_API_CONTEXT = `You are writing public technical whitepapers for ThreadPlane Agent UI for Angular.
+const CURRENT_API_CONTEXT = `You are writing public technical whitepapers for Threadplane Threadplane.
Use only the current API surface:
-- Package names are @ngaf/langgraph, @ngaf/render, @ngaf/chat, and @ngaf/ag-ui.
-- @ngaf/langgraph exposes agent(), provideAgent(), LangGraphAgent, MockAgentTransport, FetchStreamTransport, and mockLangGraphAgent().
+- Package names are @threadplane/langgraph, @threadplane/render, @threadplane/chat, and @threadplane/ag-ui.
+- @threadplane/langgraph exposes agent(), provideAgent(), LangGraphAgent, MockAgentTransport, FetchStreamTransport, and mockLangGraphAgent().
- agent() returns a runtime-neutral chat surface with messages(), status(), isLoading(), error(), toolCalls(), state(), submit(), stop(), regenerate(), interrupt(), subagents(), and LangGraph-specific langGraph* signals. status() returns only 'idle' | 'running' | 'error'. Use isLoading() for loading UI. interrupt() is AgentInterrupt | undefined on the runtime-neutral surface.
-- Configure LangGraph with assistantId and apiUrl. Do not use graphId or url as @ngaf/langgraph option names.
-- @ngaf/chat consumes the runtime-neutral Agent contract and exports ChatComponent, ChatMessageListComponent, ChatInputComponent, ChatToolCallsComponent, ChatToolCallCardComponent, and ChatInterruptPanelComponent. The debug-only secondary entry point @ngaf/chat/debug exports ChatDebugComponent. Selectors are , , , , , , and .
-- Chat messages use Message[] from @ngaf/chat for the runtime-neutral surface. Raw LangGraph messages, when needed, are exposed through langGraphMessages().
+- Configure LangGraph with assistantId and apiUrl. Do not use graphId or url as @threadplane/langgraph option names.
+- @threadplane/chat consumes the runtime-neutral Agent contract and exports ChatComponent, ChatMessageListComponent, ChatInputComponent, ChatToolCallsComponent, ChatToolCallCardComponent, and ChatInterruptPanelComponent. The debug-only secondary entry point @threadplane/chat/debug exports ChatDebugComponent. Selectors are , , , , , , and .
+- Chat messages use Message[] from @threadplane/chat for the runtime-neutral surface. Raw LangGraph messages, when needed, are exposed through langGraphMessages().
- Angular examples should call agent() directly in a component field initializer, for example: readonly chat = agent({ assistantId: 'chat', threadId: this.threadId, onThreadId: id => this.threadId.set(id) }). Do not inject LangGraphAgent as a service. Do not invent a wrapper service around LangGraphAgent.
-- @ngaf/render exposes render-spec, defineAngularRegistry(), provideRender(), signalStateStore(), JSON Patch streaming, and A2UI support. Registry examples may pass [registry] directly to or configure provideRender({ registry }).
+- @threadplane/render exposes render-spec, defineAngularRegistry(), provideRender(), signalStateStore(), JSON Patch streaming, and A2UI support. Registry examples may pass [registry] directly to or configure provideRender({ registry }).
Never mention legacy names: streamResource, provideStreamResource, AgentRef, MockStreamTransport, createMockStreamResourceRef, createMockAgentRef, injectAgentRef, isStreaming, @cacheplane/angular, @cacheplane/render, @cacheplane/chat, @cacheplane/langgraph, AgentService, or chat-prebuilt.`;
@@ -67,9 +67,9 @@ interface WhitepaperConfig {
const WHITEPAPERS: Record = {
overview: {
id: 'overview',
- title: 'Agent UI for Angular',
+ title: 'Threadplane',
subtitle: 'Production-ready chat, threads, and generative UI for AI agents',
- eyebrow: 'ThreadPlane · Enterprise Angular Agent UI',
+ eyebrow: 'Threadplane · Enterprise Angular Agent UI',
coverGradient: 'linear-gradient(135deg, #fafbfc 0%, #eaf3ff 100%)',
outputPdf: 'apps/website/public/whitepaper.pdf',
outputHtml: 'apps/website/public/whitepaper-preview.html',
@@ -77,7 +77,7 @@ const WHITEPAPERS: Record = {
{
id: 'streaming-state',
title: 'Streaming State Management',
- prompt: `Write a 400-600 word chapter for an engineering white paper titled "Agent UI for Angular: Production-ready chat, threads, and generative UI for AI agents".
+ prompt: `Write a 400-600 word chapter for an engineering white paper titled "Threadplane: Production-ready chat, threads, and generative UI for AI agents".
Chapter topic: Streaming State Management
@@ -95,7 +95,7 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
{
id: 'thread-persistence',
title: 'Thread Persistence',
- prompt: `Write a 400-600 word chapter for an engineering white paper titled "Agent UI for Angular: Production-ready chat, threads, and generative UI for AI agents".
+ prompt: `Write a 400-600 word chapter for an engineering white paper titled "Threadplane: Production-ready chat, threads, and generative UI for AI agents".
Chapter topic: Thread Persistence
@@ -114,7 +114,7 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
{
id: 'tool-call-rendering',
title: 'Tool-Call Rendering',
- prompt: `Write a 400-600 word chapter for an engineering white paper titled "Agent UI for Angular: Production-ready chat, threads, and generative UI for AI agents".
+ prompt: `Write a 400-600 word chapter for an engineering white paper titled "Threadplane: Production-ready chat, threads, and generative UI for AI agents".
Chapter topic: Tool-Call Rendering
@@ -133,7 +133,7 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
{
id: 'human-approval-flows',
title: 'Human Approval Flows',
- prompt: `Write a 400-600 word chapter for an engineering white paper titled "Agent UI for Angular: Production-ready chat, threads, and generative UI for AI agents".
+ prompt: `Write a 400-600 word chapter for an engineering white paper titled "Threadplane: Production-ready chat, threads, and generative UI for AI agents".
Chapter topic: Human Approval Flows (Interrupts)
@@ -153,7 +153,7 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
{
id: 'generative-ui',
title: 'Generative UI',
- prompt: `Write a 400-600 word chapter for an engineering white paper titled "Agent UI for Angular: Production-ready chat, threads, and generative UI for AI agents".
+ prompt: `Write a 400-600 word chapter for an engineering white paper titled "Threadplane: Production-ready chat, threads, and generative UI for AI agents".
Chapter topic: Generative UI
@@ -161,7 +161,7 @@ Context: The most advanced production agents emit structured UI specs — not ju
Cover:
- The onCustomEvent pattern in LangGraph: how agents emit structured data
-- The @ngaf/render approach: json-render specs, defineAngularRegistry(),
+- The @threadplane/render approach: json-render specs, defineAngularRegistry(),
- How JSON patch streaming enables progressive UI updates (rows appearing as data arrives)
- The registry pattern: decoupling agent from component implementation
- Code example: defineAngularRegistry() registration (8-12 lines)
@@ -172,7 +172,7 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
{
id: 'deterministic-testing',
title: 'Deterministic Testing',
- prompt: `Write a 400-600 word chapter for an engineering white paper titled "Agent UI for Angular: Production-ready chat, threads, and generative UI for AI agents".
+ prompt: `Write a 400-600 word chapter for an engineering white paper titled "Threadplane: Production-ready chat, threads, and generative UI for AI agents".
Chapter topic: Deterministic Testing
@@ -195,7 +195,7 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
id: 'angular',
title: 'The Enterprise Guide to Agent UI in Angular',
subtitle: 'Ship LangGraph and AG-UI-compatible agents without building the plumbing',
- eyebrow: 'ThreadPlane · Angular Agent UI Guide',
+ eyebrow: 'Threadplane · Angular Agent UI Guide',
coverGradient: 'linear-gradient(135deg, #fafbfc 0%, #eaf3ff 100%)',
outputPdf: 'apps/website/public/whitepapers/angular.pdf',
outputHtml: 'apps/website/public/whitepapers/angular-preview.html',
@@ -226,7 +226,7 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
Chapter topic: The agent() API
-Context: @ngaf/langgraph exposes an Angular signals-based API for connecting LangGraph agents to Angular components. The core primitive is agent() — a function that returns reactive signals wired directly to the agent stream, with no manual subscription management, no zone-patching, and no token accumulation logic.
+Context: @threadplane/langgraph exposes an Angular signals-based API for connecting LangGraph agents to Angular components. The core primitive is agent() — a function that returns reactive signals wired directly to the agent stream, with no manual subscription management, no zone-patching, and no token accumulation logic.
Cover:
- How agent() returns a LangGraphAgent with typed signals: messages(), isLoading(), error(), interrupt(), and langGraph* raw signals
@@ -265,7 +265,7 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
Chapter topic: Interrupt & Approval Flows
-Context: Agents that take real-world actions — sending emails, executing queries, modifying records — must pause for human confirmation. LangGraph's interrupt() primitive enables this on the backend. @ngaf/langgraph surfaces it as a reactive signal, eliminating the need for polling, websockets, or custom resume endpoints.
+Context: Agents that take real-world actions — sending emails, executing queries, modifying records — must pause for human confirmation. LangGraph's interrupt() primitive enables this on the backend. @threadplane/langgraph surfaces it as a reactive signal, eliminating the need for polling, websockets, or custom resume endpoints.
Cover:
- How LangGraph interrupt() pauses graph execution and what the resume payload looks like
@@ -284,7 +284,7 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
Chapter topic: Full LangGraph Feature Coverage
-Context: Most Angular LLM integrations support basic chat. @ngaf/langgraph is designed for the full LangGraph feature surface: tool calls, subgraphs, time travel, and DeepAgent multi-agent coordination. Teams shouldn't have to drop down to raw SSE parsing to access advanced graph features.
+Context: Most Angular LLM integrations support basic chat. @threadplane/langgraph is designed for the full LangGraph feature surface: tool calls, subgraphs, time travel, and DeepAgent multi-agent coordination. Teams shouldn't have to drop down to raw SSE parsing to access advanced graph features.
Cover:
- Tool call streaming: how tool invocation events surface through the agent ref without manual parsing
@@ -322,7 +322,7 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
id: 'render',
title: 'The Enterprise Guide to Generative UI in Angular',
subtitle: 'Agents that render UI — without coupling to your frontend',
- eyebrow: '@ngaf/render · Enterprise Guide',
+ eyebrow: '@threadplane/render · Enterprise Guide',
coverGradient: 'linear-gradient(135deg, #fafbfc 0%, #e8f5e9 100%)',
outputPdf: 'apps/website/public/whitepapers/render.pdf',
outputHtml: 'apps/website/public/whitepapers/render-preview.html',
@@ -353,14 +353,14 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
Chapter topic: Declarative UI Specs & the json-render Standard
-Context: Vercel's json-render spec defines a framework-agnostic standard for describing UI as structured JSON. An agent emits a json-render document. A frontend interprets it. Neither side knows how the other is implemented. @ngaf/render implements this standard for Angular, with streaming JSON patch support on top.
+Context: Vercel's json-render spec defines a framework-agnostic standard for describing UI as structured JSON. An agent emits a json-render document. A frontend interprets it. Neither side knows how the other is implemented. @threadplane/render implements this standard for Angular, with streaming JSON patch support on top.
Cover:
- What a json-render document looks like: component name, props, children (concrete example)
- Why an open standard matters: portability across frameworks, LLM prompt stability, community tooling
- How the spec handles conditional rendering, iteration, and computed properties
- Google's A2UI spec and how it extends json-render for agent-specific patterns
-- The @ngaf/render implementation: directive consumes a json-render document
+- The @threadplane/render implementation: directive consumes a json-render document
- How LLMs generate valid json-render output: prompt patterns that produce spec-compliant JSON
Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engineers.`,
@@ -372,7 +372,7 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
Chapter topic: The Component Registry
-Context: A json-render document references components by name. The registry is what maps those names to actual Angular components. defineAngularRegistry() is the @ngaf/render API for declaring this mapping — it's the seam between the open standard and your specific component library.
+Context: A json-render document references components by name. The registry is what maps those names to actual Angular components. defineAngularRegistry() is the @threadplane/render API for declaring this mapping — it's the seam between the open standard and your specific component library.
Cover:
- How defineAngularRegistry() maps string component names to Angular component classes
@@ -392,7 +392,7 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
Chapter topic: Streaming JSON Patches
-Context: Generative UI is most powerful when it streams. A data table with 50 rows should appear progressively — rows rendering as the agent produces them, not after a 3-second wait for the full JSON payload. @ngaf/render uses JSON Patch (RFC 6902) to apply incremental updates to the UI spec as it streams, enabling skeleton states and progressive rendering.
+Context: Generative UI is most powerful when it streams. A data table with 50 rows should appear progressively — rows rendering as the agent produces them, not after a 3-second wait for the full JSON payload. @threadplane/render uses JSON Patch (RFC 6902) to apply incremental updates to the UI spec as it streams, enabling skeleton states and progressive rendering.
Cover:
- Why streaming full JSON documents on each update is impractical for large UI specs
@@ -400,7 +400,7 @@ Cover:
- How the agent emits patch operations instead of full spec replacements
- Partial-JSON parsing: rendering valid portions of an incomplete JSON stream
- Skeleton states: how to show placeholder UI while the spec is still arriving
-- Code example: consuming streaming patch events in a @ngaf/render component (8-12 lines)
+- Code example: consuming streaming patch events in a @threadplane/render component (8-12 lines)
- Performance: why patch-based updates are O(change) not O(spec size)
Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engineers.`,
@@ -412,7 +412,7 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
Chapter topic: State Management & Computed Functions
-Context: Static UI specs only go so far. Production generative UI needs computed properties — values derived from other spec fields — and repeat loops for rendering collections. @ngaf/render's signalStateStore() and computed function support bring dynamic behavior into the spec without requiring custom component logic.
+Context: Static UI specs only go so far. Production generative UI needs computed properties — values derived from other spec fields — and repeat loops for rendering collections. @threadplane/render's signalStateStore() and computed function support bring dynamic behavior into the spec without requiring custom component logic.
Cover:
- signalStateStore(): agent-managed state that components can read and update
@@ -432,7 +432,7 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
id: 'chat',
title: 'The Enterprise Guide to Agent Chat Interfaces in Angular',
subtitle: 'Production agent chat UI in days, not sprints',
- eyebrow: '@ngaf/chat · Enterprise Guide',
+ eyebrow: '@threadplane/chat · Enterprise Guide',
coverGradient: 'linear-gradient(135deg, #fafbfc 0%, #f3e8ff 100%)',
outputPdf: 'apps/website/public/whitepapers/chat.pdf',
outputHtml: 'apps/website/public/whitepapers/chat-preview.html',
@@ -452,7 +452,7 @@ Cover:
- The hidden costs: accessibility is harder than it looks, streaming token display has edge cases, tool call state machines are complex
- What "good enough for demo" looks like vs. what production chat UI actually requires
- The opportunity cost: senior Angular engineers spending sprints on chat chrome instead of agent integration
-- The @ngaf/chat thesis: ship the chat UI on day one, spend the sprints on what differentiates your product
+- The @threadplane/chat thesis: ship the chat UI on day one, spend the sprints on what differentiates your product
Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engineers.`,
},
@@ -463,13 +463,13 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
Chapter topic: Batteries-Included Components
-Context: @ngaf/chat ships two tiers of components: headless primitives that own behavior and state with no styling opinions, and prebuilt components that are production-ready out of the box. Teams choose the tier that matches their customization needs.
+Context: @threadplane/chat ships two tiers of components: headless primitives that own behavior and state with no styling opinions, and prebuilt components that are production-ready out of the box. Teams choose the tier that matches their customization needs.
Cover:
- The headless tier: chat-messages, chat-input, chat-tool-calls, chat-interrupt — behavior without styling
- The prebuilt composition tier: plus companion components for a full chat interface with minimal configuration
- How the two tiers compose: using prebuilt for 90% of UI, dropping to headless for custom sections
-- The component model: how @ngaf/chat connects to the runtime-neutral Agent contract from @ngaf/langgraph
+- The component model: how @threadplane/chat connects to the runtime-neutral Agent contract from @threadplane/langgraph
- Message rendering: how Message[] from the agent signal maps to chat message display
- Code example: with an agent instance (6-10 lines)
- When to use headless vs. prebuilt and how to migrate between them
@@ -483,10 +483,10 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
Chapter topic: Theming & Design System Integration
-Context: Chat UI that looks like a generic chatbot is a product liability. Enterprise teams need chat components that match their design system — typography, color palette, border radius, spacing. @ngaf/chat uses CSS custom properties and design tokens to make this integration straightforward without requiring component source access.
+Context: Chat UI that looks like a generic chatbot is a product liability. Enterprise teams need chat components that match their design system — typography, color palette, border radius, spacing. @threadplane/chat uses CSS custom properties and design tokens to make this integration straightforward without requiring component source access.
Cover:
-- The CSS custom property API: how @ngaf/chat exposes design decisions as variables
+- The CSS custom property API: how @threadplane/chat exposes design decisions as variables
- Design token mapping: aligning chat component tokens with your existing design system tokens
- Typography integration: font family, size scale, and line height control
- Color system integration: surface colors, text colors, accent colors, and semantic state colors
@@ -503,13 +503,13 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
Chapter topic: Generative UI in Chat
-Context: The most capable agent chat interfaces don't just display text — they render agent-generated UI directly in the message stream. A financial agent renders a live data table. A scheduling agent renders a booking form. @ngaf/chat supports both the json-render spec and Google's A2UI spec out of the box, with streaming patch support.
+Context: The most capable agent chat interfaces don't just display text — they render agent-generated UI directly in the message stream. A financial agent renders a live data table. A scheduling agent renders a booking form. @threadplane/chat supports both the json-render spec and Google's A2UI spec out of the box, with streaming patch support.
Cover:
- How generative UI messages appear in the chat message stream alongside text messages
- The json-render spec: how agents emit structured UI specs that chat renders automatically
- Google's A2UI spec: what it adds for agent-specific UI patterns (actions, approvals, structured data)
-- How @ngaf/chat integrates with @ngaf/render for component resolution
+- How @threadplane/chat integrates with @threadplane/render for component resolution
- The registry pattern in a chat context: registering custom components that agents can emit
- Code example: enabling generative UI in chat with a component registry (8-12 lines)
- Progressive rendering: how streaming JSON patches create the live UI update effect in chat
@@ -523,7 +523,7 @@ Tone: Direct, technical, peer-to-peer. No fluff. Audience is senior Angular engi
Chapter topic: Debug Tooling
-Context: Debugging agent chat is hard. The message stream is opaque, tool call state transitions are fast, and interrupt flows have timing edge cases. chat-debug is @ngaf/chat/debug's built-in debug panel — a developer overlay that surfaces agent state, raw message events, tool call history, and interrupt state in real time.
+Context: Debugging agent chat is hard. The message stream is opaque, tool call state transitions are fast, and interrupt flows have timing edge cases. chat-debug is @threadplane/chat/debug's built-in debug panel — a developer overlay that surfaces agent state, raw message events, tool call history, and interrupt state in real time.
Cover:
- What chat-debug shows: Message[] state, streaming event log, tool call state machine, interrupt payload
@@ -681,7 +681,7 @@ async function generateWhitepaper(config: WhitepaperConfig): Promise {
// ── Main ─────────────────────────────────────────────────────────────────
async function main() {
- console.log('ThreadPlane White Paper Generator\n');
+ console.log('Threadplane White Paper Generator\n');
console.log(`Model: ${MODEL}`);
const paperArg = process.argv.find(a => a.startsWith('--paper='))?.split('=')[1]
diff --git a/apps/website/src/app/ag-ui/page.tsx b/apps/website/src/app/ag-ui/page.tsx
index 3631e4492..8e3f88196 100644
--- a/apps/website/src/app/ag-ui/page.tsx
+++ b/apps/website/src/app/ag-ui/page.tsx
@@ -1,5 +1,5 @@
import Link from 'next/link';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../../components/ui/Container';
import { Section } from '../../components/ui/Section';
import { Eyebrow } from '../../components/ui/Eyebrow';
@@ -12,7 +12,7 @@ import { BackendsGrid } from '../../components/landing/ag-ui/BackendsGrid';
import { createPageMetadata, SHORT_POSITIONING_DESCRIPTION } from '../../lib/site-metadata';
export const metadata = createPageMetadata({
- title: '@ngaf/ag-ui — Agent UI for Angular',
+ title: '@threadplane/ag-ui — Threadplane',
description: SHORT_POSITIONING_DESCRIPTION,
pathname: '/ag-ui',
type: 'website',
@@ -25,7 +25,7 @@ export default async function AgUiPage() {
- @ngaf/ag-ui
+ @threadplane/ag-ui
- See @ngaf/langgraph
+ See @threadplane/langgraph
{' '}
for native streaming, checkpoints, and the typed LangGraph SDK path.
@@ -88,7 +88,7 @@ export default async function AgUiPage() {
id="backends"
eyebrow="Runtime choice"
headline="Pick a backend. Keep the UI."
- body="The AG-UI protocol decouples your agent runtime from your front-end. @ngaf/ag-ui wraps any AG-UI AbstractAgent into the runtime-neutral Agent contract that @ngaf/chat consumes — so the same Angular components ship against eight different runtimes."
+ body="The AG-UI protocol decouples your agent runtime from your front-end. @threadplane/ag-ui wraps any AG-UI AbstractAgent into the runtime-neutral Agent contract that @threadplane/chat consumes — so the same Angular components ship against eight different runtimes."
bullets={[
'Stream from Python, .NET, or TypeScript backends — same chat primitives',
'Swap runtimes without rewriting the UI layer',
@@ -107,8 +107,8 @@ export default async function AgUiPage() {
-{`import { provideAgUiAgent, AG_UI_AGENT } from '@ngaf/ag-ui';
-import { ChatComponent } from '@ngaf/chat';
+{`import { provideAgUiAgent, AG_UI_AGENT } from '@threadplane/ag-ui';
+import { ChatComponent } from '@threadplane/chat';
// app.config.ts
export const appConfig: ApplicationConfig = {
diff --git a/apps/website/src/app/api/email-preview/route.ts b/apps/website/src/app/api/email-preview/route.ts
index d10f0eb4d..2d393afc0 100644
--- a/apps/website/src/app/api/email-preview/route.ts
+++ b/apps/website/src/app/api/email-preview/route.ts
@@ -16,11 +16,11 @@ const TEMPLATES: Record { subject: string; html: string }> = {
html: whitepaperDownloadHtml('Brian'),
}),
'newsletter-welcome': () => ({
- subject: 'Welcome to Agent UI for Angular updates',
+ subject: 'Welcome to Threadplane updates',
html: newsletterWelcomeHtml(),
}),
'lead-notification': () => ({
- subject: 'New lead: Brian at ThreadPlane',
+ subject: 'New lead: Brian at Threadplane',
html: leadNotificationHtml({
name: 'Sample Lead',
email: 'demo@example.com',
diff --git a/apps/website/src/app/api/ingest/route.ts b/apps/website/src/app/api/ingest/route.ts
index eae7deefa..a5e573e2a 100644
--- a/apps/website/src/app/api/ingest/route.ts
+++ b/apps/website/src/app/api/ingest/route.ts
@@ -1,6 +1,6 @@
import { PostHog } from 'posthog-node';
import { NextRequest, NextResponse } from 'next/server';
-import { normalizePostHogHost, toSafeAnalyticsString } from '@ngaf/telemetry/shared';
+import { normalizePostHogHost, toSafeAnalyticsString } from '@threadplane/telemetry/shared';
const PUBLIC_INGEST_KEY = 'phc_public_cacheplane_telemetry';
diff --git a/apps/website/src/app/api/leads/route.spec.ts b/apps/website/src/app/api/leads/route.spec.ts
index d011fe78f..d7a455d2e 100644
--- a/apps/website/src/app/api/leads/route.spec.ts
+++ b/apps/website/src/app/api/leads/route.spec.ts
@@ -20,7 +20,7 @@ vi.mock('fs', () => ({
}));
vi.mock('../../../../lib/resend', () => ({
- FROM: 'Agent UI for Angular ',
+ FROM: 'Threadplane ',
NOTIFY_TO: 'hello@cacheplane.ai',
sendEmail: sendEmailMock,
addToAudience: addToAudienceMock,
@@ -76,7 +76,7 @@ describe('/api/leads', () => {
name: 'Jane Smith',
email: 'jane@acme.com',
company: 'Acme',
- message: 'We are evaluating Agent UI for Angular.',
+ message: 'We are evaluating Threadplane.',
}) as never);
expect(response.status).toBe(200);
@@ -87,7 +87,7 @@ describe('/api/leads', () => {
'utf8',
);
expect(sendEmailMock).toHaveBeenCalledWith(expect.objectContaining({
- from: 'Agent UI for Angular ',
+ from: 'Threadplane ',
to: 'hello@cacheplane.ai',
subject: 'New lead: Jane Smith at Acme',
html: expect.stringContaining('jane@acme.com'),
@@ -131,9 +131,9 @@ describe('/api/newsletter', () => {
expect(response.status).toBe(200);
expect(sendEmailMock).toHaveBeenCalledWith(expect.objectContaining({
- from: 'Agent UI for Angular ',
+ from: 'Threadplane ',
to: 'reader@acme.com',
- subject: 'Welcome to Agent UI for Angular updates',
+ subject: 'Welcome to Threadplane updates',
}));
expect(addToAudienceMock).toHaveBeenCalledWith('reader@acme.com');
expect(loopsUpsertContactMock).toHaveBeenCalledWith(expect.objectContaining({
@@ -166,7 +166,7 @@ describe('/api/whitepaper-signup', () => {
'utf8',
);
expect(sendEmailMock).toHaveBeenCalledWith(expect.objectContaining({
- from: 'Agent UI for Angular ',
+ from: 'Threadplane ',
to: 'reader@acme.com',
subject: 'Your Enterprise Guide to Agent Chat Interfaces',
html: expect.stringContaining('https://threadplane.ai/whitepapers/chat.pdf'),
diff --git a/apps/website/src/app/api/leads/route.ts b/apps/website/src/app/api/leads/route.ts
index f8cd7dd10..e6b74a52b 100644
--- a/apps/website/src/app/api/leads/route.ts
+++ b/apps/website/src/app/api/leads/route.ts
@@ -5,7 +5,7 @@ import { sendEmail, FROM, NOTIFY_TO, addToAudience } from '../../../../lib/resen
import { loopsUpsertContact, loopsSendEvent } from '../../../../lib/loops';
import { leadNotificationHtml } from '../../../../emails/lead-notification';
import { captureLeadConversion, captureLeadQualified } from '../../../lib/analytics/server';
-import { getSourcePage } from '@ngaf/telemetry/shared';
+import { getSourcePage } from '@threadplane/telemetry/shared';
const LEADS_FILE = path.join(process.cwd(), 'data', 'leads.ndjson');
diff --git a/apps/website/src/app/api/newsletter/route.ts b/apps/website/src/app/api/newsletter/route.ts
index f733fa696..07277aef4 100644
--- a/apps/website/src/app/api/newsletter/route.ts
+++ b/apps/website/src/app/api/newsletter/route.ts
@@ -3,7 +3,7 @@ import { sendEmail, FROM, addToAudience } from '../../../../lib/resend';
import { loopsUpsertContact, loopsSendEvent } from '../../../../lib/loops';
import { newsletterWelcomeHtml } from '../../../../emails/newsletter-welcome';
import { captureNewsletterConversion } from '../../../lib/analytics/server';
-import { getSourcePage } from '@ngaf/telemetry/shared';
+import { getSourcePage } from '@threadplane/telemetry/shared';
export async function POST(req: NextRequest) {
let body: { email?: string };
@@ -26,7 +26,7 @@ export async function POST(req: NextRequest) {
sendEmail({
from: FROM,
to: email,
- subject: 'Welcome to Agent UI for Angular updates',
+ subject: 'Welcome to Threadplane updates',
html: newsletterWelcomeHtml(),
}),
addToAudience(email),
diff --git a/apps/website/src/app/api/whitepaper-signup/route.ts b/apps/website/src/app/api/whitepaper-signup/route.ts
index db8c4ba4b..1df09c269 100644
--- a/apps/website/src/app/api/whitepaper-signup/route.ts
+++ b/apps/website/src/app/api/whitepaper-signup/route.ts
@@ -9,7 +9,7 @@ import { angularDownloadHtml } from '../../../../emails/angular-download';
import { renderDownloadHtml } from '../../../../emails/render-download';
import { chatDownloadHtml } from '../../../../emails/chat-download';
import { captureWhitepaperConversion } from '../../../lib/analytics/server';
-import { getSourcePage } from '@ngaf/telemetry/shared';
+import { getSourcePage } from '@threadplane/telemetry/shared';
const SIGNUPS_FILE = path.join(process.cwd(), 'data', 'whitepaper-signups.ndjson');
diff --git a/apps/website/src/app/blog/[slug]/opengraph-image.tsx b/apps/website/src/app/blog/[slug]/opengraph-image.tsx
index 6ab822c68..cf9f4a28d 100644
--- a/apps/website/src/app/blog/[slug]/opengraph-image.tsx
+++ b/apps/website/src/app/blog/[slug]/opengraph-image.tsx
@@ -3,7 +3,7 @@ import { getPostBySlug } from '../../../lib/blog';
import { getAuthor } from '../../../lib/blog-authors';
export const runtime = 'nodejs';
-export const alt = 'ThreadPlane blog post';
+export const alt = 'Threadplane blog post';
export const size = { width: 1200, height: 630 };
export const contentType = 'image/png';
@@ -61,7 +61,7 @@ export default async function og({ params }: Params) {
fontSize: 64,
}}
>
- ThreadPlane
+ Threadplane
),
size,
@@ -103,7 +103,7 @@ export default async function og({ params }: Params) {
opacity: 0.6,
}}
>
- ThreadPlane Blog
+ Threadplane Blog
{
const { slug } = await params;
const post = getPostBySlug(slug);
if (!post || post.frontmatter.draft) {
- return { title: 'Post not found — ThreadPlane' };
+ return { title: 'Post not found — Threadplane' };
}
return createPageMetadata({
- title: `${post.frontmatter.title} — ThreadPlane`,
+ title: `${post.frontmatter.title} — Threadplane`,
description: post.frontmatter.description,
pathname: `/blog/${post.slug}`,
type: 'article',
diff --git a/apps/website/src/app/blog/page.tsx b/apps/website/src/app/blog/page.tsx
index 469c2202a..c77e5e82b 100644
--- a/apps/website/src/app/blog/page.tsx
+++ b/apps/website/src/app/blog/page.tsx
@@ -5,7 +5,7 @@ import { PostCard } from '../../components/blog/PostCard';
import { TagChips } from '../../components/blog/TagChips';
export const metadata = createPageMetadata({
- title: 'Blog — ThreadPlane',
+ title: 'Blog — Threadplane',
description:
'Long-form writing on agent UI for Angular: streaming, generative UI, threads, interrupts, production patterns.',
pathname: '/blog',
@@ -39,7 +39,7 @@ export default function BlogIndexPage() {
marginBottom: 12,
}}
>
- Notes from ThreadPlane
+ Notes from Threadplane
Writing on agent UI for Angular — production patterns, design choices,
diff --git a/apps/website/src/app/blog/rss.xml/route.ts b/apps/website/src/app/blog/rss.xml/route.ts
index bab3ed0d7..a6ad5b3f8 100644
--- a/apps/website/src/app/blog/rss.xml/route.ts
+++ b/apps/website/src/app/blog/rss.xml/route.ts
@@ -31,7 +31,7 @@ export async function GET() {
const xml = `
- ${escapeXml('ThreadPlane Blog')}
+ ${escapeXml('Threadplane Blog')}
${SITE_ORIGIN}/blog
${escapeXml('Writing on agent UI for Angular.')}
diff --git a/apps/website/src/app/chat/page.tsx b/apps/website/src/app/chat/page.tsx
index 11c0ff847..a8cc9a636 100644
--- a/apps/website/src/app/chat/page.tsx
+++ b/apps/website/src/app/chat/page.tsx
@@ -1,4 +1,4 @@
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../../components/ui/Container';
import { Section } from '../../components/ui/Section';
import { Eyebrow } from '../../components/ui/Eyebrow';
@@ -12,7 +12,7 @@ import { ChatLandingCodeShowcase } from '../../components/landing/chat-landing/C
import { createPageMetadata } from '../../lib/site-metadata';
export const metadata = createPageMetadata({
- title: '@ngaf/chat — Batteries-Included Agent Chat for Angular',
+ title: '@threadplane/chat — Batteries-Included Agent Chat for Angular',
description: 'Production agent chat UI in days, not sprints. Built on Vercel json-render and Google A2UI specs.',
pathname: '/chat',
type: 'website',
@@ -25,7 +25,7 @@ export default async function ChatPage() {
- @ngaf/chat
+ @threadplane/chat
diff --git a/apps/website/src/app/contact/page.tsx b/apps/website/src/app/contact/page.tsx
index dc8e6dcc2..81d2f6d7a 100644
--- a/apps/website/src/app/contact/page.tsx
+++ b/apps/website/src/app/contact/page.tsx
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
import React, { Suspense } from 'react';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../../components/ui/Container';
import { Section } from '../../components/ui/Section';
import { Eyebrow } from '../../components/ui/Eyebrow';
@@ -11,7 +11,7 @@ import { AltChannelRow } from '../../components/contact/AltChannelRow';
import { createPageMetadata } from '../../lib/site-metadata';
export const metadata = createPageMetadata({
- title: 'Talk to an engineer — ThreadPlane',
+ title: 'Talk to an engineer — Threadplane',
description: "Tell us what you're shipping. We'll reply within one business day — usually with code, not a calendar invite.",
pathname: '/contact',
type: 'website',
diff --git a/apps/website/src/app/docs/[library]/[section]/[slug]/page.tsx b/apps/website/src/app/docs/[library]/[section]/[slug]/page.tsx
index 80292566f..91461102e 100644
--- a/apps/website/src/app/docs/[library]/[section]/[slug]/page.tsx
+++ b/apps/website/src/app/docs/[library]/[section]/[slug]/page.tsx
@@ -1,6 +1,6 @@
import type { Metadata } from 'next';
import { notFound } from 'next/navigation';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { DocsSidebar } from '../../../../../components/docs/DocsSidebar';
import { MdxRenderer } from '../../../../../components/docs/MdxRenderer';
import { DocsSearch } from '../../../../../components/docs/DocsSearch';
@@ -45,8 +45,8 @@ export function generateStaticParams() {
export async function generateMetadata({ params }: DocsRouteProps): Promise {
const { library, section, slug } = await params;
return getDocMetadata(library, section, slug) ?? {
- title: 'Docs - Agent UI for Angular',
- description: 'Agent UI for Angular documentation',
+ title: 'Docs - Threadplane',
+ description: 'Threadplane documentation',
};
}
diff --git a/apps/website/src/app/docs/licensing/page.tsx b/apps/website/src/app/docs/licensing/page.tsx
index 5d67167e6..4ea88c709 100644
--- a/apps/website/src/app/docs/licensing/page.tsx
+++ b/apps/website/src/app/docs/licensing/page.tsx
@@ -1,5 +1,5 @@
import Link from 'next/link';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../../../components/ui/Container';
import { Section } from '../../../components/ui/Section';
import { Eyebrow } from '../../../components/ui/Eyebrow';
@@ -7,9 +7,9 @@ import { Button } from '../../../components/ui/Button';
import { createPageMetadata } from '../../../lib/site-metadata';
export const metadata = createPageMetadata({
- title: 'Licensing — ThreadPlane',
+ title: 'Licensing — Threadplane',
description:
- 'How the ThreadPlane Commercial license works, who needs one, and how to install your license token in @ngaf/chat.',
+ 'How the Threadplane Commercial license works, who needs one, and how to install your license token in @threadplane/chat.',
pathname: '/docs/licensing',
type: 'website',
});
@@ -113,7 +113,7 @@ export default function LicensingPage() {
maxWidth: '60ch',
}}
>
- How the ThreadPlane licensing model works, who needs a paid license, and how to install your license token.
+ How the Threadplane licensing model works, who needs a paid license, and how to install your license token.
@@ -124,22 +124,22 @@ export default function LicensingPage() {
The model
- Agent UI for Angular is a suite of libraries. Most are{' '}
+ Threadplane is a suite of libraries. Most are{' '}
MIT-licensed and free for any use,
- commercial or not. Only @ngaf/chat is
+ commercial or not. Only @threadplane/chat is
dual-licensed.
- @ngaf/chat is source-available under{' '}
+ @threadplane/chat is source-available under{' '}
PolyForm Noncommercial 1.0.0 for free
- noncommercial use, or a ThreadPlane Commercial license{' '}
+ noncommercial use, or a Threadplane Commercial license{' '}
for production use inside a for-profit context. The same source ships under both — you don't get a
different build.
Do you need a paid license?
- You need a ThreadPlane Commercial license if you use @ngaf/chat{' '}
+ You need a Threadplane Commercial license if you use @threadplane/chat{' '}
in any of:
@@ -164,13 +164,13 @@ export default function LicensingPage() {
Install your license
- After purchase, ThreadPlane emails a signed license token to the address on your receipt. Paste it
+ After purchase, Threadplane emails a signed license token to the address on your receipt. Paste it
into your app's provideChat(){' '}
configuration:
Pick the tier that matches how you'll deploy. All paid tiers grant the same{' '}
- ThreadPlane Commercial license; the difference is the scope of use and the number of seats.
+ Threadplane Commercial license; the difference is the scope of use and the number of seats.
- You may use @ngaf/chat commercially
+ You may use @threadplane/chat commercially
for 30 calendar days from your first
commercial use as a good-faith evaluation. There is no telemetry, no registration, no email check —
we trust you to count the days. After 30 days you must either purchase a license or stop the
diff --git a/apps/website/src/app/docs/page.tsx b/apps/website/src/app/docs/page.tsx
index c3d878a67..08b6f683e 100644
--- a/apps/website/src/app/docs/page.tsx
+++ b/apps/website/src/app/docs/page.tsx
@@ -1,5 +1,5 @@
import Link from 'next/link';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../../components/ui/Container';
import { Section } from '../../components/ui/Section';
import { Eyebrow } from '../../components/ui/Eyebrow';
@@ -9,8 +9,8 @@ import { docsConfig } from '../../lib/docs-config';
import { createPageMetadata } from '../../lib/site-metadata';
export const metadata = createPageMetadata({
- title: 'Documentation — Agent UI for Angular',
- description: 'Learn the framework. Library guides, API reference, and production patterns for Agent UI for Angular.',
+ title: 'Documentation — Threadplane',
+ description: 'Learn the framework. Library guides, API reference, and production patterns for Threadplane.',
pathname: '/docs',
type: 'website',
});
@@ -24,7 +24,7 @@ interface PopularTopic {
const POPULAR_TOPICS: PopularTopic[] = [
{
title: 'Streaming with signals',
- description: 'Token-level streaming wired into Angular signals. The defining @ngaf/langgraph capability.',
+ description: 'Token-level streaming wired into Angular signals. The defining @threadplane/langgraph capability.',
href: '/docs/agent/api/agent',
},
{
@@ -72,7 +72,7 @@ export default function DocsLandingPage() {
maxWidth: '52ch',
}}
>
- Agent UI for Angular is a suite of MIT-licensed libraries for building AI agent interfaces. Pick a library to get started.
+ Threadplane is a suite of MIT-licensed libraries for building AI agent interfaces. Pick a library to get started.
diff --git a/apps/website/src/app/error.tsx b/apps/website/src/app/error.tsx
index aeef6bf86..73ca655e3 100644
--- a/apps/website/src/app/error.tsx
+++ b/apps/website/src/app/error.tsx
@@ -1,7 +1,7 @@
'use client';
import { useEffect } from 'react';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../components/ui/Container';
import { Section } from '../components/ui/Section';
import { Eyebrow } from '../components/ui/Eyebrow';
diff --git a/apps/website/src/app/global.css b/apps/website/src/app/global.css
index 112e18fc0..99c708a3c 100644
--- a/apps/website/src/app/global.css
+++ b/apps/website/src/app/global.css
@@ -1,5 +1,5 @@
@import "tailwindcss";
-@import "@ngaf/design-tokens/theme.css";
+@import "@threadplane/design-tokens/theme.css";
* {
box-sizing: border-box;
diff --git a/apps/website/src/app/langgraph/page.tsx b/apps/website/src/app/langgraph/page.tsx
index b922128e5..0c3208813 100644
--- a/apps/website/src/app/langgraph/page.tsx
+++ b/apps/website/src/app/langgraph/page.tsx
@@ -1,4 +1,4 @@
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../../components/ui/Container';
import { Section } from '../../components/ui/Section';
import { Eyebrow } from '../../components/ui/Eyebrow';
@@ -12,7 +12,7 @@ import { LangGraphCodeShowcase } from '../../components/landing/langgraph/LangGr
import { createPageMetadata, SHORT_POSITIONING_DESCRIPTION } from '../../lib/site-metadata';
export const metadata = createPageMetadata({
- title: '@ngaf/langgraph — Agent UI for Angular',
+ title: '@threadplane/langgraph — Threadplane',
description: SHORT_POSITIONING_DESCRIPTION,
pathname: '/langgraph',
type: 'website',
@@ -25,7 +25,7 @@ export default async function LangGraphPage() {
- @ngaf/langgraph
+ @threadplane/langgraph
-{`import { provideAgent } from '@ngaf/langgraph';
+{`import { provideAgent } from '@threadplane/langgraph';
export const appConfig: ApplicationConfig = {
providers: [
diff --git a/apps/website/src/app/layout.tsx b/apps/website/src/app/layout.tsx
index 82194bd21..e567dd5c3 100644
--- a/apps/website/src/app/layout.tsx
+++ b/apps/website/src/app/layout.tsx
@@ -38,7 +38,7 @@ export const metadata: Metadata = {
icon: 'data:image/svg+xml,',
},
openGraph: {
- title: 'Agent UI for Angular',
+ title: 'Threadplane',
description: LONG_SUBHEAD,
type: 'website',
siteName: SITE_NAME,
@@ -47,7 +47,7 @@ export const metadata: Metadata = {
},
twitter: {
card: 'summary_large_image',
- title: 'Agent UI for Angular',
+ title: 'Threadplane',
description: LONG_SUBHEAD,
images: [DEFAULT_SOCIAL_IMAGE],
},
diff --git a/apps/website/src/app/llms-full.txt/route.ts b/apps/website/src/app/llms-full.txt/route.ts
index 1dd2d4655..8c15ab9ab 100644
--- a/apps/website/src/app/llms-full.txt/route.ts
+++ b/apps/website/src/app/llms-full.txt/route.ts
@@ -48,7 +48,7 @@ function loadAllPrompts(): string {
export async function GET() {
const sections = [
- '# Agent UI for Angular — Full Reference\n\nSee /llms.txt for a compact summary.\n',
+ '# Threadplane — Full Reference\n\nSee /llms.txt for a compact summary.\n',
'## API Reference (TypeDoc)\n\n' + loadApiDocs(),
'## Prompt Recipes\n\n' + loadAllPrompts(),
[
diff --git a/apps/website/src/app/llms.txt/route.ts b/apps/website/src/app/llms.txt/route.ts
index 303fa1e7d..ce83bd0fe 100644
--- a/apps/website/src/app/llms.txt/route.ts
+++ b/apps/website/src/app/llms.txt/route.ts
@@ -16,24 +16,24 @@ function loadVersion(): string {
function buildLlmsTxt(): string {
const version = loadVersion();
return [
- `# Agent UI for Angular v${version}`,
+ `# Threadplane v${version}`,
'',
- "Agent UI for Angular is a runtime-neutral chat UI SDK for Angular. The @ngaf/chat library provides streaming chat primitives bound to a runtime-neutral 'Agent' contract; runtime adapters (@ngaf/langgraph, @ngaf/ag-ui) translate between the contract and the actual backend.",
+ "Threadplane is a runtime-neutral chat UI SDK for Angular. The @threadplane/chat library provides streaming chat primitives bound to a runtime-neutral 'Agent' contract; runtime adapters (@threadplane/langgraph, @threadplane/ag-ui) translate between the contract and the actual backend.",
'',
'## Packages',
- '- @ngaf/chat — chat UI primitives (messages, input, tool calls, interrupt, debug, etc.) consuming the Agent contract',
- '- @ngaf/langgraph — adapter for LangGraph / LangGraph Platform',
- '- @ngaf/ag-ui — adapter for any AG-UI-compatible backend (CrewAI, Mastra, Microsoft AF, AG2, Pydantic AI, AWS Strands, CopilotKit runtime)',
- '- @ngaf/render — generative UI runtime (Vercel json-render + Google A2UI)',
- '- @ngaf/a2ui — protocol types, JSONL parser, dynamic value resolver, and pointer helpers for A2UI streams',
- '- @ngaf/licensing — offline license verification and non-blocking package check helpers',
- '- @ngaf/telemetry — browser, Node, and shared telemetry helpers with privacy controls',
+ '- @threadplane/chat — chat UI primitives (messages, input, tool calls, interrupt, debug, etc.) consuming the Agent contract',
+ '- @threadplane/langgraph — adapter for LangGraph / LangGraph Platform',
+ '- @threadplane/ag-ui — adapter for any AG-UI-compatible backend (CrewAI, Mastra, Microsoft AF, AG2, Pydantic AI, AWS Strands, CopilotKit runtime)',
+ '- @threadplane/render — generative UI runtime (Vercel json-render + Google A2UI)',
+ '- @threadplane/a2ui — protocol types, JSONL parser, dynamic value resolver, and pointer helpers for A2UI streams',
+ '- @threadplane/licensing — offline license verification and non-blocking package check helpers',
+ '- @threadplane/telemetry — browser, Node, and shared telemetry helpers with privacy controls',
'',
'## Install',
'# LangGraph backend:',
- 'npm install @ngaf/chat @ngaf/langgraph',
+ 'npm install @threadplane/chat @threadplane/langgraph',
'# AG-UI backend:',
- 'npm install @ngaf/chat @ngaf/ag-ui',
+ 'npm install @threadplane/chat @threadplane/ag-ui',
'',
'## Key API',
'- LangGraphAgent — unified type returned by agent(); exposes messages/status/isLoading/error/toolCalls/history signals + submit/stop methods',
@@ -43,15 +43,15 @@ function buildLlmsTxt(): string {
'- runAgentConformance / runAgentWithHistoryConformance — conformance suites for adapter authors',
'',
'## Minimal LangGraph example',
- "import { agent } from '@ngaf/langgraph';",
- "import { ChatComponent } from '@ngaf/chat';",
+ "import { agent } from '@threadplane/langgraph';",
+ "import { ChatComponent } from '@threadplane/chat';",
'// In a component:',
"chat = agent({ apiUrl: 'http://localhost:2024', assistantId: 'chat' });",
'// Template: ',
'',
'## Minimal AG-UI example',
- "import { provideAgUiAgent, AG_UI_AGENT } from '@ngaf/ag-ui';",
- "import { ChatComponent } from '@ngaf/chat';",
+ "import { provideAgUiAgent, AG_UI_AGENT } from '@threadplane/ag-ui';",
+ "import { ChatComponent } from '@threadplane/chat';",
"// app.config.ts: providers: [provideAgUiAgent({ url: 'https://your.endpoint' })]",
"// Component: agent = inject(AG_UI_AGENT);",
'// Template: ',
diff --git a/apps/website/src/app/not-found.tsx b/apps/website/src/app/not-found.tsx
index 86fd6774b..1c3857d60 100644
--- a/apps/website/src/app/not-found.tsx
+++ b/apps/website/src/app/not-found.tsx
@@ -1,11 +1,11 @@
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../components/ui/Container';
import { Section } from '../components/ui/Section';
import { Eyebrow } from '../components/ui/Eyebrow';
import { Button } from '../components/ui/Button';
export const metadata = {
- title: 'Page not found — Agent UI for Angular',
+ title: 'Page not found — Threadplane',
description: 'The page you were looking for doesn’t exist.',
};
diff --git a/apps/website/src/app/opengraph-image.tsx b/apps/website/src/app/opengraph-image.tsx
index 6c14de15f..07a3a2f2e 100644
--- a/apps/website/src/app/opengraph-image.tsx
+++ b/apps/website/src/app/opengraph-image.tsx
@@ -99,7 +99,7 @@ export default async function OpenGraphImage() {
marginBottom: 28,
}}
>
- Agent UI for Angular · MIT
+ Threadplane · MIT
{/* Headline — EB Garamond serif matches marketing-site h1 */}
diff --git a/apps/website/src/app/page.tsx b/apps/website/src/app/page.tsx
index f1fc65f4d..0a450505d 100644
--- a/apps/website/src/app/page.tsx
+++ b/apps/website/src/app/page.tsx
@@ -9,7 +9,7 @@ import { WhitePaperBlock } from '../components/landing/WhitePaperBlock';
import { Promises } from '../components/landing/Promises';
import { HomeFAQ } from '../components/landing/HomeFAQ';
import { FinalCTA } from '../components/landing/FinalCTA';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { createPageMetadata, LONG_SUBHEAD, PRIMARY_TAGLINE } from '../lib/site-metadata';
export const metadata = createPageMetadata({
@@ -39,7 +39,7 @@ export default async function HomePage() {
bullets={[
'Headless chat and durable thread state',
'Interrupts, tool progress, branch/history',
- 'Adapters: LangGraph (@ngaf/langgraph), AG-UI (@ngaf/ag-ui)',
+ 'Adapters: LangGraph (@threadplane/langgraph), AG-UI (@threadplane/ag-ui)',
'One Angular UI layer, swappable runtimes',
]}
supportingCards={[
@@ -78,7 +78,7 @@ export default async function HomePage() {
{ title: 'chat-debug', description: 'Live devtools for tool calls.' },
{ title: 'GenUI surfaces', description: 'Schema-driven UI from agent output.' },
]}
- cta={{ label: 'See @ngaf/render', href: '/render' }}
+ cta={{ label: 'See @threadplane/render', href: '/render' }}
visualLeft
visual={
diff --git a/apps/website/src/app/pilot-to-prod/page.tsx b/apps/website/src/app/pilot-to-prod/page.tsx
index 9f959b152..707188bc1 100644
--- a/apps/website/src/app/pilot-to-prod/page.tsx
+++ b/apps/website/src/app/pilot-to-prod/page.tsx
@@ -1,4 +1,4 @@
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../../components/ui/Container';
import { Section } from '../../components/ui/Section';
import { Eyebrow } from '../../components/ui/Eyebrow';
@@ -13,7 +13,7 @@ import { FinalCTA } from '../../components/landing/FinalCTA';
import { createPageMetadata } from '../../lib/site-metadata';
export const metadata = createPageMetadata({
- title: 'Pilot to Production — Agent UI for Angular',
+ title: 'Pilot to Production — Threadplane',
description: 'Close the last-mile gap. The 3-month pilot engagement is included with every app deployment license. We work alongside your Angular team to ship your first agent to production.',
pathname: '/pilot-to-prod',
type: 'website',
@@ -123,7 +123,7 @@ export default function PilotToProdPage() {
body="Working code, not slideware. We integrate against your real backend, your real auth, and your real Angular app — paired with your engineers, not behind a curtain."
bullets={[
'Real LangGraph or AG-UI backend (yours or ours, your call)',
- 'Streaming chat surface using @ngaf/chat compositions',
+ 'Streaming chat surface using @threadplane/chat compositions',
'Generative UI for the workflows that benefit from it',
'Daily syncs · weekly demo to stakeholders',
]}
@@ -132,7 +132,7 @@ export default function PilotToProdPage() {
{ title: 'Open repo', description: 'You own the source from day one.' },
{ title: 'Weekly demo', description: 'Stakeholder transparency throughout.' },
]}
- cta={{ label: 'See @ngaf/chat', href: '/chat' }}
+ cta={{ label: 'See @threadplane/chat', href: '/chat' }}
visualLeft
visual={
diff --git a/apps/website/src/app/pricing/page.tsx b/apps/website/src/app/pricing/page.tsx
index 823c7ddd0..e0357204b 100644
--- a/apps/website/src/app/pricing/page.tsx
+++ b/apps/website/src/app/pricing/page.tsx
@@ -1,4 +1,4 @@
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../../components/ui/Container';
import { Section } from '../../components/ui/Section';
import { Eyebrow } from '../../components/ui/Eyebrow';
@@ -10,9 +10,9 @@ import { FinalCTA } from '../../components/landing/FinalCTA';
import { createPageMetadata } from '../../lib/site-metadata';
export const metadata = createPageMetadata({
- title: 'Pricing — Agent UI for Angular',
+ title: 'Pricing — Threadplane',
description:
- '@ngaf/chat is free for noncommercial use under PolyForm Noncommercial 1.0.0. Commercial production use requires a ThreadPlane Commercial license. Other libraries remain MIT.',
+ '@threadplane/chat is free for noncommercial use under PolyForm Noncommercial 1.0.0. Commercial production use requires a Threadplane Commercial license. Other libraries remain MIT.',
pathname: '/pricing',
type: 'website',
});
diff --git a/apps/website/src/app/render/page.tsx b/apps/website/src/app/render/page.tsx
index 43d94b507..06ee2db58 100644
--- a/apps/website/src/app/render/page.tsx
+++ b/apps/website/src/app/render/page.tsx
@@ -1,4 +1,4 @@
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../../components/ui/Container';
import { Section } from '../../components/ui/Section';
import { Eyebrow } from '../../components/ui/Eyebrow';
@@ -12,7 +12,7 @@ import { RenderCodeShowcase } from '../../components/landing/render/RenderCodeSh
import { createPageMetadata } from '../../lib/site-metadata';
export const metadata = createPageMetadata({
- title: '@ngaf/render — Generative UI for Angular',
+ title: '@threadplane/render — Generative UI for Angular',
description: 'Agents that render UI without coupling to your frontend. Built on Vercel json-render spec.',
pathname: '/render',
type: 'website',
@@ -25,7 +25,7 @@ export default async function RenderPage() {
- @ngaf/render
+ @threadplane/render
@@ -129,7 +129,7 @@ export default async function RenderPage() {
id="fallbacks"
eyebrow="Fallbacks"
headline="Readiness gate + per-component fallback."
- body="When the agent emits a spec your registry doesn't know how to render, @ngaf/render falls back gracefully — and surfaces it to your observability layer. No mystery white screens."
+ body="When the agent emits a spec your registry doesn't know how to render, @threadplane/render falls back gracefully — and surfaces it to your observability layer. No mystery white screens."
bullets={[
'Per-component fallback API',
'Readiness gate holds renders until safe',
diff --git a/apps/website/src/app/solutions/[slug]/page.tsx b/apps/website/src/app/solutions/[slug]/page.tsx
index a6658e5e6..4a352f1b9 100644
--- a/apps/website/src/app/solutions/[slug]/page.tsx
+++ b/apps/website/src/app/solutions/[slug]/page.tsx
@@ -1,6 +1,6 @@
import { notFound } from 'next/navigation';
import Link from 'next/link';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import {
getSolutionBySlug,
getAllSolutionSlugs,
diff --git a/apps/website/src/app/solutions/page.tsx b/apps/website/src/app/solutions/page.tsx
index 3f8e1347b..a57572b67 100644
--- a/apps/website/src/app/solutions/page.tsx
+++ b/apps/website/src/app/solutions/page.tsx
@@ -1,5 +1,5 @@
import Link from 'next/link';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../../components/ui/Container';
import { Section } from '../../components/ui/Section';
import { Eyebrow } from '../../components/ui/Eyebrow';
@@ -11,8 +11,8 @@ import { SOLUTIONS } from '../../lib/solutions-data';
import { createPageMetadata } from '../../lib/site-metadata';
export const metadata = createPageMetadata({
- title: 'Solutions — Agent UI for Angular',
- description: 'See how Agent UI for Angular solves enterprise challenges — compliance, analytics, and customer support.',
+ title: 'Solutions — Threadplane',
+ description: 'See how Threadplane solves enterprise challenges — compliance, analytics, and customer support.',
pathname: '/solutions',
type: 'website',
});
diff --git a/apps/website/src/app/thanks/page.tsx b/apps/website/src/app/thanks/page.tsx
index 48a18bb88..fdcb58c4f 100644
--- a/apps/website/src/app/thanks/page.tsx
+++ b/apps/website/src/app/thanks/page.tsx
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../../components/ui/Container';
import { Section } from '../../components/ui/Section';
import { Eyebrow } from '../../components/ui/Eyebrow';
@@ -7,8 +7,8 @@ import { Button } from '../../components/ui/Button';
import { createPageMetadata } from '../../lib/site-metadata';
export const metadata = createPageMetadata({
- title: 'Payment received — ThreadPlane',
- description: 'Your @ngaf/chat license token will be emailed shortly.',
+ title: 'Payment received — Threadplane',
+ description: 'Your @threadplane/chat license token will be emailed shortly.',
pathname: '/thanks',
type: 'website',
});
@@ -52,7 +52,7 @@ export default async function ThanksPage({ searchParams }: PageProps) {
margin: '0 auto 24px',
}}
>
- Your @ngaf/chat license token will be emailed to the address on your receipt within a few minutes. Paste it into your app's provideChat() config to activate.
+ Your @threadplane/chat license token will be emailed to the address on your receipt within a few minutes. Paste it into your app's provideChat() config to activate.
diff --git a/apps/website/src/components/docs/ApiDocRenderer.tsx b/apps/website/src/components/docs/ApiDocRenderer.tsx
index ae2d10b76..5a6800ac6 100644
--- a/apps/website/src/components/docs/ApiDocRenderer.tsx
+++ b/apps/website/src/components/docs/ApiDocRenderer.tsx
@@ -1,4 +1,4 @@
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
interface ApiParam {
name: string;
diff --git a/apps/website/src/components/docs/ApiRefTable.tsx b/apps/website/src/components/docs/ApiRefTable.tsx
index 1959a7d7d..5ff3b5cef 100644
--- a/apps/website/src/components/docs/ApiRefTable.tsx
+++ b/apps/website/src/components/docs/ApiRefTable.tsx
@@ -1,4 +1,4 @@
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
export interface ApiEntry {
name: string;
diff --git a/apps/website/src/components/docs/ArchFlowDiagram.tsx b/apps/website/src/components/docs/ArchFlowDiagram.tsx
index a6919a1cf..9764f1261 100644
--- a/apps/website/src/components/docs/ArchFlowDiagram.tsx
+++ b/apps/website/src/components/docs/ArchFlowDiagram.tsx
@@ -1,6 +1,6 @@
'use client';
import { useState, useEffect, useRef } from 'react';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
interface LogEntry {
time: string;
diff --git a/apps/website/src/components/docs/CopyPromptButton.tsx b/apps/website/src/components/docs/CopyPromptButton.tsx
index 72064cbbb..4cfaf8415 100644
--- a/apps/website/src/components/docs/CopyPromptButton.tsx
+++ b/apps/website/src/components/docs/CopyPromptButton.tsx
@@ -1,6 +1,6 @@
'use client';
import { useState } from 'react';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { analyticsEvents } from '../../lib/analytics/events';
import { track } from '../../lib/analytics/client';
diff --git a/apps/website/src/components/docs/DocsBreadcrumb.tsx b/apps/website/src/components/docs/DocsBreadcrumb.tsx
index 6c9d76b8f..b27bd3c0f 100644
--- a/apps/website/src/components/docs/DocsBreadcrumb.tsx
+++ b/apps/website/src/components/docs/DocsBreadcrumb.tsx
@@ -1,5 +1,5 @@
import Link from 'next/link';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { getLibraryConfig, type LibraryId } from '../../lib/docs-config';
interface Props {
diff --git a/apps/website/src/components/docs/DocsPrevNext.tsx b/apps/website/src/components/docs/DocsPrevNext.tsx
index 2af155ffb..23d8d9acc 100644
--- a/apps/website/src/components/docs/DocsPrevNext.tsx
+++ b/apps/website/src/components/docs/DocsPrevNext.tsx
@@ -1,5 +1,5 @@
import Link from 'next/link';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Card } from '../ui/Card';
import { Eyebrow } from '../ui/Eyebrow';
import { getLibraryConfig, type LibraryId } from '../../lib/docs-config';
diff --git a/apps/website/src/components/docs/DocsSearch.tsx b/apps/website/src/components/docs/DocsSearch.tsx
index 9fa66108a..49e70761c 100644
--- a/apps/website/src/components/docs/DocsSearch.tsx
+++ b/apps/website/src/components/docs/DocsSearch.tsx
@@ -2,7 +2,7 @@
import { useState, useEffect, useRef, useCallback } from 'react';
import { useRouter } from 'next/navigation';
import { docsConfig, type LibraryId } from '../../lib/docs-config';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { analyticsEvents } from '../../lib/analytics/events';
import { track } from '../../lib/analytics/client';
diff --git a/apps/website/src/components/docs/DocsSidebar.tsx b/apps/website/src/components/docs/DocsSidebar.tsx
index 4d75e2f67..587d2d688 100644
--- a/apps/website/src/components/docs/DocsSidebar.tsx
+++ b/apps/website/src/components/docs/DocsSidebar.tsx
@@ -3,7 +3,7 @@ import { useState, useRef, useEffect } from 'react';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { docsConfig, getLibraryConfig, type DocsSection, type LibraryId } from '../../lib/docs-config';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Pill } from '../ui/Pill';
interface Props {
diff --git a/apps/website/src/components/docs/DocsTOC.tsx b/apps/website/src/components/docs/DocsTOC.tsx
index 62cb02167..ee1122d8c 100644
--- a/apps/website/src/components/docs/DocsTOC.tsx
+++ b/apps/website/src/components/docs/DocsTOC.tsx
@@ -1,6 +1,6 @@
'use client';
import { useState, useEffect } from 'react';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import type { DocHeading } from '../../lib/extract-headings';
export function DocsTOC({ headings }: { headings: DocHeading[] }) {
diff --git a/apps/website/src/components/docs/MdxRenderer.tsx b/apps/website/src/components/docs/MdxRenderer.tsx
index 33fafa032..7b8bd6b11 100644
--- a/apps/website/src/components/docs/MdxRenderer.tsx
+++ b/apps/website/src/components/docs/MdxRenderer.tsx
@@ -1,5 +1,5 @@
import { MDXRemote } from 'next-mdx-remote/rsc';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Callout } from './mdx/Callout';
import { Steps, Step } from './mdx/Steps';
import { Tabs, Tab } from './mdx/Tabs';
diff --git a/apps/website/src/components/docs/mdx/Callout.tsx b/apps/website/src/components/docs/mdx/Callout.tsx
index 82757ba79..6acd1d4bd 100644
--- a/apps/website/src/components/docs/mdx/Callout.tsx
+++ b/apps/website/src/components/docs/mdx/Callout.tsx
@@ -1,5 +1,5 @@
import type { ReactNode } from 'react';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
type CalloutType = 'tip' | 'warning' | 'info' | 'danger';
diff --git a/apps/website/src/components/docs/mdx/Card.tsx b/apps/website/src/components/docs/mdx/Card.tsx
index bb04d8ca3..2f48e01de 100644
--- a/apps/website/src/components/docs/mdx/Card.tsx
+++ b/apps/website/src/components/docs/mdx/Card.tsx
@@ -1,6 +1,6 @@
'use client';
import Link from 'next/link';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
export function CardGroup({ cols = 2, children }: { cols?: number; children: React.ReactNode }) {
return (
diff --git a/apps/website/src/components/docs/mdx/CodeGroup.tsx b/apps/website/src/components/docs/mdx/CodeGroup.tsx
index 91f16ed86..ac43e9f6e 100644
--- a/apps/website/src/components/docs/mdx/CodeGroup.tsx
+++ b/apps/website/src/components/docs/mdx/CodeGroup.tsx
@@ -1,6 +1,6 @@
'use client';
import { useState, Children, isValidElement } from 'react';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
export function CodeGroup({ children }: { children: React.ReactNode }) {
const [active, setActive] = useState(0);
diff --git a/apps/website/src/components/docs/mdx/FeatureChips.tsx b/apps/website/src/components/docs/mdx/FeatureChips.tsx
index 04c69b0fb..0bf94e1f1 100644
--- a/apps/website/src/components/docs/mdx/FeatureChips.tsx
+++ b/apps/website/src/components/docs/mdx/FeatureChips.tsx
@@ -1,6 +1,6 @@
'use client';
import Link from 'next/link';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
interface ChipData {
icon: string;
diff --git a/apps/website/src/components/docs/mdx/Steps.tsx b/apps/website/src/components/docs/mdx/Steps.tsx
index faa0d75c1..f022166b2 100644
--- a/apps/website/src/components/docs/mdx/Steps.tsx
+++ b/apps/website/src/components/docs/mdx/Steps.tsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
export function Steps({ children }: { children: React.ReactNode }) {
const steps = React.Children.toArray(children);
diff --git a/apps/website/src/components/docs/mdx/Tabs.tsx b/apps/website/src/components/docs/mdx/Tabs.tsx
index 699f2add2..4c7be4d55 100644
--- a/apps/website/src/components/docs/mdx/Tabs.tsx
+++ b/apps/website/src/components/docs/mdx/Tabs.tsx
@@ -1,6 +1,6 @@
'use client';
import { useState, Children, isValidElement } from 'react';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
interface TabProps {
label?: string;
diff --git a/apps/website/src/components/landing/Differentiator.spec.tsx b/apps/website/src/components/landing/Differentiator.spec.tsx
index 4713e6eba..cf11d27bb 100644
--- a/apps/website/src/components/landing/Differentiator.spec.tsx
+++ b/apps/website/src/components/landing/Differentiator.spec.tsx
@@ -57,9 +57,9 @@ describe('Differentiator', () => {
}
});
- it('renders the @ngaf/render primitive for the generative UI row', () => {
+ it('renders the @threadplane/render primitive for the generative UI row', () => {
render();
- expect(screen.getByText('@ngaf/render')).toBeTruthy();
+ expect(screen.getByText('@threadplane/render')).toBeTruthy();
});
it('links the footer CTA to /pilot-to-prod', () => {
diff --git a/apps/website/src/components/landing/Differentiator.tsx b/apps/website/src/components/landing/Differentiator.tsx
index e4f871062..361e7abfd 100644
--- a/apps/website/src/components/landing/Differentiator.tsx
+++ b/apps/website/src/components/landing/Differentiator.tsx
@@ -1,6 +1,6 @@
'use client';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../ui/Container';
import { Section } from '../ui/Section';
import { Eyebrow } from '../ui/Eyebrow';
@@ -36,7 +36,7 @@ const PRODUCTION_ROWS: ProductionRow[] = [
{
need: 'Generative UI on your design system',
description: 'Vercel json-render + Google A2UI rendered into your Angular components.',
- primitive: '@ngaf/render',
+ primitive: '@threadplane/render',
},
{
need: 'Recoverable errors',
@@ -119,7 +119,7 @@ export function Differentiator() {
maxWidth: 760,
}}
>
- A streaming chat tutorial takes an hour. Shipping a real agent — durable, interruptible, observable, on your design system — takes most teams six months. NGAF gives the Angular surface that the rest of the stack assumes you've already built.
+ A streaming chat tutorial takes an hour. Shipping a real agent — durable, interruptible, observable, on your design system — takes most teams six months. Threadplane gives the Angular surface that the rest of the stack assumes you've already built.
diff --git a/apps/website/src/components/landing/EcosystemStrip.tsx b/apps/website/src/components/landing/EcosystemStrip.tsx
index ddb1b384f..a58d64140 100644
--- a/apps/website/src/components/landing/EcosystemStrip.tsx
+++ b/apps/website/src/components/landing/EcosystemStrip.tsx
@@ -1,4 +1,4 @@
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../ui/Container';
import { Section } from '../ui/Section';
import { Eyebrow } from '../ui/Eyebrow';
@@ -144,7 +144,7 @@ export function EcosystemStrip() {
margin: 0,
}}
>
- NGAF gives Angular teams production-ready chat, durable threads, interrupts, subagents, planning, memory, and generative UI without locking the backend to one provider.
+ Threadplane gives Angular teams production-ready chat, durable threads, interrupts, subagents, planning, memory, and generative UI without locking the backend to one provider.
diff --git a/apps/website/src/components/landing/FeatureBlock.tsx b/apps/website/src/components/landing/FeatureBlock.tsx
index 6792b66af..271e4c884 100644
--- a/apps/website/src/components/landing/FeatureBlock.tsx
+++ b/apps/website/src/components/landing/FeatureBlock.tsx
@@ -1,6 +1,6 @@
import type { ReactNode } from 'react';
import Link from 'next/link';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../ui/Container';
import { Section } from '../ui/Section';
import { Eyebrow } from '../ui/Eyebrow';
diff --git a/apps/website/src/components/landing/FinalCTA.tsx b/apps/website/src/components/landing/FinalCTA.tsx
index c60d4c125..f84c4c106 100644
--- a/apps/website/src/components/landing/FinalCTA.tsx
+++ b/apps/website/src/components/landing/FinalCTA.tsx
@@ -1,4 +1,4 @@
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../ui/Container';
import { Section } from '../ui/Section';
import { Button } from '../ui/Button';
diff --git a/apps/website/src/components/landing/Hero.spec.tsx b/apps/website/src/components/landing/Hero.spec.tsx
index 285ad959f..b0bd4739b 100644
--- a/apps/website/src/components/landing/Hero.spec.tsx
+++ b/apps/website/src/components/landing/Hero.spec.tsx
@@ -60,9 +60,9 @@ describe('Hero', () => {
it('primary CTA copies the install command and fires cta_id=hero_install', async () => {
const { Hero } = await import('./Hero');
render();
- const btn = screen.getByRole('button', { name: /Install @ngaf\/chat/i });
+ const btn = screen.getByRole('button', { name: /Install @threadplane\/chat/i });
fireEvent.click(btn);
- expect(writeTextMock).toHaveBeenCalledWith('npm install @ngaf/chat');
+ expect(writeTextMock).toHaveBeenCalledWith('npm install @threadplane/chat');
expect(trackMock).toHaveBeenCalledWith('marketing:cta_click', expect.objectContaining({
cta_id: 'hero_install',
track: 'developer',
diff --git a/apps/website/src/components/landing/Hero.tsx b/apps/website/src/components/landing/Hero.tsx
index cfdc732f9..3a2fd7f3f 100644
--- a/apps/website/src/components/landing/Hero.tsx
+++ b/apps/website/src/components/landing/Hero.tsx
@@ -1,7 +1,7 @@
'use client';
import React, { useCallback, useState } from 'react';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../ui/Container';
import { Section } from '../ui/Section';
import { Eyebrow } from '../ui/Eyebrow';
@@ -12,7 +12,7 @@ import { track } from '../../lib/analytics/client';
import { analyticsEvents } from '../../lib/analytics/events';
import { HERO_SUBHEAD, POSITIONING_PROOF_POINTS } from '../../lib/positioning';
-const INSTALL_COMMAND = 'npm install @ngaf/chat';
+const INSTALL_COMMAND = 'npm install @threadplane/chat';
const COPY_FEEDBACK_MS = 1500;
function PrimaryInstallButton() {
@@ -35,7 +35,7 @@ function PrimaryInstallButton() {
return (
);
}
@@ -77,7 +77,7 @@ export function Hero() {
{/* Left column */}
- Agent UI for Angular · MIT framework
+ Threadplane · MIT framework
- Not another backend agent runtime. Keep LangGraph, Genkit, Mastra, CrewAI, or your own service. ThreadPlane solves the Angular UI layer.
+ Not another backend agent runtime. Keep LangGraph, Genkit, Mastra, CrewAI, or your own service. Threadplane solves the Angular UI layer.
diff --git a/apps/website/src/components/landing/HomeFAQ.tsx b/apps/website/src/components/landing/HomeFAQ.tsx
index 1f5258592..2227e2fc3 100644
--- a/apps/website/src/components/landing/HomeFAQ.tsx
+++ b/apps/website/src/components/landing/HomeFAQ.tsx
@@ -1,4 +1,4 @@
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../ui/Container';
import { Section } from '../ui/Section';
import { Eyebrow } from '../ui/Eyebrow';
@@ -7,7 +7,7 @@ import { FAQ, type FAQItem } from '../ui/FAQ';
const ITEMS: FAQItem[] = [
{
q: 'How is this different from CopilotKit or AG-UI directly?',
- a: 'CopilotKit has an Angular SDK, and AG-UI is a protocol rather than a complete Angular UI layer. ThreadPlane gives Angular teams the production surface around those runtimes: headless chat, durable threads, interrupts, subagents, planning, memory, generative UI, and adapters for LangGraph and AG-UI-compatible backends.',
+ a: 'CopilotKit has an Angular SDK, and AG-UI is a protocol rather than a complete Angular UI layer. Threadplane gives Angular teams the production surface around those runtimes: headless chat, durable threads, interrupts, subagents, planning, memory, generative UI, and adapters for LangGraph and AG-UI-compatible backends.',
},
{
q: 'Does it work with my existing Angular app?',
@@ -15,7 +15,7 @@ const ITEMS: FAQItem[] = [
},
{
q: 'Can I use this without LangGraph?',
- a: 'Yes. Use the @ngaf/ag-ui adapter for any AG-UI compliant backend, or implement the agent contract yourself. ThreadPlane keeps the Angular UI layer stable while the backend agent runtime can change.',
+ a: 'Yes. Use the @threadplane/ag-ui adapter for any AG-UI compliant backend, or implement the agent contract yourself. Threadplane keeps the Angular UI layer stable while the backend agent runtime can change.',
},
{
q: 'Is the Pilot-to-Prod program required?',
diff --git a/apps/website/src/components/landing/LiveDemoFrame.tsx b/apps/website/src/components/landing/LiveDemoFrame.tsx
index e1c0d40f7..4ff9930d2 100644
--- a/apps/website/src/components/landing/LiveDemoFrame.tsx
+++ b/apps/website/src/components/landing/LiveDemoFrame.tsx
@@ -1,6 +1,6 @@
'use client';
import { useEffect, useRef, useState } from 'react';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { BrowserFrame } from '../ui/BrowserFrame';
export function LiveDemoFrame() {
@@ -32,7 +32,7 @@ export function LiveDemoFrame() {
{shouldLoad ? (
diff --git a/apps/website/src/components/landing/ag-ui/BackendsGrid.tsx b/apps/website/src/components/landing/ag-ui/BackendsGrid.tsx
index f3b250e29..ee8515c77 100644
--- a/apps/website/src/components/landing/ag-ui/BackendsGrid.tsx
+++ b/apps/website/src/components/landing/ag-ui/BackendsGrid.tsx
@@ -1,4 +1,4 @@
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
interface Backend {
readonly name: string;
diff --git a/apps/website/src/components/landing/chat-landing/ChatLandingCodeShowcase.tsx b/apps/website/src/components/landing/chat-landing/ChatLandingCodeShowcase.tsx
index 4e449f8c2..9145b450a 100644
--- a/apps/website/src/components/landing/chat-landing/ChatLandingCodeShowcase.tsx
+++ b/apps/website/src/components/landing/chat-landing/ChatLandingCodeShowcase.tsx
@@ -1,8 +1,8 @@
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { HighlightedCode } from '../HighlightedCode';
-const SNIPPET_1 = `import { agent } from '@ngaf/langgraph';
-import { ChatComponent, a2uiBasicCatalog } from '@ngaf/chat';
+const SNIPPET_1 = `import { agent } from '@threadplane/langgraph';
+import { ChatComponent, a2uiBasicCatalog } from '@threadplane/chat';
@Component({
template: \`
diff --git a/apps/website/src/components/landing/langgraph/LangGraphCodeShowcase.tsx b/apps/website/src/components/landing/langgraph/LangGraphCodeShowcase.tsx
index 969ea3d84..0f1bbdae6 100644
--- a/apps/website/src/components/landing/langgraph/LangGraphCodeShowcase.tsx
+++ b/apps/website/src/components/landing/langgraph/LangGraphCodeShowcase.tsx
@@ -1,7 +1,7 @@
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { HighlightedCode } from '../HighlightedCode';
-const SNIPPET_1 = `import { agent } from '@ngaf/langgraph';
+const SNIPPET_1 = `import { agent } from '@threadplane/langgraph';
const chat = agent({
assistantId: 'my-agent',
@@ -13,7 +13,7 @@ chat.messages(); // Signal
chat.isLoading(); // Signal
chat.interrupt(); // Signal`;
-const SNIPPET_2 = `import { agent, provideAgent, MockAgentTransport, FetchStreamTransport } from '@ngaf/langgraph';
+const SNIPPET_2 = `import { agent, provideAgent, MockAgentTransport, FetchStreamTransport } from '@threadplane/langgraph';
provideAgent({
apiUrl: environment.langgraphUrl,
diff --git a/apps/website/src/components/landing/render/RenderCodeShowcase.tsx b/apps/website/src/components/landing/render/RenderCodeShowcase.tsx
index 0859dec91..93dd43f84 100644
--- a/apps/website/src/components/landing/render/RenderCodeShowcase.tsx
+++ b/apps/website/src/components/landing/render/RenderCodeShowcase.tsx
@@ -1,7 +1,7 @@
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { HighlightedCode } from '../HighlightedCode';
-const SNIPPET_1 = `import { defineAngularRegistry } from '@ngaf/render';
+const SNIPPET_1 = `import { defineAngularRegistry } from '@threadplane/render';
import { TableComponent } from './table.component';
import { ChartComponent } from './chart.component';
diff --git a/apps/website/src/components/pricing/CompareTable.tsx b/apps/website/src/components/pricing/CompareTable.tsx
index e5fbf075a..7f3609653 100644
--- a/apps/website/src/components/pricing/CompareTable.tsx
+++ b/apps/website/src/components/pricing/CompareTable.tsx
@@ -1,7 +1,7 @@
'use client';
import { useState } from 'react';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Button } from '../ui/Button';
import { trackCtaClick } from '../../lib/analytics/client';
import type { CtaId } from '../../lib/analytics/events';
@@ -24,7 +24,7 @@ const CTAS: Record = {
community: {
cta: 'Start free',
ctaId: 'pricing_tier_community',
- ctaHref: 'https://www.npmjs.com/package/@ngaf/chat',
+ ctaHref: 'https://www.npmjs.com/package/@threadplane/chat',
ctaExternal: true,
},
developer_seat: {
diff --git a/apps/website/src/components/pricing/CompatibilityMatrix.tsx b/apps/website/src/components/pricing/CompatibilityMatrix.tsx
index f98ac240f..589263c0d 100644
--- a/apps/website/src/components/pricing/CompatibilityMatrix.tsx
+++ b/apps/website/src/components/pricing/CompatibilityMatrix.tsx
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
import React from 'react';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
interface Row {
label: string;
diff --git a/apps/website/src/components/pricing/LeadForm.tsx b/apps/website/src/components/pricing/LeadForm.tsx
index 1e23d715f..5ce381654 100644
--- a/apps/website/src/components/pricing/LeadForm.tsx
+++ b/apps/website/src/components/pricing/LeadForm.tsx
@@ -1,6 +1,6 @@
'use client';
import { useState } from 'react';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { analyticsEvents } from '../../lib/analytics/events';
import { track } from '../../lib/analytics/client';
import { Container } from '../ui/Container';
@@ -11,7 +11,7 @@ import { Card } from '../ui/Card';
const VALUE_PROPS = [
{
- title: 'ThreadPlane Commercial license',
+ title: 'Threadplane Commercial license',
body: 'Multi-app coverage, unlimited developers, custom contract — built for procurement.',
},
{
diff --git a/apps/website/src/components/pricing/PricingFAQ.spec.tsx b/apps/website/src/components/pricing/PricingFAQ.spec.tsx
index b630f89db..0ce145623 100644
--- a/apps/website/src/components/pricing/PricingFAQ.spec.tsx
+++ b/apps/website/src/components/pricing/PricingFAQ.spec.tsx
@@ -15,7 +15,7 @@ vi.mock('../ui/Eyebrow', () => ({
}));
const EXPECTED_QUESTIONS = [
- 'Is @ngaf/chat open source?',
+ 'Is @threadplane/chat open source?',
'Can I use it for free?',
'Can I use it at work?',
'Do my end users need licenses?',
diff --git a/apps/website/src/components/pricing/PricingFAQ.tsx b/apps/website/src/components/pricing/PricingFAQ.tsx
index f76f32868..87bb44a18 100644
--- a/apps/website/src/components/pricing/PricingFAQ.tsx
+++ b/apps/website/src/components/pricing/PricingFAQ.tsx
@@ -1,4 +1,4 @@
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { Container } from '../ui/Container';
import { Section } from '../ui/Section';
import { Eyebrow } from '../ui/Eyebrow';
@@ -6,8 +6,8 @@ import { FAQ, type FAQItem } from '../ui/FAQ';
const ITEMS: FAQItem[] = [
{
- q: 'Is @ngaf/chat open source?',
- a: '@ngaf/chat is source-available under the PolyForm Noncommercial License 1.0.0. Because commercial use requires a license, it is not OSI open source.',
+ q: 'Is @threadplane/chat open source?',
+ a: '@threadplane/chat is source-available under the PolyForm Noncommercial License 1.0.0. Because commercial use requires a license, it is not OSI open source.',
},
{
q: 'Can I use it for free?',
@@ -15,15 +15,15 @@ const ITEMS: FAQItem[] = [
},
{
q: 'Can I use it at work?',
- a: 'You can evaluate it at work for 30 calendar days from your first commercial use. After that, production use in a commercial product, internal tool, SaaS app, or client deliverable requires a ThreadPlane Commercial license. The eval window is good-faith — no telemetry, no registration.',
+ a: 'You can evaluate it at work for 30 calendar days from your first commercial use. After that, production use in a commercial product, internal tool, SaaS app, or client deliverable requires a Threadplane Commercial license. The eval window is good-faith — no telemetry, no registration.',
},
{
q: 'Do my end users need licenses?',
- a: 'No. Commercial licenses are for the developers, organization, or production application using @ngaf/chat, depending on the plan.',
+ a: 'No. Commercial licenses are for the developers, organization, or production application using @threadplane/chat, depending on the plan.',
},
{
q: 'Can I modify the source?',
- a: 'Yes, for permitted noncommercial use under the PolyForm Noncommercial license, or for commercial production use under a paid ThreadPlane Commercial license.',
+ a: 'Yes, for permitted noncommercial use under the PolyForm Noncommercial license, or for commercial production use under a paid Threadplane Commercial license.',
},
{
q: 'Can I redistribute it?',
diff --git a/apps/website/src/components/shared/AnnouncementToast.tsx b/apps/website/src/components/shared/AnnouncementToast.tsx
index 0ae5c7540..01acbd8e9 100644
--- a/apps/website/src/components/shared/AnnouncementToast.tsx
+++ b/apps/website/src/components/shared/AnnouncementToast.tsx
@@ -1,6 +1,6 @@
'use client';
import { useState, useEffect } from 'react';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { analyticsEvents } from '../../lib/analytics/events';
import { track, trackWhitepaperDownloadClick } from '../../lib/analytics/client';
import { Button } from '../ui/Button';
diff --git a/apps/website/src/components/shared/Footer.tsx b/apps/website/src/components/shared/Footer.tsx
index a6690f016..be3ab597b 100644
--- a/apps/website/src/components/shared/Footer.tsx
+++ b/apps/website/src/components/shared/Footer.tsx
@@ -1,7 +1,7 @@
'use client';
import { useState } from 'react';
import Link from 'next/link';
-import { tokens } from '@ngaf/design-tokens';
+import { tokens } from '@threadplane/design-tokens';
import { analyticsEvents } from '../../lib/analytics/events';
import { track, trackCtaClick, trackExternalLinkClick } from '../../lib/analytics/client';
import { SHORT_POSITIONING_DESCRIPTION } from '../../lib/positioning';
@@ -143,10 +143,10 @@ export function Footer() {
aria-label="GitHub">
- trackExternalLinkClick('https://www.npmjs.com/package/@ngaf/langgraph', {
+ onClick={() => trackExternalLinkClick('https://www.npmjs.com/package/@threadplane/langgraph', {
surface: 'footer',
cta_id: 'footer_npm_icon',
cta_text: 'npm',
@@ -289,10 +289,10 @@ export function Footer() {
onMouseLeave={(e) => (e.currentTarget.style.color = tokens.colors.textSecondary)}>
Blog
- trackExternalLinkClick('https://www.npmjs.com/package/@ngaf/langgraph', {
+ onClick={() => trackExternalLinkClick('https://www.npmjs.com/package/@threadplane/langgraph', {
surface: 'footer',
cta_id: 'footer_npm_package',
cta_text: 'npm Package',
@@ -313,7 +313,7 @@ export function Footer() {
{/* Bottom bar */}