From 2e48fb91c4d4d554deb3e8ce5bfd1f334970236d Mon Sep 17 00:00:00 2001 From: Nicholas Kissel Date: Sat, 20 Jun 2026 16:43:10 -0700 Subject: [PATCH 1/7] Add Agent OS homepage diagrams: harness architecture + cold-start comparison MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two native React + inline SVG + Tailwind + framer-motion visuals on the Agent OS homepage, themed to the site palette: - HarnessArchitecture: a cross diagram framed as Agent OS — a cycling agent logo at the center routes requests/responses to Tools, Session, Sandbox, and Orchestration with animated flow dots; collapses to a stacked layout on mobile. - ColdStartRace: a containers-vs-Agent OS cold-start comparison. Each container boots on its own (red→green + mini bar) carrying its own ~1 GB; Agent OS packs all agents into one shared process at ~131 MB each. Includes live ms counters, a speed slider to control playback, and a stats row (92x faster, 8x less memory, 32x cheaper) sourced from bench.ts. Also bundles pre-existing in-progress site changes from this workspace: Navigation, Footer, registry (RegistryPageClient, registry.ts, registry-icons.ts, registry/[slug].astro), pricing page, and favicon. Co-Authored-By: Claude Opus 4.8 --- website/.astro/content-modules.mjs | 2 +- website/public/favicon.svg | 36 ++- website/src/components/Footer.tsx | 29 +- website/src/components/Navigation.tsx | 22 +- .../marketing/diagrams/ColdStartRace.tsx | 265 +++++++++++++++++ .../diagrams/HarnessArchitecture.tsx | 276 ++++++++++++++++++ .../marketing/registry/RegistryPageClient.tsx | 5 +- .../marketing/solutions/AgentOSPage.tsx | 61 +++- .../solutions/AgentOSPricingPage.tsx | 2 +- website/src/data/registry-icons.ts | 15 + website/src/data/registry.ts | 19 +- website/src/pages/registry/[slug].astro | 3 +- 12 files changed, 686 insertions(+), 49 deletions(-) create mode 100644 website/src/components/marketing/diagrams/ColdStartRace.tsx create mode 100644 website/src/components/marketing/diagrams/HarnessArchitecture.tsx create mode 100644 website/src/data/registry-icons.ts diff --git a/website/.astro/content-modules.mjs b/website/.astro/content-modules.mjs index 0efe088f7..e070527f8 100644 --- a/website/.astro/content-modules.mjs +++ b/website/.astro/content-modules.mjs @@ -2,8 +2,8 @@ export default new Map([ ["src/content/docs/docs/agent-to-agent.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fagent-to-agent.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/authentication.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fauthentication.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/benchmarks.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fbenchmarks.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/configuration.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fconfiguration.mdx&astroContentModuleFlag=true")], +["src/content/docs/docs/benchmarks.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fbenchmarks.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/core.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fcore.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/crash-course.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fcrash-course.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/cron.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fcron.mdx&astroContentModuleFlag=true")], diff --git a/website/public/favicon.svg b/website/public/favicon.svg index d7119e885..33655f670 100644 --- a/website/public/favicon.svg +++ b/website/public/favicon.svg @@ -1,8 +1,30 @@ - - - - - - - + + + + + + + + + + + + + + + + + + OS + + + + diff --git a/website/src/components/Footer.tsx b/website/src/components/Footer.tsx index 3f48ff37c..93b459816 100644 --- a/website/src/components/Footer.tsx +++ b/website/src/components/Footer.tsx @@ -1,7 +1,6 @@ "use client"; import { motion } from "framer-motion"; -import { MessageCircle } from "lucide-react"; const footer = { product: [ @@ -14,16 +13,15 @@ const footer = { { name: "Changelog", href: "https://github.com/rivet-dev/agent-os/releases" }, { name: "GitHub", href: "https://github.com/rivet-dev/agent-os" }, ], - legal: [ - { name: "Terms", href: "https://rivet.dev/terms" }, - { name: "Privacy Policy", href: "https://rivet.dev/privacy" }, - { name: "Acceptable Use", href: "https://rivet.dev/acceptable-use" }, - ], social: [ { name: "Discord", href: "https://rivet.dev/discord", - icon: , + icon: ( + + + + ), }, { name: "GitHub", @@ -59,7 +57,7 @@ export function Footer() { className="space-y-6 xl:col-span-4" > - Agent OS + Agent OS

A portable open-source operating system for agents.

@@ -78,7 +76,7 @@ export function Footer() {
-
+

Product

    @@ -104,19 +102,6 @@ export function Footer() { ))}
- - -

Legal

- -
diff --git a/website/src/components/Navigation.tsx b/website/src/components/Navigation.tsx index e9ea9f03c..6d48e8fdb 100644 --- a/website/src/components/Navigation.tsx +++ b/website/src/components/Navigation.tsx @@ -1,9 +1,23 @@ "use client"; import { useState, useEffect } from "react"; -import { Menu, X, MessageCircle } from "lucide-react"; +import { Menu, X } from "lucide-react"; import { GitHubStars } from "./GitHubStars"; +function DiscordIcon({ className }: { className?: string }) { + return ( + + ); +} + const NAV_LINKS = [ { href: "/use-cases", label: "Use Cases" }, { href: "/pricing", label: "Pricing" }, @@ -53,7 +67,7 @@ export function Navigation() {
Agent OS @@ -74,7 +88,7 @@ export function Navigation() { className="inline-flex h-10 items-center justify-center whitespace-nowrap rounded-md border border-ink/15 px-4 py-2 text-sm text-ink-soft transition-colors hover:border-ink/30 hover:text-ink" aria-label="Discord" > - + setMobileMenuOpen(false)} aria-label="Discord" > - + Discord green + mini bar) and carries its own ~1 GB of memory. +// Agent OS — every agent is packed into ONE shared process: a single box +// that boots once and shares memory, ~131 MB per agent. +// The contrast (four separate boots vs one grouped boot) is the point. Numbers +// come from bench.ts so they stay accurate. +// --------------------------------------------------------------------------- + +const AGENTOS_MARK = '/images/agent-os/agentos-logo-ink.svg'; +const AGENT_LOGOS = [ + '/images/agent-logos/pi.svg', + '/images/agent-logos/claude-code.svg', + '/images/agent-logos/codex.svg', + '/images/agent-logos/opencode.svg', + '/images/agent-logos/amp.svg', +]; +const agentAt = (i: number) => AGENT_LOGOS[(i * 7) % AGENT_LOGOS.length]; + +const RED = '#d6453a'; +const GREEN = '#3f9a59'; +const BORDER_RED = 'rgba(214,69,58,0.6)'; +const BORDER_GREEN = 'rgba(63,154,89,0.65)'; + +// ---- Sourced numbers ------------------------------------------------------- +const cold = benchColdStart[0]; // p50 +const AOS_MS = Math.round(cold.agentOS); // ~5 ms +const CONTAINER_MS = cold.sandbox; // ~440 ms +const SPEEDUP = Math.round(cold.sandbox / cold.agentOS); // ~92x +const mem = benchWorkloads.agent.memory; // { agentOS:"~131 MB", sandbox:"~1024 MB", multiplier:"8x smaller" } +const cost = benchWorkloads.agent.cost[0]; // AWS ARM { ratio, multiplier } +const MEM_X = mem.multiplier.split('x')[0]; // "8" +const CONTAINER_MEM = '~1 GB'; // ~1024 MB sandbox baseline, rounded for the chip +const AOS_MEM = mem.agentOS; // "~131 MB" + +// ---- Animation timing ------------------------------------------------------ +const BOOT_SEC = 2.7; // base animation seconds for the container boot (speed-adjustable) +const AOS_DONE = 0.04; // fraction of the timeline at which Agent OS is finished +// The speed slider maps to a playback-rate multiplier on the looping boot. +const speedFromSlider = (s: number) => 0.2 * Math.pow(30, s / 100); // 0.2x .. 6x +const slowdownLabel = (speed: number) => { + const factor = (BOOT_SEC * 1000) / CONTAINER_MS / speed; // ~6 / speed + return factor < 1.4 ? 'real time' : `slowed ~${Math.round(factor)}×`; +}; + +// A dashed grey box showing a memory figure. +const MemBox = ({ value, sub }: { value: string; sub: string }) => ( + + {value} + {sub} + +); + +const MiniBar = ({ width, color }: { width: MotionValue; color: MotionValue }) => ( +
+ +
+); + +// One container: its own agent + its own memory, booting on its own. +const ContainerBox = ({ progress, lo, hi, logo }: { progress: MotionValue; lo: number; hi: number; logo: string }) => { + const border = useTransform(progress, [lo, hi], [BORDER_RED, BORDER_GREEN]); + const barWidth = useTransform(progress, [lo, hi], ['14%', '100%']); + const barColor = useTransform(progress, [lo, hi], [RED, GREEN]); + return ( +
+ + + + + +
+ ); +}; + +// Agent OS: all agents packed inside ONE process box that boots once. +const SharedProcessBox = ({ progress, count }: { progress: MotionValue; count: number }) => { + const border = useTransform(progress, [0, AOS_DONE], [BORDER_RED, BORDER_GREEN]); + const barWidth = useTransform(progress, [0, AOS_DONE], ['14%', '100%']); + const barColor = useTransform(progress, [0, AOS_DONE], [RED, GREEN]); + return ( +
+ +
+ {Array.from({ length: count }).map((_, i) => ( + + + + ))} + +
+
+ +
+ ); +}; + +type HostCfg = { + name: ReactNode; + finalMs: number; + doneAt: number; + units: number; + grouped: boolean; // Agent OS packs all agents into one process box + accent: boolean; + badge?: ReactNode; +}; + +const Host = ({ cfg, progress }: { cfg: HostCfg; progress: MotionValue }) => { + const counter = useTransform(progress, (p) => `~${Math.round(Math.min(1, p / cfg.doneAt) * cfg.finalMs)} ms`); + const checkOpacity = useTransform(progress, [0, cfg.doneAt * 0.95, cfg.doneAt], [0, 0, 1]); + return ( +
+
+ {cfg.name} +
+ {cfg.badge} + + {counter} +
+
+ {cfg.grouped ? ( + + ) : ( +
+ {Array.from({ length: cfg.units }).map((_, i) => { + const lo = (i / cfg.units) * 0.08; + return ; + })} +
+ )} +
+ ); +}; + +const Stat = ({ value, label, sub }: { value: string; label: string; sub: string }) => ( +
+
{value}
+
{label}
+
{sub}
+
+); + +export const ColdStartRace = () => { + const reduced = useReducedMotion(); + const ref = useRef(null); + const inView = useInView(ref, { once: true, margin: '-15% 0px' }); + const progress = useMotionValue(0); + const [slider, setSlider] = useState(50); + const speed = speedFromSlider(slider); + const speedRef = useRef(speed); + speedRef.current = speed; + const controlsRef = useRef(null); + + // Create the looping boot once it scrolls into view; speed is adjusted live. + useEffect(() => { + if (reduced) { + progress.set(1); + return; + } + if (!inView) return; + const controls = animate(progress, [0, 1], { duration: BOOT_SEC, ease: 'easeInOut', repeat: Infinity, repeatDelay: 0.9 }); + controls.speed = speedRef.current; + controlsRef.current = controls; + return () => controls.stop(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [inView, reduced]); + + useEffect(() => { + if (controlsRef.current) controlsRef.current.speed = speed; + }, [speed]); + + return ( +
+ +
+
+ Cold start · spinning up agents +
+ Slow + setSlider(Number(e.target.value))} + aria-label='Animation playback speed' + className='h-1.5 w-28 cursor-pointer accent-accent' + /> + Fast + {slowdownLabel(speed)} +
+
+ +
+ +
+ +

+ Same host, same memory. Each container is its own process with its own ~1 GB; Agent OS packs every agent into one shared process at {AOS_MEM} each ({MEM_X}× less memory). Real cold start: ~{AOS_MS} ms vs ~{CONTAINER_MS} ms ({SPEEDUP}× faster) — drag the slider to set playback speed. +

+
+
+ + + + + + +
+ ); +}; diff --git a/website/src/components/marketing/diagrams/HarnessArchitecture.tsx b/website/src/components/marketing/diagrams/HarnessArchitecture.tsx new file mode 100644 index 000000000..88f20a163 --- /dev/null +++ b/website/src/components/marketing/diagrams/HarnessArchitecture.tsx @@ -0,0 +1,276 @@ +'use client'; + +import { AnimatePresence, motion, useReducedMotion } from 'framer-motion'; +import { useEffect, useState } from 'react'; +import type { ReactNode } from 'react'; +import { Briefcase, ListChecks, SquareTerminal, Workflow } from 'lucide-react'; +import { EASE, VIEWPORT } from '../motion'; + +// --------------------------------------------------------------------------- +// Harness architecture diagram. A plus/cross layout branded as Agent OS: the +// running agent sits at the center (cycling through every supported agent) and +// the harness brokers bidirectional request/response traffic out to Tools, +// Session, Sandbox, and Orchestration. Flow dots animate along the arrows to +// show that everything routes through Agent OS. +// --------------------------------------------------------------------------- + +const ARROW_COLOR = '#8A8478'; // ink-faint +const ACCENT = '#CB5A33'; +const AGENTOS_MARK = '/images/agent-os/agentos-logo-ink.svg'; + +const AGENT_LOGOS = [ + { src: '/images/agent-logos/pi.svg', name: 'Pi' }, + { src: '/images/agent-logos/claude-code.svg', name: 'Claude Code' }, + { src: '/images/agent-logos/codex.svg', name: 'Codex' }, + { src: '/images/agent-logos/opencode.svg', name: 'OpenCode' }, + { src: '/images/agent-logos/amp.svg', name: 'Amp' }, +]; + +// The center node: cross-fades through every supported agent logo, conveying +// that any agent plugs into the harness. +const CyclingAgentLogo = ({ size }: { size: string }) => { + const reduced = useReducedMotion(); + const [i, setI] = useState(0); + useEffect(() => { + if (reduced) return; + const id = setInterval(() => setI((p) => (p + 1) % AGENT_LOGOS.length), 1900); + return () => clearInterval(id); + }, [reduced]); + const a = AGENT_LOGOS[i]; + return ( +
+ + + +
+ ); +}; + +// A single diagram card: a header strip with the title and a body with one icon. +const DiagramCard = ({ + title, + subtitle, + icon, + accent, +}: { + title: string; + subtitle?: string; + icon: ReactNode; + accent?: boolean; +}) => ( +
+
+
+ {title} +
+ {subtitle ?
{subtitle}
: null} +
+
{icon}
+
+); + +const SATELLITES = { + tools: { title: 'Tools', subtitle: '+ Resources / MCP', icon:
+ {/* Containers vs Isolate density comparison */} + +

+ Booting an agent in a container takes a full process and hundreds of milliseconds. Agent OS starts one in a lightweight isolate in about {Math.round(benchColdStart[0].agentOS)} ms — and packs far more into the same memory. +

+ +
+ {/* Benchmarks */} @@ -1959,6 +1975,34 @@ const TechnologyAndBenchmarks = () => ( ); +const HarnessSection = () => ( +
+
+ +

+ Everything routes through the harness. +

+

+ The harness is the kernel of every agent session — brokering requests and responses between your tools and MCP resources, session state, the sandbox where code runs, and the orchestration layer that ties agents together. Each piece stays isolated, yet composable. +

+
+ + + +
+
+); + // --- Before/After Slider --- const BeforeAfterSlider = ({ before, after }: { before: string; after: string }) => { const containerRef = useRef(null); @@ -2030,6 +2074,18 @@ const SisterProducts = () => { href: 'https://sandboxagent.dev/', cta: 'sandboxagent.dev', }, + { + name: 'Rivet Actors', + tagline: 'Durable, stateful serverless for agents and realtime apps.', + bullets: [ + 'Long-lived, in-memory state — no external database', + 'Built-in persistence, realtime, and workflow orchestration', + 'Deploy Agent OS sessions as durable actors', + 'Geo-distributed at the edge; scale to zero', + ], + href: 'https://rivet.dev/', + cta: 'rivet.dev', + }, ]; return ( @@ -2052,11 +2108,11 @@ const SisterProducts = () => { transition={{ duration: 0.5, delay: 0.1 }} className='text-base leading-relaxed text-ink-soft md:text-lg' > - Agent OS is where agents live. Secure Exec is how you safely run the code they generate. Sandbox Agent SDK is how you control coding agents over HTTP. + Agent OS is where agents live. Secure Exec is how you safely run the code they generate. Sandbox Agent SDK is how you control coding agents over HTTP. Rivet Actors is how you deploy and scale them as durable, stateful services. -
+
{products.map((product, idx) => ( + diff --git a/website/src/components/marketing/solutions/AgentOSPricingPage.tsx b/website/src/components/marketing/solutions/AgentOSPricingPage.tsx index 10bf6f2f8..70e555566 100644 --- a/website/src/components/marketing/solutions/AgentOSPricingPage.tsx +++ b/website/src/components/marketing/solutions/AgentOSPricingPage.tsx @@ -157,7 +157,7 @@ const CTASection = () => ( href='/docs' className='inline-flex items-center gap-2 rounded-md bg-accent-deep px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-accent' > - Start for Free + Get Started = { + HardDrive, + Database, + Monitor, +}; diff --git a/website/src/data/registry.ts b/website/src/data/registry.ts index 0b01eab14..60dd22e7d 100644 --- a/website/src/data/registry.ts +++ b/website/src/data/registry.ts @@ -1,5 +1,4 @@ -import type { LucideIcon } from "lucide-react"; -import { HardDrive, Database, Monitor } from "lucide-react"; +import type { RegistryIconName } from "./registry-icons"; export interface RegistryEntryBase { slug: string; @@ -7,8 +6,10 @@ export interface RegistryEntryBase { description: string; types: ("file-system" | "tool" | "agent" | "sandbox-extension" | "software")[]; featured?: boolean; - // Lucide icon component, used when no `image` is provided. - icon?: LucideIcon; + // Lucide icon name, resolved via REGISTRY_ICONS. Used when no `image` is + // provided. Must be a serializable string so it survives the Astro island + // prop boundary. + icon?: RegistryIconName; image?: string; } @@ -240,7 +241,7 @@ export const registry: RegistryEntry[] = [ description: "Mount and manage virtual filesystems with support for S3, local, and overlay drivers.", types: ["file-system"], - icon: HardDrive, + icon: "HardDrive", }, { slug: "s3", @@ -260,7 +261,7 @@ export const registry: RegistryEntry[] = [ description: "Mount a SQLite-backed virtual filesystem for persistent, queryable storage.", types: ["file-system"], - icon: Database, + icon: "Database", }, { slug: "postgres", @@ -269,7 +270,7 @@ export const registry: RegistryEntry[] = [ description: "Mount a Postgres-backed filesystem for shared, durable storage across agents.", types: ["file-system"], - icon: Database, + icon: "Database", }, { slug: "google-drive", @@ -292,7 +293,7 @@ export const registry: RegistryEntry[] = [ description: "Mount a sandbox filesystem and expose process management tools. Works with any Sandbox Agent provider.", types: ["tool", "file-system"], - icon: Monitor, + icon: "Monitor", }, { slug: "browserbase", @@ -313,7 +314,7 @@ export const registry: RegistryEntry[] = [ description: "Run sandboxes directly on the local machine for development and testing.", types: ["sandbox-extension"], - icon: Monitor, + icon: "Monitor", }, { slug: "docker", diff --git a/website/src/pages/registry/[slug].astro b/website/src/pages/registry/[slug].astro index c3dec9f98..b56c2bd2b 100644 --- a/website/src/pages/registry/[slug].astro +++ b/website/src/pages/registry/[slug].astro @@ -3,6 +3,7 @@ import Layout from "../../layouts/Layout.astro"; import { Navigation } from "../../components/Navigation"; import { Footer } from "../../components/Footer"; import { registry } from "../../data/registry"; +import { REGISTRY_ICONS } from "../../data/registry-icons"; import { InkChip } from "../../components/marketing/editorial/InkPanel"; export function getStaticPaths() { @@ -24,7 +25,7 @@ const TYPE_LABELS: Record = { const isComingSoon = entry.status === "coming-soon"; const installCmd = !isComingSoon ? `npm install ${entry.package}` : null; -const EntryIcon = entry.icon; +const EntryIcon = entry.icon ? REGISTRY_ICONS[entry.icon] : undefined; --- Date: Sun, 21 Jun 2026 00:35:26 -0700 Subject: [PATCH 2/7] Homepage: animated performance benchmarks + architecture copy fixes Replace the static benchmark cards with three animated, light-styled diagrams (cold-start race with p50/p95/p99 toggle, memory-overhead squares, execution-density packing), extract shared benchUI primitives (BenchToggle/CountUpStat/BenchInfoTooltip), add per-tier execs/costPerHour to bench.ts, link hero stats to their diagrams, and fix the info tooltips and the agentOS boot timing. Correct the architecture framing to match the product: an OS for all AI agents and arbitrary code, many lightweight in-process VMs packed into one process on an in-process kernel. Also bundles related in-progress homepage edits (navigation, footer, registry, pricing, use-cases, config). Co-Authored-By: Claude Opus 4.8 --- website/.astro/content-modules.mjs | 20 +- website/astro.config.mjs | 2 +- website/docs.config.mjs | 4 +- website/src/components/Footer.tsx | 4 +- website/src/components/Navigation.tsx | 25 +- .../marketing/diagrams/ColdStartRace.tsx | 260 ++++---- .../marketing/diagrams/ExecutionDensity.tsx | 222 +++++++ .../diagrams/HarnessArchitecture.tsx | 11 +- .../marketing/diagrams/MemoryOverhead.tsx | 144 +++++ .../components/marketing/diagrams/benchUI.tsx | 151 +++++ .../marketing/registry/RegistryPageClient.tsx | 2 +- .../marketing/solutions/AgentOSPage.tsx | 567 +++++++----------- .../solutions/AgentOSPricingPage.tsx | 8 +- .../solutions/AgentOSUseCasesPage.tsx | 4 +- website/src/data/bench.ts | 16 +- website/src/data/faqs/agent-os-pricing.ts | 10 +- website/src/data/registry.ts | 8 +- website/src/layouts/Layout.astro | 4 +- website/src/pages/index.astro | 6 +- website/src/pages/pricing.astro | 4 +- website/src/pages/registry/index.astro | 8 +- website/src/pages/use-cases.astro | 4 +- website/src/styles/global.css | 2 +- 23 files changed, 947 insertions(+), 539 deletions(-) create mode 100644 website/src/components/marketing/diagrams/ExecutionDensity.tsx create mode 100644 website/src/components/marketing/diagrams/MemoryOverhead.tsx create mode 100644 website/src/components/marketing/diagrams/benchUI.tsx diff --git a/website/.astro/content-modules.mjs b/website/.astro/content-modules.mjs index e070527f8..f29c754ec 100644 --- a/website/.astro/content-modules.mjs +++ b/website/.astro/content-modules.mjs @@ -1,15 +1,15 @@ export default new Map([ -["src/content/docs/docs/agent-to-agent.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fagent-to-agent.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/authentication.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fauthentication.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/configuration.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fconfiguration.mdx&astroContentModuleFlag=true")], +["src/content/docs/docs/agent-to-agent.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fagent-to-agent.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/benchmarks.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fbenchmarks.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/core.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fcore.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/crash-course.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fcrash-course.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/cron.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fcron.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/deployment.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fdeployment.mdx&astroContentModuleFlag=true")], +["src/content/docs/docs/cron.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fcron.mdx&astroContentModuleFlag=true")], +["src/content/docs/docs/crash-course.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fcrash-course.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/events.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fevents.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/filesystem.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Ffilesystem.mdx&astroContentModuleFlag=true")], +["src/content/docs/docs/core.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fcore.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/index.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Findex.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/limitations.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Flimitations.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/llm-credentials.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fllm-credentials.mdx&astroContentModuleFlag=true")], @@ -18,23 +18,23 @@ export default new Map([ ["src/content/docs/docs/networking.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fnetworking.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/permissions.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fpermissions.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/persistence.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fpersistence.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/processes.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fprocesses.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/queues.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fqueues.mdx&astroContentModuleFlag=true")], +["src/content/docs/docs/processes.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fprocesses.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/quickstart.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fquickstart.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/sandbox.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fsandbox.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/security-model.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fsecurity-model.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/security.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fsecurity.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/sessions.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fsessions.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/software.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fsoftware.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/sqlite.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fsqlite.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/system-prompt.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fsystem-prompt.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/tools.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Ftools.mdx&astroContentModuleFlag=true")], +["src/content/docs/docs/sessions.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fsessions.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/versus-sandbox.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fversus-sandbox.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/webhooks.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fwebhooks.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/workflows.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fworkflows.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/agents/amp.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fagents%2Famp.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/agents/claude.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fagents%2Fclaude.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/agents/codex.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fagents%2Fcodex.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/agents/opencode.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fagents%2Fopencode.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/agents/pi.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fagents%2Fpi.mdx&astroContentModuleFlag=true")]]); +["src/content/docs/docs/agents/codex.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fagents%2Fcodex.mdx&astroContentModuleFlag=true")], +["src/content/docs/docs/agents/pi.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fagents%2Fpi.mdx&astroContentModuleFlag=true")], +["src/content/docs/docs/agents/amp.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fagents%2Famp.mdx&astroContentModuleFlag=true")], +["src/content/docs/docs/agents/claude.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fagents%2Fclaude.mdx&astroContentModuleFlag=true")]]); \ No newline at end of file diff --git a/website/astro.config.mjs b/website/astro.config.mjs index b4772a49e..8b8f3d93c 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -18,7 +18,7 @@ export default defineConfig({ tailwind({ applyBaseStyles: false }), // The shared Rivet docs theme — wraps Starlight entirely. All docs // branding/chrome lives in @rivet-dev/docs-theme; docs.config.mjs maps - // Agent OS's identity, nav, and pages onto it. + // agentOS's identity, nav, and pages onto it. ...docsTheme(starlight, siteConfig), sitemap(), ], diff --git a/website/docs.config.mjs b/website/docs.config.mjs index a65753cc9..57ffa43f8 100644 --- a/website/docs.config.mjs +++ b/website/docs.config.mjs @@ -1,5 +1,5 @@ /** - * Agent OS docs configuration — the only non-content surface consumed by + * agentOS docs configuration — the only non-content surface consumed by * @rivet-dev/docs-theme. Everything visual (theme, header chrome, sidebar * icons, code blocks) lives in the package; this file maps agentOS's product * identity, navigation, and pages onto it. @@ -11,7 +11,7 @@ * @type {import('@rivet-dev/docs-theme').SiteConfig} */ export const siteConfig = { - product: "Agent OS", + product: "agentOS", productLogo: "/images/agent-os/agentos-hero-logo.svg", productHome: "/", favicon: "/favicon.svg", diff --git a/website/src/components/Footer.tsx b/website/src/components/Footer.tsx index 93b459816..cf3dff338 100644 --- a/website/src/components/Footer.tsx +++ b/website/src/components/Footer.tsx @@ -57,7 +57,7 @@ export function Footer() { className="space-y-6 xl:col-span-4" > - Agent OS + agentOS

A portable open-source operating system for agents.

@@ -112,7 +112,7 @@ export function Footer() { transition={{ duration: 0.5, delay: 0.3 }} className="mt-12 border-t border-ink/10 pt-8" > -

© {new Date().getFullYear()} Agent OS. Apache 2.0 licensed.

+

© {new Date().getFullYear()} agentOS. Apache 2.0 licensed.

diff --git a/website/src/components/Navigation.tsx b/website/src/components/Navigation.tsx index 6d48e8fdb..318fdc6b0 100644 --- a/website/src/components/Navigation.tsx +++ b/website/src/components/Navigation.tsx @@ -3,6 +3,7 @@ import { useState, useEffect } from "react"; import { Menu, X } from "lucide-react"; import { GitHubStars } from "./GitHubStars"; +import { registry } from "../data/registry"; function DiscordIcon({ className }: { className?: string }) { return ( @@ -18,20 +19,29 @@ function DiscordIcon({ className }: { className?: string }) { ); } -const NAV_LINKS = [ +const NAV_LINKS: { href: string; label: string; badge?: number }[] = [ { href: "/use-cases", label: "Use Cases" }, { href: "/pricing", label: "Pricing" }, - { href: "/registry", label: "Registry" }, + { href: "/registry", label: "Registry", badge: registry.length }, { href: "/docs", label: "Docs" }, ]; -function NavItem({ href, children }: { href: string; children: React.ReactNode }) { +function NavBadge({ count }: { count: number }) { + return ( + + {count} + + ); +} + +function NavItem({ href, children, badge }: { href: string; children: React.ReactNode; badge?: number }) { return ( {children} + {badge != null && } ); } @@ -68,14 +78,14 @@ export function Navigation() { Agent OS
{NAV_LINKS.map((link) => ( - + {link.label} ))} @@ -114,10 +124,11 @@ export function Navigation() { setMobileMenuOpen(false)} > {link.label} + {link.badge != null && } ))}
diff --git a/website/src/components/marketing/diagrams/ColdStartRace.tsx b/website/src/components/marketing/diagrams/ColdStartRace.tsx index eae5e3fb6..c147d6cf2 100644 --- a/website/src/components/marketing/diagrams/ColdStartRace.tsx +++ b/website/src/components/marketing/diagrams/ColdStartRace.tsx @@ -1,21 +1,23 @@ 'use client'; import { animate, motion, useInView, useMotionValue, useTransform, useReducedMotion } from 'framer-motion'; -import type { AnimationPlaybackControls, MotionValue } from 'framer-motion'; +import type { MotionValue } from 'framer-motion'; import { useEffect, useRef, useState } from 'react'; import type { ReactNode } from 'react'; import { Box, Check } from 'lucide-react'; -import { EASE, VIEWPORT, Reveal } from '../motion'; -import { benchColdStart, benchWorkloads } from '../../../data/bench'; +import { Reveal } from '../motion'; +import { BenchToggle, BenchInfoTooltip } from './benchUI'; +import { benchColdStart, SANDBOX_COLDSTART_PROVIDER, BENCHMARK_DATE } from '../../../data/bench'; // --------------------------------------------------------------------------- // Cold-start comparison. Two hosts spin up agents, once, when scrolled into view. // Containers — each agent gets its own process: a separate box that boots on -// its own (border red -> green + mini bar) and carries its own ~1 GB of memory. -// Agent OS — every agent is packed into ONE shared process: a single box -// that boots once and shares memory, ~131 MB per agent. -// The contrast (four separate boots vs one grouped boot) is the point. Numbers -// come from bench.ts so they stay accurate. +// its own (border red -> green + mini bar). +// agentOS — every agent is packed into ONE shared process: a single box +// that boots once. +// The contrast (four separate boots vs one grouped boot) is the point. The +// container boot is shown slowed ~6x so the wait is visible. Numbers come from +// bench.ts so they stay accurate. // --------------------------------------------------------------------------- const AGENTOS_MARK = '/images/agent-os/agentos-logo-ink.svg'; @@ -33,34 +35,25 @@ const GREEN = '#3f9a59'; const BORDER_RED = 'rgba(214,69,58,0.6)'; const BORDER_GREEN = 'rgba(63,154,89,0.65)'; -// ---- Sourced numbers ------------------------------------------------------- -const cold = benchColdStart[0]; // p50 -const AOS_MS = Math.round(cold.agentOS); // ~5 ms -const CONTAINER_MS = cold.sandbox; // ~440 ms -const SPEEDUP = Math.round(cold.sandbox / cold.agentOS); // ~92x -const mem = benchWorkloads.agent.memory; // { agentOS:"~131 MB", sandbox:"~1024 MB", multiplier:"8x smaller" } -const cost = benchWorkloads.agent.cost[0]; // AWS ARM { ratio, multiplier } -const MEM_X = mem.multiplier.split('x')[0]; // "8" -const CONTAINER_MEM = '~1 GB'; // ~1024 MB sandbox baseline, rounded for the chip -const AOS_MEM = mem.agentOS; // "~131 MB" - // ---- Animation timing ------------------------------------------------------ -const BOOT_SEC = 2.7; // base animation seconds for the container boot (speed-adjustable) -const AOS_DONE = 0.04; // fraction of the timeline at which Agent OS is finished -// The speed slider maps to a playback-rate multiplier on the looping boot. -const speedFromSlider = (s: number) => 0.2 * Math.pow(30, s / 100); // 0.2x .. 6x -const slowdownLabel = (speed: number) => { - const factor = (BOOT_SEC * 1000) / CONTAINER_MS / speed; // ~6 / speed - return factor < 1.4 ? 'real time' : `slowed ~${Math.round(factor)}×`; +// The boot is scaled to each percentile's REAL container cold start, always +// slowed 6x — so p99 crawls ~6x longer than p50, in true proportion. +const SLOWDOWN = 6; +// agentOS boots near-instantly, so its box snaps done in a fixed, snappy time — +// independent of the container's 6x slowdown. It must never appear to "wait". +const AOS_BOOT_SEC = 0.5; +const bootDuration = (containerMs: number) => (containerMs / 1000) * SLOWDOWN; +const slowdownFactor = (containerMs: number) => (bootDuration(containerMs) * 1000) / containerMs; +const slowdownLabel = (containerMs: number) => { + const factor = slowdownFactor(containerMs); + return factor < 1.4 ? 'in real time' : `slowed ~${Math.round(factor)}×`; +}; +// Pill copy for the containers row. Phrased as a playback note so it reads as a +// display speed, not a perf claim that would clash with agentOS's "Nx faster". +const slowdownPill = (containerMs: number) => { + const factor = slowdownFactor(containerMs); + return factor < 1.4 ? 'shown in real time' : `shown ~${Math.round(factor)}× slower`; }; - -// A dashed grey box showing a memory figure. -const MemBox = ({ value, sub }: { value: string; sub: string }) => ( - - {value} - {sub} - -); const MiniBar = ({ width, color }: { width: MotionValue; color: MotionValue }) => (
@@ -68,30 +61,29 @@ const MiniBar = ({ width, color }: { width: MotionValue; color: MotionVa
); -// One container: its own agent + its own memory, booting on its own. +// One container: its own agent, booting on its own. const ContainerBox = ({ progress, lo, hi, logo }: { progress: MotionValue; lo: number; hi: number; logo: string }) => { const border = useTransform(progress, [lo, hi], [BORDER_RED, BORDER_GREEN]); const barWidth = useTransform(progress, [lo, hi], ['14%', '100%']); const barColor = useTransform(progress, [lo, hi], [RED, GREEN]); return ( -
+
-
); }; -// Agent OS: all agents packed inside ONE process box that boots once. -const SharedProcessBox = ({ progress, count }: { progress: MotionValue; count: number }) => { - const border = useTransform(progress, [0, AOS_DONE], [BORDER_RED, BORDER_GREEN]); - const barWidth = useTransform(progress, [0, AOS_DONE], ['14%', '100%']); - const barColor = useTransform(progress, [0, AOS_DONE], [RED, GREEN]); +// agentOS: all agents packed inside ONE process box that boots once. +const SharedProcessBox = ({ progress, count, doneAt }: { progress: MotionValue; count: number; doneAt: number }) => { + const border = useTransform(progress, [0, doneAt], [BORDER_RED, BORDER_GREEN]); + const barWidth = useTransform(progress, [0, doneAt], ['14%', '100%']); + const barColor = useTransform(progress, [0, doneAt], [RED, GREEN]); return (
@@ -101,7 +93,6 @@ const SharedProcessBox = ({ progress, count }: { progress: MotionValue; ))} -
@@ -114,7 +105,7 @@ type HostCfg = { finalMs: number; doneAt: number; units: number; - grouped: boolean; // Agent OS packs all agents into one process box + grouped: boolean; // agentOS packs all agents into one process box accent: boolean; badge?: ReactNode; }; @@ -125,7 +116,7 @@ const Host = ({ cfg, progress }: { cfg: HostCfg; progress: MotionValue } return (
- {cfg.name} + {cfg.name}
{cfg.badge}
{cfg.grouped ? ( - + ) : (
{Array.from({ length: cfg.units }).map((_, i) => { @@ -148,118 +139,103 @@ const Host = ({ cfg, progress }: { cfg: HostCfg; progress: MotionValue } ); }; -const Stat = ({ value, label, sub }: { value: string; label: string; sub: string }) => ( -
-
{value}
-
{label}
-
{sub}
-
-); - export const ColdStartRace = () => { const reduced = useReducedMotion(); const ref = useRef(null); const inView = useInView(ref, { once: true, margin: '-15% 0px' }); - const progress = useMotionValue(0); - const [slider, setSlider] = useState(50); - const speed = speedFromSlider(slider); - const speedRef = useRef(speed); - speedRef.current = speed; - const controlsRef = useRef(null); - - // Create the looping boot once it scrolls into view; speed is adjusted live. + const progress = useMotionValue(0); // containers — slowed boot + const aosProgress = useMotionValue(0); // agentOS — fixed snappy boot + const [pct, setPct] = useState(0); // p50 by default + + const cold = benchColdStart[pct]; + const aosMs = Math.round(cold.agentOS); + const containerMs = cold.sandbox; + const speedup = Math.round(cold.sandbox / cold.agentOS); + const durationSec = bootDuration(containerMs); + + // Play the boot once it scrolls into view; replay when the percentile changes. + // The containers crawl over the slowed duration; agentOS snaps done in a fixed + // fast time so it never appears to scale with the container slowdown. useEffect(() => { if (reduced) { progress.set(1); + aosProgress.set(1); return; } if (!inView) return; - const controls = animate(progress, [0, 1], { duration: BOOT_SEC, ease: 'easeInOut', repeat: Infinity, repeatDelay: 0.9 }); - controls.speed = speedRef.current; - controlsRef.current = controls; - return () => controls.stop(); + progress.set(0); + aosProgress.set(0); + const c1 = animate(progress, [0, 1], { duration: durationSec, ease: 'easeInOut' }); + const c2 = animate(aosProgress, [0, 1], { duration: AOS_BOOT_SEC, ease: 'easeOut' }); + return () => { + c1.stop(); + c2.stop(); + }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [inView, reduced]); - - useEffect(() => { - if (controlsRef.current) controlsRef.current.speed = speed; - }, [speed]); + }, [inView, reduced, pct]); return ( -
- -
-
- Cold start · spinning up agents -
- Slow - setSlider(Number(e.target.value))} - aria-label='Animation playback speed' - className='h-1.5 w-28 cursor-pointer accent-accent' - /> - Fast - {slowdownLabel(speed)} -
+ +
+
+
+ Cold start + {slowdownPill(containerMs)}
- -
- -
-

- Same host, same memory. Each container is its own process with its own ~1 GB; Agent OS packs every agent into one shared process at {AOS_MEM} each ({MEM_X}× less memory). Real cold start: ~{AOS_MS} ms vs ~{CONTAINER_MS} ms ({SPEEDUP}× faster) — drag the slider to set playback speed. -

+
+ +
- - - - - - -
+

+ Each container is its own process that boots on its own; agentOS packs every agent into one shared process that boots once. Real {cold.label} cold start: ~{aosMs} ms vs ~{containerMs.toLocaleString()} ms ({speedup}× faster) — container boot shown {slowdownLabel(containerMs)}. +

+
+
); }; diff --git a/website/src/components/marketing/diagrams/ExecutionDensity.tsx b/website/src/components/marketing/diagrams/ExecutionDensity.tsx new file mode 100644 index 000000000..c53d4e605 --- /dev/null +++ b/website/src/components/marketing/diagrams/ExecutionDensity.tsx @@ -0,0 +1,222 @@ +'use client'; + +import { motion, useReducedMotion } from 'framer-motion'; +import { useEffect, useRef, useState } from 'react'; +import type { ReactNode } from 'react'; +import { Server, Container, SquareTerminal } from 'lucide-react'; +import { EASE, VIEWPORT, Reveal } from '../motion'; +import { BenchToggle, CountUpStat, BenchInfoTooltip } from './benchUI'; +import { benchWorkloads, SANDBOX_COST_PROVIDER, BENCHMARK_DATE, type WorkloadKey } from '../../../data/bench'; + +// --------------------------------------------------------------------------- +// Cost-per-execution-second, told as a density story. One server packs N +// concurrent executions (N = executions that fit per server at 70% utilization, +// from bench.ts) while a sandbox holds exactly one. The packed count is the +// denominator of the cost, so the packing animation resolves into the price: +// one $X/hr server / N executions = $Y per execution-second. +// Laid out as a full-width horizontal card. Driven by the shared workload toggle +// plus a local hardware-tier toggle. +// --------------------------------------------------------------------------- + +const WORKLOAD_KEYS = Object.keys(benchWorkloads) as WorkloadKey[]; +const AGENT_LOGOS = [ + '/images/agent-logos/pi.svg', + '/images/agent-logos/claude-code.svg', + '/images/agent-logos/codex.svg', + '/images/agent-logos/opencode.svg', + '/images/agent-logos/amp.svg', +]; +const CHIP_CAP = 48; // cap rendered chips; the rest fold into a "+N more" pill + +// Smoothly animates its own height to match its content. A ResizeObserver tracks +// the inner element's natural height (unaffected by child transforms), so when +// the packed-chip count changes the card grows/shrinks instead of jumping. The +// inner element keeps its real size — nothing is scaled — so no text distortion. +function AutoHeight({ children }: { children: ReactNode }) { + const reduced = useReducedMotion(); + const innerRef = useRef(null); + const [height, setHeight] = useState('auto'); + + useEffect(() => { + const el = innerRef.current; + if (!el) return; + const update = () => setHeight(el.offsetHeight); + update(); + const ro = new ResizeObserver(update); + ro.observe(el); + return () => ro.disconnect(); + }, []); + + return ( + +
{children}
+
+ ); +} + +export const ExecutionDensity = ({ workload, onWorkloadChange }: { workload: WorkloadKey; onWorkloadChange: (w: WorkloadKey) => void }) => { + const reduced = useReducedMotion(); + const [tierIdx, setTierIdx] = useState(0); // AWS ARM default + const [inView, setInView] = useState(false); + + const wl = benchWorkloads[workload]; + const tier = wl.cost[tierIdx]; + const execs = tier.execs; + const [mult, verb] = tier.multiplier.split(' '); // ['171x', 'cheaper'] + const shown = Math.min(execs, CHIP_CAP); + const overflow = execs - shown; + const activeIdx = WORKLOAD_KEYS.indexOf(workload); + + if (overflow > 0 && import.meta.env.DEV) { + console.info(`[ExecutionDensity] ${execs} execs (${workload}/${tier.label}); rendering ${shown} chips +${overflow} more (cap=${CHIP_CAP}).`); + } + + const chipGlyph = (i: number) => + workload === 'agent' ? ( + + ) : ( +
); -export const HarnessArchitecture = () => { +export const HarnessArchitecture = ({ footer }: { footer?: ReactNode }) => { const reduced = useReducedMotion(); return (
- Agent OS + agentOS + {footer}
); }; diff --git a/website/src/components/marketing/diagrams/MemoryOverhead.tsx b/website/src/components/marketing/diagrams/MemoryOverhead.tsx new file mode 100644 index 000000000..485342544 --- /dev/null +++ b/website/src/components/marketing/diagrams/MemoryOverhead.tsx @@ -0,0 +1,144 @@ +'use client'; + +import { motion, useReducedMotion } from 'framer-motion'; +import { useState } from 'react'; +import { VIEWPORT, Reveal } from '../motion'; +import { BenchToggle, CountUpStat, BenchInfoTooltip } from './benchUI'; +import { benchWorkloads, SANDBOX_COST_PROVIDER, BENCHMARK_DATE, type WorkloadKey } from '../../../data/bench'; + +// --------------------------------------------------------------------------- +// Memory-per-instance comparison, drawn as two side-by-side squares. A full +// reservation square (1 GiB sandbox) sits next to a smaller agentOS square whose +// AREA is proportional to the memory ratio — so the visible size gap equals the +// real reduction (131 MB -> ~13% area / 8x; 22 MB -> ~2% area / 47x). Toggling +// the workload (coding agent <-> execution) GROWS and SHRINKS the agentOS +// square; the floating MB caption rides its top edge and the headline multiplier +// re-counts. Laid out as a full-width horizontal card. Numbers from bench.ts. +// --------------------------------------------------------------------------- + +const WORKLOAD_KEYS = Object.keys(benchWorkloads) as WorkloadKey[]; + +// Ease-in-out (easeInOutCubic) so the agentOS square grows/shrinks on an S curve: +// slow start, quick middle, gentle settle. +const S_CURVE = [0.65, 0, 0.35, 1] as const; + +const Row = ({ label, value, highlight }: { label: React.ReactNode; value: string; highlight?: boolean }) => ( +
+ + {label} + + + {value} + +
+); + +export function MemoryOverhead({ workload, onWorkloadChange }: { workload: WorkloadKey; onWorkloadChange: (w: WorkloadKey) => void }) { + const reduced = useReducedMotion(); + const [inView, setInView] = useState(false); + + const mem = benchWorkloads[workload].memory; + const [mult, verb] = mem.multiplier.split(' '); // ['8x', 'smaller'] + // agentOSBar is the memory ratio as a percentage of the reservation, i.e. the + // target AREA of the inner square. Side = sqrt(area) keeps area proportional + // to memory: '35.8%' side (agent, ~13% area) | '14.5%' side (execution, ~2%). + const targetSide = `${(Math.sqrt(mem.agentOSBar / 100) * 100).toFixed(1)}%`; + const activeIdx = WORKLOAD_KEYS.indexOf(workload); + + return ( + + setInView(true)} + viewport={VIEWPORT} + > + {/* Header: eyebrow + workload toggle */} +
+ Memory Per Instance +
+ benchWorkloads[k].label)} + active={activeIdx} + onChange={(i) => onWorkloadChange(WORKLOAD_KEYS[i])} + /> +
+
+ + {/* Body: copy + ledger on the left, the squares visual on the right */} +
+
+ {/* Headline multiplier */} +
+ + + + {verb} +
+ + {/* Comparison ledger */} +
+ + agentOS + + What's measured: Memory footprint added per concurrent execution. +

+ Why the gap: In-process isolates share the host's memory. Each additional execution only adds its own heap and stack. Sandboxes allocate a dedicated environment with a minimum memory reservation, even if the code inside uses far less. +

+ Sandbox baseline: {SANDBOX_COST_PROVIDER}, the cheapest mainstream sandbox provider as of {BENCHMARK_DATE}. Default sandbox: 1 vCPU + 1 GiB RAM. +

+ agentOS: {workload === 'agent' ? `${benchWorkloads.agent.memory.agentOS} for a full Pi coding agent session with MCP servers and file system mounts.` : `${benchWorkloads.shell.memory.agentOS} for the minimal shell workload under sustained load.`} +
+ + } + value={mem.agentOS} + /> + +
+ +

Sandboxes reserve idle RAM per agent; agentOS isolates share the host.

+
+ + {/* Visual: two squares, bottom-aligned, area ∝ memory */} +
+ {/* Sandbox — full reservation square, static */} +
+
+ {mem.sandbox} +
+ Sandbox +
+ + {/* agentOS — proportional square, animated */} +
+
+ + + + + + +
+
+ +
+ agentOS +
+
+
+ + + ); +} diff --git a/website/src/components/marketing/diagrams/benchUI.tsx b/website/src/components/marketing/diagrams/benchUI.tsx new file mode 100644 index 000000000..7c693a4c1 --- /dev/null +++ b/website/src/components/marketing/diagrams/benchUI.tsx @@ -0,0 +1,151 @@ +'use client'; + +import { useId, useState, useEffect, useRef, useMemo } from 'react'; +import type { ReactNode } from 'react'; +import { motion, useReducedMotion } from 'framer-motion'; + +// --------------------------------------------------------------------------- +// Shared primitives for the benchmark diagrams. Extracted from AgentOSPage so +// the cold-start / memory / execution diagram components can reuse them without +// importing from the page component. Styled for the light marketing cards. +// --------------------------------------------------------------------------- + +// A help icon with a hover tooltip. The popup is anchored to the icon itself +// (the wrapper is `relative`), so it works on any card regardless of the card's +// own positioning. It opens above the icon, left-aligned, with a mobile clamp, +// and resets inherited case/tracking from mono labels. +export function BenchInfoTooltip({ children }: { children: ReactNode }) { + return ( + + + + + + {children} + + + ); +} + +// Segmented control with a framer-motion layoutId pill. Used for the cold-start +// percentile toggle, the hardware-tier toggle, and the workload toggle. +export function BenchToggle({ options, active, onChange }: { options: string[]; active: number; onChange: (idx: number) => void }) { + const layoutId = useId(); + const columns = + options.length === 4 ? 'grid-cols-2 sm:grid-cols-4' : options.length === 3 ? 'grid-cols-3' : 'grid-cols-2'; + + return ( +
+ {options.map((label, i) => { + const isActive = i === active; + return ( + onChange(i)} + aria-pressed={isActive} + whileTap={{ scale: 0.94 }} + className={`relative flex h-7 min-w-0 items-center justify-center rounded-md px-1.5 text-center font-mono text-[10px] uppercase tracking-[0.12em] transition-colors ${ + isActive ? 'text-cream' : 'text-ink-soft hover:text-ink' + }`} + > + {isActive && ( + + )} + {label} + + ); + })} +
+ ); +} + +// Splits a stat string into a leading symbol prefix, the numeric portion, and a +// trailing unit suffix so the number can be counted up while the units stay put. +// Returns null when there is no number to animate (e.g. "Infinite"). +export function parseStatNumber(text: string) { + const match = text.match(/^([^\d-]*)(-?[\d,]*\.?\d+)(.*)$/); + if (!match) return null; + const [, prefix, rawNumber, suffix] = match; + const normalized = rawNumber.replace(/,/g, ''); + const decimals = normalized.includes('.') ? normalized.split('.')[1].length : 0; + return { + prefix, + suffix, + value: Number.parseFloat(normalized), + decimals, + grouped: rawNumber.includes(','), + }; +} + +// Counts the numeric part of a stat from 0 up to its value. The first run is +// gated on `active` (the card scrolling into view) and only fires once; later +// value changes (toggling workload or tier) re-trigger the count from the +// previous value. Honors reduced-motion by rendering the final value outright. +export function CountUpStat({ text, active }: { text: string; active: boolean }) { + const parsed = useMemo(() => parseStatNumber(text), [text]); + const reducedMotion = useReducedMotion(); + const target = parsed?.value ?? 0; + + const [display, setDisplay] = useState(0); + const startedRef = useRef(false); + const fromRef = useRef(0); + const rafRef = useRef(0); + + useEffect(() => { + if (!parsed) return; + if (reducedMotion) { + setDisplay(target); + fromRef.current = target; + startedRef.current = true; + return; + } + // Not yet scrolled into view: stay primed at zero for the first count-up. + if (!active) { + if (!startedRef.current) setDisplay(0); + return; + } + const from = startedRef.current ? fromRef.current : 0; + startedRef.current = true; + const duration = 850; + let start = 0; + const step = (now: number) => { + if (!start) start = now; + const t = Math.min(1, (now - start) / duration); + const eased = 1 - (1 - t) ** 3; + setDisplay(from + (target - from) * eased); + if (t < 1) { + rafRef.current = requestAnimationFrame(step); + } else { + fromRef.current = target; + } + }; + rafRef.current = requestAnimationFrame(step); + return () => cancelAnimationFrame(rafRef.current); + }, [parsed, target, active, reducedMotion]); + + if (!parsed) return <>{text}; + + const formatted = parsed.grouped + ? display.toLocaleString(undefined, { + minimumFractionDigits: parsed.decimals, + maximumFractionDigits: parsed.decimals, + }) + : display.toFixed(parsed.decimals); + + return ( + + {parsed.prefix} + {formatted} + {parsed.suffix} + + ); +} diff --git a/website/src/components/marketing/registry/RegistryPageClient.tsx b/website/src/components/marketing/registry/RegistryPageClient.tsx index f9fa7de58..91ea4e92b 100644 --- a/website/src/components/marketing/registry/RegistryPageClient.tsx +++ b/website/src/components/marketing/registry/RegistryPageClient.tsx @@ -28,7 +28,7 @@ const CATEGORY_ORDER: { type: string; label: string; description: string }[] = [ type: "sandbox-extension", label: "Sandbox Mounting", description: - "Agent OS is a hybrid OS. Mount sandbox file systems and interact with them via tools for heavier workloads. Use Agent OS natively for lightweight tasks.", + "agentOS is a hybrid OS. Mount sandbox file systems and interact with them via tools for heavier workloads. Use agentOS natively for lightweight tasks.", }, { type: "software", diff --git a/website/src/components/marketing/solutions/AgentOSPage.tsx b/website/src/components/marketing/solutions/AgentOSPage.tsx index 348bdfcbb..9c5645d5a 100644 --- a/website/src/components/marketing/solutions/AgentOSPage.tsx +++ b/website/src/components/marketing/solutions/AgentOSPage.tsx @@ -18,7 +18,6 @@ import { HardDrive, Code, Cpu, - Package, Users, Webhook, Workflow, @@ -38,6 +37,8 @@ import { GLOW_PILL_CLASS, handleGlowPillMouseMove } from '../glowPill'; import { registry } from '../../../data/registry'; import { HarnessArchitecture } from '../diagrams/HarnessArchitecture'; import { ColdStartRace } from '../diagrams/ColdStartRace'; +import { MemoryOverhead } from '../diagrams/MemoryOverhead'; +import { ExecutionDensity } from '../diagrams/ExecutionDensity'; interface HeroTabCode { key: string; @@ -785,16 +786,11 @@ const heroTabMeta: Array<{ key: string; icon?: typeof Bot; label: string; docsHr { key: 'permissions', icon: ShieldCheck, label: 'Permissions', docsHref: '/docs/permissions' }, ]; -const Hero = ({ heroTabs }: { heroTabs: HeroTabCode[] }) => { - const [activeTab, setActiveTab] = useState(0); +const Hero = () => { const [hoveredAgent, setHoveredAgent] = useState<{ src: string; name: string } | null>(null); const [autoPlayAgent, setAutoPlayAgent] = useState<{ src: string; name: string } | null>(null); const [autoPlayComplete, setAutoPlayComplete] = useState(false); - - const getStartedTabs = heroTabMeta.map((tab) => ({ - ...tab, - ...heroTabs.find((heroTab) => heroTab.key === tab.key), - })); + const [statsIn, setStatsIn] = useState(false); // Auto-cycle through agents starting 2.5s before stroke animation ends useEffect(() => { @@ -825,66 +821,157 @@ const Hero = ({ heroTabs }: { heroTabs: HeroTabCode[] }) => { // Displayed agent is either hovered (if autoplay complete) or autoplay agent const displayedAgent = autoPlayComplete ? hoveredAgent : autoPlayAgent; + // Highlight stats — best-case "up to" figures, sourced from bench.ts. + const heroStats = [ + { value: `${Math.round(benchColdStart[2].sandbox / benchColdStart[2].agentOS)}×`, label: 'faster cold starts', sub: 'vs. fastest sandbox', href: '#bench-cold-start' }, + { value: `${benchWorkloads.agent.memory.multiplier.split('x')[0]}×`, label: 'less memory', sub: 'per agent · vs. sandbox', href: '#bench-memory' }, + { value: `${Math.max(...Object.values(benchWorkloads).flatMap((w) => w.cost.map((t) => t.ratio)))}×`, label: 'cheaper to run', sub: 'vs. cheapest sandbox', href: '#bench-cost' }, + ]; + return (
-
- {/* Title */} +
+ {/* Top row: copy left, architecture image right */} +
+ {/* Left column */} +
+ {/* Brand mark */} + + + + + {/* Lead line (carries the hero now that the title is gone) */} + + An open-source computer for agents that you can run anywhere.{' '} + Faster, cheaper, and less memory than sandboxes. + + + {/* Supported Harnesses */} + + Works with +
+ {agents.map((agent) => ( +
autoPlayComplete && setHoveredAgent(agent)} + onMouseLeave={() => autoPlayComplete && setHoveredAgent(null)} + > + {agent.name} + {agent.name}{agent.comingSoon && '*'} +
+ ))} +
+ *Coming Soon +
+ + {/* CTAs */} + + + Get started + + + + +
+ + {/* Right column — architecture image, right-aligned */} + + + +
+ + {/* Bottom row: larger stat cards */} setStatsIn(true)} + className='mt-12 grid grid-cols-1 gap-4 sm:grid-cols-3' > -
- - Beta -
+ {heroStats.map((stat) => ( + +
+ Up to +
+
+ +
+
{stat.label}
+
{stat.sub}
+
+ ))}
+
+
+ ); +}; - {/* Subtitle */} - - A portable open-source operating system for agents. ~6 ms coldstarts, 32x cheaper than sandboxes. Powered by WebAssembly and V8 isolates. - - {/* Supported Harnesses */} +// --- Quickstart --- +const Quickstart = ({ heroTabs }: { heroTabs: HeroTabCode[] }) => { + const [activeTab, setActiveTab] = useState(0); + const getStartedTabs = heroTabMeta.map((tab) => ({ + ...tab, + ...heroTabs.find((heroTab) => heroTab.key === tab.key), + })); + + return ( +
+
- Works with -
- {agents.map((agent) => ( -
autoPlayComplete && setHoveredAgent(agent)} - onMouseLeave={() => autoPlayComplete && setHoveredAgent(null)} - > - {agent.name} - {agent.name}{agent.comingSoon && '*'} -
- ))} -
- *Coming Soon +

Up and running in seconds.

+

+ A full agent — sessions, tools, and isolated code execution — in a few lines. It's just an npm package. +

- - {/* Code snippets */} - {/* Tabs */} - - {/* Code block */}
@@ -892,7 +979,7 @@ const Hero = ({ heroTabs }: { heroTabs: HeroTabCode[] }) => {
{getStartedTabs[activeTab]?.fileName ?? 'index.ts'}
-
+
{
+ - - {/* Buttons */} - - - Read the Docs - - - -
); }; - // --- Feature Card --- const FeatureCard = ({ icon: IconComponent, @@ -1069,7 +1134,7 @@ const themedSections: ThemedSection[] = [ { icon: Terminal, title: 'Easy to deploy on prem', description: 'A single npm package. No Kubernetes operators, no sidecar containers. Just install and run.', docsHref: '/docs/deployment' }, { icon: Clock, title: 'Low overhead', description: 'No VMs to boot. No containers to pull. Start in milliseconds with minimal memory footprint.' }, { icon: FolderOpen, title: 'Mount anything as a file system', description: 'S3, GitHub, databases. No per-agent credentials needed. The host handles access scoping.', docsHref: '/docs/filesystem' }, - { icon: Shield, title: 'Extend with a sandbox when needed', description: 'Agent OS handles most tasks, but pairs seamlessly with sandboxes for heavier workloads.', docsHref: '/docs/sandbox' }, + { icon: Shield, title: 'Extend with a sandbox when needed', description: 'agentOS handles most tasks, but pairs seamlessly with sandboxes for heavier workloads.', docsHref: '/docs/sandbox' }, ], }, { @@ -1121,15 +1186,11 @@ const StackingFeatureCards = () => { return () => observer.disconnect(); }, []); - const coldStartP99 = benchColdStart[2]; // p99 - const awsArmAgentCost = benchWorkloads.agent.cost[0]; // AWS ARM - const stackFeatures = [ - { icon: Clock, title: 'Low overhead and cost.', description: 'No VMs to boot. No containers to pull. Start in milliseconds with minimal memory footprint.', detail: 'Traditional sandboxes take seconds to spin up and consume hundreds of megabytes. Agent OS starts instantly and runs lean, so you can scale to thousands of agents without the cost. More details in benchmarks below.', metrics: [{ value: `~${Math.round(coldStartP99.agentOS)}ms`, label: 'p99 coldstart' }, { value: `${awsArmAgentCost.ratio}x`, label: 'cheaper than sandboxes' }] }, { icon: Terminal, title: 'Embed in your backend.', detail: 'Your APIs. Your toolchains. No complex agent authentication needed. Just JavaScript functions or hooks.' }, - { icon: FolderOpen, title: 'Mount anything as a file system.', description: 'S3, SQLite, Google Drive, or the host file system. No per-agent credentials needed.', detail: 'Agents think in files. Agent OS lets you expose any storage backend as a familiar directory tree. The host handles credential scoping, so agents never see API keys or secrets.' }, + { icon: FolderOpen, title: 'Mount anything as a file system.', description: 'S3, SQLite, Google Drive, or the host file system. No per-agent credentials needed.', detail: 'Agents think in files. agentOS lets you expose any storage backend as a familiar directory tree. The host handles credential scoping, so agents never see API keys or secrets.' }, { icon: Shield, title: 'Granular security.', detail: 'Fully configurable network and file system security. Control rate limits, bandwidth limits, and file system permissions. Set precise CPU and memory limitations per agent.' }, - { icon: Globe, title: 'Your laptop, your infra, or on-prem.', description: 'Railway, Vercel, Kubernetes, and more. Deploy wherever your code already runs.', detail: 'Agent OS is just an npm package. No vendor lock-in, no special infrastructure. Your agents run in your stack, on your terms.', tags: ['Railway', 'Vercel', 'Kubernetes', 'ECS', 'Lambda', 'Google Cloud Run'] }, + { icon: Globe, title: 'Your laptop, your infra, or on-prem.', description: 'Rivet, Railway, Vercel, Kubernetes, and more. Deploy wherever your code already runs.', detail: 'agentOS is just an npm package. No vendor lock-in, no special infrastructure. Your agents run in your stack, on your terms.', tags: ['Rivet', 'Railway', 'Vercel', 'Kubernetes', 'ECS', 'Lambda', 'Google Cloud Run'] }, ]; return ( @@ -1471,7 +1532,7 @@ const RegistryCallout = () => ( >

- Agent OS Registry + agentOS Registry

A marketplace for agent capabilities. Browse and install pre-built tools, integrations, file systems, databases, and sandboxes — one command away. @@ -1501,7 +1562,6 @@ const AgentOSFeatures = () => (

-
); @@ -1733,15 +1793,15 @@ function BenchColdStartChart() { { label: ( <> - Agent OS + agentOS What's measured: Time from requesting an execution to first code running.

- Why the gap: Agent OS runs agents in-process — V8 isolates and Wasm inside your host. No VM to boot, no network hop, no disk image. Sandboxes must boot an entire environment, allocate memory, and establish a network connection before code can run. + Why the gap: agentOS runs agents in-process — V8 isolates and Wasm inside your host. No VM to boot, no network hop, no disk image. Sandboxes must boot an entire environment, allocate memory, and establish a network connection before code can run.

Sandbox baseline: {SANDBOX_COLDSTART_PROVIDER}, the fastest mainstream sandbox provider as of {BENCHMARK_DATE}.

- Agent OS: Median of 10,000 runs (100 iterations x 100 samples) on Intel i7-12700KF. + agentOS: Median of 10,000 runs (100 iterations x 100 samples) on Intel i7-12700KF.
), @@ -1767,7 +1827,7 @@ function BenchMemoryBar({ workload }: { workload: WorkloadKey }) { { label: ( <> - Agent OS + agentOS What's measured: Memory footprint added per concurrent execution.

@@ -1775,7 +1835,7 @@ function BenchMemoryBar({ workload }: { workload: WorkloadKey }) {

Sandbox baseline: {SANDBOX_COST_PROVIDER}, the cheapest mainstream sandbox provider as of {BENCHMARK_DATE}. Default sandbox: 1 vCPU + 1 GiB RAM.

- Agent OS: {workload === 'agent' ? `${benchWorkloads.agent.memory.agentOS} for a full Pi coding agent session with MCP servers and file system mounts.` : `${benchWorkloads.shell.memory.agentOS} for the minimal shell workload under sustained load.`} + agentOS: {workload === 'agent' ? `${benchWorkloads.agent.memory.agentOS} for a full Pi coding agent session with MCP servers and file system mounts.` : `${benchWorkloads.shell.memory.agentOS} for the minimal shell workload under sustained load.`}
), @@ -1806,7 +1866,7 @@ function BenchCostChart({ workload }: { workload: WorkloadKey }) { { label: ( <> - Agent OS + agentOS What's measured: server price per second / concurrent executions per server

@@ -1814,7 +1874,7 @@ function BenchCostChart({ workload }: { workload: WorkloadKey }) {

Sandbox baseline: {SANDBOX_COST_PROVIDER}, the cheapest mainstream sandbox provider as of {BENCHMARK_DATE}. Default sandbox: 1 vCPU + 1 GiB RAM at $0.0504/vCPU-h + $0.0162/GiB-h.

- Agent OS: {benchWorkloads[workload].memory.agentOS} baseline per execution, assuming 70% utilization (industry-standard HPA scaling threshold). Select a hardware tier above to compare. + agentOS: {benchWorkloads[workload].memory.agentOS} baseline per execution, assuming 70% utilization (industry-standard HPA scaling threshold). Select a hardware tier above to compare.
), @@ -1829,75 +1889,23 @@ function BenchCostChart({ workload }: { workload: WorkloadKey }) { } function BenchmarkSection() { - const [workload, setWorkload] = useState('agent'); - const wl = benchWorkloads[workload]; + // Each card owns its own workload toggle so they switch independently. + const [memoryWorkload, setMemoryWorkload] = useState('agent'); + const [costWorkload, setCostWorkload] = useState('agent'); return ( - -
-

- Performance benchmarks -

-

- Agent OS vs. traditional sandboxes. -

+
+
+
- -
-

- Workload:{' '} - - - {wl.description} - - -

-
- {(Object.keys(benchWorkloads) as WorkloadKey[]).map((key) => { - const isActive = workload === key; - return ( - setWorkload(key)} - aria-pressed={isActive} - whileTap={{ scale: 0.96 }} - className={`relative rounded-md px-2.5 py-1 text-xs font-medium transition-colors max-sm:flex max-sm:min-h-10 max-sm:w-full max-sm:items-center max-sm:justify-center max-sm:rounded-lg max-sm:py-2 max-sm:text-center ${ - isActive ? 'text-cream' : 'text-ink-soft hover:text-ink' - }`} - > - {isActive && ( - - )} - {benchWorkloads[key].label} - - ); - })} -
+
+
- -
- - - +
+
-

+

Measured on Intel i7-12700KF. Cold start baseline: {SANDBOX_COLDSTART_PROVIDER}, the fastest mainstream sandbox provider as of {BENCHMARK_DATE}. Cost baseline: {SANDBOX_COST_PROVIDER}, the cheapest mainstream sandbox provider as of {BENCHMARK_DATE} (1 vCPU + 1 GiB default). Cost assumes 70% utilization on self-hosted hardware vs. per-second sandbox billing.{' '}

- +
); } -const TechnologyAndBenchmarks = () => ( -
+const FoundationCard = ({ icon, title, body }: { icon: React.ReactNode; title: string; body: string }) => ( +
+
+
{icon}
+

{title}

+
+

{body}

+
+); + +const reveal = { + initial: { opacity: 0, y: 20 }, + whileInView: { opacity: 1, y: 0 }, + viewport: { once: true }, + transition: { duration: 0.5 }, +} as const; + +// The architecture section: one narrative in three movements — the OS framing, +// the harness (structure + the isolate foundation it runs on), then the payoff +// (cold start, memory, and cost diagrams that prove the model). +const OperatingSystemArchitecture = () => ( +
- {/* Technology intro */} - + {/* 1 — Framing */} +

A new operating system architecture.

-

- Built from the ground up for lightweight agents. Agent OS provides the flexibility of Linux with lower overhead than sandboxes. +

+ agentOS gives every agent — and the code it runs — its own lightweight VM: a V8 isolate with WebAssembly, not a full sandbox, with many packed into a single process. It's a real operating system for agents: an in-process kernel hands each VM its own filesystem, processes, and network, exposes your backend functions as host tools the agent calls directly, and schedules and bounds every isolate on its own — the flexibility of Linux at a fraction of the overhead.

-
-
-
-
- WebAssembly -
-

WebAssembly + V8 Isolates

-
-

- High-performance virtualization without specialized infrastructure. The same battle-hardened isolation technology that powers Google Chrome. -

-
-
-
-
- -
-

Battle-tested technology

-
-

- You're probably using this technology right now to view this page. Bring the same power to your agents. No VMs, no containers, no overhead. -

+ + + {/* 2 — The harness (structure) + the foundation it runs on */} + +
+

+ One OS for every agent. +

+

+ The agent sits at the center. The OS brokers Tools & Resources over MCP and host tools, persists Session state, mounts a Sandbox for heavier code, and drives Orchestration — so any supported agent gets the same capabilities with no bespoke glue. +

+
+
+
- {/* Containers vs Isolate density comparison */} - -

- Booting an agent in a container takes a full process and hundreds of milliseconds. Agent OS starts one in a lightweight isolate in about {Math.round(benchColdStart[0].agentOS)} ms — and packs far more into the same memory. + {/* 3 — The payoff (proof) */} + +

+ Faster, lighter, cheaper than sandboxes. +

+

+ No VM to boot, no container to pull, no full gigabyte reserved per idle agent. agentOS cold-starts in about {Math.round(benchColdStart[0].agentOS)} ms and packs far more work into the same memory.

-
- {/* Benchmarks */} - -
-
-); - -const HarnessSection = () => ( -
-
- -

- Everything routes through the harness. -

-

- The harness is the kernel of every agent session — brokering requests and responses between your tools and MCP resources, session state, the sandbox where code runs, and the orchestration layer that ties agents together. Each piece stays isolated, yet composable. -

-
- - -
); @@ -2041,111 +2030,13 @@ const BeforeAfterSlider = ({ before, after }: { before: string; after: string }) Unix Operators
- Agent OS Operators + agentOS Operators
); }; // --- Pairs With --- -const SisterProducts = () => { - const products = [ - { - name: 'Secure Exec', - tagline: 'Secure Node.js execution without a sandbox.', - bullets: [ - 'V8 isolates with bridged Node APIs', - 'npm-compatible: fs, child_process, http', - '176x faster cold start than containers', - 'Just `npm install` — no Docker, no VMs', - ], - href: 'https://secureexec.dev/', - cta: 'secureexec.dev', - }, - { - name: 'Sandbox Agent SDK', - tagline: 'Run coding agents in sandboxes. Control them over HTTP.', - bullets: [ - 'One interface for Claude Code, Codex, OpenCode, Amp', - 'Streams events, handles permissions, manages sessions', - 'Replay, audit, and retain full transcripts', - 'Swap agents with a config change', - ], - href: 'https://sandboxagent.dev/', - cta: 'sandboxagent.dev', - }, - { - name: 'Rivet Actors', - tagline: 'Durable, stateful serverless for agents and realtime apps.', - bullets: [ - 'Long-lived, in-memory state — no external database', - 'Built-in persistence, realtime, and workflow orchestration', - 'Deploy Agent OS sessions as durable actors', - 'Geo-distributed at the edge; scale to zero', - ], - href: 'https://rivet.dev/', - cta: 'rivet.dev', - }, - ]; - - return ( -
-
-
- - Pairs with Agent OS. - - - Agent OS is where agents live. Secure Exec is how you safely run the code they generate. Sandbox Agent SDK is how you control coding agents over HTTP. Rivet Actors is how you deploy and scale them as durable, stateful services. - -
- -
- {products.map((product, idx) => ( - -

{product.name}

-

{product.tagline}

-
    - {product.bullets.map((bullet) => ( -
  • - - {bullet} -
  • - ))} -
-
- {product.cta} - -
-
- ))} -
-
-
- ); -}; const FromUnixToAgents = () => (
@@ -2197,11 +2088,11 @@ export default function AgentOSPage({ heroTabs }: AgentOSPageProps) { return (
- - - + + + + -
diff --git a/website/src/components/marketing/solutions/AgentOSPricingPage.tsx b/website/src/components/marketing/solutions/AgentOSPricingPage.tsx index 70e555566..ec18ff0f5 100644 --- a/website/src/components/marketing/solutions/AgentOSPricingPage.tsx +++ b/website/src/components/marketing/solutions/AgentOSPricingPage.tsx @@ -16,7 +16,7 @@ import { HERO_H1_CLASS, SECTION_H2_CLASS } from '../typography'; const pricingTiers = [ { name: 'Free', - description: 'Run Agent OS anywhere. Free forever.', + description: 'Run agentOS anywhere. Free forever.', price: 'Free', priceSuffix: 'Apache 2.0', icon: Server, @@ -25,7 +25,7 @@ const pricingTiers = [ copyCommand: 'npm install @agent-os/core', highlight: false, features: [ - { text: 'Full Agent OS runtime', included: true }, + { text: 'Full agentOS runtime', included: true }, { text: 'Unlimited agents', included: true }, { text: 'WebAssembly + V8 isolation', included: true }, { text: 'File system mounting (S3, local, etc.)', included: true }, @@ -150,7 +150,7 @@ const CTASection = () => (

Ready to get started?

- Deploy Agent OS today. Start with the open source version or contact us for enterprise support. + Deploy agentOS today. Start with the open source version or contact us for enterprise support.

diff --git a/website/src/components/marketing/solutions/AgentOSUseCasesPage.tsx b/website/src/components/marketing/solutions/AgentOSUseCasesPage.tsx index 97cb69141..190e562f3 100644 --- a/website/src/components/marketing/solutions/AgentOSUseCasesPage.tsx +++ b/website/src/components/marketing/solutions/AgentOSUseCasesPage.tsx @@ -188,7 +188,7 @@ export default function AgentOSUseCasesPage() { transition={{ duration: 0.5, delay: 0.05 }} className='mx-auto max-w-2xl text-lg text-ink-soft md:text-xl' > - From personal assistants to enterprise fleets, Agent OS powers every kind of AI agent. + From personal assistants to enterprise fleets, agentOS powers every kind of AI agent.
@@ -223,7 +223,7 @@ export default function AgentOSUseCasesPage() { transition={{ duration: 0.5, delay: 0.1 }} className='mb-8 text-base leading-relaxed text-ink-soft' > - Get started with Agent OS in minutes. One npm install, zero infrastructure. + Get started with agentOS in minutes. One npm install, zero infrastructure. - + diff --git a/website/src/pages/index.astro b/website/src/pages/index.astro index 883d7bb89..7bc48e535 100644 --- a/website/src/pages/index.astro +++ b/website/src/pages/index.astro @@ -174,7 +174,7 @@ const vm = await AgentOs.create({ mounts: [{ path: "/mnt/data", driver: s3 }], }); -await vm.writeFile("/mnt/data/notes.txt", "Hello from Agent OS!"); +await vm.writeFile("/mnt/data/notes.txt", "Hello from agentOS!"); const content = await vm.readFile("/mnt/data/notes.txt"); console.log(content);` }, @@ -311,7 +311,7 @@ const vm = await AgentOs.create({ }); // Write a file through the mounted sandbox filesystem -await vm.writeFile("/sandbox/hello.txt", "Hello from Agent OS!"); +await vm.writeFile("/sandbox/hello.txt", "Hello from agentOS!"); const content = await vm.readFile("/sandbox/hello.txt"); console.log(new TextDecoder().decode(content)); @@ -357,7 +357,7 @@ const heroTabs = await Promise.all( --- diff --git a/website/src/pages/pricing.astro b/website/src/pages/pricing.astro index eb698e306..faf2175de 100644 --- a/website/src/pages/pricing.astro +++ b/website/src/pages/pricing.astro @@ -8,8 +8,8 @@ import { agentOsPricingFaqs } from "../data/faqs/agent-os-pricing"; --- diff --git a/website/src/pages/registry/index.astro b/website/src/pages/registry/index.astro index 2ba32a630..55ef181f6 100644 --- a/website/src/pages/registry/index.astro +++ b/website/src/pages/registry/index.astro @@ -8,18 +8,18 @@ import { HERO_H1_CLASS } from "../../components/marketing/typography"; ---

- Agent OS Registry + agentOS Registry

- Browse agents, tools, file systems, and sandbox mounting for Agent OS. + Browse agents, tools, file systems, and sandbox mounting for agentOS.

diff --git a/website/src/styles/global.css b/website/src/styles/global.css index e1bc19198..687521533 100644 --- a/website/src/styles/global.css +++ b/website/src/styles/global.css @@ -465,7 +465,7 @@ animation: none; } -/* ── Porcelain editorial marketing surfaces (Agent OS) ─────────────────── */ +/* ── Porcelain editorial marketing surfaces (agentOS) ─────────────────── */ @layer utilities { /* Porcelain editorial surface. The page field is a cool porcelain gray with a From a71ca607b65c233841bdfe4fb6152c9b2a2bb81c Mon Sep 17 00:00:00 2001 From: Nicholas Kissel Date: Sun, 21 Jun 2026 22:04:10 -0700 Subject: [PATCH 3/7] Homepage: rework feature sections, real syntax highlighting, remove pricing - Reorganize the two overlapping homepage feature sections. "Meet your agent's new operating system" now maps 1:1 to the harness architecture diagram (Agent + Tools/MCP, Session, Sandbox, Orchestration), and the "Everything agents need, built in" bento covers distinct cross-cutting capabilities (fault isolation, CPU/memory limits, network control, filesystem mounts, embed-in-backend, deploy-anywhere) with no duplication. - Replace the plain code emitter with a TS/JS tokenizer so the hero code tabs get real inline-colored syntax highlighting (highlight-code.ts). - Drop monospace from UI labels: `font-mono` now renders the sans stack; real code/terminal blocks use the new `font-code` (JetBrains Mono). - Remove the pricing page and its nav/footer links (AgentOSPricingPage, pricing.astro, agent-os-pricing faqs). Co-Authored-By: Claude Opus 4.8 --- website/src/components/Footer.tsx | 1 - website/src/components/Navigation.tsx | 1 - .../marketing/solutions/AgentOSPage.tsx | 1031 +++++++---------- .../solutions/AgentOSPricingPage.tsx | 213 ---- website/src/data/faqs/agent-os-pricing.ts | 31 - website/src/lib/highlight-code.ts | 164 ++- website/src/pages/pricing.astro | 18 - website/tailwind.config.mjs | 8 +- 8 files changed, 608 insertions(+), 859 deletions(-) delete mode 100644 website/src/components/marketing/solutions/AgentOSPricingPage.tsx delete mode 100644 website/src/data/faqs/agent-os-pricing.ts delete mode 100644 website/src/pages/pricing.astro diff --git a/website/src/components/Footer.tsx b/website/src/components/Footer.tsx index cf3dff338..179b4ebdc 100644 --- a/website/src/components/Footer.tsx +++ b/website/src/components/Footer.tsx @@ -5,7 +5,6 @@ import { motion } from "framer-motion"; const footer = { product: [ { name: "Use Cases", href: "/use-cases" }, - { name: "Pricing", href: "/pricing" }, { name: "Registry", href: "/registry" }, ], developers: [ diff --git a/website/src/components/Navigation.tsx b/website/src/components/Navigation.tsx index 318fdc6b0..8f50bb9d2 100644 --- a/website/src/components/Navigation.tsx +++ b/website/src/components/Navigation.tsx @@ -21,7 +21,6 @@ function DiscordIcon({ className }: { className?: string }) { const NAV_LINKS: { href: string; label: string; badge?: number }[] = [ { href: "/use-cases", label: "Use Cases" }, - { href: "/pricing", label: "Pricing" }, { href: "/registry", label: "Registry", badge: registry.length }, { href: "/docs", label: "Docs" }, ]; diff --git a/website/src/components/marketing/solutions/AgentOSPage.tsx b/website/src/components/marketing/solutions/AgentOSPage.tsx index 9c5645d5a..64f9212ee 100644 --- a/website/src/components/marketing/solutions/AgentOSPage.tsx +++ b/website/src/components/marketing/solutions/AgentOSPage.tsx @@ -11,6 +11,9 @@ import { Layers, Globe, Bot, + Briefcase, + ListChecks, + SquareTerminal, Wrench, CalendarClock, ExternalLink, @@ -18,6 +21,7 @@ import { HardDrive, Code, Cpu, + Package, Users, Webhook, Workflow, @@ -31,14 +35,12 @@ import { Hexagon, FileCode, } from 'lucide-react'; -import { AnimatePresence, motion, useReducedMotion } from 'framer-motion'; +import { AnimatePresence, motion, useMotionTemplate, useMotionValue, useReducedMotion, useSpring, useTransform, type MotionValue } from 'framer-motion'; import { InkPanel } from '../editorial/InkPanel'; import { GLOW_PILL_CLASS, handleGlowPillMouseMove } from '../glowPill'; import { registry } from '../../../data/registry'; +import { REGISTRY_ICONS } from '../../../data/registry-icons'; import { HarnessArchitecture } from '../diagrams/HarnessArchitecture'; -import { ColdStartRace } from '../diagrams/ColdStartRace'; -import { MemoryOverhead } from '../diagrams/MemoryOverhead'; -import { ExecutionDensity } from '../diagrams/ExecutionDensity'; interface HeroTabCode { key: string; @@ -616,11 +618,11 @@ const FakeTerminal = () => {
- terminal + terminal
{terminalLines.slice(0, visibleCount).map((line, i) => (
@@ -723,7 +725,7 @@ const HeroTabs = ({ tabs, activeTab, onTabChange }: { tabs: HeroTabEntry[]; acti key={tab.label} type='button' onClick={() => onTabChange(idx)} - className='relative inline-flex shrink-0 items-center gap-2 whitespace-nowrap rounded-lg px-3 py-1.5 font-mono text-xs transition-colors md:px-4' + className='relative inline-flex shrink-0 items-center gap-2 whitespace-nowrap rounded-lg px-3 py-1.5 font-sans text-xs transition-colors md:px-4' > {activeTab === idx && ( { +const Hero = ({ heroTabs }: { heroTabs: HeroTabCode[] }) => { + const [activeTab, setActiveTab] = useState(0); const [hoveredAgent, setHoveredAgent] = useState<{ src: string; name: string } | null>(null); const [autoPlayAgent, setAutoPlayAgent] = useState<{ src: string; name: string } | null>(null); const [autoPlayComplete, setAutoPlayComplete] = useState(false); const [statsIn, setStatsIn] = useState(false); + // Highlight stats — best-case "up to" figures, sourced from bench.ts. + const heroStats = [ + { value: `${Math.round(benchColdStart[2].sandbox / benchColdStart[2].agentOS)}×`, label: 'faster cold starts', sub: 'vs. fastest sandbox', href: '#bench-cold-start' }, + { value: `${benchWorkloads.agent.memory.multiplier.split('x')[0]}×`, label: 'less memory', sub: 'per agent · vs. sandbox', href: '#bench-memory' }, + { value: `${Math.max(...Object.values(benchWorkloads).flatMap((w) => w.cost.map((t) => t.ratio)))}×`, label: 'cheaper to run', sub: 'vs. cheapest sandbox', href: '#bench-cost' }, + ]; + + const getStartedTabs = heroTabMeta.map((tab) => ({ + ...tab, + ...heroTabs.find((heroTab) => heroTab.key === tab.key), + })); + // Auto-cycle through agents starting 2.5s before stroke animation ends useEffect(() => { const logoAnimationDuration = 800; // Start cycling 2.5s before the 3.3s animation ends @@ -821,157 +836,64 @@ const Hero = () => { // Displayed agent is either hovered (if autoplay complete) or autoplay agent const displayedAgent = autoPlayComplete ? hoveredAgent : autoPlayAgent; - // Highlight stats — best-case "up to" figures, sourced from bench.ts. - const heroStats = [ - { value: `${Math.round(benchColdStart[2].sandbox / benchColdStart[2].agentOS)}×`, label: 'faster cold starts', sub: 'vs. fastest sandbox', href: '#bench-cold-start' }, - { value: `${benchWorkloads.agent.memory.multiplier.split('x')[0]}×`, label: 'less memory', sub: 'per agent · vs. sandbox', href: '#bench-memory' }, - { value: `${Math.max(...Object.values(benchWorkloads).flatMap((w) => w.cost.map((t) => t.ratio)))}×`, label: 'cheaper to run', sub: 'vs. cheapest sandbox', href: '#bench-cost' }, - ]; - return (
-
- {/* Top row: copy left, architecture image right */} - - - {/* Bottom row: larger stat cards */} + -
- ); -}; - -// --- Quickstart --- -const Quickstart = ({ heroTabs }: { heroTabs: HeroTabCode[] }) => { - const [activeTab, setActiveTab] = useState(0); - const getStartedTabs = heroTabMeta.map((tab) => ({ - ...tab, - ...heroTabs.find((heroTab) => heroTab.key === tab.key), - })); + {/* Description */} + + A faster, lighter, cheaper alternative to sandboxes{' '} + — with agent orchestration built in. + - return ( -
-
+ {/* Supported Harnesses */} -

Up and running in seconds.

-

- A full agent — sessions, tools, and isolated code execution — in a few lines. It's just an npm package. -

+ Works with +
+ {agents.map((agent) => ( +
autoPlayComplete && setHoveredAgent(agent)} + onMouseLeave={() => autoPlayComplete && setHoveredAgent(null)} + > + {agent.name} + {agent.name}{agent.comingSoon && '*'} +
+ ))} +
+ *Coming Soon
+ + {/* Code snippets */} + {/* Tabs */} + + {/* Code block */}
@@ -979,7 +901,7 @@ const Quickstart = ({ heroTabs }: { heroTabs: HeroTabCode[] }) => {
{getStartedTabs[activeTab]?.fileName ?? 'index.ts'}
-
+
{ animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={{ duration: 0.2 }} - className='overflow-x-auto p-6 font-mono text-sm leading-relaxed text-zinc-600 [&_.line]:break-all [&_.shiki]:!m-0 [&_.shiki]:!bg-transparent [&_.shiki]:!p-0 [&_.shiki]:font-mono [&_.shiki]:text-sm [&_.shiki]:leading-relaxed [&_pre]:whitespace-pre-wrap' + className='overflow-x-auto p-6 font-code text-sm leading-relaxed text-zinc-600 [&_.line]:break-all [&_.shiki]:!m-0 [&_.shiki]:!bg-transparent [&_.shiki]:!p-0 [&_.shiki]:font-code [&_.shiki]:text-sm [&_.shiki]:leading-relaxed [&_pre]:whitespace-pre-wrap' > {
-
- - Read the docs - + + + {/* Buttons */} + + + Read the Docs + + + +
+ + + View Package Registry + + + + + {/* Benchmark stat cards */} + setStatsIn(true)} + className='mt-10 grid grid-cols-1 gap-4 sm:grid-cols-3' + > + {heroStats.map((stat) => ( + +
+ Up to +
+
+ +
+
{stat.label}
+
{stat.sub}
-
+ ))} +
); }; + // --- Feature Card --- const FeatureCard = ({ icon: IconComponent, @@ -1096,348 +1068,303 @@ const IconBox = ({ children }: { children: React.ReactNode }) => (
); -// --- Themed Feature Sections (card carousel) --- -interface ThemedFeature { - title: string; - description: string; - icon: React.ComponentType<{ className?: string }>; - comingSoon?: boolean; - docsHref?: string; -} - -interface ThemedSection { - category: string; - title: string; - subtitle: string; - features: ThemedFeature[]; -} - -const themedSections: ThemedSection[] = [ - { - category: 'Agents', - title: 'Agents that just work.', - subtitle: 'Every agent deserves a runtime that understands it.', - features: [ - { icon: Bot, title: 'Supports Claude Code, Codex, OpenCode, Amp, and more', description: 'Run any coding agent with a single unified API. Swap agents without changing your infrastructure.' }, - { icon: Code, title: 'Simple sessions API', description: 'Create, manage, and resume agent sessions with a few lines of code. State persists automatically.', docsHref: '/docs/sessions' }, - { icon: Activity, title: 'Embedded LLM metering', description: 'Track token usage, cost, and latency per agent. No per-agent API keys needed. The host handles credential scoping.', comingSoon: true, docsHref: '/docs/llm-gateway' }, - { icon: Layers, title: 'Universal transcript format', description: 'One transcript format across all agents. Powered by ACP. Compare, debug, and audit any session.', docsHref: '/docs/sessions' }, - { icon: Clock, title: 'Automatic transcript persistence', description: 'Every conversation is saved. Replay sessions, audit behavior, and build on past context without extra code.', docsHref: '/docs/persistence' }, - ], - }, - { - category: 'Infrastructure', - title: 'Infrastructure that disappears.', - subtitle: 'Deploy anywhere. Scale to anything. Forget about servers.', - features: [ - { icon: Globe, title: 'Runs on your infra', description: 'Managed hosting or self-hosted. Same API, same experience, your choice of where it runs.', docsHref: '/docs/deployment' }, - { icon: Terminal, title: 'Easy to deploy on prem', description: 'A single npm package. No Kubernetes operators, no sidecar containers. Just install and run.', docsHref: '/docs/deployment' }, - { icon: Clock, title: 'Low overhead', description: 'No VMs to boot. No containers to pull. Start in milliseconds with minimal memory footprint.' }, - { icon: FolderOpen, title: 'Mount anything as a file system', description: 'S3, GitHub, databases. No per-agent credentials needed. The host handles access scoping.', docsHref: '/docs/filesystem' }, - { icon: Shield, title: 'Extend with a sandbox when needed', description: 'agentOS handles most tasks, but pairs seamlessly with sandboxes for heavier workloads.', docsHref: '/docs/sandbox' }, - ], - }, - { - category: 'Orchestration', - title: 'Orchestration without complexity.', - subtitle: 'Coordinate agents, humans, and systems out of the box.', - features: [ - { icon: Shield, title: 'Authentication', description: 'Authenticate agent connections with your existing auth model. Validate credentials and attach user state on connect.', docsHref: '/docs/authentication' }, - { icon: Globe, title: 'Webhooks', description: 'Receive external events and route them into agents with lightweight HTTP handlers and durable queues.', docsHref: '/docs/webhooks' }, - { icon: Bot, title: 'Multiplayer & Realtime', description: 'Multiple clients can observe and collaborate with the same agent environment in real time.', docsHref: '/docs/multiplayer' }, - { icon: Layers, title: 'Agent-to-Agent', description: 'Let agents delegate work to other agents through host-defined tools and shared orchestration flows.', docsHref: '/docs/agent-to-agent' }, - { icon: Wrench, title: 'Workflows', description: 'Chain agent tasks into durable workflows with retries, branching, and resumable execution built in.', docsHref: '/docs/workflows' }, - { icon: HardDrive, title: 'Queues', description: 'Serialize agent work with durable queues for backpressure, async processing, and ordered execution.', docsHref: '/docs/queues' }, - { icon: Code, title: 'SQLite', description: 'Give agents access to a persistent SQLite database through host tools for structured state and queryable memory.', docsHref: '/docs/sqlite' }, - ], - }, - { - category: 'Security', - title: 'Security without compromise.', - subtitle: 'The same isolation technology trusted by browsers worldwide.', - features: [ - { icon: Activity, title: 'Restrict CPU and memory granularly', description: 'Set precise resource limits per agent. No runaway processes, no noisy neighbors.', docsHref: '/docs/security' }, - { icon: Globe, title: 'Programmatic network control', description: 'Allow, deny, or proxy any outbound connection. Full control over what your agents can reach.', docsHref: '/docs/security' }, - { icon: Shield, title: 'Custom authentication', description: 'Bring your own auth. API keys, OAuth, JWTs. Agents authenticate on your terms.', docsHref: '/docs/authentication' }, - { icon: Layers, title: 'Isolated private network', description: 'Each agent runs in its own network namespace. No cross-talk between tenants.', docsHref: '/docs/security' }, - { icon: HardDrive, title: 'Powered by WebAssembly and V8 isolates', description: 'The same sandboxing technology behind Google Chrome. Battle-tested at planet scale.', docsHref: '/docs/architecture' }, - ], - }, -]; - +// --- Meet your agent's new operating system (value-prop cards + harness) --- const StackingFeatureCards = () => { - const CARD_HEIGHT = 560; - const STACK_OFFSET = 12; const sectionRef = useRef(null); + const lastCardRef = useRef(null); const [isInView, setIsInView] = useState(false); + // Title fade/blur — driven imperatively from the last card's position (below), + // so it triggers exactly when that card reaches its sticky slot. + const titleOpacity = useMotionValue(1); + const titleBlurPx = useMotionValue(0); + const titleFilter = useMotionTemplate`blur(${titleBlurPx}px)`; + + // Show the bottom fade only while this section is on screen, so the stacking + // deck dissolves into the page background (matches the original main design). useEffect(() => { const section = sectionRef.current; if (!section) return; - const observer = new IntersectionObserver( - ([entry]) => { - setIsInView(entry.isIntersecting); - }, + ([entry]) => setIsInView(entry.isIntersecting), { threshold: 0.1 } ); - observer.observe(section); return () => observer.disconnect(); }, []); + // Fade + blur the title out exactly as the LAST card settles into its sticky + // position — measured from the card itself, so it triggers on arrival no matter + // the card heights or viewport. The card's sticky top is 340 + idx*14px (see the + // card style); the title fades over the final FADE_PX of the card's approach and + // is fully gone the moment it locks in. + useEffect(() => { + const FADE_PX = 160; + const stickTop = 340 + (stackFeatures.length - 1) * 14; + const update = () => { + const el = lastCardRef.current; + if (!el) return; + const top = el.getBoundingClientRect().top; + const p = Math.min(1, Math.max(0, (stickTop + FADE_PX - top) / FADE_PX)); + titleOpacity.set(1 - p); + titleBlurPx.set(p * 8); + }; + update(); + window.addEventListener('scroll', update, { passive: true }); + window.addEventListener('resize', update); + return () => { + window.removeEventListener('scroll', update); + window.removeEventListener('resize', update); + }; + }, [titleOpacity, titleBlurPx]); + const stackFeatures = [ - { icon: Terminal, title: 'Embed in your backend.', detail: 'Your APIs. Your toolchains. No complex agent authentication needed. Just JavaScript functions or hooks.' }, - { icon: FolderOpen, title: 'Mount anything as a file system.', description: 'S3, SQLite, Google Drive, or the host file system. No per-agent credentials needed.', detail: 'Agents think in files. agentOS lets you expose any storage backend as a familiar directory tree. The host handles credential scoping, so agents never see API keys or secrets.' }, - { icon: Shield, title: 'Granular security.', detail: 'Fully configurable network and file system security. Control rate limits, bandwidth limits, and file system permissions. Set precise CPU and memory limitations per agent.' }, - { icon: Globe, title: 'Your laptop, your infra, or on-prem.', description: 'Rivet, Railway, Vercel, Kubernetes, and more. Deploy wherever your code already runs.', detail: 'agentOS is just an npm package. No vendor lock-in, no special infrastructure. Your agents run in your stack, on your terms.', tags: ['Rivet', 'Railway', 'Vercel', 'Kubernetes', 'ECS', 'Lambda', 'Google Cloud Run'] }, + { icon: Bot, title: 'Your agent, at the center.', description: 'Any supported harness, including Claude Code, Codex, and Pi, runs inside the OS instead of beside it.', detail: 'The agent speaks ACP. agentOS brokers every tool call, file read, and network request it makes, then streams every response back. The host stays in control of what the agent can see and do.' }, + { icon: Briefcase, title: 'Tools and resources over MCP.', description: 'Expose any API, toolchain, or data source as a tool or resource the agent can use.', detail: 'Host-defined tools and MCP servers plug straight into the session. The agent calls them like local functions while agentOS handles routing and scoping, so it never holds a raw API key.' }, + { icon: ListChecks, title: 'Durable agent sessions.', description: 'Every run is a managed session with its own state, history, and lifecycle.', detail: 'Start, pause, resume, and replay. Session state lives in the host, so you can attach lifecycle hooks, persist transcripts, and pick a conversation back up exactly where it left off.' }, + { icon: SquareTerminal, title: 'Extend with a sandbox.', description: 'agentOS runs most work in-process and reaches for a full sandbox when a job needs more.', detail: 'Hand heavier or untrusted workloads, like a real kernel, native binaries, or a GPU, to a sandbox without leaving the session. agentOS handles the fast path while sandboxes cover the long tail.' }, + { icon: Workflow, title: 'Orchestrate agents and work.', description: 'Let agents delegate to other agents through host-defined tools, workflows, and cron.', detail: 'Fan work out to sub-agents, coordinate multi-step flows, and schedule recurring jobs. The host brokers every delegated call so it runs under the same limits and permissions.' }, ]; return ( -
- {/* Fade gradient overlay at bottom - only show when section is in view */} +
+ {/* Bottom fade — only while this section is on screen — so the deck + dissolves into the page background instead of hard-clipping. */} {isInView && (
)} -
+
+ {/* Sticky title — pinned while the deck stacks, then fades + blurs out the + instant the last card reaches its sticky slot (driven from that card's + measured position). Opacity/filter are safe on a sticky element. */} Meet your agent's new operating system. -
-
-
-
+ +
+ {/* Left: cards that stack into a deck as you scroll. Plain divs + (not motion) — transforms would break position: sticky. They pin + below the sticky title (340px) so the two never overlap. */} +
{stackFeatures.map((feature, idx) => { const Icon = feature.icon; return (
-
+
-

+

{feature.title} -

-

- {feature.description} -

+ + {feature.description && ( +

+ {feature.description} +

+ )} {feature.detail && ( -

+

{feature.detail}

)} {feature.tags && ( -
+
{feature.tags.map((tag) => ( {tag} ))}
)} - {feature.metrics && ( -
- {feature.metrics.map((m) => ( -
- - {m.value} - - {m.label} -
- ))} -
- )}
); })}
+ + {/* Right: harness diagram, pinned beside the deck (aligns with the first card) */} +
+ +
); }; -const FeatureCardCarousel = ({ section }: { section: ThemedSection }) => { - const scrollRef = useRef(null); - const [canScrollLeft, setCanScrollLeft] = useState(false); - const [canScrollRight, setCanScrollRight] = useState(true); - - const checkScroll = useCallback(() => { - const el = scrollRef.current; - if (!el) return; - setCanScrollLeft(el.scrollLeft > 4); - setCanScrollRight(el.scrollLeft < el.scrollWidth - el.clientWidth - 4); - }, []); +// --- Feature Bento (the most important capabilities, condensed) --- +interface BentoFeature { + icon: React.ComponentType<{ className?: string }>; + title: string; + description: string; + docsHref?: string; + featured?: boolean; + span?: string; +} - useEffect(() => { - const el = scrollRef.current; - if (!el) return; - checkScroll(); - el.addEventListener('scroll', checkScroll, { passive: true }); - window.addEventListener('resize', checkScroll); - return () => { - el.removeEventListener('scroll', checkScroll); - window.removeEventListener('resize', checkScroll); - }; - }, [checkScroll]); +const bentoFeatures: BentoFeature[] = [ + { icon: Bot, title: 'Run any agent harness', description: 'Claude Code, Codex, OpenCode, Amp, and Pi all run behind one unified API. Swap or add agents without touching your infrastructure.', docsHref: '/docs/sessions', featured: true, span: 'lg:col-span-2 lg:row-span-2' }, + { icon: Shield, title: "One agent can't crash the rest", description: 'Each agent runs in its own V8 isolate with a bounded heap, stack, and CPU slice. A memory bomb or infinite loop ends that isolate while the host and every other agent keep running.', docsHref: '/docs/architecture' }, + { icon: Activity, title: 'Restrict CPU & memory granularly', description: 'Set precise resource limits per agent. No runaway processes, no noisy neighbors.', docsHref: '/docs/security' }, + { icon: Globe, title: 'Programmatic network control', description: 'Allow, deny, or proxy any outbound connection. Full control over what your agents can reach.', docsHref: '/docs/security' }, + { icon: FolderOpen, title: 'Mount anything as a file system', description: 'S3, GitHub, databases. No per-agent credentials needed, since the host handles access scoping.', docsHref: '/docs/filesystem' }, + { icon: Code, title: 'Embed in your backend', description: 'agentOS is a library, not a service. Drop it into your existing API and toolchain, and agents call your code as plain JavaScript functions or hooks with no separate agent auth to wire up.', docsHref: '/docs/sessions', span: 'lg:col-span-2' }, + { icon: Package, title: 'Deploy anywhere', description: 'Just an npm package, with no vendor lock-in and no special infrastructure. Run agents on your laptop, Railway, Vercel, Kubernetes, ECS, Lambda, or on-prem. Wherever your code runs, agents run.', docsHref: '/docs/architecture', span: 'lg:col-span-2' }, +]; - const scroll = (dir: 'left' | 'right') => { - const el = scrollRef.current; - if (!el) return; - const cardWidth = el.querySelector('div')?.offsetWidth ?? 300; - el.scrollBy({ left: dir === 'left' ? -cardWidth - 16 : cardWidth + 16, behavior: 'smooth' }); - }; +// --- Floating agent logos for the featured "Run any agent harness" card --- +// Each tile idles with a gentle bob and drifts with the cursor (parallax) while +// the card is hovered. `depth` varies per tile so nearer logos move further. +const FLOATING_AGENTS = [ + { src: '/images/registry/claude-code.svg', label: 'Claude Code', left: '71%', top: '11%', size: 62, depth: 13, float: 10, dur: 6.6, delay: 0 }, + { src: '/images/registry/codex.svg', label: 'Codex', left: '85%', top: '38%', size: 50, depth: 17, float: 8, dur: 7.8, delay: 0.6 }, + { src: '/images/registry/opencode.svg', label: 'OpenCode', left: '67%', top: '60%', size: 54, depth: 20, float: 12, dur: 7.1, delay: 1.2 }, + { src: '/images/registry/amp.svg', label: 'Amp', left: '44%', top: '73%', size: 48, depth: 15, float: 9, dur: 6.9, delay: 0.4 }, + { src: '/images/registry/pi.svg', label: 'PI', left: '19%', top: '67%', size: 46, depth: 23, float: 8, dur: 8.2, delay: 1.6 }, +] as const; + +type FloatingAgent = (typeof FLOATING_AGENTS)[number]; + +const FloatingAgentTile = ({ agent, mx, my, reduce }: { agent: FloatingAgent; mx: MotionValue; my: MotionValue; reduce: boolean }) => { + const x = useTransform(mx, (v) => v * agent.depth); + const y = useTransform(my, (v) => v * agent.depth); + const logo = Math.round(agent.size * 0.52); + return ( + + + {agent.label} + + + ); +}; - // Fade the row's edges wherever a card is cut off, so partially visible - // cards dissolve into the page instead of being hard-clipped. - const maskImage = - canScrollLeft && canScrollRight - ? 'linear-gradient(to right, transparent, #000 56px, #000 calc(100% - 56px), transparent)' - : canScrollRight - ? 'linear-gradient(to right, #000 calc(100% - 56px), transparent)' - : canScrollLeft - ? 'linear-gradient(to right, transparent, #000 56px, #000)' - : undefined; +const FeaturedHarnessCard = ({ feature }: { feature: BentoFeature }) => { + const Icon = feature.icon; + const reduce = useReducedMotion() ?? false; + const mxRaw = useMotionValue(0); + const myRaw = useMotionValue(0); + const mx = useSpring(mxRaw, { stiffness: 90, damping: 18, mass: 0.6 }); + const my = useSpring(myRaw, { stiffness: 90, damping: 18, mass: 0.6 }); + + const handleMove = useCallback( + (e: React.MouseEvent) => { + const rect = e.currentTarget.getBoundingClientRect(); + mxRaw.set(((e.clientX - rect.left) / rect.width - 0.5) * 2); + myRaw.set(((e.clientY - rect.top) / rect.height - 0.5) * 2); + }, + [mxRaw, myRaw], + ); + const handleLeave = useCallback(() => { + mxRaw.set(0); + myRaw.set(0); + }, [mxRaw, myRaw]); return ( -
- {/* Cards */} -
+ {/* Floating agent logos — desktop only, behind the copy */} +
+ {FLOATING_AGENTS.map((agent) => ( + + ))} +
+ +
+
+ +
+

{feature.title}

+

{feature.description}

+ {feature.docsHref && ( +
+ +
+ )} +
+ + ); +}; + +const FeatureBento = () => ( +
+
+ - {section.features.map((feature) => { +

+ Everything agents need, built in. +

+

+ Isolation, resource limits, networking, and storage in one npm package, no glue code. +

+
+ +
+ {bentoFeatures.map((feature) => { + if (feature.featured) { + return ; + } const Icon = feature.icon; - return ( -
- {feature.comingSoon && ( - - Coming Soon - - )} + return ( +
-

+

{feature.title}

-

- {feature.description} -

- {feature.docsHref && ( -
- -
- )} -
+

+ {feature.description} +

+ {feature.docsHref && ( +
+ +
+ )} + ); })}
- - {/* Navigation */} -
- - -
- ); -}; - -const ThemedFeatureSections = () => ( -
- {themedSections.map((section) => ( -
-
- {/* Section header */} - -

- {section.title} -

-

- {section.subtitle} -

-
- - {/* Card carousel */} - - - -
-
- ))} -
+
); // --- agentOS Features Section --- @@ -1464,7 +1391,7 @@ const registryRowB = pickRegistry(REGISTRY_ROW_B); const RegistryAppTile = ({ entry, hidden }: { entry: (typeof registry)[number]; hidden?: boolean }) => { const available = entry.status === 'available'; const category = REGISTRY_TYPE_LABELS[entry.types[0]] ?? 'Integration'; - const IconComponent = entry.icon; + const IconComponent = entry.icon ? REGISTRY_ICONS[entry.icon] : undefined; return ( ( const AgentOSFeatures = () => (
- + +
); @@ -1741,10 +1669,6 @@ function BenchCard({ {/* Eyebrow rail */}
{title} - - - lower is better -
{/* Verdict: the headline multiplier */} @@ -1889,23 +1813,81 @@ function BenchCostChart({ workload }: { workload: WorkloadKey }) { } function BenchmarkSection() { - // Each card owns its own workload toggle so they switch independently. - const [memoryWorkload, setMemoryWorkload] = useState('agent'); - const [costWorkload, setCostWorkload] = useState('agent'); + const [workload, setWorkload] = useState('agent'); + const wl = benchWorkloads[workload]; return ( -
-
- + +
+

+ Performance benchmarks +

+

+ agentOS vs. traditional sandboxes. +

-
- + +
+

+ Workload:{' '} + + + {wl.description} + + +

+
+ {(Object.keys(benchWorkloads) as WorkloadKey[]).map((key) => { + const isActive = workload === key; + return ( + setWorkload(key)} + aria-pressed={isActive} + whileTap={{ scale: 0.96 }} + className={`relative rounded-md px-2.5 py-1 text-xs font-medium transition-colors max-sm:flex max-sm:min-h-10 max-sm:w-full max-sm:items-center max-sm:justify-center max-sm:rounded-lg max-sm:py-2 max-sm:text-center ${ + isActive ? 'text-cream' : 'text-ink-soft hover:text-ink' + }`} + > + {isActive && ( + + )} + {benchWorkloads[key].label} + + ); + })} +
-
+ ); } -const FoundationCard = ({ icon, title, body }: { icon: React.ReactNode; title: string; body: string }) => ( -
-
-
{icon}
-

{title}

-
-

{body}

-
-); - -const reveal = { - initial: { opacity: 0, y: 20 }, - whileInView: { opacity: 1, y: 0 }, - viewport: { once: true }, - transition: { duration: 0.5 }, -} as const; - -// The architecture section: one narrative in three movements — the OS framing, -// the harness (structure + the isolate foundation it runs on), then the payoff -// (cold start, memory, and cost diagrams that prove the model). -const OperatingSystemArchitecture = () => ( -
+const TechnologyAndBenchmarks = () => ( +
- {/* 1 — Framing */} - + {/* Technology intro */} +

A new operating system architecture.

-

- agentOS gives every agent — and the code it runs — its own lightweight VM: a V8 isolate with WebAssembly, not a full sandbox, with many packed into a single process. It's a real operating system for agents: an in-process kernel hands each VM its own filesystem, processes, and network, exposes your backend functions as host tools the agent calls directly, and schedules and bounds every isolate on its own — the flexibility of Linux at a fraction of the overhead. +

+ Built from the ground up for lightweight agents. agentOS provides the flexibility of Linux with lower overhead than sandboxes.

-
- - {/* 2 — The harness (structure) + the foundation it runs on */} - -
-

- One OS for every agent. -

-

- The agent sits at the center. The OS brokers Tools & Resources over MCP and host tools, persists Session state, mounts a Sandbox for heavier code, and drives Orchestration — so any supported agent gets the same capabilities with no bespoke glue. -

-
-
-
-); - -// --- Before/After Slider --- -const BeforeAfterSlider = ({ before, after }: { before: string; after: string }) => { - const containerRef = useRef(null); - const [position, setPosition] = useState(50); - - const updatePosition = useCallback((clientX: number) => { - const el = containerRef.current; - if (!el) return; - const rect = el.getBoundingClientRect(); - const pct = ((clientX - rect.left) / rect.width) * 100; - setPosition(Math.max(0, Math.min(100, pct))); - }, []); - return ( -
updatePosition(e.clientX)} - onTouchMove={(e) => updatePosition(e.touches[0].clientX)} - > - {/* After (full) */} - After - {/* Before (clipped) */} -
- Before -
- {/* Divider */} -
-
- -
-
- {/* Labels */} -
- Unix Operators -
-
- agentOS Operators -
-
- ); -}; - -// --- Pairs With --- - -const FromUnixToAgents = () => ( -
-
-
- - -

- Left: Unix timesharing, UW-Madison, 1978. Right: "Data flock (digits)" by Philipp Schmitt, CC BY-SA 4.0 -

-
- -

- From humans to agents -

-

- The operating system is changing for the next generation of software operators. -

- - Learn more - - -
-
); @@ -2088,12 +1956,9 @@ export default function AgentOSPage({ heroTabs }: AgentOSPageProps) { return (
- - - - + + -
); diff --git a/website/src/components/marketing/solutions/AgentOSPricingPage.tsx b/website/src/components/marketing/solutions/AgentOSPricingPage.tsx deleted file mode 100644 index ec18ff0f5..000000000 --- a/website/src/components/marketing/solutions/AgentOSPricingPage.tsx +++ /dev/null @@ -1,213 +0,0 @@ -'use client'; - -import { useState } from 'react'; -import { motion } from 'framer-motion'; -import { - ArrowRight, - Check, - Server, - Headphones, - Copy, -} from 'lucide-react'; -import { FaqSection } from '../../faq/FaqSection'; -import { agentOsPricingFaqs } from '../../../data/faqs/agent-os-pricing'; -import { HERO_H1_CLASS, SECTION_H2_CLASS } from '../typography'; - -const pricingTiers = [ - { - name: 'Free', - description: 'Run agentOS anywhere. Free forever.', - price: 'Free', - priceSuffix: 'Apache 2.0', - icon: Server, - cta: 'npm install @agent-os/core', - ctaHref: '', - copyCommand: 'npm install @agent-os/core', - highlight: false, - features: [ - { text: 'Full agentOS runtime', included: true }, - { text: 'Unlimited agents', included: true }, - { text: 'WebAssembly + V8 isolation', included: true }, - { text: 'File system mounting (S3, local, etc.)', included: true }, - { text: 'Tool registry', included: true }, - { text: 'Cron, webhooks, queues', included: true }, - { text: 'Network security controls', included: true }, - { text: 'Community support (Discord, GitHub)', included: true }, - ], - }, - { - name: 'Enterprise', - description: 'On-premise deployment with dedicated support.', - price: 'Custom', - priceSuffix: '', - icon: Server, - cta: 'Contact Sales', - ctaHref: 'mailto:hello@agentos-sdk.dev', - highlight: false, - features: [ - { text: 'On-premise deployment', included: true }, - { text: 'Air-gapped environments', included: true }, - { text: 'Custom SLAs', included: true }, - { text: 'Priority support (Slack)', included: true }, - { text: 'Custom integrations', included: true }, - { text: 'Security reviews & compliance', included: true }, - ], - }, -]; - -// Ink command strip with a copy affordance. The install command is the free -// tier's call to action, so it gets the page's single code moment treatment. -const CopyButton = ({ command }: { command: string }) => { - const [copied, setCopied] = useState(false); - - const handleCopy = async () => { - try { - await navigator.clipboard.writeText(command); - setCopied(true); - setTimeout(() => setCopied(false), 2000); - } catch (err) { - console.error('Failed to copy:', err); - } - }; - - return ( - - ); -}; - -const PricingCard = ({ tier, index }: { tier: typeof pricingTiers[0]; index: number }) => { - const Icon = tier.icon; - - return ( - -
-
- -
-

{tier.name}

-

{tier.description}

-
- -
-
- {tier.price} -
- {tier.priceSuffix && ( -

{tier.priceSuffix}

- )} -
- - {tier.copyCommand ? ( - - ) : ( - - {tier.cta} - - - )} - -
    - {tier.features.map((feature) => ( -
  • - - {feature.text} -
  • - ))} -
-
- ); -}; - -const CTASection = () => ( - -
-

Ready to get started?

-

- Deploy agentOS today. Start with the open source version or contact us for enterprise support. -

- -
-
-); - -export default function AgentOSPricingPage() { - return ( -
-
- {/* Hero */} -
-
- -

Free and open source.

-

- agentOS is Apache 2.0 licensed and free to self-host. Contact us for enterprise support and on-premise deployment. -

-
-
-
- - {/* Pricing Cards */} -
-
-
- {pricingTiers.map((tier, index) => ( - - ))} -
-
-
- - {/* No motion wrapper here. The FAQ must stay visible without JavaScript - because the page's FaqJsonLd requires the content to be on-page. */} - - -
-
- ); -} diff --git a/website/src/data/faqs/agent-os-pricing.ts b/website/src/data/faqs/agent-os-pricing.ts deleted file mode 100644 index 2acf99ee8..000000000 --- a/website/src/data/faqs/agent-os-pricing.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { FaqItem } from './types'; - -// FAQ content for the agentOS pricing page. Rendered by AgentOSPricingPage -// and emitted as FAQPage JSON-LD from pages/pricing.astro. -export const agentOsPricingFaqs: FaqItem[] = [ - { - question: 'Is agentOS really free?', - answerHtml: - 'Yes. agentOS is open source under the Apache 2.0 license. You can run it on your own infrastructure at no cost, forever.', - }, - { - question: 'Can I use agentOS in production?', - answerHtml: - 'Absolutely. agentOS is designed to run in production from your laptop to on-prem clusters. It is just an npm package, so it deploys wherever your code already runs.', - }, - { - question: 'What does the Enterprise tier include?', - answerHtml: - 'Enterprise includes on-premise and air-gapped deployment support, custom SLAs, priority support, custom integrations, and security reviews & compliance assistance.', - }, - { - question: 'What support is available for open source users?', - answerHtml: - 'Open source users can get help through our Discord community and GitHub issues. Enterprise customers receive dedicated support channels with guaranteed response times.', - }, - { - question: 'Do you offer volume discounts?', - answerHtml: - 'Yes. Contact our sales team for custom pricing on high-volume usage or enterprise deployments.', - }, -]; diff --git a/website/src/lib/highlight-code.ts b/website/src/lib/highlight-code.ts index af6bdbb03..56d49097c 100644 --- a/website/src/lib/highlight-code.ts +++ b/website/src/lib/highlight-code.ts @@ -1,10 +1,11 @@ -// Dependency-free code "highlighter" for the marketing hero code tabs. +// Dependency-free syntax highlighter for the marketing hero code tabs. // // The original Rivet site rendered these snippets with Shiki at build time and -// styled the resulting `.shiki` / `.line` markup. Shiki is not a dependency of -// this site, so we emit the same `.shiki` > `.line` structure with the source -// HTML-escaped. The hero code block styles the container with a monospace font -// and muted foreground, so plain (unhighlighted) code still reads cleanly. +// styled the resulting `.shiki` / `.line` markup. Shiki is not resolvable from +// this package, so we tokenize the (TS/JS) source ourselves and emit the same +// `.shiki` > `.line` structure with inline-colored token spans. The hero code +// block styles the container (`[&_.shiki]:!bg-transparent`, muted base text), so +// only the token foregrounds matter here. // // Kept async + same signature as the prior `highlightCodeHtml` so callers // (Astro pages) do not change. @@ -16,14 +17,157 @@ function escapeHtml(code: string): string { .replace(/>/g, ">"); } +// Light-theme palette: purple keywords, orange strings, gray-italic comments, +// blue function calls. Tuned to read on the light (`bg-zinc-50`) code block. +const STYLES: Record = { + comment: "color:#8b949e;font-style:italic", + keyword: "color:#8250df", + string: "color:#b45309", + number: "color:#0550ae", + fn: "color:#0550ae", +}; + +const KEYWORDS = new Set([ + "import", "export", "from", "const", "let", "var", "await", "async", + "function", "return", "new", "class", "extends", "implements", "interface", + "type", "enum", "if", "else", "for", "while", "do", "switch", "case", + "break", "continue", "default", "try", "catch", "finally", "throw", + "typeof", "instanceof", "in", "of", "void", "yield", "this", "super", + "static", "public", "private", "protected", "readonly", "as", "satisfies", + "namespace", "declare", "true", "false", "null", "undefined", +]); + +interface Token { + type: keyof typeof STYLES | "text"; + value: string; +} + +function tokenize(code: string): Token[] { + const tokens: Token[] = []; + const n = code.length; + let i = 0; + let text = ""; + + const flushText = () => { + if (text) { + tokens.push({ type: "text", value: text }); + text = ""; + } + }; + + const isIdentStart = (c: string) => /[A-Za-z_$]/.test(c); + const isIdent = (c: string) => /[\w$]/.test(c); + + while (i < n) { + const c = code[i]; + const next = code[i + 1]; + + // Line comment + if (c === "/" && next === "/") { + flushText(); + let j = i + 2; + while (j < n && code[j] !== "\n") j++; + tokens.push({ type: "comment", value: code.slice(i, j) }); + i = j; + continue; + } + + // Block comment + if (c === "/" && next === "*") { + flushText(); + let j = i + 2; + while (j < n && !(code[j] === "*" && code[j + 1] === "/")) j++; + j = Math.min(n, j + 2); + tokens.push({ type: "comment", value: code.slice(i, j) }); + i = j; + continue; + } + + // Strings and template literals + if (c === '"' || c === "'" || c === "`") { + flushText(); + const quote = c; + let j = i + 1; + while (j < n) { + if (code[j] === "\\") { + j += 2; + continue; + } + if (code[j] === quote) { + j++; + break; + } + j++; + } + tokens.push({ type: "string", value: code.slice(i, j) }); + i = j; + continue; + } + + // Numbers + if (/[0-9]/.test(c) && !(text && isIdent(text[text.length - 1]))) { + flushText(); + let j = i; + while (j < n && /[0-9._a-fxA-FXn]/.test(code[j])) j++; + tokens.push({ type: "number", value: code.slice(i, j) }); + i = j; + continue; + } + + // Identifiers / keywords / function calls + if (isIdentStart(c)) { + flushText(); + let j = i + 1; + while (j < n && isIdent(code[j])) j++; + const word = code.slice(i, j); + if (KEYWORDS.has(word)) { + tokens.push({ type: "keyword", value: word }); + } else { + // Function call if the next non-space char is "(" + let k = j; + while (k < n && (code[k] === " " || code[k] === "\t")) k++; + tokens.push({ type: code[k] === "(" ? "fn" : "text", value: word }); + } + i = j; + continue; + } + + text += c; + i++; + } + + flushText(); + return tokens; +} + +function renderTokens(tokens: Token[]): string { + // Build per-line markup, splitting token values that span newlines so each + // `.line` stays self-contained (the container styles `.line` for wrapping). + const lines: string[][] = [[]]; + + for (const token of tokens) { + const parts = token.value.split("\n"); + parts.forEach((part, idx) => { + if (idx > 0) lines.push([]); + if (part === "") return; + const escaped = escapeHtml(part); + const style = token.type === "text" ? undefined : STYLES[token.type]; + lines[lines.length - 1].push( + style ? `${escaped}` : escaped, + ); + }); + } + + return lines + .map((parts) => `${parts.join("") || " "}`) + .join("\n"); +} + export async function highlightCodeHtml( code: string, _lang = "ts", _theme?: string, ): Promise { - const lines = code - .split("\n") - .map((line) => `${escapeHtml(line) || " "}`) - .join("\n"); - return `
${lines}
`; + const html = renderTokens(tokenize(code)); + return `
${html}
`; } diff --git a/website/src/pages/pricing.astro b/website/src/pages/pricing.astro deleted file mode 100644 index faf2175de..000000000 --- a/website/src/pages/pricing.astro +++ /dev/null @@ -1,18 +0,0 @@ ---- -import Layout from "../layouts/Layout.astro"; -import { Navigation } from "../components/Navigation"; -import { Footer } from "../components/Footer"; -import AgentOSPricingPage from "../components/marketing/solutions/AgentOSPricingPage"; -import FaqJsonLd from "../components/faq/FaqJsonLd.astro"; -import { agentOsPricingFaqs } from "../data/faqs/agent-os-pricing"; ---- - - - - - -