Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
96c4006
docs(specs): homepage live stage — one real run, scrubbed by scroll
blove Sep 5, 2026
0540d4f
docs(plans): homepage restructure (live-stage plan 1 of 3)
blove Sep 5, 2026
bd091e8
feat(website): single-source copy for the final mile, reliability rec…
blove Sep 5, 2026
9480289
fix(website): the runtimes receipt links the measured matrix on the a…
blove Sep 5, 2026
cb654c4
fix(website): receipts name real runtimes and a real link; the receip…
blove Sep 5, 2026
08390a3
feat(website): Reliability section — proof cells, three receipts, wor…
blove Sep 5, 2026
bd7518c
test(website): Reliability spec pins internal-vs-external receipt lin…
blove Sep 5, 2026
c799e2f
fix(website): Reliability reuses the tracked adapter link, labels the…
blove Sep 5, 2026
dad276a
feat(website): the scope table leads with the last-mile line
blove Sep 5, 2026
41d415b
fix(website): the final-mile eyebrow names where Threadplane fits, si…
blove Sep 5, 2026
ed8e625
feat(website): FinalCTA takes prove-it rows and extra caption links
blove Sep 5, 2026
a4ab105
fix(website): FinalCTA caption links never lead with a separator; pro…
blove Sep 5, 2026
a725b45
feat(website): TeamsBlock merges the pilot program and the field repo…
blove Sep 5, 2026
e830c51
fix(website): WhitePaperForm types its analytics surface; TeamsBlock …
blove Sep 5, 2026
e90e6c7
feat(website): homepage FAQ keeps four questions; the rest move to th…
blove Sep 5, 2026
fb7b299
fix(website): adapter-guide FAQ stops repeating its page; HomeFAQ com…
blove Sep 5, 2026
905df8e
docs(website): coding-agent setup prompt gets its own getting-started…
blove Sep 5, 2026
cf44a15
docs(website): coding-agents page description fits the meta budget; p…
blove Sep 5, 2026
38fd1a3
feat(website): the footer newsletter form steps aside on the homepage
blove Sep 5, 2026
5ada14e
feat(website): homepage restructure — eight-block spine, Reliability …
blove Sep 5, 2026
8c59e07
chore(website): purge CSS for the retired homepage sections; drop the…
blove Sep 5, 2026
9689a2f
fix(website): the runtimes receipt reads as a sentence and deep-links…
blove Sep 5, 2026
e7df8c4
Merge branch 'main' into blove/homepage-restructure
blove Sep 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions apps/website/content/docs/chat/getting-started/coding-agents.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
title: Coding agents
description: A maintained setup prompt for Claude Code, Codex and other coding agents adding Threadplane to an Angular app, plus the references they should read first.
---

# Coding agents

Threadplane publishes maintained, machine-readable setup context. Give your coding agent the prompt below; it starts with a fake agent, verifies the Angular surface, then connects LangGraph or AG-UI.

The prompt starts from provideFakeAgent(), renders the smallest accessible chat surface, adds a focused test, and only then explains the LangGraph or AG-UI configuration.

```text
Add Threadplane to this Angular application.

1. Read https://threadplane.ai/AGENTS.md and the current Threadplane quickstart.
2. Inspect this repository's Angular version, application configuration, design
system, test runner, and existing agent/backend code.
3. Begin with Threadplane's provideFakeAgent() path so the UI can be verified
without a server or LLM.
4. Render the smallest accessible <chat> experience using the app's existing
layout and styles.
5. Add a focused test for the integration.
6. After the fake path passes, explain the exact configuration needed for
either LangGraph or AG-UI. Do not invent credentials, endpoint URLs, or
backend capabilities.
7. Run the repository's relevant lint, test, and build commands and report
every changed file.
```

## What the agent should read

- [AGENTS.md](/AGENTS.md), the repository-level playbook.
- [The full agent reference](/llms-full.txt), every docs page in one file.
- [Try without a backend](/docs/chat/getting-started/try-without-a-backend), the human quickstart the prompt starts from.
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ The `detectChanges()` call after the input event matters: the send button stays
</Step>
</Steps>

## Testing without a model

`provideFakeAgent()` streams canned tokens in-process, and the mock transports script tool calls and interrupts, so component specs stay deterministic and fast. See the [testing guide](/docs/langgraph/guides/testing).

## Connect a real adapter

Replace `provideFakeAgent(...)` with one line and keep every component as it is:
Expand Down
8 changes: 8 additions & 0 deletions apps/website/content/docs/choosing-an-adapter/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,14 @@ The `Agent` contract from `@threadplane/chat` is intentionally runtime-neutral.

Both adapters are MIT-licensed and live in the same monorepo.

## Frequently asked

**Does Threadplane require LangGraph?** No. `@threadplane/ag-ui` connects any AG-UI-compatible backend, and `@threadplane/langgraph` is the direct LangGraph adapter.

**What is the difference between the two adapters?** See [Why two adapters?](#why-two-adapters) above and the [measured runtime support](#measured-runtime-support) table.

**How does Threadplane differ from a raw streaming SDK?** A streaming SDK gives you events. Threadplane gives you the Angular state model, chat UX, threads, approvals, generated UI, recovery, and tests on top of them.

## Next steps

- [LangGraph quickstart](/docs/langgraph/getting-started/quickstart) if your backend is LangGraph Platform and you want native streaming, checkpoints, threads, interrupts, and history APIs.
Expand Down
4 changes: 4 additions & 0 deletions apps/website/content/docs/langgraph/guides/persistence.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,10 @@ Setting the `threadId` signal (or calling `switchThread()`) loads the target thr
</Step>
</Steps>

## Where threads and checkpoints live

In your backend's persistence layer. Threadplane exposes thread, history, and resume behavior in the UI; durability comes from the runtime you operate.

## What's Next

<CardGroup cols={2}>
Expand Down
25 changes: 0 additions & 25 deletions apps/website/e2e/demo-modal.spec.ts

This file was deleted.

36 changes: 28 additions & 8 deletions apps/website/e2e/website.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,33 @@ test('landing page renders the dark proof band', async ({ page }) => {
await expect(page.locator('#proof[data-surface="dark"]')).toBeVisible();
});

test('landing page renders feature blocks (Stream/Persist/Approve/Render/Test)', async ({ page }) => {
test('landing page renders the spine in order (live-stage spec §3)', async ({ page }) => {
await page.goto('/');
await expect(page.locator('#stream-heading')).toBeVisible();
await expect(page.locator('#persist-heading')).toBeVisible();
await expect(page.locator('#approve-heading')).toBeVisible();
await expect(page.locator('#render-heading')).toBeVisible();
await expect(page.locator('#test-heading')).toBeVisible();
const ids = [
'hero-heading',
'proof-heading',
'why-heading',
'stream-heading',
'persist-heading',
'approve-heading',
'render-heading',
'final-cta-heading',
'pilot-heading',
'faq-heading',
];
const tops: number[] = [];
for (const id of ids) {
const el = page.locator(`#${id}`);
await expect(el).toBeAttached();
tops.push((await el.boundingBox())?.y ?? -1);
}
expect([...tops].sort((a, b) => a - b)).toEqual(tops);
await expect(page.locator('#test-heading')).toHaveCount(0);
await expect(page.locator('#parity-heading')).toHaveCount(0);
await expect(page.locator('#how-it-works-heading')).toHaveCount(0);
await expect(page.locator('#coding-agent-heading')).toHaveCount(0);
await expect(page.locator('#whitepaper-block')).toHaveCount(0);
await expect(page.locator('main form')).toHaveCount(1);
});

test('landing page no longer carries the retired promises section', async ({ page }) => {
Expand Down Expand Up @@ -165,7 +185,7 @@ test('footer newsletter form posts to /api/newsletter and renders success state'
});
});

await page.goto('/');
await page.goto('/pricing');
const footer = page.locator('footer');
const input = footer.getByLabel('Email');
// Regression guard: the disclosure once sat inside the flex row and the input collapsed to 26px.
Expand Down Expand Up @@ -519,7 +539,7 @@ test('representative docs pages do not create page-level horizontal overflow', a

test('marketing pages link to downloadable whitepaper PDFs', async ({ page }) => {
const expectedDownloads: Record<string, string> = {
'/': '/whitepaper.pdf',
'/ag-ui': '/whitepaper.pdf',
'/langgraph': '/whitepapers/angular.pdf',
'/render': '/whitepapers/render.pdf',
'/chat': '/whitepapers/chat.pdf',
Expand Down
63 changes: 14 additions & 49 deletions apps/website/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
import { Hero } from '../components/landing/Hero';
import { LogoRibbon } from '../components/landing/LogoRibbon';
import { ProofStrip } from '../components/landing/ProofStrip';
import { RuntimeParity } from '../components/landing/RuntimeParity';
import { ThreeSteps } from '../components/landing/ThreeSteps';
import { Reliability } from '../components/landing/Reliability';
import { ScopeTable } from '../components/landing/ScopeTable';
import { FeatureBlock } from '../components/landing/FeatureBlock';
import { DemoShowcase } from '../components/landing/DemoShowcase';
import { MediumSwitcher } from '../components/landing/MediumSwitcher';
import { CodingAgentQuickstart } from '../components/landing/CodingAgentQuickstart';
import { ScopeTable } from '../components/landing/ScopeTable';
import { SECTION_MEDIA } from '../lib/section-media';
import { buildPanes } from '../lib/build-panes';
import { PilotBlock } from '../components/landing/PilotBlock';
import { WhitePaperBlock } from '../components/landing/WhitePaperBlock';
import { TeamsBlock } from '../components/landing/TeamsBlock';
import { HomeFAQ } from '../components/landing/HomeFAQ';
import { FinalCTA } from '../components/landing/FinalCTA';
import { RecentArticles } from '../components/landing/RecentArticles';
import { Section } from '../components/ui/Section';
import { Container } from '../components/ui/Container';
import { PROVE_IT_ROWS } from '../lib/positioning';
import {
createPageMetadata,
HERO_SECONDARY_HREF,
Expand All @@ -35,20 +28,20 @@ export const metadata = createPageMetadata({

export default async function HomePage() {
const formPolicy = getFormPolicy();
const [streamPanes, persistPanes, approvePanes, renderPanes, testPanes] = await Promise.all(
(['stream', 'persist', 'approve', 'render', 'test'] as const).map((key) =>
const [streamPanes, persistPanes, approvePanes, renderPanes] = await Promise.all(
(['stream', 'persist', 'approve', 'render'] as const).map((key) =>
buildPanes(SECTION_MEDIA[key], SECTION_MEDIA[key].video?.url ?? ''),
),
);

return (
<>
<Hero />
<LogoRibbon />
<ProofStrip />
<RuntimeParity />
<ThreeSteps />
<Reliability />
<ScopeTable />

{/* The four capability acts stay as FeatureBlocks until plan 3 replaces
them with the live stage (spec §4). */}
{/* Stream */}
<FeatureBlock
id="stream"
Expand Down Expand Up @@ -122,47 +115,19 @@ export default async function HomePage() {
visual={<MediumSwitcher sectionId="render" panes={renderPanes} />}
/>

{/* Test */}
<FeatureBlock
id="test"
eyebrow="Test"
headline="Verify UI behavior without a model or backend."
body={
<>
<code className="home-code">provideFakeAgent()</code> streams canned tokens in-process; mock transports
script tool calls and interrupts. Your component specs stay deterministic and fast.
</>
}
rows={[
{ claim: 'No key, no server, no network', api: 'provideFakeAgent()' },
{ claim: 'Script tool calls and interrupts', api: 'mockLangGraphAgent()' },
{ claim: 'Same UI code in test and production', api: 'Agent' },
]}
cta={{ label: 'Try without a backend', href: INSTALL_OPTIONS[0].quickstartHref }}
visual={<MediumSwitcher sectionId="test" panes={testPanes} />}
/>

{/* Interactive demo showcase */}
<Section surface="canvas">
<Container>
<DemoShowcase />
</Container>
</Section>

<CodingAgentQuickstart />
<ScopeTable />
<WhitePaperBlock formPolicy={formPolicy} />
<PilotBlock />
<HomeFAQ />
<FinalCTA
variant="dark"
rows={PROVE_IT_ROWS}
headline="Prove the Angular UI before you connect the backend."
subtext="Start with a fake agent, render a real Threadplane surface, then swap in LangGraph or AG-UI when the integration is ready."
primary={{ label: 'Start the quickstart', href: INSTALL_OPTIONS[0].quickstartHref, ctaId: 'hero_quickstart' }}
secondary={{ label: 'Run live examples', href: HERO_SECONDARY_HREF, ctaId: 'hero_live_demo' }}
caption="MIT · no account, no cloud"
captionLink={{ label: 'Talk to an engineer', href: '/contact' }}
captionLinks={[{ label: 'Setup prompt for coding agents', href: '/docs/chat/getting-started/coding-agents' }]}
/>
<TeamsBlock formPolicy={formPolicy} />
<HomeFAQ />
<RecentArticles />
</>
);
Expand Down
4 changes: 2 additions & 2 deletions apps/website/src/components/landing/AdapterGuideLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import { trackCtaClick } from '../../lib/analytics/client';
* `data-cta` attribute on a server-rendered `<Link>` has no handler wired to
* it and never tracks.
*/
export function AdapterGuideLink() {
export function AdapterGuideLink({ className = 'parity-cta' }: { className?: string }) {
return (
<Link
href="/docs/choosing-an-adapter"
className="parity-cta"
className={className}
data-cta="home_adapter_guide"
onClick={() =>
trackCtaClick({
Expand Down
69 changes: 0 additions & 69 deletions apps/website/src/components/landing/CodingAgentQuickstart.spec.tsx

This file was deleted.

Loading
Loading