- 01 - coverage
+ Coverage
- One daemon. 23 agent harnesses.
+ One Daemon. 23 agent harnesses.
diff --git a/frontend/src/landing/components/LandingFeatures.tsx b/frontend/src/landing/components/LandingFeatures.tsx
index 19bb6b838..3d56e5cc7 100644
--- a/frontend/src/landing/components/LandingFeatures.tsx
+++ b/frontend/src/landing/components/LandingFeatures.tsx
@@ -1,208 +1,1113 @@
-const features = [
+"use client";
+
+import { useMemo, useState } from "react";
+
+type AgentHarness = {
+ id: string;
+ name: string;
+ org: string;
+ logo?: string;
+ command: string;
+ delivery: string;
+ restore: string;
+ hooks: string;
+};
+
+const primaryAgents: AgentHarness[] = [
{
- kicker: "the substrate",
- title: "An operating system, not a wrapper.",
- desc: "Inbound and outbound port contracts. Swappable adapters. A CDC stream. The kind of substrate that survives the next model upgrade - and the one after that.",
- visual: "ports",
- accent: true,
- span: "lg:col-span-2",
+ id: "claude-code",
+ name: "Claude Code",
+ org: "Anthropic",
+ logo: "/docs/logos/claude-code.svg",
+ command: "claude --append-system-prompt-file .ao/AGENTS.md",
+ delivery: "native CLI launch",
+ restore: "resume supported",
+ hooks: "workspace hooks",
},
{
- kicker: "isolation",
- title: "Every agent gets a worktree.",
- desc: "No branch collisions. No stash gymnastics. Each session lives in its own git worktree with its own attachable pane.",
- visual: "branch",
- span: "lg:col-span-1",
+ id: "codex",
+ name: "Codex",
+ org: "OpenAI",
+ logo: "/docs/logos/codex.svg",
+ command: "codex --config ao.session=session/ao-204",
+ delivery: "session flags",
+ restore: "codex resume",
+ hooks: "session flags",
},
{
- kicker: "feedback loop",
- title: "PRs watched. Agents nudged.",
- desc: "CI failure, requested change, merge conflict - the lifecycle manager routes each fact back to the owning agent automatically.",
- visual: "pr",
- span: "lg:col-span-1",
+ id: "opencode",
+ name: "OpenCode",
+ org: "OpenCode",
+ logo: "/docs/logos/opencode.svg",
+ command: "opencode run --session session/ao-204",
+ delivery: "terminal agent",
+ restore: "session API",
+ hooks: "activity bridge",
},
{
- kicker: "durability",
- title: "Durable facts. Derived status.",
- desc: "SQLite stores a small set of session facts. Display state is computed at read time. Triggers append to change_log; CDC fans events out via SSE.",
- visual: "log",
- span: "lg:col-span-2",
+ id: "aider",
+ name: "Aider",
+ org: "Aider",
+ logo: "/docs/logos/aider.png",
+ command: "aider --message-file .ao/prompt.md",
+ delivery: "prompt file",
+ restore: "supported",
+ hooks: "PATH wrappers",
},
{
- kicker: "trust model",
- title: "Bound to 127.0.0.1.",
- desc: "No auth, no CORS, no TLS. No SaaS in the loop. Your threat model fits on a sticky note.",
- span: "lg:col-span-1",
+ id: "cursor",
+ name: "Cursor",
+ org: "Cursor",
+ logo: "/docs/logos/cursor.svg",
+ command: "cursor-agent --print --force",
+ delivery: "one-shot CLI",
+ restore: "fresh launch",
+ hooks: "terminal activity",
},
{
- kicker: "lifecycle",
- title: "Lifecycle manager + reaper.",
- desc: "Reduces runtime, activity and PR observations into durable state. Crash-safe reconcile on every boot.",
- span: "lg:col-span-1",
- },
- {
- kicker: "interfaces",
- title: "ao CLI and Electron app.",
- desc: "Both drive the same daemon over loopback. Spawn from a terminal; supervise in a desktop kanban.",
- span: "lg:col-span-1",
+ id: "goose",
+ name: "Goose",
+ org: "Block",
+ logo: "https://www.google.com/s2/favicons?domain=goose-docs.ai&sz=64",
+ command: "goose run --resume --session-id ao-204",
+ delivery: "native CLI launch",
+ restore: "session id",
+ hooks: "workspace hooks",
},
];
+const adapterNames = [
+ "Claude Code",
+ "Codex",
+ "Cursor",
+ "OpenCode",
+ "Aider",
+ "Amp",
+ "Goose",
+ "Copilot",
+ "Grok",
+ "Qwen",
+ "Kimi",
+ "Crush",
+ "Cline",
+ "Droid",
+ "Devin",
+ "Auggie",
+ "Continue",
+ "Kiro",
+ "Kilo Code",
+ "Agy",
+ "Roo Code",
+ "Windsurf",
+ "Vibe",
+];
+
+const workspaceSessions = [
+ {
+ id: "ao-204",
+ title: "Split terminal mux responsibilities",
+ agent: "Claude Code",
+ branch: "session/ao-204",
+ path: ".ao/worktrees/ao-204",
+ status: "working",
+ color: "#f59f4c",
+ files: ["backend/internal/terminal/manager.go", "frontend/src/renderer/components/TerminalPane.tsx"],
+ },
+ {
+ id: "int-8",
+ title: "fix auth timeout retry loop",
+ agent: "Codex",
+ branch: "fix/auth-timeouts",
+ path: ".ao/worktrees/int-8",
+ status: "ci failed",
+ color: "#ff6b73",
+ files: ["backend/internal/httpd/auth.go", "backend/internal/session_manager/restore.go"],
+ },
+ {
+ id: "ao-211",
+ title: "publish linux desktop install path",
+ agent: "Aider",
+ branch: "docs/linux-install",
+ path: ".ao/worktrees/ao-211",
+ status: "approved",
+ color: "#6ee79a",
+ files: ["frontend/src/landing/content/docs/installation.mdx", "README.md"],
+ },
+];
+
+const feedbackSessions = [
+ {
+ id: "pr-184",
+ number: "#184",
+ title: "fix auth timeout retry loop",
+ agent: "Codex",
+ branch: "fix/auth-timeouts",
+ session: "int-8",
+ state: "needs you",
+ color: "#ff6b73",
+ checks: [
+ { name: "lint", state: "passed", color: "#6ee79a" },
+ { name: "unit", state: "passed", color: "#6ee79a" },
+ { name: "e2e", state: "failed", color: "#ff6b73" },
+ ],
+ comments: ["Auth retry leaks stale token after timeout", "Add regression coverage for 401 retry path"],
+ nudge: "CI failed on PR #184. Fix auth retry timeout and push an update.",
+ },
+ {
+ id: "pr-185",
+ number: "#185",
+ title: "add rate limit headers",
+ agent: "OpenCode",
+ branch: "feat/rate-limit-headers",
+ session: "ao-185",
+ state: "in review",
+ color: "#93b4f8",
+ checks: [
+ { name: "lint", state: "passed", color: "#6ee79a" },
+ { name: "unit", state: "passed", color: "#6ee79a" },
+ { name: "review", state: "pending", color: "#93b4f8" },
+ ],
+ comments: ["Reviewer asked for header docs", "Open question on retry-after semantics"],
+ nudge: "Review comments landed on PR #185. Address docs and retry-after behavior.",
+ },
+ {
+ id: "pr-204",
+ number: "#204",
+ title: "Build onboarding test for published npm package",
+ agent: "Cursor",
+ branch: "test/onboarding-harness",
+ session: "ao-204",
+ state: "ready to merge",
+ color: "#6ee79a",
+ checks: [
+ { name: "lint", state: "passed", color: "#6ee79a" },
+ { name: "unit", state: "passed", color: "#6ee79a" },
+ { name: "review", state: "approved", color: "#6ee79a" },
+ ],
+ comments: ["Approved with two reviews", "Mergeability clean"],
+ nudge: "PR #204 is approved and mergeable. Ready for final merge.",
+ },
+];
+
+const daemonChecks = [
+ { label: "daemon", value: "ready on 127.0.0.1:3001", state: "ok" },
+ { label: "database", value: "~/.ao/data/ao.sqlite", state: "ok" },
+ { label: "git", value: "available", state: "ok" },
+ { label: "runtime", value: "tmux detected", state: "ok" },
+];
+
export function LandingFeatures() {
+ const [workerId, setWorkerId] = useState("codex");
+ const [orchestratorId, setOrchestratorId] = useState("claude-code");
+ const [workspaceId, setWorkspaceId] = useState("int-8");
+ const [feedbackId, setFeedbackId] = useState("pr-184");
+
+ const worker = useMemo(() => primaryAgents.find((agent) => agent.id === workerId) ?? primaryAgents[0], [workerId]);
+ const orchestrator = useMemo(
+ () => primaryAgents.find((agent) => agent.id === orchestratorId) ?? primaryAgents[0],
+ [orchestratorId],
+ );
+ const workspace = useMemo(
+ () => workspaceSessions.find((session) => session.id === workspaceId) ?? workspaceSessions[0],
+ [workspaceId],
+ );
+ const feedback = useMemo(
+ () => feedbackSessions.find((session) => session.id === feedbackId) ?? feedbackSessions[0],
+ [feedbackId],
+ );
+
return (
-
+
-
02 - what's inside
+
What's inside
- Built like an operating system,{" "}
- not a wrapper.
+ Run the agent you already use.
+
+ AO wraps the workflow around it.
+
-
- Inbound/outbound port contracts. Swappable adapters. A CDC stream - the kind of substrate that survives
- the next model upgrade. And the one after that.
+
+ Claude Code, Codex, Cursor, OpenCode, Aider, Goose, Droid, Kilo and the rest stay native terminal
+ tools. AO standardizes launch, restore, hooks, activity and PR ownership through one adapter contract.
-
- {features.map((feature, i) => (
-
- ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
}
-function FeatureCard({ feature, index }: { feature: (typeof features)[number]; index: number }) {
+function FeatureNarrative({ worker, orchestrator }: { worker: AgentHarness; orchestrator: AgentHarness }) {
return (
-
-
-
- {String(index + 1).padStart(2, "0")}
+
+
+
+
+ feature 01
+
+
+ Agent-agnostic by design.
+
+
+
+ 23 harnesses
-
- {feature.kicker}
-
-
- {feature.title}
-
- {feature.desc}
- {feature.visual === "ports" && }
- {feature.visual === "branch" && }
- {feature.visual === "pr" && }
- {feature.visual === "log" && }
+
+
+
+
+
+
+
+
+
+
+ adapter surface
+
+
+
+
+
+
+
+
+
+
+
+ agent-orchestrator.yaml
+
+
+
+ {`agents:
+ worker: ${worker.id}
+ orchestrator: ${orchestrator.id}
+workspace: worktree
+runtime: platform-native`}
+
+
);
}
-function PortsVisual() {
+function AgentHarnessDemo({
+ worker,
+ orchestrator,
+ workerId,
+ orchestratorId,
+ onWorkerChange,
+ onOrchestratorChange,
+}: {
+ worker: AgentHarness;
+ orchestrator: AgentHarness;
+ workerId: string;
+ orchestratorId: string;
+ onWorkerChange: (id: string) => void;
+ onOrchestratorChange: (id: string) => void;
+}) {
return (
-
- {["Agent", "Runtime", "Workspace", "SCM", "Tracker", "Reviewer"].map((port, i) => (
-
-
- {port}
+
+
+
+
+
+
Project agents
+
/repo/agent-orchestrator
+
- ))}
+
+ adapter contract
+
+
+
+
+
+
+
+
+ {primaryAgents.map((agent) => (
+
onWorkerChange(agent.id)}
+ onDoubleClick={() => onOrchestratorChange(agent.id)}
+ className={`group relative flex min-h-[82px] cursor-pointer flex-col items-start justify-between overflow-hidden rounded-lg border p-3 text-left transition duration-200 ease-out hover:-translate-y-0.5 hover:border-white/15 hover:bg-white/[0.045] ${
+ workerId === agent.id
+ ? "border-white/18 bg-white/[0.055] shadow-[inset_0_0_0_1px_rgba(147,180,248,0.16)]"
+ : "border-[color:var(--border)] bg-white/[0.025]"
+ }`}
+ aria-pressed={workerId === agent.id}
+ >
+ {workerId === agent.id ? (
+
+ ) : null}
+
+
+
+ {agent.restore.includes("fresh") ? "new" : "resume"}
+
+
+
+
{agent.name}
+
{agent.org}
+
+
+ ))}
+
+
+
+ Click to set the worker. Double click to promote an agent into the orchestrator slot.
+
+
+
+
+
+
+
Launch preview
+
same daemon route, different native CLI
+
+
+ ready
+
+
+
+
+
+
+
+
+ ao spawn
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {adapterNames.map((name) => (
+
+ {name}
+
+ ))}
+
+
+
+
+
+
+ );
+}
+
+function ContractRow({ label, value, sub }: { label: string; value: string; sub: string }) {
+ return (
+
);
}
-function BranchVisual() {
+function MiniStat({ title, value }: { title: string; value: string }) {
return (
-
-
-
-
-
-
-
-
-
-
-
+
);
}
-function PrVisual() {
+function AgentSelectLabel({ label, agent }: { label: string; agent: AgentHarness }) {
return (
-
-
|
-
|
-
|
-
|
-
- -> nudge -> sess_8f2
+
+
{label}
+
+
+
+
{agent.name}
+
{agent.id}
+
);
}
-function Row({
- color,
- label,
- status,
- highlight,
+function AgentLogo({ agent, className }: { agent: AgentHarness; className: string }) {
+ if (!agent.logo) {
+ return (
+
+ {agent.name.slice(0, 1)}
+
+ );
+ }
+
+ return
;
+}
+
+function TerminalLine({
+ text,
+ muted,
+ accent,
+ success,
}: {
- color: string;
- label: string;
- status: string;
- highlight?: boolean;
+ text: string;
+ muted?: boolean;
+ accent?: boolean;
+ success?: boolean;
}) {
return (
-
-
-
- {label}
-
-
- {status}
-
+
+ {text}
);
}
-function LogVisual() {
+function PipelineStep({ title, detail, active }: { title: string; detail: string; active?: boolean }) {
return (
-
- {[
- ["0x1f", "sess.spawn", "var(--fg-muted)"],
- ["0x20", "pr.opened", "var(--fg-muted)"],
- ["0x21", "ci.fail -> nudge", "var(--status-fail)"],
- ["0x22", "agent.resume", "var(--fg-muted)"],
- ["0x23", "pr.merged", "var(--status-ok)"],
- ].map(([hex, label, color]) => (
-
- {label}
- {hex}
-
- ))}
+
+
+
+ {title}
+
+
{detail}
+
+ );
+}
+
+function AdapterNode({ agent, label }: { agent: AgentHarness; label: string }) {
+ return (
+
+
+
+
{label}
+
{agent.name}
+
+
+ );
+}
+
+function WorkspaceIsolationDemo({
+ activeId,
+ onSelect,
+ workspace,
+}: {
+ activeId: string;
+ onSelect: (id: string) => void;
+ workspace: (typeof workspaceSessions)[number];
+}) {
+ return (
+
+
+
+
+
+
+
Agent Orchestrator
+
+
+
+
+
+
+ Projects
+ +
+
+
+
+
+ agent-orchestrator
+ 3
+
+
+
+
+ {workspaceSessions.map((session) => (
+
onSelect(session.id)}
+ className={`group relative flex w-full cursor-pointer items-start gap-2 rounded-md px-3 py-2.5 text-left transition duration-200 hover:bg-white/[0.05] ${
+ activeId === session.id ? "bg-white/[0.065]" : ""
+ }`}
+ >
+ {activeId === session.id ? (
+
+ ) : null}
+
+
+
+ {session.title}
+
+
{session.id}
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
Session
+
+ {workspace.status}
+
+
+
+ {workspace.agent} {"->"} {workspace.branch}
+
+
+
+
+ Restore
+
+
+ Open PR
+
+
+
+
+
+
+
+
+
{workspace.title}
+
{workspace.path}
+
+
+ {workspace.id}
+
+
+
+
+
+
+
+
+
+ terminal
+
+
+
+
+
+
+ {workspace.files.map((file) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+function WorkspaceNarrative({ workspace }: { workspace: (typeof workspaceSessions)[number] }) {
+ return (
+
+
+
feature 02
+
+ Every agent gets its own checkout.
+
+
+ AO spawns each task into a separate git worktree with its own runtime pane, branch and session metadata. One
+ agent can fail CI while another keeps moving without branch collisions or stash cleanup.
+
+
+
+
+
+
+
+
+
+
+
+ why it matters
+
+
+
+
+
+
+
+
+ );
+}
+
+function InspectorFact({ label, value }: { label: string; value: string }) {
+ return (
+
+ );
+}
+
+function FeedbackNarrative({ feedback }: { feedback: (typeof feedbackSessions)[number] }) {
+ return (
+
+
+
feature 03
+
+ PR feedback goes back to the right agent.
+
+
+ AO does not just show a board. It watches PR state, CI checks, reviews, mergeability and pending comments,
+ then routes the actionable fact to the session that owns the work.
+
+
+
+
+
+
+
+
+
+
+
+ routing loop
+
+
+
+
+
+
+
+
+ );
+}
+
+function FeedbackRoutingDemo({
+ activeId,
+ onSelect,
+ feedback,
+}: {
+ activeId: string;
+ onSelect: (id: string) => void;
+ feedback: (typeof feedbackSessions)[number];
+}) {
+ return (
+
+
+
+
Pull requests
+
CI, reviews and comments mapped to sessions
+
+
+ lifecycle
+
+
+
+
+
+
+
+
+
+
+ {feedback.number}
+
+ {feedback.title}
+
+
+
+ {feedback.branch} {"->"} {feedback.agent} session {feedback.session}
+
+
+
+ Send to agent
+
+
+
+
+
+
+
+ checks
+
+
+ {feedback.checks.map((check) => (
+
+
+
+ {check.name}
+
+
+ {check.state}
+
+
+ ))}
+
+
+
+
+
+ review comments
+
+
+ {feedback.comments.map((comment) => (
+
+ {comment}
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+function DaemonControlDemo() {
+ return (
+
+
+
+
Local control plane
+
desktop and CLI talk to the same daemon
+
+
+ 127.0.0.1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {daemonChecks.map((check) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+ event stream
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+function DaemonNarrative() {
+ return (
+
+
+
feature 04
+
+ One local daemon runs the whole loop.
+
+
+ The desktop app and `ao` CLI both drive the same loopback daemon. It starts sessions, stores durable facts,
+ streams changes, attaches terminals and keeps the product local-first.
+
+
+
+
+
+
+
+
+
+
+
+ system pieces
+
+
+
+
+
+
+
+
+ );
+}
+
+function DaemonNode({ title, body, active }: { title: string; body: string; active?: boolean }) {
+ return (
+
+
+
+ {title}
+
+
{body}
+
+ );
+}
+
+function EventRow({ seq, label, detail }: { seq: string; label: string; detail: string }) {
+ return (
+
+ {seq}
+ {label}
+ {detail}
);
}
diff --git a/frontend/src/landing/components/LandingFooter.tsx b/frontend/src/landing/components/LandingFooter.tsx
index 34f4fae1e..1adf7e71e 100644
--- a/frontend/src/landing/components/LandingFooter.tsx
+++ b/frontend/src/landing/components/LandingFooter.tsx
@@ -1,4 +1,34 @@
-const LOGO_URL = "/ao-logo.svg";
+const LOGO_URL = "/ao-logo-transparent.png";
+
+const columns = [
+ {
+ title: "Product",
+ links: [
+ { label: "Features", href: "#features" },
+ { label: "Agents", href: "#agents" },
+ { label: "Install", href: "/docs/installation" },
+ { label: "CLI", href: "/docs/cli" },
+ ],
+ },
+ {
+ title: "Docs",
+ links: [
+ { label: "Overview", href: "/docs" },
+ { label: "Architecture", href: "/docs/architecture" },
+ { label: "Plugins", href: "/docs/plugins" },
+ { label: "Changelog", href: "/docs/changelog" },
+ ],
+ },
+ {
+ title: "Community",
+ links: [
+ { label: "GitHub", href: "https://github.com/AgentWrapper/agent-orchestrator" },
+ { label: "Issues", href: "https://github.com/AgentWrapper/agent-orchestrator/issues" },
+ { label: "Pull requests", href: "https://github.com/AgentWrapper/agent-orchestrator/pulls" },
+ { label: "Releases", href: "https://github.com/AgentWrapper/agent-orchestrator/releases" },
+ ],
+ },
+];
function GithubIcon({ className = "" }: { className?: string }) {
return (
@@ -8,86 +38,69 @@ function GithubIcon({ className = "" }: { className?: string }) {
);
}
-const productLinks = [
- { label: "Features", href: "#features" },
- { label: "How it works", href: "#how" },
- { label: "Architecture", href: "#architecture" },
- { label: "Quickstart", href: "#quickstart" },
-];
-
-const resourceLinks = [
- { label: "GitHub", href: "https://github.com/AgentWrapper/agent-orchestrator" },
- { label: "Architecture docs", href: "/docs/architecture" },
- { label: "CLI reference", href: "/docs/cli" },
- { label: "Releases", href: "https://github.com/AgentWrapper/agent-orchestrator/releases" },
-];
-
-const communityLinks = [
- { label: "Contributors", href: "https://github.com/AgentWrapper/agent-orchestrator/graphs/contributors" },
- { label: "Issues", href: "https://github.com/AgentWrapper/agent-orchestrator/issues" },
- { label: "Pull requests", href: "https://github.com/AgentWrapper/agent-orchestrator/pulls" },
- { label: "ao-agents.com", href: "https://ao-agents.com" },
-];
-
export function LandingFooter() {
return (
-
-
-
-
-
-
-
- Agent Orchestrator
+
+
+
+
+
+
+ Agent Orchestrator
+
+
+ Open-source orchestration for terminal-native coding agents. Local daemon, isolated worktrees, live
+ sessions, and PR feedback routed to the right worker.
+
+
-
- The open-source orchestration layer for parallel AI coding agents. Loopback-only, Apache 2.0 licensed,
- runs on your laptop.
-
-
-
-
+
+ {columns.map((column) => (
+
+ ))}
+
-
);
}
-
-function FooterCol({ title, links }: { title: string; links: Array<{ label: string; href: string }> }) {
- return (
-
- );
-}
diff --git a/frontend/src/landing/components/LandingHero.tsx b/frontend/src/landing/components/LandingHero.tsx
index 3df05310b..9347f66aa 100644
--- a/frontend/src/landing/components/LandingHero.tsx
+++ b/frontend/src/landing/components/LandingHero.tsx
@@ -558,15 +558,16 @@ export function LandingHero() {
Stop babysitting coding agents.
-
- Start merging real work.
+
+ Start merging real work.
diff --git a/frontend/src/landing/components/LandingNav.tsx b/frontend/src/landing/components/LandingNav.tsx
index 518f2f9bd..2809bad0b 100644
--- a/frontend/src/landing/components/LandingNav.tsx
+++ b/frontend/src/landing/components/LandingNav.tsx
@@ -71,7 +71,7 @@ const socials = [
const navLinks = [
{ label: "Demo", href: "#see-it" },
- { label: "Agents", href: "#agents" },
+ { label: "Features", href: "#features" },
{ label: "Docs", href: "/docs" },
];
diff --git a/frontend/src/landing/components/LandingSocialProof.tsx b/frontend/src/landing/components/LandingSocialProof.tsx
index 5f9ed3388..293ba981b 100644
--- a/frontend/src/landing/components/LandingSocialProof.tsx
+++ b/frontend/src/landing/components/LandingSocialProof.tsx
@@ -1,12 +1,18 @@
"use client";
-import { useEffect, useState } from "react";
+import { useEffect, useRef, useState } from "react";
declare global {
interface Window {
twttr?: {
+ ready?: (callback: () => void) => void;
widgets?: {
- load?: () => void;
+ load?: (element?: HTMLElement) => void;
+ createTweet?: (
+ tweetId: string,
+ element: HTMLElement,
+ options?: { theme?: "dark" | "light"; dnt?: boolean; conversation?: "none"; width?: number },
+ ) => Promise;
};
};
}
@@ -19,6 +25,8 @@ const posts = [
label: "Signal",
author: "Teknium",
note: "Most important outside validation.",
+ text: "Outside validation that AO is landing with serious agent builders.",
+ meta: "builder signal",
},
{
handle: "facito0",
@@ -26,6 +34,8 @@ const posts = [
label: "Mood",
author: "FacitoO",
note: "A lightweight social proof hit from daily AO usage.",
+ text: "A small but useful signal from someone actually using the workflow.",
+ meta: "daily AO usage",
},
{
handle: "buchireddy",
@@ -33,6 +43,8 @@ const posts = [
label: "Builder",
author: "Buchi Reddy B",
note: "Went all-in early on the AO building blocks.",
+ text: "I really loved the building blocks present in @aoagents, hence we went all-in on that pretty early. Happy to share more details if it helps others.",
+ meta: "3:41 AM - Jun 9, 2026",
},
{
handle: "oxwizzdom",
@@ -40,6 +52,8 @@ const posts = [
label: "Code read",
author: "oxwizzdom",
note: "Weekend codebase teardown and minimal rebuild.",
+ text: "1/ @agent_wrapper & @composio shipped @aoagents a while back. runs 50 coding agents in parallel on the same repo. i spent a weekend reading the codebase. found 5 techniques that make it work.",
+ meta: "repo teardown",
},
{
handle: "addddiiie",
@@ -47,6 +61,8 @@ const posts = [
label: "Use case",
author: "Adi",
note: "Parallel dev agents framed in one clean line.",
+ text: "The core use case explained simply: parallel agents without babysitting.",
+ meta: "parallel workflow",
},
{
handle: "aoagents",
@@ -54,6 +70,8 @@ const posts = [
label: "Official",
author: "Agent Orchestrator",
note: "A short official signal from the AO account.",
+ text: "Best as it gets",
+ meta: "official AO",
},
];
@@ -61,6 +79,10 @@ function postUrl(post: (typeof posts)[number]) {
return `https://twitter.com/${post.handle}/status/${post.statusIdParts.join("")}`;
}
+function postId(post: (typeof posts)[number]) {
+ return post.statusIdParts.join("");
+}
+
function ArrowUpRightIcon({ className = "" }: { className?: string }) {
return (
@@ -78,15 +100,21 @@ function MessageCircleIcon({ className = "" }: { className?: string }) {
);
}
-function loadTwitterWidgets() {
+function loadTwitterWidgets(target?: HTMLElement | null, onReady?: () => void) {
+ const load = () => {
+ window.twttr?.widgets?.load?.(target ?? undefined);
+ window.twttr?.ready?.(() => onReady?.());
+ onReady?.();
+ };
+
if (window.twttr?.widgets) {
- window.twttr.widgets.load?.();
+ load();
return;
}
const existing = document.getElementById("twitter-wjs");
if (existing) {
- existing.addEventListener("load", () => window.twttr?.widgets?.load?.(), { once: true });
+ existing.addEventListener("load", load, { once: true });
return;
}
@@ -95,7 +123,7 @@ function loadTwitterWidgets() {
script.src = "https://platform.twitter.com/widgets.js";
script.async = true;
script.charset = "utf-8";
- script.onload = () => window.twttr?.widgets?.load?.();
+ script.onload = load;
document.body.appendChild(script);
}
@@ -119,9 +147,43 @@ function usePageTheme() {
export function LandingSocialProof() {
const theme = usePageTheme();
+ const tweetRefs = useRef>({});
useEffect(() => {
- loadTwitterWidgets();
+ const target = document.getElementById("testimonials");
+ const renderTweets = () => {
+ for (const post of posts) {
+ const id = postId(post);
+ const node = tweetRefs.current[id];
+ if (!node || node.dataset.tweetRendered === `${id}-${theme}`) continue;
+ if (!window.twttr?.widgets?.createTweet) continue;
+
+ node.dataset.tweetRendered = `${id}-${theme}`;
+ node.innerHTML = "";
+ void window.twttr.widgets
+ .createTweet(id, node, {
+ theme: theme === "light" ? "light" : "dark",
+ dnt: true,
+ conversation: "none",
+ width: 420,
+ })
+ .catch(() => {
+ delete node.dataset.tweetRendered;
+ });
+ }
+ };
+
+ loadTwitterWidgets(target, renderTweets);
+ window.twttr?.ready?.(renderTweets);
+
+ const timers = [350, 1000, 2200, 4200, 7000].map((delay) =>
+ window.setTimeout(() => {
+ window.twttr?.ready?.(renderTweets);
+ renderTweets();
+ }, delay),
+ );
+
+ return () => timers.forEach((timer) => window.clearTimeout(timer));
}, [theme]);
return (
@@ -134,7 +196,7 @@ export function LandingSocialProof() {
-
06 - in the wild
+
In the wild
{posts.map((post, index) => (
-
+ {
+ tweetRefs.current[postId(post)] = node;
+ }}
+ />
))}
@@ -163,7 +232,47 @@ export function LandingSocialProof() {
);
}
-function TweetCard({ post, index, theme }: { post: (typeof posts)[number]; index: number; theme: string }) {
+function TweetFallback({ post, url }: { post: (typeof posts)[number]; url: string }) {
+ return (
+
+
+
+
+ {post.author.slice(0, 1)}
+
+
+
{post.author}
+
@{post.handle}
+
+
+
X
+
+
+
{post.text}
+
+
+ {post.meta}
+
+
+
+ );
+}
+
+function TweetCard({
+ post,
+ index,
+ setTweetRef,
+}: {
+ post: (typeof posts)[number];
+ index: number;
+ setTweetRef: (node: HTMLDivElement | null) => void;
+}) {
const url = postUrl(post);
return (
@@ -195,15 +304,12 @@ function TweetCard({ post, index, theme }: { post: (typeof posts)[number]; index
diff --git a/frontend/src/landing/styles/globals.css b/frontend/src/landing/styles/globals.css
index 31b751422..4a9b335dd 100644
--- a/frontend/src/landing/styles/globals.css
+++ b/frontend/src/landing/styles/globals.css
@@ -239,6 +239,17 @@ body::-webkit-scrollbar,
background: var(--bg-deep);
}
+.tweet-fallback {
+ min-height: 240px;
+ border-radius: 14px;
+ border: 1px solid var(--border);
+ background:
+ linear-gradient(180deg, rgba(130, 170, 255, 0.035), transparent 36%),
+ #050607;
+ padding: 18px;
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
+}
+
.tweet-shell .twitter-tweet,
.tweet-shell iframe {
width: 100% !important;
@@ -558,6 +569,54 @@ body::-webkit-scrollbar,
animation: landing-sse-pulse 1.6s ease-in-out infinite;
}
+@keyframes landing-adapter-pulse {
+ 0% {
+ transform: translateX(-24px);
+ opacity: 0;
+ }
+ 18%,
+ 72% {
+ opacity: 1;
+ }
+ 100% {
+ transform: translateX(24px);
+ opacity: 0;
+ }
+}
+
+.landing-adapter-pulse {
+ animation: landing-adapter-pulse 1.7s cubic-bezier(0.4, 0.8, 0.6, 1) infinite;
+}
+
+.landing-feature-stack-card {
+ will-change: transform;
+}
+
+.landing-feature-stack-cover {
+ isolation: isolate;
+}
+
+.landing-feature-stack-cover::before {
+ content: "";
+ position: absolute;
+ inset: -28px -2px -28px -2px;
+ z-index: -1;
+ border-radius: 24px;
+ background: var(--bg);
+ box-shadow: 0 -80px 0 80px var(--bg);
+}
+
+@media (max-width: 1023px) {
+ .landing-feature-stack-card {
+ position: relative;
+ top: auto;
+ }
+
+ .landing-feature-stack-cover::before {
+ display: none;
+ }
+}
+
/* Switcher progress bar */
@keyframes landing-switcher-progress {
from {