From 2d542eeb7e249b4c25ea9236e46cc77437dd42b1 Mon Sep 17 00:00:00 2001 From: Matt Sywulak <51167140+msywulak@users.noreply.github.com> Date: Thu, 3 Sep 2026 15:31:03 -0400 Subject: [PATCH 1/8] =?UTF-8?q?feat(www):=20the=20fold=20says=20the=20sent?= =?UTF-8?q?ence=20=E2=80=94=20H1=20verbatim,=20the=20MCP=20command=20as=20?= =?UTF-8?q?the=20CTA,=20the=20demo=20exchange=20in=20the=20recording's=20s?= =?UTF-8?q?lot,=20trust=20tiers=20in=20the=20PRD's=20words=20(#5606)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/www/public/llms.txt | 12 +- apps/www/src/app/layout.tsx | 14 +- apps/www/src/components/copy-command.tsx | 55 +++++ apps/www/src/components/landing/big-stat.tsx | 12 +- apps/www/src/components/landing/data.ts | 78 ++++++- .../components/landing/drop-in-surfaces.tsx | 59 +---- apps/www/src/components/landing/end-cta.tsx | 44 ++-- apps/www/src/components/landing/hero.tsx | 220 ++++++++---------- .../src/components/landing/how-it-works.tsx | 13 +- apps/www/src/components/webmcp.tsx | 23 +- 10 files changed, 307 insertions(+), 223 deletions(-) create mode 100644 apps/www/src/components/copy-command.tsx diff --git a/apps/www/public/llms.txt b/apps/www/public/llms.txt index 8ab4ca13fa..c0dff5b43f 100644 --- a/apps/www/public/llms.txt +++ b/apps/www/public/llms.txt @@ -1,8 +1,16 @@ # Atlas -> Deploy-anywhere text-to-SQL data analyst agent. Open-source under AGPL-3.0. +> Atlas is the company facts your AI agents can trust: every one carries its source, its date, and the name of the person who approved it. Open source, runs in your VPC. -Atlas connects to your database, auto-generates a YAML semantic layer from your schema, and lets an AI agent query your data in plain English. It validates every query (read-only, AST-parsed, table-whitelisted) and returns structured results with charts and narrative. +To connect an AI agent to Atlas, run this in a terminal. It configures Claude Desktop, Cursor or Continue (or prints a config block for any other MCP client with `--client generic`) against the hosted NovaMart demo, with no account and no email: + +```bash +bunx @useatlas/mcp init --hosted --demo --write +``` + +Then ask: "What is NovaMart's return window?" The answer names its source, its date and the person who approved it, and surfaces the contradiction between Finance and Support without picking a side. Full guide: https://docs.useatlas.dev/guides/mcp. Machine-readable docs: https://docs.useatlas.dev/llms.txt. + +Three kinds of thing live in the Atlas, and every answer says which it is drawing on: **Surveyed** (read live from the company's own data through a semantic layer, SELECT-only, validated seven ways — it cannot go stale), **Attested** (extracted from something someone wrote, then approved by a named person who is on the record), and **On the record** (the raw source, unedited). Surveyed outranks Attested wherever they overlap. Contradictions are shown with both sources; Atlas picks neither. The complete Atlas runs self-hosted under AGPL-3.0; hosted Atlas is in the US, with EU and APAC regions built and brought online on request. ## Core capabilities diff --git a/apps/www/src/app/layout.tsx b/apps/www/src/app/layout.tsx index 2fccc3acfb..b5296c391a 100644 --- a/apps/www/src/app/layout.tsx +++ b/apps/www/src/app/layout.tsx @@ -18,15 +18,15 @@ const jetbrainsMono = JetBrains_Mono({ export const metadata: Metadata = { metadataBase: new URL("https://www.useatlas.dev"), title: { - default: "Atlas — Ask your data anything, trust the answer.", + default: "Atlas — the company facts your AI agents can trust", template: "%s — Atlas", }, description: - "Atlas is the AI data analyst you can run anywhere. It answers plain-English questions across your SQL warehouses and REST APIs, grounded in a semantic layer you control. Run it in the cloud or self-host it — open source.", + "Atlas is the company facts your AI agents can trust: every one carries its source, its date, and the name of the person who approved it. Open source, runs in your VPC.", openGraph: { - title: "Atlas — Ask your data anything, trust the answer.", + title: "Atlas — the company facts your AI agents can trust", description: - "Atlas reads your semantic layer, writes the SQL, and runs it read-only behind 7 validators — SELECT-only, single-statement, whitelisted to your schema. Cloud or self-hosted.", + "Atlas is the company facts your AI agents can trust: every one carries its source, its date, and the name of the person who approved it. Open source, runs in your VPC.", url: "https://www.useatlas.dev", siteName: "Atlas", type: "website", @@ -36,15 +36,15 @@ export const metadata: Metadata = { url: "/og.png", width: 1200, height: 630, - alt: "Atlas — Ask your data anything, trust the answer.", + alt: "Atlas — the company facts your AI agents can trust", }, ], }, twitter: { card: "summary_large_image", - title: "Atlas — Ask your data anything, trust the answer.", + title: "Atlas — the company facts your AI agents can trust", description: - "Plain-English questions answered across your SQL warehouses and REST APIs, grounded in a semantic layer you control. Cloud or self-hosted, open source.", + "Atlas is the company facts your AI agents can trust: every one carries its source, its date, and the name of the person who approved it. Open source, runs in your VPC.", images: ["/og.png"], }, }; diff --git a/apps/www/src/components/copy-command.tsx b/apps/www/src/components/copy-command.tsx new file mode 100644 index 0000000000..e1301b0a30 --- /dev/null +++ b/apps/www/src/components/copy-command.tsx @@ -0,0 +1,55 @@ +"use client"; + +import { useState } from "react"; + +type CopyState = "idle" | "copied" | "failed"; + +const LABEL: Record = { + idle: "Copy", + copied: "Copied", + failed: "Select & copy", +}; + +/** + * A one-line command rendered as the page's primary call to action: a dark + * code pane (the brand's fixed terminal surface) with a copy button. Clipboard + * access can be denied (insecure context, permissions policy), so a failure + * is reported in the button label rather than swallowed. + */ +export function CopyCommand({ command, className = "" }: { command: string; className?: string }) { + const [state, setState] = useState("idle"); + + async function copy() { + try { + await navigator.clipboard.writeText(command); + setState("copied"); + setTimeout(() => setState("idle"), 2000); + } catch (err) { + console.warn( + "[copy-command] clipboard write failed:", + err instanceof Error ? err.message : String(err), + ); + setState("failed"); + } + } + + return ( +
+ $ + + {command} + + +
+ ); +} diff --git a/apps/www/src/components/landing/big-stat.tsx b/apps/www/src/components/landing/big-stat.tsx index cd1c89fed4..d1655a0756 100644 --- a/apps/www/src/components/landing/big-stat.tsx +++ b/apps/www/src/components/landing/big-stat.tsx @@ -1,3 +1,8 @@ +/** + * The Surveyed tier's introduction: the analyst is the tier that cannot be + * wrong. The "0" is writes — every query is SELECT-only — and the copy says + * why the data outranks anyone's recollection. + */ export function BigStat() { return (
+

// surveyed — the tier that cannot be wrong

- writes. Every query Atlas runs is SELECT-only, single-statement, and - whitelisted to your semantic layer — enforced by seven validators, not - suggested by a prompt. + writes. Every Surveyed answer is a SELECT-only, single-statement query, + whitelisted to a semantic layer you author, re-read from live rows — + so the data outranks what anyone remembers.

// empty check · mutation guard · AST parse · table whitelist · row-level security · auto LIMIT · statement timeout diff --git a/apps/www/src/components/landing/data.ts b/apps/www/src/components/landing/data.ts index 97f19a0f14..1bbbd30b18 100644 --- a/apps/www/src/components/landing/data.ts +++ b/apps/www/src/components/landing/data.ts @@ -1,16 +1,81 @@ /** - * Shared sample data used across landing-page components. + * Shared copy and sample data for the landing page. * - * Hoisted here so the hero answer card and the how-it-works reply pane, plus - * any future surface that quotes the same NovaMart "top categories by GMV" - * answer, read from a single source. No copy/paste drift between them. + * Hoisted here so every surface that quotes the sentence, the demo command or + * the NovaMart exchange reads from one source. The sentence is decided in + * docs/prd/launch-cycle.md and renders verbatim; the exchange mirrors the + * seeded demo corpus (packages/api/src/lib/brain/demo-corpus/corpus.ts), so + * what the page shows is what the hosted demo answers. */ + +/** The launch cycle's sentence, verbatim (docs/prd/launch-cycle.md). */ +export const SENTENCE = + "Atlas is the company facts your AI agents can trust: every one carries its source, its date, and the name of the person who approved it. Open source, runs in your VPC."; + +/** The one command every launch surface prints — no account, no email. */ +export const MCP_DEMO_COMMAND = "bunx @useatlas/mcp init --hosted --demo --write"; + +/** The demo's one question. */ +export const DEMO_QUESTION = "What is NovaMart's return window?"; + +/** + * The demo exchange as the hosted NovaMart corpus answers it: the attested + * claim with its speaker, channel and date, and the contradiction Atlas shows + * beside it without picking a side. Dates and names are the corpus's own. + */ +export const DEMO_EXCHANGE = { + attested: { + claim: "30 days from delivery, for every category.", + speaker: "Priya Natarajan", + role: "Head of Finance", + channel: "#finance", + date: "14 Jul 2026", + }, + contradiction: { + claim: "14 days from delivery. Please stop quoting 30.", + speaker: "Marcus Adeyemi", + role: "Support", + channel: "#support", + date: "2 Aug 2026", + }, +} as const; + +/** + * The three kinds of thing that live in the Atlas, in the PRD's language + * (docs/prd/company-atlas.md § What a person can trust). Every answer says + * which one it is drawing on. + */ +export type TrustTier = { + readonly name: string; + readonly what: string; + readonly why: string; +}; + +export const TRUST_TIERS: ReadonlyArray = [ + { + name: "Surveyed", + what: "Drawn directly from the company's own data.", + why: "True by construction — the answer re-reads the live rows. Nobody interpreted anything, and it cannot go stale between readings.", + }, + { + name: "Attested", + what: "Extracted from something someone wrote, then approved.", + why: "A named person in your company read this claim and stood behind it. That person is on the record.", + }, + { + name: "On the record", + what: "The raw source material itself.", + why: "Not a claim about what is true — what was actually said, unedited. Trustworthy as testimony, not as fact.", + }, +]; + export type CategoryRow = { readonly category: string; readonly gmv: string; readonly orders: string; }; +/** Sample rows for the Surveyed pane in how-it-works. */ export const CATEGORY_ROWS: ReadonlyArray = [ { category: "Bedding", gmv: "$184,219", orders: "2,041" }, { category: "Kitchen", gmv: "$142,718", orders: "1,587" }, @@ -19,9 +84,6 @@ export const CATEGORY_ROWS: ReadonlyArray = [ { category: "Accessories", gmv: "$54,011", orders: "693" }, ]; -/** - * The canonical demo question. Shared by the hero answer card and the - * how-it-works reply pane so the prompt text never drifts between surfaces. - */ +/** The canonical analyst question, for the Surveyed pane. */ export const TOP_CATEGORY_QUESTION = "What's our top-performing category by GMV this month?"; diff --git a/apps/www/src/components/landing/drop-in-surfaces.tsx b/apps/www/src/components/landing/drop-in-surfaces.tsx index 7c75efa4af..0883d6e73f 100644 --- a/apps/www/src/components/landing/drop-in-surfaces.tsx +++ b/apps/www/src/components/landing/drop-in-surfaces.tsx @@ -9,35 +9,6 @@ function DropInItem({ name, desc }: DropInProps) { ); } -/** - * Queryable read datasources Atlas ships today (#3994). Verified against the - * shipped connection/plugin code — every entry is a datasource you can connect - * and query, not an action or write target. Elasticsearch and OpenSearch are - * one unified engine, so they share a chip. Twenty (CRM action) and Obsidian - * (a surface + vault-reader action) are intentionally absent — they aren't - * analytics datasources. - * - * Postgres/MySQL are native (packages/api/src/lib/db/connection.ts); the - * warehouses/search engines are `datasource`-typed plugins under plugins/; - * Stripe/Notion/GitHub and arbitrary OpenAPI specs are REST/OpenAPI presets in - * packages/api/src/lib/openapi/data-candidates.ts — so there is no plugins/ - * directory for them, and that's expected, not stale. - */ -const DATASOURCES: ReadonlyArray = [ - "PostgreSQL", - "MySQL", - "ClickHouse", - "Snowflake", - "BigQuery", - "DuckDB", - "Elasticsearch / OpenSearch", - "Salesforce", - "Stripe", - "Notion", - "GitHub", - "any OpenAPI 3.x spec", -]; - /** * The "drop-in surfaces" band. Carried over from the old Primitives section — * the four architecture cards were cut as too internal for a plain-language @@ -88,27 +59,15 @@ export function DropInSurfaces() {

-
-

- // connect anything — read-only, behind the same validators -

-
    - {DATASOURCES.map((name) => ( -
  • - {name} -
  • - ))} -
-

- SQL warehouses, search engines, and REST APIs all become datasources - you can ask in plain English. Bring any OpenAPI spec and Atlas reads - it like a table. -

-
+

+ SQL warehouses, search engines and REST APIs all become datasources you + can ask in plain English, read-only, behind the same validators. The + full list lives in the docs:{" "} + + connect your data + + . +

); } diff --git a/apps/www/src/components/landing/end-cta.tsx b/apps/www/src/components/landing/end-cta.tsx index 429d46a016..c82cbae7de 100644 --- a/apps/www/src/components/landing/end-cta.tsx +++ b/apps/www/src/components/landing/end-cta.tsx @@ -1,7 +1,10 @@ +import { CopyCommand } from "../copy-command"; +import { MCP_DEMO_COMMAND, SENTENCE } from "./data"; + /** * Closing CTA — the page's one deep-green "drenched" band: a full-bleed forest * ground with cream text and the bright brand teal as the spark, echoing the - * hero headline as a bookend. The only place the dark/green register returns on + * sentence as a bookend. The only place the dark/green register returns on * the otherwise light page. See PRODUCT.md › Aesthetic Direction. */ export function EndCta() { @@ -14,34 +17,21 @@ export function EndCta() { color: "var(--drench-fg)", }} > -
-

- Ask your data anything. - - Trust the answer. - +
+

+ {SENTENCE}

- -

- 14-day trial, no credit card. Or self-host — free and open source:{" "} - - bun create atlas-agent - + , free and open source.

diff --git a/apps/www/src/components/landing/hero.tsx b/apps/www/src/components/landing/hero.tsx index 753641e6d5..5e5b1d207b 100644 --- a/apps/www/src/components/landing/hero.tsx +++ b/apps/www/src/components/landing/hero.tsx @@ -1,19 +1,14 @@ -import { Fragment } from "react"; - -import { CATEGORY_ROWS, TOP_CATEGORY_QUESTION } from "./data"; - -const HEADLINE_LINES = ["Ask your data anything.", "Trust the answer."] as const; -const ITALIC_LINE_INDEX = 1; - -const SUBHEAD = - "Atlas is the AI data analyst you can run anywhere. It turns plain-English questions into trustworthy answers across your SQL warehouses and REST APIs, grounded in a semantic layer you control."; +import { CopyCommand } from "../copy-command"; +import { DEMO_EXCHANGE, DEMO_QUESTION, MCP_DEMO_COMMAND, SENTENCE, TRUST_TIERS } from "./data"; /** - * The hero's payload: a plain-English question and the validated answer it - * returns. No SQL here — the mechanism (YAML + generated SQL) lives in the - * YAML section below, so the two surfaces don't duplicate. + * The hero visual: the demo exchange, rendered as the hosted NovaMart corpus + * answers it. It stands in the slot the recording (#5605) takes; when the + * dated GIF lands it replaces this card in one commit and the card's copy + * moves nowhere, because the recording shows the same exchange. */ -function AnswerCard() { +function DemoExchange() { + const { attested, contradiction } = DEMO_EXCHANGE; return (
- atlas · agent reply + claude desktop · atlas-demo - chat · mcp · widget + searchAtlas
-

- // asked in plain english -

-

{TOP_CATEGORY_QUESTION}

+

// you ask

+

{DEMO_QUESTION}

-

- // validated answer -

+

// the answer, with a name on it

-
- category - gmv - orders +
+ + Attested + + + {attested.speaker} · {attested.role} · {attested.channel} · {attested.date} +
- {CATEGORY_ROWS.slice(0, 3).map((row, i) => ( -
- {row.category} - {row.gmv} - {row.orders} -
- ))} +

{attested.claim}

+

+ approved by a named person · source and date on the record +

-
- - 7 validators - - · - read-only - · - row-limited - · - audited +
+

// also on the record — Atlas picks neither

+
+
+ + Contradiction + + + {contradiction.speaker} · {contradiction.role} · {contradiction.channel} · {contradiction.date} + +
+

{contradiction.claim}

+
); } -type Stage = { readonly label: string; readonly value: string; readonly highlight: boolean }; - -const STAGES: ReadonlyArray = [ - { label: "ask", value: '"top category by gmv…"', highlight: false }, - { label: "semantic layer", value: "your YAML", highlight: false }, - { label: "validate", value: "7 checks · read-only", highlight: false }, - { label: "answer", value: "grounded · audited", highlight: true }, -]; - /** - * The four-stage path: ask → semantic layer → validate → answer. One straight - * read left-to-right; the highlight lands on the answer to reinforce the - * headline's promise (a grounded, audited result you can trust). + * The three kinds of thing that live in the Atlas, in the PRD's language. + * Sits under the fold as the first thing a reader meets after the exchange, + * so the chip on the card above ("Attested") is explained one screen later. */ -function PipelineStrip() { +function TierStrip() { return (

- // every question takes the same path + // three kinds of thing live in the Atlas — every answer says which it is drawing on

-
- {STAGES.map((stage, i) => ( - -
- {stage.label} - {stage.value} -
- {i < STAGES.length - 1 && ( - - → - - )} -
+
+ {TRUST_TIERS.map((tier) => ( +
+ {tier.name} + {tier.what} + {tier.why} +
))}
+

+ Surveyed outranks Attested wherever they overlap: a recollection never overwrites the data. + Nothing becomes Attested without a person approving it, and there is no setting that turns that off. +

); } +const [SENTENCE_HEAD, SENTENCE_TAIL] = (() => { + const i = SENTENCE.indexOf(":"); + return [SENTENCE.slice(0, i + 1), SENTENCE.slice(i + 1).trim()]; +})(); + export function Hero() { return ( -
+
{/* - The above-the-fold hero text (h1, subhead, CTAs, trial note) paints - immediately — no `animate-fade-in-up`. That keyframe starts at - `opacity: 0`, and Chrome's LCP algorithm won't register an element - painted transparent as an LCP candidate at its paint time. With the - headline (the mobile LCP element) fading in, Lighthouse mobile reported - `NO_LCP` and an inflated Speed Index (content still settling ~2.6s after - FCP). Entrance polish stays on below-the-fold / non-LCP surfaces - (PipelineStrip); the decorative AnswerCard also paints immediately so it - can't become a late LCP candidate on narrow viewports. + The above-the-fold text (h1, command, links) paints immediately — no + `animate-fade-in-up`. That keyframe starts at `opacity: 0`, and + Chrome's LCP algorithm won't register an element painted transparent + as an LCP candidate at its paint time (Lighthouse reported `NO_LCP` + when the headline faded in). Entrance polish stays below the fold + (TierStrip); the DemoExchange also paints immediately so it can't + become a late LCP candidate on narrow viewports. */}
-
-

- {HEADLINE_LINES.map((line, i) => ( - - {i === ITALIC_LINE_INDEX ? ( - {line} - ) : ( - line - )} - - ))} +
+

+ {SENTENCE_HEAD} + {SENTENCE_TAIL}

-

{SUBHEAD}

- -

- 14-day trial, no credit card. Or self-host — free and open source:{" "} - bun create atlas-agent

- +

- +
); } diff --git a/apps/www/src/components/landing/how-it-works.tsx b/apps/www/src/components/landing/how-it-works.tsx index 60cdd06d10..40a366b089 100644 --- a/apps/www/src/components/landing/how-it-works.tsx +++ b/apps/www/src/components/landing/how-it-works.tsx @@ -161,8 +161,9 @@ function AnswerPane() {
-

- // result · {CATEGORY_ROWS.length} rows · 7 validators passed +

+ Surveyed + // result · {CATEGORY_ROWS.length} rows · 7 validators passed

+

// surveyed

- Why you can trust the answer. + Why a Surveyed answer cannot be wrong.

You define your data once in YAML — the entities, joins, and the terms your team actually uses. Atlas reads it on every question, writes the SQL, and runs it read-only behind seven validators, so you see exactly - what ran. Self-host Atlas and that YAML lives in your own repo, - versioned and reviewed in pull requests like the rest of your code. + what ran and the rows it read. Self-host Atlas and that YAML lives in + your own repo, versioned and reviewed in pull requests like the rest of + your code.

diff --git a/apps/www/src/components/webmcp.tsx b/apps/www/src/components/webmcp.tsx index 25ade25db6..c95295149b 100644 --- a/apps/www/src/components/webmcp.tsx +++ b/apps/www/src/components/webmcp.tsx @@ -41,7 +41,28 @@ function openAndReport(url: string, openedText: string): { return { content: [{ type: "text", text }] }; } +const SENTENCE = + "Atlas is the company facts your AI agents can trust: every one carries its source, its date, and the name of the person who approved it. Open source, runs in your VPC."; + +const MCP_DEMO_COMMAND = "bunx @useatlas/mcp init --hosted --demo --write"; + const TOOLS: ModelContextTool[] = [ + { + name: "atlas_connect_agent_to_demo", + description: + `${SENTENCE} Returns the one terminal command that connects an MCP client (Claude Desktop, Cursor, Continue, or any other via --client generic) to the hosted NovaMart demo with no account and no email, plus the question to ask first.`, + inputSchema: { type: "object", properties: {}, additionalProperties: false }, + async execute() { + return { + content: [ + { + type: "text", + text: `Run this in a terminal, then restart the MCP client:\n\n${MCP_DEMO_COMMAND}\n\nThen ask: "What is NovaMart's return window?" The answer names its source, its date and the person who approved it, and shows the contradiction between Finance and Support without picking a side. Guide: https://docs.useatlas.dev/guides/mcp`, + }, + ], + }; + }, + }, { name: "atlas_start_free_trial", description: @@ -58,7 +79,7 @@ const TOOLS: ModelContextTool[] = [ { name: "atlas_open_live_demo", description: - "Open the Atlas live demo at app.useatlas.dev/demo against a sample database. No account required — just an email.", + "Open the Atlas web demo at app.useatlas.dev/demo in a browser. No account, but it asks for an email; for a no-email path use atlas_connect_agent_to_demo.", inputSchema: { type: "object", properties: {}, additionalProperties: false }, async execute() { const url = "https://app.useatlas.dev/demo"; From 3b8c1f5d8310a2b5953ef97893f29a9f60f796fa Mon Sep 17 00:00:00 2001 From: Matt Sywulak <51167140+msywulak@users.noreply.github.com> Date: Thu, 3 Sep 2026 15:35:28 -0400 Subject: [PATCH 2/8] =?UTF-8?q?feat(www):=20review=20fixes=20=E2=80=94=20t?= =?UTF-8?q?he=20h1=20reads=20verbatim=20to=20assistive=20tech,=20both=20de?= =?UTF-8?q?mo=20claims=20carry=20the=20Attested=20chip=20with=20a=20tensio?= =?UTF-8?q?n=20marker,=20tier=20copy=20in=20the=20PRD's=20exact=20words,?= =?UTF-8?q?=20the=20card=20says=20what=20the=20tool=20shows,=20breadth=20c?= =?UTF-8?q?ounts=20leave=20the=20www=20llms.txt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/www/public/llms.txt | 13 ++++--------- apps/www/src/components/landing/data.ts | 4 ++-- apps/www/src/components/landing/hero.tsx | 14 ++++++++++---- scripts/check-plugin-count.sh | 1 - 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/www/public/llms.txt b/apps/www/public/llms.txt index c0dff5b43f..852d42b81a 100644 --- a/apps/www/public/llms.txt +++ b/apps/www/public/llms.txt @@ -14,15 +14,10 @@ Three kinds of thing live in the Atlas, and every answer says which it is drawin ## Core capabilities -- **Text-to-SQL agent**: Multi-step reasoning powered by Vercel AI SDK. Explores schema, writes validated SQL, runs Python analysis, returns charts and narrative. -- **Semantic layer**: YAML-based entity definitions with auto-profiling, glossary terms, metrics, joins, and LLM enrichment. Versioned in git, reviewed in PRs. -- **8 databases**: PostgreSQL, MySQL, ClickHouse, Snowflake, DuckDB, BigQuery, Salesforce, Elasticsearch/OpenSearch. -- **6 LLM providers**: Anthropic, OpenAI, AWS Bedrock, Ollama, OpenAI-compatible (vLLM, TGI, LiteLLM), AI Gateway. -- **24 plugins**: Datasource adapters, sandbox backends (nsjail, E2B, Daytona, Vercel sandbox), interaction channels, action triggers, context providers. Extensible via Plugin SDK. -- **9+ integration channels**: Slack, Microsoft Teams, Discord, Email, Google Chat, Telegram, GitHub, Linear, WhatsApp, plus webhooks. -- **Embeddable**: Script tag widget, React component (`@useatlas/react`), TypeScript SDK (`@useatlas/sdk`), headless API. -- **MCP server**: Works with Claude Desktop, Cursor, and any MCP-compatible client. -- **Dynamic learning**: Learns query patterns over time. Stored as auditable YAML, not opaque embeddings. +- **The Company Atlas**: facts extracted from what the company already says (chat, transcripts, mail), each approved by a named person before it counts, carrying its source and date; contradictions surfaced with both sources; a coverage page that marks what nobody has surveyed. +- **The analyst (Surveyed tier)**: a YAML semantic layer you author — entities, joins, glossary terms, pinned metrics — and an agent that writes validated, read-only SQL against it and returns rows, charts and narrative. +- **Agent-native**: an MCP server (hosted over OAuth 2.1, self-hosted over stdio) for Claude Desktop, Cursor, Continue and any MCP client; a TypeScript SDK; an embeddable React component and script-tag widget; chat-platform adapters. +- **Datasources, LLM providers, plugins and integrations**: the full inventories live in the docs — https://docs.useatlas.dev/getting-started/connect-your-data, https://docs.useatlas.dev/guides/model-routing, https://docs.useatlas.dev/plugins/authoring-guide, https://docs.useatlas.dev/guides/integrations. ## Security diff --git a/apps/www/src/components/landing/data.ts b/apps/www/src/components/landing/data.ts index 1bbbd30b18..024b6fe899 100644 --- a/apps/www/src/components/landing/data.ts +++ b/apps/www/src/components/landing/data.ts @@ -55,7 +55,7 @@ export const TRUST_TIERS: ReadonlyArray = [ { name: "Surveyed", what: "Drawn directly from the company's own data.", - why: "True by construction — the answer re-reads the live rows. Nobody interpreted anything, and it cannot go stale between readings.", + why: "True by construction — the answer re-reads the live rows. Nobody interpreted anything, so nothing can have been interpreted wrong, and it cannot go stale between readings.", }, { name: "Attested", @@ -65,7 +65,7 @@ export const TRUST_TIERS: ReadonlyArray = [ { name: "On the record", what: "The raw source material itself.", - why: "Not a claim about what is true — what was actually said, unedited. Trustworthy as testimony, not as fact.", + why: "It is not a claim about what is true — it is what was actually said, unedited. Trustworthy as testimony, not as fact.", }, ]; diff --git a/apps/www/src/components/landing/hero.tsx b/apps/www/src/components/landing/hero.tsx index 5e5b1d207b..fd34be2208 100644 --- a/apps/www/src/components/landing/hero.tsx +++ b/apps/www/src/components/landing/hero.tsx @@ -47,20 +47,23 @@ function DemoExchange() {

{attested.claim}

- approved by a named person · source and date on the record + who said it · where · when — approved before it counted

-

// also on the record — Atlas picks neither

+

// also attested — Atlas shows both and picks neither

+ + Attested + - Contradiction + In tension {contradiction.speaker} · {contradiction.role} · {contradiction.channel} · {contradiction.date} @@ -109,9 +112,12 @@ function TierStrip() { ); } +// Split for line layout only. The tail keeps its leading space so the h1's +// text content — what assistive tech and scrapers read — is the sentence +// character for character. const [SENTENCE_HEAD, SENTENCE_TAIL] = (() => { const i = SENTENCE.indexOf(":"); - return [SENTENCE.slice(0, i + 1), SENTENCE.slice(i + 1).trim()]; + return [SENTENCE.slice(0, i + 1), SENTENCE.slice(i + 1)]; })(); export function Hero() { diff --git a/scripts/check-plugin-count.sh b/scripts/check-plugin-count.sh index ac50d423c9..fbb4510437 100755 --- a/scripts/check-plugin-count.sh +++ b/scripts/check-plugin-count.sh @@ -109,7 +109,6 @@ echo ":: Canonical plugin count derived from plugins/: ${N} (${typed_dirs[*]})" SURFACES=( "apps/www/src/components/landing/comparison.tsx" "apps/www/src/app/blog/announcing-atlas/page.tsx" - "apps/www/public/llms.txt" "apps/www/content/social/twitter-launch.md" "apps/www/content/social/linkedin-launch.md" "apps/docs/content/shared/comparisons/metabase.mdx" From 8246e1ed15dcace7d40c5ea93594e9a062a9ab84 Mon Sep 17 00:00:00 2001 From: Matt Sywulak <51167140+msywulak@users.noreply.github.com> Date: Thu, 3 Sep 2026 15:37:11 -0400 Subject: [PATCH 3/8] =?UTF-8?q?feat(www):=20review=20fixes=20=E2=80=94=20c?= =?UTF-8?q?ode-surface=20tokens,=20no=20future-tense=20docblock,=20the=20s?= =?UTF-8?q?entence=20and=20command=20single-sourced=20from=20landing/data,?= =?UTF-8?q?=20two=20remaining=20approver=20overclaims=20reworded;=20script?= =?UTF-8?q?s/check-launch-sentence.sh=20gates=20the=20sentence=20across=20?= =?UTF-8?q?six=20surfaces?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 3 ++ CLAUDE.md | 2 +- apps/www/public/llms.txt | 2 +- apps/www/src/app/layout.tsx | 10 ++--- apps/www/src/components/copy-command.tsx | 7 ++-- apps/www/src/components/landing/data.ts | 2 +- apps/www/src/components/landing/hero.tsx | 27 ++++-------- apps/www/src/components/webmcp.tsx | 9 ++-- scripts/check-launch-sentence.sh | 52 ++++++++++++++++++++++++ scripts/ci-local.sh | 1 + 10 files changed, 77 insertions(+), 38 deletions(-) create mode 100755 scripts/check-launch-sentence.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71accfdfd3..3d265638b7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -319,6 +319,9 @@ jobs: - name: Adversarial fixtures for the plugin-count gate (#4066) run: bash scripts/__tests__/check-plugin-count.test.sh + - name: Check the launch sentence renders verbatim on every surface (#5606) + run: bash scripts/check-launch-sentence.sh + - name: Check boot-loaded plugins ↔ api Dockerfile wiring lockstep (#4880) run: bun scripts/check-plugin-lockstep.ts diff --git a/CLAUDE.md b/CLAUDE.md index 5952c367ea..13a1e039e8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -33,7 +33,7 @@ These hold everywhere. The rest of this file is orientation, not rules. ### Tests - **`bun test --parallel`, never bare `bun test`** — `--parallel` implies `--isolate`: a fresh global + module registry per file. Bare `bun test` shares one global across every file and will pass on state a sibling left behind. Single file OK: `bun test path/to/file.test.ts`. ⚠️ **Never `--no-isolate`** — it trades that isolation for speed, and at least one suite (`agent-compaction.test.ts`) leaks module state across same-process runs today -- **Remote CI on the PR is the gate, not a local `/ci`** — push, open the PR as a **draft**, and let `ci.yml` run (~4 min, parallel) while you review. The local pre-flight is the cheap subset: `cd packages/api && bun test --parallel --changed=origin/main`, plus `bun run lint`, `bun run type` and `bun run lint:type-aware`. **`lint:type-aware` is on that list because it is its own CI-blocking job and costs ~11s** — leaving it off is what let a single type-aware diagnostic red-flag two CI jobs on #5083 *after* the pre-flight came back clean. Run the full `scripts/ci-local.sh` (43 ci-local gates, ~25 min, serial, rewrites source in place for the mutation gate) only when remote CI is broken or when you reshaped something `mutation-tables` anchors on. **Not "before tagging a release" — that clause is gone (#5410):** the local wrapper does not go green on an unchanged tree, so requiring it blocked every release including ones already serving prod. Remote CI on the tagged SHA is the release gate; local `/ci` is advisory. ⚠️ And without `TEST_DATABASE_URL` the local run self-skips all 104 real-Postgres suites — 1,432 assertions when last measured (2026-08-24, at 87 suites) — so it now reports `DECLINED`/exit 3 rather than a green that verified none of them +- **Remote CI on the PR is the gate, not a local `/ci`** — push, open the PR as a **draft**, and let `ci.yml` run (~4 min, parallel) while you review. The local pre-flight is the cheap subset: `cd packages/api && bun test --parallel --changed=origin/main`, plus `bun run lint`, `bun run type` and `bun run lint:type-aware`. **`lint:type-aware` is on that list because it is its own CI-blocking job and costs ~11s** — leaving it off is what let a single type-aware diagnostic red-flag two CI jobs on #5083 *after* the pre-flight came back clean. Run the full `scripts/ci-local.sh` (44 ci-local gates, ~25 min, serial, rewrites source in place for the mutation gate) only when remote CI is broken or when you reshaped something `mutation-tables` anchors on. **Not "before tagging a release" — that clause is gone (#5410):** the local wrapper does not go green on an unchanged tree, so requiring it blocked every release including ones already serving prod. Remote CI on the tagged SHA is the release gate; local `/ci` is advisory. ⚠️ And without `TEST_DATABASE_URL` the local run self-skips all 104 real-Postgres suites — 1,432 assertions when last measured (2026-08-24, at 87 suites) — so it now reports `DECLINED`/exit 3 rather than a green that verified none of them ### Merge discipline Rationale + override rules: [docs/development/branch-protection.md](docs/development/branch-protection.md). These are workflow rules — no file-read triggers them, so they stay here: diff --git a/apps/www/public/llms.txt b/apps/www/public/llms.txt index 852d42b81a..93f0933965 100644 --- a/apps/www/public/llms.txt +++ b/apps/www/public/llms.txt @@ -8,7 +8,7 @@ To connect an AI agent to Atlas, run this in a terminal. It configures Claude De bunx @useatlas/mcp init --hosted --demo --write ``` -Then ask: "What is NovaMart's return window?" The answer names its source, its date and the person who approved it, and surfaces the contradiction between Finance and Support without picking a side. Full guide: https://docs.useatlas.dev/guides/mcp. Machine-readable docs: https://docs.useatlas.dev/llms.txt. +Then ask: "What is NovaMart's return window?" The answer names who said it, where and when, marks that a person approved it before it counted, and surfaces the contradiction between Finance and Support without picking a side. Full guide: https://docs.useatlas.dev/guides/mcp. Machine-readable docs: https://docs.useatlas.dev/llms.txt. Three kinds of thing live in the Atlas, and every answer says which it is drawing on: **Surveyed** (read live from the company's own data through a semantic layer, SELECT-only, validated seven ways — it cannot go stale), **Attested** (extracted from something someone wrote, then approved by a named person who is on the record), and **On the record** (the raw source, unedited). Surveyed outranks Attested wherever they overlap. Contradictions are shown with both sources; Atlas picks neither. The complete Atlas runs self-hosted under AGPL-3.0; hosted Atlas is in the US, with EU and APAC regions built and brought online on request. diff --git a/apps/www/src/app/layout.tsx b/apps/www/src/app/layout.tsx index b5296c391a..d8bae18516 100644 --- a/apps/www/src/app/layout.tsx +++ b/apps/www/src/app/layout.tsx @@ -2,6 +2,7 @@ import type { Metadata } from "next"; import { Sora, JetBrains_Mono } from "next/font/google"; import "./globals.css"; import WebMCP from "@/components/webmcp"; +import { SENTENCE } from "@/components/landing/data"; const sora = Sora({ subsets: ["latin"], @@ -21,12 +22,10 @@ export const metadata: Metadata = { default: "Atlas — the company facts your AI agents can trust", template: "%s — Atlas", }, - description: - "Atlas is the company facts your AI agents can trust: every one carries its source, its date, and the name of the person who approved it. Open source, runs in your VPC.", + description: SENTENCE, openGraph: { title: "Atlas — the company facts your AI agents can trust", - description: - "Atlas is the company facts your AI agents can trust: every one carries its source, its date, and the name of the person who approved it. Open source, runs in your VPC.", + description: SENTENCE, url: "https://www.useatlas.dev", siteName: "Atlas", type: "website", @@ -43,8 +42,7 @@ export const metadata: Metadata = { twitter: { card: "summary_large_image", title: "Atlas — the company facts your AI agents can trust", - description: - "Atlas is the company facts your AI agents can trust: every one carries its source, its date, and the name of the person who approved it. Open source, runs in your VPC.", + description: SENTENCE, images: ["/og.png"], }, }; diff --git a/apps/www/src/components/copy-command.tsx b/apps/www/src/components/copy-command.tsx index e1301b0a30..881e803264 100644 --- a/apps/www/src/components/copy-command.tsx +++ b/apps/www/src/components/copy-command.tsx @@ -35,11 +35,10 @@ export function CopyCommand({ command, className = "" }: { command: string; clas return (
- $ - + $ + {command}