From 922290e29db1fc8babe1c949c2e673d23636eb7d Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 20 May 2026 20:50:02 -0700 Subject: [PATCH 01/13] docs(superpowers): spec for pricing rebuild + sitewide MIT-qualification (PR B) 5-tier pricing model, /pricing rebuild with header/FAQ/notes, hero eyebrow update, footer link update, root README + COMMERCIAL.md rewrites. Stripe Checkout wiring lives in a parallel PR B-Stripe. Co-Authored-By: Claude Opus 4.7 (1M context) --- ...ng-rebuild-and-mit-qualification-design.md | 184 ++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-20-pricing-rebuild-and-mit-qualification-design.md diff --git a/docs/superpowers/specs/2026-05-20-pricing-rebuild-and-mit-qualification-design.md b/docs/superpowers/specs/2026-05-20-pricing-rebuild-and-mit-qualification-design.md new file mode 100644 index 00000000..299f76e6 --- /dev/null +++ b/docs/superpowers/specs/2026-05-20-pricing-rebuild-and-mit-qualification-design.md @@ -0,0 +1,184 @@ +# PR B — Pricing rebuild + sitewide MIT-claim qualification + +**Status:** Design approved, ready for implementation plan. +**Owner:** apps/website + root docs +**Affects:** `/pricing` page, hero eyebrow, footer link, root `README.md`, root `COMMERCIAL.md`. No library code. + +## Goal + +After PR A (`@ngaf/chat` relicense) merged, the public posture lags: the homepage hero still says "Agent UI for Angular · MIT," the footer Resources column links a "MIT License" item, the `/pricing` page claims "MIT-licensed libraries are free forever," and root `README.md`/`COMMERCIAL.md` both state the whole framework is MIT. This PR closes that gap in a single coordinated public-posture sweep. + +Two intertwined deliverables: + +1. **Pricing-page rebuild.** Replace the existing 2-tier (Open Source / Enterprise) `PricingGrid` with the user-defined 5-tier model (Community / Indie Commercial / Developer Seat / App Deployment / Enterprise). New page header, subheader, commercial-use note, evaluation note, OSS clarification, FAQ section. Comparison matrix updated to the new tiers. +2. **Sitewide MIT-claim qualification.** Hero eyebrow text. Footer Resources column link and bottom-bar text. Root `README.md` lines that say "all libraries MIT." Root `COMMERCIAL.md` rewrite to lead with chat as the dual-licensed exception. + +## Out of scope + +- **Stripe Checkout.** Tier CTAs route to `/contact?source=pricing_tier_` so the page can ship before billing infrastructure exists. Real Stripe products + Checkout + webhook entitlement lives in a separate parallel brainstorm + PR ("PR B-Stripe"). +- **Verification runtime.** Boot-time enforcement, prod public-key in CI, nag UI — that's PR C. +- **Per-library README updates** for libraries that stay MIT (`@ngaf/render`, etc.) — they don't need to change; they're still MIT and their READMEs say so accurately. +- **New `/licensing` route.** Inline qualification only. The pricing page + root `COMMERCIAL.md` carry the canonical explanation. +- **Docs MDX content updates.** No content/docs/* files change. (Audit didn't flag any docs MDX MIT claims that need updating.) + +## Content + +### /pricing page + +**Header (h1):** `Pricing for production AI chat interfaces` + +**Subheader (body-lg):** `@ngaf/chat is free for noncommercial use. Commercial production use requires a Threadplane license. Other libraries in the framework remain MIT.` + +**Tier cards (in order, left-to-right or top-to-bottom on mobile):** + +| # | Name | Price | Period | CTA label | CTA href | Highlight? | +|---|---|---|---|---|---|---| +| 1 | Community / Noncommercial | Free | forever | Start free | `https://www.npmjs.com/package/@ngaf/chat` (external) | no | +| 2 | Indie Commercial | $149 | /year | Buy indie license | `/contact?source=pricing_tier_indie` | no | +| 3 | Developer Seat | $299 | /developer/year | Buy developer seat | `/contact?source=pricing_tier_developer_seat` | yes | +| 4 | App Deployment | $1,499 | /app/year | License an app | `/contact?source=pricing_tier_app_deployment` | no | +| 5 | Enterprise | Custom | starting at $10k/year | Contact sales | `/contact?source=pricing_tier_enterprise` | no | + +**Tier feature lists** (4–5 bullets each, derived verbatim from the user's brief): + +- **Community:** Personal, student, academic, nonprofit, demo · Source access · Noncommercial use · Commercial evaluation (30 days) · License: PolyForm Noncommercial 1.0.0 +- **Indie:** 1 developer · 1 commercial app · Unlimited end users · Commercial license · Best for: solo devs, indie products, consultants with one app +- **Developer Seat:** Commercial use · Unlimited end users · Dev / staging / production · Apps owned by your org · Best for: startups & growing teams +- **App Deployment:** Unlimited developers · 1 production app · Unlimited end users · Procurement-friendly · Best for: agencies, CI/CD-heavy teams +- **Enterprise:** Custom contract & SLA · Procurement support · Security review · Multi-app licensing · Priority + private support channel + +**Commercial-use note (small text, below grid):** + +> A license is required when `@ngaf/chat` is used in a commercial product, SaaS app, internal business tool, paid client project, or production application operated by or for a for-profit entity. + +**Evaluation note (small text, between tier grid and FAQ):** + +> Commercial evaluation is free for 30 days. A paid license is required before production deployment. + +**OSS clarification (small text, footer-adjacent):** + +> 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. + +**FAQ section** — 7 Q&A items verbatim from the user's brief. Plain expandable-list style (no accordion JS — semantic `
`/`` keeps the page accessible without client interactivity). Each Q is the ``, each A is the body. Questions: + +1. Is `@ngaf/chat` open source? +2. Can I use it for free? +3. Can I use it at work? +4. Do my end users need licenses? +5. Can I modify the source? +6. Can I redistribute it? +7. What happens to older MIT versions? + +Answers verbatim from the brief. + +**Comparison matrix:** Replaces the existing `CompareTable` row set. New rows compare across 5 tiers (Community / Indie / Developer Seat / App Deployment / Enterprise) on these dimensions: + +- License model +- Commercial production use +- Developers +- Apps covered +- End users +- Environments (dev/staging/prod) +- Support +- SLA +- Security review + +Same `CompareTable` component, new data. `CompatibilityMatrix` is unchanged (it describes ecosystem capability, not licensing). + +**Lead form + Final CTA:** Both unchanged. + +### Sitewide MIT qualification + +**Hero eyebrow** (`apps/website/src/components/landing/Hero.tsx:80`): + +From `Agent UI for Angular · MIT` to `Agent UI for Angular · MIT framework` (one-word add). Conveys that the framework as a whole is permissive while leaving room for the chat exception to be discoverable on `/pricing`. + +**Footer Resources column** (`apps/website/src/components/shared/Footer.tsx`): + +The current `MIT License` link (line 286-298) — relabel to `Licensing`, href changes from `https://github.com/cacheplane/angular-agent-framework/blob/main/LICENSE` to `/pricing#faq`. Tracking `cta_id` updated to `footer_licensing`. + +**Footer bottom bar** (`apps/website/src/components/shared/Footer.tsx`): + +Currently reads: `MIT License · Pricing`. Replace with: `Licensing · Pricing` where "Licensing" links to `/pricing#faq`. Tracking `cta_id` updated to `footer_licensing_bottom`. + +**Root `README.md`:** + +- **Line 18 (MIT badge):** Drop the badge entirely. The qualified license paragraph below it (next bullet) carries the full posture; one badge can't accurately capture a per-library split, and shields.io variants are fragile. +- **Lines 135-137** (the "all libraries MIT" paragraph): rewrite to: + + > 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. + +**Root `COMMERCIAL.md`** (rewrite the whole 13-line file): + +```markdown +# 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). + +## `@ngaf/chat` + +Starting with the next published version, `@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. + +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. + +## Questions + +- Website: +- Pricing: +- Sales: +``` + +## File map + +- **Modify:** `apps/website/src/app/pricing/page.tsx` — metadata + header + subhead + add FAQ section + add commercial/evaluation/OSS notes +- **Modify:** `apps/website/src/components/pricing/PricingGrid.tsx` — 2 plans → 5 tiers +- **Modify:** `apps/website/src/components/pricing/CompareTable.tsx` — new row set for 5-tier comparison +- **Create:** `apps/website/src/components/pricing/PricingFAQ.tsx` — `
`/`` list of 7 Q&A +- **Create:** `apps/website/src/components/pricing/PricingFAQ.spec.tsx` — covers FAQ render + linkability +- **Modify:** `apps/website/src/components/landing/Hero.tsx` — eyebrow text +- **Modify:** `apps/website/src/components/shared/Footer.tsx` — Resources column link + bottom bar text + new `cta_id`s +- **Modify:** `apps/website/src/lib/analytics/events.ts` — add `footer_licensing` and `footer_licensing_bottom` to `CtaId` union; also extend it with the new `pricing_tier_*` cta_ids if the pricing CTAs are click-tracked (they are; using existing `footer_*` pattern won't fit). Actually they're plain anchor clicks on the pricing grid — tracked via the existing `trackCtaClick({ surface: 'pricing', cta_id: 'pricing_tier_indie', ... })` pattern; we'll add 5 new cta_id literals. +- **Modify:** `README.md` (root) — line 18 badge + lines 135-137 paragraph +- **Modify:** `COMMERCIAL.md` (root) — full rewrite + +Total: 9 files modified, 2 created. + +## Acceptance criteria + +1. `/pricing` renders 5 tier cards in the order Community → Indie → Developer Seat → App Deployment → Enterprise. Developer Seat is highlighted. +2. Each tier CTA links to either `npmjs.com/package/@ngaf/chat` (Community) or `/contact?source=pricing_tier_` (paid tiers). All paid-tier CTA clicks fire `trackCtaClick` with `cta_id: 'pricing_tier_'`. +3. `/pricing` page contains the literal copy: header, subheader, commercial-use note, evaluation note, OSS clarification — exactly as written in this spec. +4. `/pricing` contains a FAQ section with 7 `
`/`` items. Each `` is a question from the user's brief and the body is its verbatim answer. +5. `CompareTable` rows compare across 5 tiers on the 9 dimensions listed in this spec. +6. Hero eyebrow reads `Agent UI for Angular · MIT framework`. +7. Footer Resources column has a `Licensing` link to `/pricing#faq`. Footer bottom bar reads `Licensing · Pricing` with the licensing link going to `/pricing#faq`. Both fire their respective new `cta_id`s. +8. Root `README.md` no longer claims the whole repo is MIT in its license-summary paragraph (lines ~135-137). The new paragraph explicitly names chat as the exception. +9. Root `COMMERCIAL.md` leads with the dual-license model for chat, preserves the minting-service section, and updates the contact links. +10. Existing tests (`Hero.spec.tsx`, `Differentiator.spec.tsx`, `site-metadata.spec.ts`, `docs.spec.ts`) still pass. `PricingFAQ.spec.tsx` is new and green. +11. `npx nx run website:lint` is green. `npx vitest run` from `apps/website/` reports the same baseline plus the new FAQ spec. + +## Verification + +- `cd apps/website && npx vitest run` +- `cd apps/website && npx nx run website:lint` +- Visual check: dev server at `http://localhost:3000/pricing` at 1280×820 and at mobile preset 375×812. +- DOM check: confirm each tier CTA `href` and `cta_id` match the table above. +- DOM check: hero eyebrow shows `Agent UI for Angular · MIT framework`. +- DOM check: footer link inventory matches the spec. + +## Risks + +- **Pricing CTAs route to a contact form, not Checkout.** Anyone clicking "Buy indie license" lands on the lead form. Mitigation: append `source=pricing_tier_` query param so the lead form can capture intent; the PR-B-Stripe followup replaces the hrefs with Stripe Checkout URLs once products exist. +- **Public posture briefly diverges between merging PR A and this PR.** PR A landed without a public pricing page that explains the dual model; this PR closes that gap. Merge order: this PR ships immediately after PR A. +- **Compare table can grow unwieldy.** With 5 tiers and 9 rows, the matrix is 45 cells. The plan uses a single full table with horizontal scroll on mobile (`overflow-x: auto` on the wrapper) — the existing `CompareTable` component already supports this pattern; no responsive rewrite needed. From 4fe6eda257d8f06537bb19d613f83e8e1f33ed84 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 20 May 2026 20:53:37 -0700 Subject: [PATCH 02/13] docs(superpowers): plan for pricing rebuild + MIT qualification (PR B) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 11 tasks: CtaId union, hero eyebrow, PricingGrid (5 tiers), CompareTable (5×9), PricingFAQ + spec, /pricing page integration, footer relabel, root COMMERCIAL.md rewrite, root README.md license paragraph rewrite, final verification. Co-Authored-By: Claude Opus 4.7 (1M context) --- ...0-pricing-rebuild-and-mit-qualification.md | 1289 +++++++++++++++++ 1 file changed, 1289 insertions(+) create mode 100644 docs/superpowers/plans/2026-05-20-pricing-rebuild-and-mit-qualification.md diff --git a/docs/superpowers/plans/2026-05-20-pricing-rebuild-and-mit-qualification.md b/docs/superpowers/plans/2026-05-20-pricing-rebuild-and-mit-qualification.md new file mode 100644 index 00000000..6e16e362 --- /dev/null +++ b/docs/superpowers/plans/2026-05-20-pricing-rebuild-and-mit-qualification.md @@ -0,0 +1,1289 @@ +# Pricing Rebuild + Sitewide MIT Qualification (PR B) Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Land the public-facing posture changes that accompany the `@ngaf/chat` relicense (PR A). Rebuild `/pricing` to a 5-tier model with FAQ + commercial-use / evaluation / OSS notes, qualify the homepage hero eyebrow + footer link + bottom bar, rewrite root `README.md` license paragraph and root `COMMERCIAL.md`. + +**Architecture:** All website changes follow existing patterns (inline styles via `@ngaf/design-tokens`, `Card`/`Section`/`Container`/`Eyebrow` primitives, `trackCtaClick` for tracked anchors). The CompareTable row shape extends from boolean-per-tier to a discriminated value type so cells can hold either a checkmark/dash or a short text label (e.g., "1 dev", "unlimited"). Stripe Checkout is **not** in this PR; purchase CTAs link to `/contact?source=pricing_tier_`. + +**Tech Stack:** Next.js 16 (App Router, RSC + 'use client'), React 19, TypeScript, `@ngaf/design-tokens`, Vitest + React Testing Library (`@vitest-environment jsdom`). + +**Reference:** Spec at `docs/superpowers/specs/2026-05-20-pricing-rebuild-and-mit-qualification-design.md`. + +--- + +## File map + +- **Modify:** `apps/website/src/lib/analytics/events.ts` — extend `CtaId` union with 6 new literals: `pricing_tier_community`, `pricing_tier_indie`, `pricing_tier_developer_seat`, `pricing_tier_app_deployment`, `pricing_tier_enterprise`, `footer_licensing`, `footer_licensing_bottom`. +- **Modify:** `apps/website/src/components/pricing/PricingGrid.tsx` — 2 plans → 5 tiers, click tracking. +- **Modify:** `apps/website/src/components/pricing/CompareTable.tsx` — 4 cols → 5 cols; cell value type widened to `boolean | string`; new 9-row data. +- **Create:** `apps/website/src/components/pricing/PricingFAQ.tsx` — semantic `
`/`` 7-Q&A. +- **Create:** `apps/website/src/components/pricing/PricingFAQ.spec.tsx` — render + structure tests. +- **Modify:** `apps/website/src/app/pricing/page.tsx` — metadata, header/subhead, integrate notes + FAQ + final OSS clarification. +- **Modify:** `apps/website/src/components/landing/Hero.tsx` — eyebrow text only. +- **Modify:** `apps/website/src/components/shared/Footer.tsx` — Resources column link relabel + href; bottom bar text + `cta_id`. +- **Modify:** `COMMERCIAL.md` (root) — full rewrite. +- **Modify:** `README.md` (root) — drop MIT badge; rewrite license paragraph. + +Total: 9 modified, 2 created. + +--- + +## Task 1: Add new CtaId literals + +**Files:** +- Modify: `apps/website/src/lib/analytics/events.ts` + +- [ ] **Step 1: Read the current `CtaId` union** + +Run from repo root: `grep -n "CtaId\|hero_install\|home_why_pilot" apps/website/src/lib/analytics/events.ts` + +Confirm the union currently extends through `'home_why_pilot_to_prod'` and includes hero pill literals like `'hero_proof_pill'`. + +- [ ] **Step 2: Extend the union** + +Use Edit on `apps/website/src/lib/analytics/events.ts`. Find: + +```ts + // Why this exists section + | 'home_why_pilot_to_prod' +``` + +Replace with: + +```ts + // Why this exists section + | 'home_why_pilot_to_prod' + // Pricing tier CTAs + | 'pricing_tier_community' + | 'pricing_tier_indie' + | 'pricing_tier_developer_seat' + | 'pricing_tier_app_deployment' + | 'pricing_tier_enterprise' + // Footer licensing links + | 'footer_licensing' + | 'footer_licensing_bottom' +``` + +- [ ] **Step 3: Type-check** + +Run from repo root: `npx tsc -p apps/website/tsconfig.json --noEmit 2>&1 | grep -E "events\.ts|CtaId" || echo "ok"` +Expected: `ok`. + +- [ ] **Step 4: Commit** + +```bash +git add apps/website/src/lib/analytics/events.ts +git commit -m "$(cat <<'EOF' +chore(website): extend CtaId union for pricing + footer licensing CTAs + +Adds 5 pricing_tier_* literals and 2 footer_licensing* literals so the +5-tier pricing grid and the relabeled footer Licensing link can fire +strictly-typed trackCtaClick events. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +## Task 2: Update Hero eyebrow text + +**Files:** +- Modify: `apps/website/src/components/landing/Hero.tsx` + +- [ ] **Step 1: Apply the edit** + +Use Edit on `apps/website/src/components/landing/Hero.tsx`: + +- `old_string`: ` Agent UI for Angular · MIT` +- `new_string`: ` Agent UI for Angular · MIT framework` + +- [ ] **Step 2: Verify** + +Run: `grep -c "Agent UI for Angular · MIT framework" apps/website/src/components/landing/Hero.tsx` +Expected: `1`. + +Run: `grep -c "Agent UI for Angular · MIT$" apps/website/src/components/landing/Hero.tsx || echo "ok no bare MIT"` +Expected: `ok no bare MIT`. + +- [ ] **Step 3: Commit** + +```bash +git add apps/website/src/components/landing/Hero.tsx +git commit -m "$(cat <<'EOF' +docs(website): hero eyebrow — qualify "MIT" to "MIT framework" + +@ngaf/chat is no longer MIT in future versions; the framework as a +whole is still MIT for every library except chat. Eyebrow now reads +"Agent UI for Angular · MIT framework" so the implication doesn't +extend to chat. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +## Task 3: Rewrite PricingGrid for 5 tiers + +**Files:** +- Modify: `apps/website/src/components/pricing/PricingGrid.tsx` + +- [ ] **Step 1: Replace the PLANS array and add click tracking** + +The current file imports `tokens`, `Container`, `Section`, `Card`, `Button`, `Eyebrow` and exports `PricingGrid` with a 2-plan `PLANS` array. Replace the file with the following content. Read it carefully — only the imports, the `Plan` interface, the `PLANS` array, and the ` + + ))} + + + + ); +} +``` + +- [ ] **Step 2: Type-check + lint** + +Run from repo root: +``` +npx tsc -p apps/website/tsconfig.json --noEmit 2>&1 | grep -i PricingGrid || echo "ok" +npx nx run website:lint 2>&1 | grep -iE "PricingGrid|error " || echo "ok" +``` +Expected: `ok` for both. + +- [ ] **Step 3: Commit** + +```bash +git add apps/website/src/components/pricing/PricingGrid.tsx +git commit -m "$(cat <<'EOF' +feat(website): pricing grid — 2 tiers → 5 tiers with click tracking + +Community / Indie Commercial / Developer Seat (highlighted) / +App Deployment / Enterprise. Each card shows 5 features, a price, +a period, and a tracked CTA. Paid-tier CTAs route to /contact with +a source parameter until Stripe Checkout lands in a separate PR. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +## Task 4: Rewrite CompareTable across 5 tiers + +**Files:** +- Modify: `apps/website/src/components/pricing/CompareTable.tsx` + +- [ ] **Step 1: Replace the file** + +Write `apps/website/src/components/pricing/CompareTable.tsx` with this content. The shape change: each row holds `cells: Record`; the renderer handles both. The wrapper already had `overflow-x-auto` so mobile horizontal scroll still works without further changes. + +```tsx +'use client'; +import { tokens } from '@ngaf/design-tokens'; + +type TierKey = 'community' | 'indie' | 'seat' | 'app' | 'enterprise'; + +interface Row { + feature: string; + cells: Record; +} + +const TIERS: { key: TierKey; label: string }[] = [ + { key: 'community', label: 'Community' }, + { key: 'indie', label: 'Indie' }, + { key: 'seat', label: 'Developer Seat' }, + { key: 'app', label: 'App Deployment' }, + { key: 'enterprise', label: 'Enterprise' }, +]; + +const ROWS: Row[] = [ + { + feature: 'License model', + cells: { + community: 'PolyForm NC 1.0.0', + indie: 'Commercial', + seat: 'Commercial', + app: 'Commercial', + enterprise: 'Commercial + custom', + }, + }, + { + feature: 'Commercial production use', + cells: { community: false, indie: true, seat: true, app: true, enterprise: true }, + }, + { + feature: 'Developers', + cells: { community: 'Unlimited (noncommercial)', indie: '1', seat: 'Per seat', app: 'Unlimited', enterprise: 'Unlimited' }, + }, + { + feature: 'Apps covered', + cells: { community: 'Unlimited (noncommercial)', indie: '1', seat: 'All apps owned by your org', app: '1', enterprise: 'Multi-app' }, + }, + { + feature: 'End users', + cells: { community: 'Unlimited', indie: 'Unlimited', seat: 'Unlimited', app: 'Unlimited', enterprise: 'Unlimited' }, + }, + { + feature: 'Environments (dev / staging / prod)', + cells: { community: false, indie: true, seat: true, app: true, enterprise: true }, + }, + { + feature: 'Support', + cells: { community: 'Community', indie: 'Email', seat: 'Email', app: 'Email', enterprise: 'Priority + private channel' }, + }, + { + feature: 'SLA', + cells: { community: false, indie: false, seat: false, app: false, enterprise: true }, + }, + { + feature: 'Security review', + cells: { community: false, indie: false, seat: false, app: false, enterprise: true }, + }, +]; + +const Check = () => ; +const X = () => ; + +function renderCell(value: boolean | string): React.ReactNode { + if (typeof value === 'boolean') return value ? : ; + return {value}; +} + +export function CompareTable() { + return ( +
+
+ + + + + {TIERS.map((t) => ( + + ))} + + + + {ROWS.map((row) => ( + (e.currentTarget.style.background = tokens.colors.accentSurface)} + onMouseLeave={(e) => (e.currentTarget.style.background = 'transparent')} + > + + {TIERS.map((t) => ( + + ))} + + ))} + +
+ Feature + + {t.label} +
+ {row.feature} + + {renderCell(row.cells[t.key])} +
+
+
+ ); +} +``` + +- [ ] **Step 2: Type-check** + +Run: `npx tsc -p apps/website/tsconfig.json --noEmit 2>&1 | grep -i CompareTable || echo "ok"` +Expected: `ok`. + +- [ ] **Step 3: Commit** + +```bash +git add apps/website/src/components/pricing/CompareTable.tsx +git commit -m "$(cat <<'EOF' +feat(website): compare table — 4 cols → 5 cols, text-or-bool cells + +Adds Indie tier; widens cell value type so rows like Developers / +Apps covered / Support / License model can carry short text labels +instead of just check/dash. Mobile horizontal scroll preserved via +the existing overflow-x-auto wrapper. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +## Task 5: Create PricingFAQ component + +**Files:** +- Create: `apps/website/src/components/pricing/PricingFAQ.tsx` + +- [ ] **Step 1: Create the file** + +Write `apps/website/src/components/pricing/PricingFAQ.tsx`: + +```tsx +import { tokens } from '@ngaf/design-tokens'; +import { Container } from '../ui/Container'; +import { Section } from '../ui/Section'; +import { Eyebrow } from '../ui/Eyebrow'; + +interface QA { + q: string; + a: string; +} + +const ITEMS: readonly QA[] = [ + { + 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: 'Can I use it for free?', + a: 'Yes. Personal, educational, nonprofit, academic, demo, open-source, and evaluation use are free under the noncommercial license.', + }, + { + q: 'Can I use it at work?', + a: 'You can evaluate it at work for 30 days. Production use in a commercial product, internal tool, SaaS app, or client deliverable requires a commercial license.', + }, + { + 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.', + }, + { + 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 license.', + }, + { + q: 'Can I redistribute it?', + a: 'You may bundle it inside a larger licensed application. You may not redistribute it as a standalone package or as part of a competing component library, SDK, template kit, app builder, or design system.', + }, + { + q: 'What happens to older MIT versions?', + a: 'Versions previously released under MIT remain available under their original license terms. The new license applies only to future versions where the license change is introduced.', + }, +]; + +export function PricingFAQ() { + return ( +
+ +
+ FAQ +

+ Licensing FAQ +

+
+ {ITEMS.map((item) => ( +
+ + {item.q} + +

+ {item.a} +

+
+ ))} +
+
+
+
+ ); +} +``` + +- [ ] **Step 2: Type-check** + +Run: `npx tsc -p apps/website/tsconfig.json --noEmit 2>&1 | grep -i PricingFAQ || echo "ok"` +Expected: `ok`. + +- [ ] **Step 3: Commit** + +```bash +git add apps/website/src/components/pricing/PricingFAQ.tsx +git commit -m "$(cat <<'EOF' +feat(website): pricing FAQ section — 7 Q&As as semantic
+ +Server component (no client interactivity needed) using native +
/. Anchor target #faq lets the footer Licensing +link deep-link into the FAQ. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +## Task 6: Add Vitest spec for PricingFAQ + +**Files:** +- Create: `apps/website/src/components/pricing/PricingFAQ.spec.tsx` + +- [ ] **Step 1: Create the file** + +Write `apps/website/src/components/pricing/PricingFAQ.spec.tsx`: + +```tsx +// @vitest-environment jsdom +import React from 'react'; +import { describe, expect, it, vi } from 'vitest'; +import { render, screen } from '@testing-library/react'; +import { PricingFAQ } from './PricingFAQ'; + +// Layout primitives are not under test here; stub them so the test +// focuses on the FAQ content + structure. +vi.mock('../ui/Container', () => ({ + Container: ({ children }: { children: React.ReactNode }) =>
{children}
, +})); +vi.mock('../ui/Section', () => ({ + Section: ({ children }: { children: React.ReactNode }) =>
{children}
, +})); +vi.mock('../ui/Eyebrow', () => ({ + Eyebrow: ({ children }: { children: React.ReactNode }) => {children}, +})); + +const EXPECTED_QUESTIONS = [ + 'Is @ngaf/chat open source?', + 'Can I use it for free?', + 'Can I use it at work?', + 'Do my end users need licenses?', + 'Can I modify the source?', + 'Can I redistribute it?', + 'What happens to older MIT versions?', +]; + +describe('PricingFAQ', () => { + it('renders the FAQ heading', () => { + render(); + expect( + screen.getByRole('heading', { level: 2, name: 'Licensing FAQ' }), + ).toBeTruthy(); + }); + + it('renders all 7 questions as elements inside
', () => { + const { container } = render(); + const summaries = container.querySelectorAll('details > summary'); + expect(summaries.length).toBe(7); + const texts = Array.from(summaries, (s) => s.textContent); + expect(texts).toEqual(EXPECTED_QUESTIONS); + }); + + it('exposes an #faq anchor for footer deep-linking', () => { + const { container } = render(); + expect(container.querySelector('#faq')).toBeTruthy(); + }); + + it('renders the open-source clarification answer', () => { + render(); + expect( + screen.getByText(/source-available under the PolyForm Noncommercial License 1\.0\.0/i), + ).toBeTruthy(); + }); +}); +``` + +- [ ] **Step 2: Run the spec** + +Run from `apps/website/`: `npx vitest run src/components/pricing/PricingFAQ.spec.tsx 2>&1 | tail -10` +Expected: `Tests 4 passed (4)`. Exit code 0. + +- [ ] **Step 3: Commit** + +```bash +git add apps/website/src/components/pricing/PricingFAQ.spec.tsx +git commit -m "$(cat <<'EOF' +test(website): cover PricingFAQ — heading, 7 questions, #faq anchor + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +## Task 7: Update /pricing page — header, subhead, notes, FAQ integration + +**Files:** +- Modify: `apps/website/src/app/pricing/page.tsx` + +- [ ] **Step 1: Replace the file** + +Write `apps/website/src/app/pricing/page.tsx`: + +```tsx +import { tokens } from '@ngaf/design-tokens'; +import { Container } from '../../components/ui/Container'; +import { Section } from '../../components/ui/Section'; +import { Eyebrow } from '../../components/ui/Eyebrow'; +import { PricingGrid } from '../../components/pricing/PricingGrid'; +import { CompareTable } from '../../components/pricing/CompareTable'; +import { CompatibilityMatrix } from '../../components/pricing/CompatibilityMatrix'; +import { PricingFAQ } from '../../components/pricing/PricingFAQ'; +import { LeadForm } from '../../components/pricing/LeadForm'; +import { FinalCTA } from '../../components/landing/FinalCTA'; +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.', + pathname: '/pricing', + type: 'website', +}); + +function SmallNote({ children }: { children: React.ReactNode }) { + return ( +

+ {children} +

+ ); +} + +export default function PricingPage() { + return ( + <> +
+ +
+ Pricing +

+ Pricing for production AI chat interfaces +

+

+ @ngaf/chat is free for noncommercial use. Commercial production use requires a Threadplane license. Other libraries in the framework remain MIT. +

+
+
+
+ + + +
+ + + A license is required when @ngaf/chat is used in a commercial product, SaaS app, internal business tool, paid client project, or production application operated by or for a for-profit entity. + + +
+ + + +
+ + + Commercial evaluation is free for 30 days. A paid license is required before production deployment. + + +
+ +
+ + Compatibility +

+ Works with your agent stack +

+ +
+
+ + + +
+ + + 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. + + +
+ + + + + ); +} +``` + +Note: The existing pricing page had a "Compatibility" `Eyebrow` + `h2` + `CompatibilityMatrix` block inline. That structure is preserved (sandwiched between the evaluation note and the FAQ) so the existing `CompatibilityMatrix` keeps rendering with its header. The PR does not modify `CompatibilityMatrix` itself. + +If the original file has additional Sections you can't see in the visible 60 lines above (e.g., custom outro copy after `CompatibilityMatrix`), preserve them — but the layout above is the canonical pre-FAQ structure already. Confirm by reading the full original file before replacing. + +- [ ] **Step 2: Type-check + lint** + +Run from repo root: +``` +npx tsc -p apps/website/tsconfig.json --noEmit 2>&1 | grep -i "pricing/page" || echo "ok" +npx nx run website:lint 2>&1 | grep -iE "pricing/page|error " || echo "ok" +``` +Expected: `ok` for both. + +- [ ] **Step 3: Commit** + +```bash +git add apps/website/src/app/pricing/page.tsx +git commit -m "$(cat <<'EOF' +feat(website): pricing page — new header, notes, FAQ integration + +- Header: "Pricing for production AI chat interfaces" +- Subhead names the chat NC license + clarifies other libs stay MIT +- Adds commercial-use note (below grid), evaluation note (between + matrix and FAQ), OSS clarification (below FAQ) +- Integrates PricingFAQ between CompatibilityMatrix and LeadForm +- Metadata description updated for SEO + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +## Task 8: Update Footer — Licensing link + bottom bar + +**Files:** +- Modify: `apps/website/src/components/shared/Footer.tsx` + +- [ ] **Step 1: Resources column "MIT License" link → "Licensing"** + +The current block (around lines 286-297) reads: + +```tsx + trackExternalLinkClick('https://github.com/cacheplane/angular-agent-framework/blob/main/LICENSE', { + surface: 'footer', + cta_id: 'footer_mit_license', + cta_text: 'MIT License', + })} + onMouseEnter={(e) => (e.currentTarget.style.color = tokens.colors.accent)} + onMouseLeave={(e) => (e.currentTarget.style.color = tokens.colors.textSecondary)}> + MIT License + +``` + +Replace it with: + +```tsx + trackFooterCta('Licensing', '/pricing#faq')} + onMouseEnter={(e) => (e.currentTarget.style.color = tokens.colors.accent)} + onMouseLeave={(e) => (e.currentTarget.style.color = tokens.colors.textSecondary)}> + Licensing + +``` + +(Switches from external `` to internal `` since `/pricing#faq` is local. `trackFooterCta` is already defined in the file and produces the cta_id `footer_licensing` via the slug-from-label rule. Verify by checking the existing `trackFooterCta` helper.) + +Actually — confirm the helper. Read the file: `grep -n "trackFooterCta" apps/website/src/components/shared/Footer.tsx | head -5`. Expected: helper defined around line 99, called with `(label, href)` and slugifies label into `footer_`. With label `'Licensing'`, the cta_id becomes `'footer_licensing'`, which we just added to the `CtaId` union in Task 1. + +- [ ] **Step 2: Bottom-bar "MIT License" → "Licensing"** + +Current block (around lines 304-309): + +```tsx +
+ © {new Date().getFullYear()} Agent UI for Angular. All rights reserved. + MIT License · trackFooterCta('Pricing Bottom', '/pricing')} + onMouseEnter={(e) => (e.currentTarget.style.color = tokens.colors.accent)} + onMouseLeave={(e) => (e.currentTarget.style.color = tokens.colors.textMuted)}>Pricing +
+``` + +Replace the `MIT License · ...` content with: + +```tsx + + trackFooterCta('Licensing Bottom', '/pricing#faq')} + onMouseEnter={(e) => (e.currentTarget.style.color = tokens.colors.accent)} + onMouseLeave={(e) => (e.currentTarget.style.color = tokens.colors.textMuted)} + > + Licensing + +  ·  + trackFooterCta('Pricing Bottom', '/pricing')} + onMouseEnter={(e) => (e.currentTarget.style.color = tokens.colors.accent)} + onMouseLeave={(e) => (e.currentTarget.style.color = tokens.colors.textMuted)} + > + Pricing + + +``` + +The slugified label `'Licensing Bottom'` produces `'footer_licensing_bottom'`, which we added to the `CtaId` union in Task 1. + +- [ ] **Step 3: Type-check + lint** + +``` +npx tsc -p apps/website/tsconfig.json --noEmit 2>&1 | grep -i Footer || echo "ok" +npx nx run website:lint 2>&1 | grep -iE "Footer|error " || echo "ok" +``` +Expected: `ok` for both. + +- [ ] **Step 4: Commit** + +```bash +git add apps/website/src/components/shared/Footer.tsx +git commit -m "$(cat <<'EOF' +feat(website): footer — replace "MIT License" with "Licensing" → /pricing#faq + +The whole framework is no longer MIT (chat is dual-licensed). Resources +column link relabeled Licensing, targets /pricing#faq. Bottom bar now +shows "Licensing · Pricing" instead of "MIT License · Pricing". +Tracking ids footer_licensing and footer_licensing_bottom. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +## Task 9: Rewrite root COMMERCIAL.md + +**Files:** +- Modify: `COMMERCIAL.md` (repo root) + +- [ ] **Step 1: Replace the file content** + +Write `COMMERCIAL.md` at the repo root with this exact content: + +```markdown +# 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). + +## `@ngaf/chat` + +Starting with the next published version, `@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. + +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. + +## Questions + +- Website: +- Pricing: +- Sales: +``` + +- [ ] **Step 2: Verify** + +```bash +grep -c "Starting with the next published version" COMMERCIAL.md # 1 +grep -c "Minting Service" COMMERCIAL.md # 1 +grep -c "are released under the \*\*MIT License\*\*" COMMERCIAL.md # 1 +``` + +- [ ] **Step 3: Commit** + +```bash +git add COMMERCIAL.md +git commit -m "$(cat <<'EOF' +docs: rewrite root COMMERCIAL.md to lead with @ngaf/chat dual-license + +Replaces the all-MIT framing with: most libs MIT, @ngaf/chat dual +(PolyForm-NC OR Threadplane-Commercial), minting service untouched. +Updates Questions contact links to threadplane.ai/{pricing,contact}. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +## Task 10: Update root README.md + +**Files:** +- Modify: `README.md` (repo root) + +- [ ] **Step 1: Read the relevant section** + +Run: `sed -n '15,22p;130,142p' README.md` +Confirm: line ~18 has a `License: MIT` badge; lines ~130-140 contain the paragraph that claims "all libraries in this repository are released under the MIT License". + +- [ ] **Step 2: Drop the MIT badge** + +Use Edit. The current badge line on or around line 18 looks like one of these patterns (verify before editing): + +``` +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) +``` + +or + +``` +License: MIT +``` + +Delete that single line. Leave the line above and below untouched. + +- [ ] **Step 3: Rewrite the license paragraph** + +Find the existing paragraph that begins approximately: + +``` +**MIT** — free for any use +``` + +or: + +``` +All libraries in this repository are released under the MIT License. +``` + +Replace the full paragraph (one or two sentences) with: + +```markdown +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. +``` + +- [ ] **Step 4: Verify** + +```bash +! grep -q "License: MIT" README.md && echo "OK: MIT badge gone" +grep -c "PolyForm Noncommercial 1.0.0 OR a Threadplane commercial license" README.md # 1 +grep -c "Most libraries in this repository" README.md # 1 +! grep -q "all libraries in this repository are released under the MIT License" README.md && echo "OK: old all-MIT claim gone" +``` + +- [ ] **Step 5: Commit** + +```bash +git add README.md +git commit -m "$(cat <<'EOF' +docs: root README — qualify license paragraph for @ngaf/chat exception + +Drops the all-MIT badge (no single badge captures a per-lib split) +and rewrites the license paragraph to name @ngaf/chat explicitly as +PolyForm-NC OR Threadplane-Commercial, while keeping the other 8 +libraries' MIT framing intact. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +## Task 11: Final verification + +**Files:** none (verification only). + +- [ ] **Step 1: Full website test suite** + +Run from `apps/website/`: `npx vitest run 2>&1 | tail -8` +Expected: same pre-PR baseline plus the new 4 PricingFAQ tests. No regressions. + +- [ ] **Step 2: Lint** + +Run from repo root: `npx nx run website:lint 2>&1 | tail -5` +Expected: `Successfully ran target lint for project website`. + +- [ ] **Step 3: Build** + +Run from repo root: `npx nx build website 2>&1 | tail -10` +Expected: `Successfully ran target build for project website`. + +- [ ] **Step 4: DOM verification** + +Start the dev server (or use the running one) and reload `/pricing` and `/`. Then via preview eval or playwright: + +```js +// /pricing checks +const tiers = [...document.querySelectorAll('[data-ui="eyebrow"]')].map(e => e.textContent); +// Should include: 'Community / Noncommercial', 'Indie Commercial', 'Developer Seat', 'App Deployment', 'Enterprise' + +const ctas = [...document.querySelectorAll('a[href^="/contact?source=pricing_tier_"]')].map(a => a.href); +// Should be 4: indie, developer_seat, app_deployment, enterprise + +const npmCta = document.querySelector('a[href*="npmjs.com/package/@ngaf/chat"]'); +// Should exist + +const faqs = document.querySelectorAll('details > summary'); +// Should be 7 + +// / checks +const heroEyebrow = document.querySelector('h1#hero-heading')?.previousElementSibling?.textContent; +// Should be 'AGENT UI FOR ANGULAR · MIT FRAMEWORK' (eyebrow is uppercase via CSS) + +const footerLicensing = [...document.querySelectorAll('footer a')].find(a => a.textContent.trim() === 'Licensing'); +// Should exist; href should end with '/pricing#faq' +``` + +- [ ] **Step 5: Scope check** + +```bash +# No library code changes +git diff --name-only origin/main..HEAD | grep '^libs/' | head # expect empty +# No cockpit changes +git diff --name-only origin/main..HEAD | grep '^cockpit/' | head # expect empty +# No example changes +git diff --name-only origin/main..HEAD | grep '^examples/' | head # expect empty +``` + +- [ ] **Step 6: Mark PR description** + +When opening the PR, include in the description: +- The 5 tier names and prices. +- The 7 FAQ questions. +- The before/after hero eyebrow. +- A note: Stripe Checkout wiring lands in PR B-Stripe. + +--- + +## Self-review + +**Spec coverage:** +- Spec § /pricing page header/subhead → Task 7 Step 1. ✓ +- Spec § Tier cards (5 tiers, prices, features, CTAs, highlight on Developer Seat) → Task 3 Step 1. ✓ +- Spec § Commercial-use note → Task 7 Step 1. ✓ +- Spec § Evaluation note → Task 7 Step 1. ✓ +- Spec § OSS clarification → Task 7 Step 1. ✓ +- Spec § FAQ 7 Q&As → Tasks 5 + 6. ✓ +- Spec § CompareTable 5 cols × 9 rows → Task 4 Step 1. ✓ +- Spec § Hero eyebrow → Task 2. ✓ +- Spec § Footer Resources link → Task 8 Step 1. ✓ +- Spec § Footer bottom bar → Task 8 Step 2. ✓ +- Spec § Root COMMERCIAL.md rewrite → Task 9. ✓ +- Spec § Root README.md badge drop + paragraph rewrite → Task 10. ✓ +- Spec § Analytics CtaId union additions → Task 1. ✓ +- Spec § PricingFAQ spec.tsx → Task 6. ✓ +- Spec § Acceptance criterion #10 (existing tests still pass) → Task 11 Step 1. ✓ + +**Placeholder scan:** Every code block is fully written. The only conditional path is Task 10's "verify before editing" for the MIT badge syntax — both common patterns are documented inline. + +**Type consistency:** `CtaId` literals declared in Task 1 are consumed in Tasks 3 (5 pricing literals) and Task 8 (2 footer literals via the slug-from-label rule in `trackFooterCta`). `Plan.ctaId` typed against `CtaId` ensures the grid won't ship with a typo. `TierKey` in Task 4 is consistent across `TIERS`, `ROWS.cells`, and the renderer. + +Plan complete. From 6187de97d100abad615a625f74ee0226b5c11196 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 20 May 2026 20:54:46 -0700 Subject: [PATCH 03/13] chore(website): extend CtaId union for pricing + footer licensing CTAs Adds 5 pricing_tier_* literals and 2 footer_licensing* literals so the 5-tier pricing grid and the relabeled footer Licensing link can fire strictly-typed trackCtaClick events. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/website/src/lib/analytics/events.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/website/src/lib/analytics/events.ts b/apps/website/src/lib/analytics/events.ts index 2ce0c88d..8ade2d16 100644 --- a/apps/website/src/lib/analytics/events.ts +++ b/apps/website/src/lib/analytics/events.ts @@ -58,6 +58,15 @@ export type CtaId = | 'home_whitepaper_direct_inline' // Why this exists section | 'home_why_pilot_to_prod' + // Pricing tier CTAs + | 'pricing_tier_community' + | 'pricing_tier_indie' + | 'pricing_tier_developer_seat' + | 'pricing_tier_app_deployment' + | 'pricing_tier_enterprise' + // Footer licensing links + | 'footer_licensing' + | 'footer_licensing_bottom' // Announcement toast | 'toast_get_guide' | 'toast_direct_download' From 8b0f81d1f1967b14e14a9a48b912d563b88abdce Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 20 May 2026 20:54:50 -0700 Subject: [PATCH 04/13] =?UTF-8?q?docs(website):=20hero=20eyebrow=20?= =?UTF-8?q?=E2=80=94=20qualify=20"MIT"=20to=20"MIT=20framework"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @ngaf/chat is no longer MIT in future versions; the framework as a whole is still MIT for every library except chat. Eyebrow now reads "Agent UI for Angular · MIT framework" so the implication doesn't extend to chat. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/website/src/components/landing/Hero.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/website/src/components/landing/Hero.tsx b/apps/website/src/components/landing/Hero.tsx index b1db984e..cfdc732f 100644 --- a/apps/website/src/components/landing/Hero.tsx +++ b/apps/website/src/components/landing/Hero.tsx @@ -77,7 +77,7 @@ export function Hero() { {/* Left column */}
- Agent UI for Angular · MIT + Agent UI for Angular · MIT framework

Date: Wed, 20 May 2026 20:56:32 -0700 Subject: [PATCH 05/13] =?UTF-8?q?feat(website):=20pricing=20grid=20?= =?UTF-8?q?=E2=80=94=202=20tiers=20=E2=86=92=205=20tiers=20with=20click=20?= =?UTF-8?q?tracking?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Community / Indie Commercial / Developer Seat (highlighted) / App Deployment / Enterprise. Each card shows 5 features, a price, a period, and a tracked CTA. Paid-tier CTAs route to /contact with a source parameter until Stripe Checkout lands in a separate PR. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/components/pricing/PricingGrid.tsx | 136 ++++++++++++++---- 1 file changed, 111 insertions(+), 25 deletions(-) diff --git a/apps/website/src/components/pricing/PricingGrid.tsx b/apps/website/src/components/pricing/PricingGrid.tsx index e77763d8..4bb5e922 100644 --- a/apps/website/src/components/pricing/PricingGrid.tsx +++ b/apps/website/src/components/pricing/PricingGrid.tsx @@ -1,40 +1,107 @@ +'use client'; + import { tokens } from '@ngaf/design-tokens'; import { Container } from '../ui/Container'; import { Section } from '../ui/Section'; import { Card } from '../ui/Card'; import { Button } from '../ui/Button'; import { Eyebrow } from '../ui/Eyebrow'; +import { trackCtaClick } from '../../lib/analytics/client'; +import type { CtaId } from '../../lib/analytics/events'; interface Plan { name: string; price: string; period: string; - features: string[]; + features: readonly string[]; highlight: boolean; cta: string; ctaHref: string; + ctaId: CtaId; ctaExternal?: boolean; } -const PLANS: Plan[] = [ +const PLANS: readonly Plan[] = [ { - name: 'Open Source', + name: 'Community / Noncommercial', price: 'Free', period: 'forever', - features: ['MIT License', 'All libraries', 'Commercial use welcome', 'Community support'], + features: [ + 'Personal, student, academic, nonprofit, demo', + 'Source access', + 'Noncommercial use', + 'Commercial evaluation (30 days)', + 'License: PolyForm Noncommercial 1.0.0', + ], highlight: false, - cta: 'Get Started', - ctaHref: 'https://www.npmjs.com/package/@ngaf/langgraph', + cta: 'Start free', + ctaHref: 'https://www.npmjs.com/package/@ngaf/chat', + ctaId: 'pricing_tier_community', ctaExternal: true, }, + { + name: 'Indie Commercial', + price: '$149', + period: '/year', + features: [ + '1 developer', + '1 commercial app', + 'Unlimited end users', + 'Commercial license', + 'Best for: solo devs, indie products, consultants with one app', + ], + highlight: false, + cta: 'Buy indie license', + ctaHref: '/contact?source=pricing_tier_indie', + ctaId: 'pricing_tier_indie', + }, + { + name: 'Developer Seat', + price: '$299', + period: '/developer/year', + features: [ + 'Commercial use', + 'Unlimited end users', + 'Dev / staging / production', + 'Apps owned by your org', + 'Best for: startups & growing teams', + ], + highlight: true, + cta: 'Buy developer seat', + ctaHref: '/contact?source=pricing_tier_developer_seat', + ctaId: 'pricing_tier_developer_seat', + }, + { + name: 'App Deployment', + price: '$1,499', + period: '/app/year', + features: [ + 'Unlimited developers', + '1 production app', + 'Unlimited end users', + 'Procurement-friendly', + 'Best for: agencies, CI/CD-heavy teams', + ], + highlight: false, + cta: 'License an app', + ctaHref: '/contact?source=pricing_tier_app_deployment', + ctaId: 'pricing_tier_app_deployment', + }, { name: 'Enterprise', price: 'Custom', - period: 'contact for details', - features: ['Priority support', 'SLA', 'Managed service (coming soon)', 'Custom contract'], - highlight: true, - cta: 'Contact Us', - ctaHref: '#lead-form', + period: 'starting at $10k/year', + features: [ + 'Custom contract & SLA', + 'Procurement support', + 'Security review', + 'Multi-app licensing', + 'Priority + private support channel', + ], + highlight: false, + cta: 'Contact sales', + ctaHref: '/contact?source=pricing_tier_enterprise', + ctaId: 'pricing_tier_enterprise', }, ]; @@ -45,9 +112,9 @@ export function PricingGrid() {
@@ -69,7 +136,7 @@ export function PricingGrid() { style={{ fontFamily: tokens.typography.fontSerif, fontWeight: 700, - fontSize: 48, + fontSize: 40, color: tokens.colors.textPrimary, lineHeight: 1, marginBottom: 4, @@ -80,9 +147,10 @@ export function PricingGrid() {

@@ -92,34 +160,52 @@ export function PricingGrid() { style={{ listStyle: 'none', padding: 0, - margin: '0 0 24px 0', + margin: '0 0 20px 0', display: 'flex', flexDirection: 'column', gap: 8, flex: 1, }} > - {plan.features.map((f) => ( + {plan.features.map((feature) => (

  • - {f} + + {feature}
  • ))} From 30afc88906b36dd0ae5f0884f964b36ac2ac85b8 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 20 May 2026 20:57:53 -0700 Subject: [PATCH 06/13] =?UTF-8?q?feat(website):=20compare=20table=20?= =?UTF-8?q?=E2=80=94=204=20cols=20=E2=86=92=205=20cols,=20text-or-bool=20c?= =?UTF-8?q?ells?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds Indie tier; widens cell value type so rows like Developers / Apps covered / Support / License model can carry short text labels instead of just check/dash. Mobile horizontal scroll preserved via the existing overflow-x-auto wrapper. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/components/pricing/CompareTable.tsx | 121 ++++++++++++++---- 1 file changed, 96 insertions(+), 25 deletions(-) diff --git a/apps/website/src/components/pricing/CompareTable.tsx b/apps/website/src/components/pricing/CompareTable.tsx index bb96cda2..a12417cc 100644 --- a/apps/website/src/components/pricing/CompareTable.tsx +++ b/apps/website/src/components/pricing/CompareTable.tsx @@ -1,35 +1,102 @@ 'use client'; import { tokens } from '@ngaf/design-tokens'; -const ROWS = [ - { feature: 'npm install', oss: true, seat: true, app: true, enterprise: true }, - { feature: 'Commercial use', oss: false, seat: true, app: true, enterprise: true }, - { feature: 'See compatibility matrix below', oss: true, seat: true, app: true, enterprise: true }, - { feature: 'Email support', oss: false, seat: true, app: true, enterprise: true }, - { feature: 'Source access', oss: true, seat: true, app: true, enterprise: true }, - { feature: 'Per-app deployment', oss: false, seat: false, app: true, enterprise: true }, - { feature: 'Volume licensing', oss: false, seat: false, app: false, enterprise: true }, - { feature: 'Priority support', oss: false, seat: false, app: false, enterprise: true }, +type TierKey = 'community' | 'indie' | 'seat' | 'app' | 'enterprise'; + +interface Row { + feature: string; + cells: Record; +} + +const TIERS: { key: TierKey; label: string }[] = [ + { key: 'community', label: 'Community' }, + { key: 'indie', label: 'Indie' }, + { key: 'seat', label: 'Developer Seat' }, + { key: 'app', label: 'App Deployment' }, + { key: 'enterprise', label: 'Enterprise' }, +]; + +const ROWS: Row[] = [ + { + feature: 'License model', + cells: { + community: 'PolyForm NC 1.0.0', + indie: 'Commercial', + seat: 'Commercial', + app: 'Commercial', + enterprise: 'Commercial + custom', + }, + }, + { + feature: 'Commercial production use', + cells: { community: false, indie: true, seat: true, app: true, enterprise: true }, + }, + { + feature: 'Developers', + cells: { community: 'Unlimited (noncommercial)', indie: '1', seat: 'Per seat', app: 'Unlimited', enterprise: 'Unlimited' }, + }, + { + feature: 'Apps covered', + cells: { community: 'Unlimited (noncommercial)', indie: '1', seat: 'All apps owned by your org', app: '1', enterprise: 'Multi-app' }, + }, + { + feature: 'End users', + cells: { community: 'Unlimited', indie: 'Unlimited', seat: 'Unlimited', app: 'Unlimited', enterprise: 'Unlimited' }, + }, + { + feature: 'Environments (dev / staging / prod)', + cells: { community: false, indie: true, seat: true, app: true, enterprise: true }, + }, + { + feature: 'Support', + cells: { community: 'Community', indie: 'Email', seat: 'Email', app: 'Email', enterprise: 'Priority + private channel' }, + }, + { + feature: 'SLA', + cells: { community: false, indie: false, seat: false, app: false, enterprise: true }, + }, + { + feature: 'Security review', + cells: { community: false, indie: false, seat: false, app: false, enterprise: true }, + }, ]; const Check = () => ; const X = () => ; +function renderCell(value: boolean | string): React.ReactNode { + if (typeof value === 'boolean') return value ? : ; + return {value}; +} + export function CompareTable() { return (
    -
    - +
    +
    - - {['Community', 'Developer Seat', 'App Deployment', 'Enterprise'].map((h) => ( - + + {TIERS.map((t) => ( + ))} @@ -39,12 +106,16 @@ export function CompareTable() { key={row.feature} style={{ borderBottom: `1px solid ${tokens.colors.accentBorder}` }} onMouseEnter={(e) => (e.currentTarget.style.background = tokens.colors.accentSurface)} - onMouseLeave={(e) => (e.currentTarget.style.background = 'transparent')}> - - - - - + onMouseLeave={(e) => (e.currentTarget.style.background = 'transparent')} + > + + {TIERS.map((t) => ( + + ))} ))} From 252d4985a720d5eb059b2ef54f5371f7ad2f20bc Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 20 May 2026 20:59:13 -0700 Subject: [PATCH 07/13] =?UTF-8?q?feat(website):=20pricing=20FAQ=20section?= =?UTF-8?q?=20=E2=80=94=207=20Q&As=20as=20semantic=20
    ?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Server component (no client interactivity needed) using native
    /. Anchor target #faq lets the footer Licensing link deep-link into the FAQ. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/components/pricing/PricingFAQ.tsx | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 apps/website/src/components/pricing/PricingFAQ.tsx diff --git a/apps/website/src/components/pricing/PricingFAQ.tsx b/apps/website/src/components/pricing/PricingFAQ.tsx new file mode 100644 index 00000000..6febda73 --- /dev/null +++ b/apps/website/src/components/pricing/PricingFAQ.tsx @@ -0,0 +1,104 @@ +import { tokens } from '@ngaf/design-tokens'; +import { Container } from '../ui/Container'; +import { Section } from '../ui/Section'; +import { Eyebrow } from '../ui/Eyebrow'; + +interface QA { + q: string; + a: string; +} + +const ITEMS: readonly QA[] = [ + { + 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: 'Can I use it for free?', + a: 'Yes. Personal, educational, nonprofit, academic, demo, open-source, and evaluation use are free under the noncommercial license.', + }, + { + q: 'Can I use it at work?', + a: 'You can evaluate it at work for 30 days. Production use in a commercial product, internal tool, SaaS app, or client deliverable requires a commercial license.', + }, + { + 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.', + }, + { + 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 license.', + }, + { + q: 'Can I redistribute it?', + a: 'You may bundle it inside a larger licensed application. You may not redistribute it as a standalone package or as part of a competing component library, SDK, template kit, app builder, or design system.', + }, + { + q: 'What happens to older MIT versions?', + a: 'Versions previously released under MIT remain available under their original license terms. The new license applies only to future versions where the license change is introduced.', + }, +]; + +export function PricingFAQ() { + return ( +
    + +
    + FAQ +

    + Licensing FAQ +

    +
    + {ITEMS.map((item) => ( +
    + + {item.q} + +

    + {item.a} +

    +
    + ))} +
    +
    +
    +
    + ); +} From 4aa5bc91c70a4c550abc208798df8294a0c64183 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 20 May 2026 20:59:31 -0700 Subject: [PATCH 08/13] =?UTF-8?q?test(website):=20cover=20PricingFAQ=20?= =?UTF-8?q?=E2=80=94=20heading,=207=20questions,=20#faq=20anchor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- .../components/pricing/PricingFAQ.spec.tsx | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 apps/website/src/components/pricing/PricingFAQ.spec.tsx diff --git a/apps/website/src/components/pricing/PricingFAQ.spec.tsx b/apps/website/src/components/pricing/PricingFAQ.spec.tsx new file mode 100644 index 00000000..cd4ba263 --- /dev/null +++ b/apps/website/src/components/pricing/PricingFAQ.spec.tsx @@ -0,0 +1,54 @@ +// @vitest-environment jsdom +import React from 'react'; +import { describe, expect, it, vi } from 'vitest'; +import { render, screen } from '@testing-library/react'; +import { PricingFAQ } from './PricingFAQ'; + +vi.mock('../ui/Container', () => ({ + Container: ({ children }: { children: React.ReactNode }) =>
    {children}
    , +})); +vi.mock('../ui/Section', () => ({ + Section: ({ children }: { children: React.ReactNode }) =>
    {children}
    , +})); +vi.mock('../ui/Eyebrow', () => ({ + Eyebrow: ({ children }: { children: React.ReactNode }) => {children}, +})); + +const EXPECTED_QUESTIONS = [ + 'Is @ngaf/chat open source?', + 'Can I use it for free?', + 'Can I use it at work?', + 'Do my end users need licenses?', + 'Can I modify the source?', + 'Can I redistribute it?', + 'What happens to older MIT versions?', +]; + +describe('PricingFAQ', () => { + it('renders the FAQ heading', () => { + render(); + expect( + screen.getByRole('heading', { level: 2, name: 'Licensing FAQ' }), + ).toBeTruthy(); + }); + + it('renders all 7 questions as elements inside
    ', () => { + const { container } = render(); + const summaries = container.querySelectorAll('details > summary'); + expect(summaries.length).toBe(7); + const texts = Array.from(summaries, (s) => s.textContent); + expect(texts).toEqual(EXPECTED_QUESTIONS); + }); + + it('exposes an #faq anchor for footer deep-linking', () => { + const { container } = render(); + expect(container.querySelector('#faq')).toBeTruthy(); + }); + + it('renders the open-source clarification answer', () => { + render(); + expect( + screen.getByText(/source-available under the PolyForm Noncommercial License 1\.0\.0/i), + ).toBeTruthy(); + }); +}); From f81d55aa7e00179212c83e28373798f91e8c5f66 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 20 May 2026 21:01:12 -0700 Subject: [PATCH 09/13] =?UTF-8?q?feat(website):=20pricing=20page=20?= =?UTF-8?q?=E2=80=94=20new=20header,=20notes,=20FAQ=20integration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Header: "Pricing for production AI chat interfaces" - Subhead names the chat NC license + clarifies other libs stay MIT - Adds commercial-use note (below grid), evaluation note (between matrix and FAQ), OSS clarification (below FAQ) - Integrates PricingFAQ between CompatibilityMatrix and LeadForm - Metadata description updated for SEO Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/website/src/app/pricing/page.tsx | 75 +++++++++++++++++++++------ 1 file changed, 59 insertions(+), 16 deletions(-) diff --git a/apps/website/src/app/pricing/page.tsx b/apps/website/src/app/pricing/page.tsx index 2cab8e80..c3d2290f 100644 --- a/apps/website/src/app/pricing/page.tsx +++ b/apps/website/src/app/pricing/page.tsx @@ -5,23 +5,43 @@ import { Eyebrow } from '../../components/ui/Eyebrow'; import { PricingGrid } from '../../components/pricing/PricingGrid'; import { CompareTable } from '../../components/pricing/CompareTable'; import { CompatibilityMatrix } from '../../components/pricing/CompatibilityMatrix'; +import { PricingFAQ } from '../../components/pricing/PricingFAQ'; import { LeadForm } from '../../components/pricing/LeadForm'; import { FinalCTA } from '../../components/landing/FinalCTA'; import { createPageMetadata } from '../../lib/site-metadata'; export const metadata = createPageMetadata({ title: 'Pricing — Agent UI for Angular', - description: 'Simple, transparent pricing. MIT-licensed libraries are free forever. Enterprise contracts available.', + 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.', pathname: '/pricing', type: 'website', }); +function SmallNote({ children }: { children: React.ReactNode }) { + return ( +

    + {children} +

    + ); +} + export default function PricingPage() { return ( <>
    -
    +
    Pricing

    - Simple, transparent pricing. + Pricing for production AI chat interfaces

    - MIT-licensed libraries are free forever. Enterprise contracts available for teams that want priority support and an SLA. + @ngaf/chat is free for noncommercial use. Commercial production use requires a Threadplane license. Other libraries in the framework remain MIT.

    + + +
    + + + A license is required when @ngaf/chat is used in a commercial product, SaaS app, internal business tool, paid client project, or production application operated by or for a for-profit entity. + + +
    + + +
    + + + Commercial evaluation is free for 30 days. A paid license is required before production deployment. + + +
    +
    Compatibility @@ -61,26 +100,30 @@ export default function PricingPage() { style={{ fontFamily: tokens.typography.h2.family, fontSize: tokens.typography.h2.size, - margin: 0, - marginBottom: 16, + lineHeight: tokens.typography.h2.line, + fontWeight: 700, color: tokens.colors.textPrimary, - }} - > - Angular version support - -

    - We ship against the versions our CI tests. Other versions may work but aren't guaranteed. -

    + Works with your agent stack +
    + + + +
    + + + 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. + + +
    + From 64ee4b4430f5d20f853937cce67948c8f1a46878 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 20 May 2026 21:02:10 -0700 Subject: [PATCH 10/13] =?UTF-8?q?fix(website):=20pricing=20=E2=80=94=20res?= =?UTF-8?q?tore=20"Angular=20version=20support"=20compatibility=20h2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plan template accidentally replaced the original compatibility section header with a homepage-style "Works with your agent stack" header, dropping the CI-tested-versions paragraph in the process. Restores the original h2 + paragraph; the CompatibilityMatrix below it is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/website/src/app/pricing/page.tsx | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/website/src/app/pricing/page.tsx b/apps/website/src/app/pricing/page.tsx index c3d2290f..de07919f 100644 --- a/apps/website/src/app/pricing/page.tsx +++ b/apps/website/src/app/pricing/page.tsx @@ -100,16 +100,23 @@ export default function PricingPage() { style={{ fontFamily: tokens.typography.h2.family, fontSize: tokens.typography.h2.size, - lineHeight: tokens.typography.h2.line, - fontWeight: 700, + margin: 0, + marginBottom: 16, color: tokens.colors.textPrimary, + }} + > + Angular version support + +

    - Works with your agent stack - + We ship against the versions our CI tests. Other versions may work but aren't guaranteed. +

    From 064cd8e4c445670c9b8ff7c72067a4298733556a Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 20 May 2026 21:03:33 -0700 Subject: [PATCH 11/13] =?UTF-8?q?feat(website):=20footer=20=E2=80=94=20rep?= =?UTF-8?q?lace=20"MIT=20License"=20with=20"Licensing"=20=E2=86=92=20/pric?= =?UTF-8?q?ing#faq?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The whole framework is no longer MIT (chat is dual-licensed). Resources column link relabeled Licensing, targets /pricing#faq. Bottom bar now shows "Licensing · Pricing" instead of "MIT License · Pricing". Tracking ids footer_licensing and footer_licensing_bottom. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/website/src/components/shared/Footer.tsx | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/apps/website/src/components/shared/Footer.tsx b/apps/website/src/components/shared/Footer.tsx index 85ff2590..2cb665bd 100644 --- a/apps/website/src/components/shared/Footer.tsx +++ b/apps/website/src/components/shared/Footer.tsx @@ -295,18 +295,12 @@ export function Footer() { onMouseLeave={(e) => (e.currentTarget.style.color = tokens.colors.textSecondary)}> npm Package - trackExternalLinkClick('https://github.com/cacheplane/angular-agent-framework/blob/main/LICENSE', { - surface: 'footer', - cta_id: 'footer_mit_license', - cta_text: 'MIT License', - })} + trackFooterCta('Licensing', '/pricing#faq')} onMouseEnter={(e) => (e.currentTarget.style.color = tokens.colors.accent)} onMouseLeave={(e) => (e.currentTarget.style.color = tokens.colors.textSecondary)}> - MIT License - + Licensing + @@ -314,10 +308,27 @@ export function Footer() {
    © {new Date().getFullYear()} Agent UI for Angular. All rights reserved. - MIT License · trackFooterCta('Pricing Bottom', '/pricing')} - onMouseEnter={(e) => (e.currentTarget.style.color = tokens.colors.accent)} - onMouseLeave={(e) => (e.currentTarget.style.color = tokens.colors.textMuted)}>Pricing + + trackFooterCta('Licensing Bottom', '/pricing#faq')} + onMouseEnter={(e) => (e.currentTarget.style.color = tokens.colors.accent)} + onMouseLeave={(e) => (e.currentTarget.style.color = tokens.colors.textMuted)} + > + Licensing + +  ·  + trackFooterCta('Pricing Bottom', '/pricing')} + onMouseEnter={(e) => (e.currentTarget.style.color = tokens.colors.accent)} + onMouseLeave={(e) => (e.currentTarget.style.color = tokens.colors.textMuted)} + > + Pricing + +
    From af39420e0e4c2f88a252fcbaccf5830c80f45245 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 20 May 2026 21:04:44 -0700 Subject: [PATCH 12/13] docs: rewrite root COMMERCIAL.md to lead with @ngaf/chat dual-license Replaces the all-MIT framing with: most libs MIT, @ngaf/chat dual (PolyForm-NC OR Threadplane-Commercial), minting service untouched. Updates Questions contact links to threadplane.ai/{pricing,contact}. Co-Authored-By: Claude Opus 4.7 (1M context) --- COMMERCIAL.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/COMMERCIAL.md b/COMMERCIAL.md index 45021025..963690f8 100644 --- a/COMMERCIAL.md +++ b/COMMERCIAL.md @@ -1,6 +1,17 @@ # Licensing -The libraries in this repository (`@ngaf/langgraph`, `@ngaf/chat`, and all related packages) are released under the **MIT License**. You are free to use, modify, and distribute them in any project — commercial or noncommercial — at no cost. See [`LICENSE`](./LICENSE). +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). + +## `@ngaf/chat` + +Starting with the next published version, `@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. + +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 @@ -8,5 +19,6 @@ The ThreadPlane minting service (`apps/minting-service/`) is a proprietary inter ## Questions -- Website: https://threadplane.ai -- Email: hello@cacheplane.ai +- Website: +- Pricing: +- Sales: From 631f9b2c235430980365a8bc5d3d93fff76296eb Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 20 May 2026 21:05:10 -0700 Subject: [PATCH 13/13] =?UTF-8?q?docs:=20root=20README=20=E2=80=94=20quali?= =?UTF-8?q?fy=20license=20paragraph=20for=20@ngaf/chat=20exception?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drops the all-MIT badge (no single badge captures a per-lib split) and rewrites the license paragraph to name @ngaf/chat explicitly as PolyForm-NC OR Threadplane-Commercial, while keeping the other 8 libraries' MIT framing intact. Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 10e1fc50..d818dc90 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,6 @@ npm version - - License: MIT - Angular 20+ @@ -132,6 +129,6 @@ That's it. `chat.messages()` and `chat.status()` are Angular Signals. Bind them ## License -**MIT** — free for any use. See [`LICENSE`](./LICENSE). +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/langgraph` and all libraries in this repository are released under the [MIT License](./LICENSE). You are free to use, modify, and distribute them in both commercial and noncommercial projects without restriction. +**`@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.
    Feature{h} + Feature + + {t.label} +
    {row.feature}{row.oss ? : }{row.seat ? : }{row.app ? : }{row.enterprise ? : } + {row.feature} + + {renderCell(row.cells[t.key])} +