From 6eab191cb8de21749f858c3964f41106e28bf954 Mon Sep 17 00:00:00 2001
From: Brian Love
Date: Fri, 22 May 2026 10:15:06 -0700
Subject: [PATCH 1/2] docs(licensing): align ThreadPlane branding, add
/docs/licensing landing page
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Editorial cleanup across all licensing-touching surfaces:
- New /docs/licensing landing page (linked from email + footer + /thanks)
- Email copy: "Thanks for subscribing" → "Thanks for your ThreadPlane license
purchase"; CACHEPLANE_LICENSE → THREADPLANE_LICENSE in installation snippet;
install snippet now shows provideChat() pattern (the actual API), not
process.env-only
- Brand: "Threadplane" → "ThreadPlane" in customer-visible copy and library
NOTICE/README files
- License name: always "ThreadPlane Commercial license" (capitalized)
- Tense: drop "Starting with the next published version" from COMMERCIAL.md and
root README — the license is live
- Eval policy: precise "30 calendar days from first commercial use, good-faith,
no telemetry" wording in libs/chat/COMMERCIAL-USE.md and PricingFAQ
- Tier scoping: standardize "Indie" name, prefix paid features with
"ThreadPlane Commercial license", drop Enterprise "starting at $10k/year"
display period (was inconsistent with "Custom")
- Footer "Licensing" link → /docs/licensing (was /pricing#faq)
- /thanks page button → /docs/licensing (was /docs/chat/...)
Co-Authored-By: Claude Opus 4.7 (1M context)
---
COMMERCIAL.md | 8 +-
README.md | 2 +-
apps/minting-service/src/lib/email.spec.ts | 6 +-
apps/minting-service/src/lib/email.ts | 34 +-
apps/website/src/app/docs/licensing/page.tsx | 302 ++++++++++++++++++
apps/website/src/app/pricing/page.tsx | 6 +-
apps/website/src/app/thanks/page.tsx | 6 +-
.../src/components/pricing/PricingFAQ.tsx | 4 +-
apps/website/src/components/shared/Footer.tsx | 8 +-
libs/chat/COMMERCIAL-USE.md | 2 +-
libs/chat/NOTICE.md | 4 +-
libs/chat/README.md | 18 +-
pricing/tiers.config.ts | 12 +-
13 files changed, 360 insertions(+), 52 deletions(-)
create mode 100644 apps/website/src/app/docs/licensing/page.tsx
diff --git a/COMMERCIAL.md b/COMMERCIAL.md
index 963690f8..421a62ff 100644
--- a/COMMERCIAL.md
+++ b/COMMERCIAL.md
@@ -4,12 +4,10 @@ Most libraries in this repository — `@ngaf/render`, `@ngaf/agent`, `@ngaf/lang
## `@ngaf/chat`
-Starting with the next published version, `@ngaf/chat` is dual-licensed:
+`@ngaf/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-day commercial evaluation).
-- **Threadplane commercial license** for commercial production use.
-
-Historical MIT releases of `@ngaf/chat` remain under their original terms.
+- **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.
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.
diff --git a/README.md b/README.md
index d818dc90..0e4c078c 100644
--- a/README.md
+++ b/README.md
@@ -131,4 +131,4 @@ That's it. `chat.messages()` and `chat.status()` are Angular Signals. Bind them
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, including commercial, with attribution.
-**`@ngaf/chat`** is the exception. Future versions are licensed under **PolyForm Noncommercial 1.0.0 OR a Threadplane commercial license**. Historical npm releases remain MIT. See [`libs/chat/LICENSE.md`](./libs/chat/LICENSE.md), [`libs/chat/COMMERCIAL-USE.md`](./libs/chat/COMMERCIAL-USE.md), and [`COMMERCIAL.md`](./COMMERCIAL.md) for details.
+**`@ngaf/chat`** is the exception. It is dual-licensed under **PolyForm Noncommercial 1.0.0** for free noncommercial use, or a **ThreadPlane Commercial license** for production use inside a for-profit context. See [`libs/chat/LICENSE.md`](./libs/chat/LICENSE.md), [`libs/chat/COMMERCIAL-USE.md`](./libs/chat/COMMERCIAL-USE.md), [`COMMERCIAL.md`](./COMMERCIAL.md), and [threadplane.ai/docs/licensing](https://threadplane.ai/docs/licensing) for details.
diff --git a/apps/minting-service/src/lib/email.spec.ts b/apps/minting-service/src/lib/email.spec.ts
index 19e575ee..43a81d24 100644
--- a/apps/minting-service/src/lib/email.spec.ts
+++ b/apps/minting-service/src/lib/email.spec.ts
@@ -10,9 +10,9 @@ describe('renderLicenseEmail', () => {
expiresAt: new Date('2027-04-20T00:00:00Z'),
});
- expect(out.text).toContain('-----BEGIN CACHEPLANE LICENSE-----');
+ expect(out.text).toContain('-----BEGIN THREADPLANE LICENSE-----');
expect(out.text).toContain('PAYLOAD.SIG');
- expect(out.text).toContain('-----END CACHEPLANE LICENSE-----');
+ expect(out.text).toContain('-----END THREADPLANE LICENSE-----');
});
it('subject includes tier and seat count with plural s for seats > 1', () => {
@@ -54,6 +54,6 @@ describe('renderLicenseEmail', () => {
});
expect(out.html).toContain('
+ // .env
+ THREADPLANE_LICENSE=
Docs: https://threadplane.ai/docs/licensing
Questions: reply to this email.
@@ -48,16 +51,21 @@ Questions: reply to this email.
-- The ThreadPlane team
`;
- const html = `
Thanks for subscribing to ThreadPlane.
-
Your license token is below. Set it as the CACHEPLANE_LICENSE environment variable in your application:
-
-----BEGIN CACHEPLANE LICENSE-----
+ const html = `
Thanks for your ThreadPlane license purchase.
+
Your license is valid for 12 months from today. Paste the token below into your @ngaf/chat configuration:
+ How the ThreadPlane licensing model works, who needs a paid license, and how to install your license token.
+
+
+
+
+
+
+
+
+
The model
+
+ Agent UI for Angular is a suite of libraries. Most are{' '}
+ MIT-licensed and free for any use,
+ commercial or not. Only @ngaf/chat is
+ dual-licensed.
+
+
+ @ngaf/chat is source-available under{' '}
+ PolyForm Noncommercial 1.0.0 for free
+ 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{' '}
+ in any of:
+
+
+
A commercial product or SaaS
+
An internal business tool inside a for-profit company
+
An agency deliverable or paid client project
+
Any application operated by or for a for-profit entity
+
+
You do not need a paid license for:
+
+
Personal, hobby, student, academic, or nonprofit projects
+
Public demos and tutorials
+
Open-source applications released under an OSI-approved license
+
Commercial evaluation, up to 30 calendar days from your first commercial use
+
+
+
+
+
+
+
+
+
Install your license
+
+ After purchase, ThreadPlane emails a signed license token to the address on your receipt. Paste it
+ into your app's provideChat(){' '}
+ configuration:
+
+ The library verifies the token's Ed25519 signature on boot. The check is{' '}
+ advisory-only: a missing, expired, or
+ tampered token logs a console.warn but
+ never blocks rendering. Verification is fully offline; no calls leave your app at runtime.
+
+
+ The token is safe to commit to a private repository, or to read from a build-time environment variable
+ for public repos. Public-repo demos are exempt from the commercial-use definition, but if your
+ public repo backs a commercial product, the deployed bundle does need a license.
+
+
+
+
+
+
+
+
+
Tier scoping
+
+ 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.
+
+
+
+
+
+
Tier
+
Developers
+
Commercial apps
+
Best for
+
+
+
+
+
Indie — $149/yr
+
1
+
1
+
Solo devs, single indie product
+
+
+
Developer Seat — $299/dev/yr
+
Per seat
+
Unlimited apps owned by your org
+
Startups, growing teams
+
+
+
App Deployment — $1,499/app/yr
+
Unlimited
+
1 production app per license
+
Agencies, CI/CD-heavy teams
+
+
+
Enterprise — custom
+
Custom
+
Multi-app, custom terms
+
Procurement, SLA, security review
+
+
+
+
+
+ Every license is valid for 12 months from the date of purchase. Renewal is a fresh annual purchase —
+ we don't auto-charge.
+
+
+
+
+
+
+
+
+
Evaluation
+
+ You may use @ngaf/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
+ commercial use.
+
+
+
Refunds
+
+ If you refund a license through Stripe, the token is revoked automatically and we email a confirmation.
+ The verification check warns on boot. There's no clawback of the source code you already have —
+ everything is source-available under PolyForm Noncommercial by default.
+
+
+
Questions
+
+ Volume pricing, multi-app licensing, audit clauses, custom terms — any of those, reach out and we'll
+ work it out.
+
+
+
+
+
+ Pricing FAQ →
+
+
+
+
+
+ >
+ );
+}
diff --git a/apps/website/src/app/pricing/page.tsx b/apps/website/src/app/pricing/page.tsx
index de07919f..52c3d478 100644
--- a/apps/website/src/app/pricing/page.tsx
+++ b/apps/website/src/app/pricing/page.tsx
@@ -13,7 +13,7 @@ import { createPageMetadata } from '../../lib/site-metadata';
export const metadata = createPageMetadata({
title: 'Pricing — Agent UI for Angular',
description:
- '@ngaf/chat is free for noncommercial use under PolyForm Noncommercial 1.0.0. Commercial production use requires a Threadplane license. Other libraries remain MIT.',
+ '@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.',
pathname: '/pricing',
type: 'website',
});
@@ -67,7 +67,7 @@ export default function PricingPage() {
margin: 0,
}}
>
- @ngaf/chat is free for noncommercial use. Commercial production use requires a Threadplane license. Other libraries in the framework remain MIT.
+ @ngaf/chat is free for noncommercial use. Commercial production use requires a ThreadPlane Commercial license. Other libraries in the framework remain MIT.
@@ -126,7 +126,7 @@ export default function PricingPage() {
- Because commercial use requires a license, @ngaf/chat is source-available rather than OSI open source. Threadplane keeps ecosystem packages (@ngaf/render, @ngaf/agent, @ngaf/langgraph, @ngaf/ag-ui, @ngaf/a2ui, @ngaf/licensing, @ngaf/telemetry, @ngaf/design-tokens) permissively MIT-licensed.
+ Because commercial use requires a license, @ngaf/chat is source-available rather than OSI open source. ThreadPlane keeps ecosystem packages (@ngaf/render, @ngaf/agent, @ngaf/langgraph, @ngaf/ag-ui, @ngaf/a2ui, @ngaf/licensing, @ngaf/telemetry, @ngaf/design-tokens) permissively MIT-licensed.
diff --git a/apps/website/src/app/thanks/page.tsx b/apps/website/src/app/thanks/page.tsx
index 1dd98470..cf2f5cb9 100644
--- a/apps/website/src/app/thanks/page.tsx
+++ b/apps/website/src/app/thanks/page.tsx
@@ -7,7 +7,7 @@ import { Button } from '../../components/ui/Button';
import { createPageMetadata } from '../../lib/site-metadata';
export const metadata = createPageMetadata({
- title: 'Payment received — Threadplane',
+ title: 'Payment received — ThreadPlane',
description: 'Your @ngaf/chat license token will be emailed shortly.',
pathname: '/thanks',
type: 'website',
@@ -57,8 +57,8 @@ export default function ThanksPage() {
If you don't see the email within 10 minutes, check spam or contact us.