Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions packages/ui/public/llms.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# AgentSea

> AgentSea launches supported AI coding agents locally or on cloud infrastructure, pre-wired to The Grid inference API.

## Start here

- Homepage: https://agentsea.thegrid.ai/
- CLI reference: https://agentsea.thegrid.ai/cli
- How AgentSea works: https://agentsea.thegrid.ai/how-it-works
- Why AgentSea: https://agentsea.thegrid.ai/why-agentsea
- Sitemap: https://agentsea.thegrid.ai/sitemap.xml
- Public agent and cloud manifest: https://agentsea.thegrid.ai/manifest.json
- Source repository: https://github.com/the-gridai/agentsea

## Priority launch guides

- OpenClaw locally: https://agentsea.thegrid.ai/openclaw/local
- OpenClaw on DigitalOcean: https://agentsea.thegrid.ai/openclaw/digitalocean
- Hermes Agent locally: https://agentsea.thegrid.ai/hermes/local
- Hermes Agent on DigitalOcean: https://agentsea.thegrid.ai/hermes/digitalocean

Use the sitemap to enumerate every supported agent and cloud launch guide. Every launch guide has a self-referencing canonical URL and contains the exact AgentSea command for that combination.

## The Grid

- The Grid homepage: https://thegrid.ai/
- The Grid agent map: https://thegrid.ai/llms.txt
- Integration documentation: https://thegrid.ai/docs/integrations-and-best-practices/integrations
- OpenClaw integration: https://thegrid.ai/docs/integrations-and-best-practices/integrations/openclaw.md
- Hermes Agent integration: https://thegrid.ai/docs/integrations-and-best-practices/integrations/hermes-agent.md
2 changes: 2 additions & 0 deletions packages/ui/src/app/[agent]/[cloud]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ type PageProps = {
params: Promise<{ agent: string; cloud: string }>;
};

export const dynamicParams = false;

export async function generateMetadata({ params }: PageProps) {
const { agent: agentSlug, cloud: cloudSlug } = await params;
const manifest = await loadManifest(false);
Expand Down
3 changes: 3 additions & 0 deletions packages/ui/src/app/cli/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export async function generateMetadata({ searchParams }: CliGuidePageProps): Pro
return {
title: "CLI Reference",
description: "Install and use the agentsea CLI: commands, environment variables, and tokens.",
alternates: { canonical: "https://agentsea.thegrid.ai/cli" },
};
}

Expand All @@ -44,6 +45,7 @@ export async function generateMetadata({ searchParams }: CliGuidePageProps): Pro
return {
title: "CLI Reference",
description: "Install and use the agentsea CLI: commands, environment variables, and tokens.",
alternates: { canonical: "https://agentsea.thegrid.ai/cli" },
};
}

Expand All @@ -56,6 +58,7 @@ export async function generateMetadata({ searchParams }: CliGuidePageProps): Pro
return {
title: "CLI reference — AgentSea",
description: "Install and use the agentsea CLI: commands, environment variables, and tokens.",
alternates: { canonical: "https://agentsea.thegrid.ai/cli" },
};
}

Expand Down
19 changes: 7 additions & 12 deletions packages/ui/src/app/how-it-works/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@ import Link from "next/link";

import { CopyCode } from "../copy-code";
import { hoodStepsForCloud } from "../how-it-works-steps";
import {
AGENTSEA_INSTALL_URL,
AGENTSEA_PUBLIC_ORIGIN,
THE_GRID_EXTERNAL_URL,
} from "../home-public-constants";
import { AGENTSEA_INSTALL_URL, AGENTSEA_PUBLIC_ORIGIN, THE_GRID_EXTERNAL_URL } from "../home-public-constants";
import { SiteHeader } from "../site-header";
import styles from "../cli/page.module.scss";
import homeStyles from "../page.module.scss";
Expand All @@ -20,6 +16,7 @@ export const metadata: Metadata = {
title: "How it works",
description:
"How AgentSea provisions cloud VMs, wires The Grid API, and connects you to interactive AI agents — from install to SSH session.",
alternates: { canonical: "https://agentsea.thegrid.ai/how-it-works" },
openGraph: {
title: "How it works — AgentSea",
description:
Expand Down Expand Up @@ -113,11 +110,9 @@ export default function HowItWorksPage() {
</ol>
<p className={styles["referenceSection__p"]}>
Bootstrap scripts are served from the CDN at{" "}
<code className={styles["inlineCode"]}>
{AGENTSEA_PUBLIC_ORIGIN}/&lt;cloud&gt;/&lt;agent&gt;.sh
</code>
. The VM inherits <code className={styles["inlineCode"]}>THEGRID_API_KEY</code> and OpenAI-compatible
base URLs targeting the Grid API.
<code className={styles["inlineCode"]}>{AGENTSEA_PUBLIC_ORIGIN}/&lt;cloud&gt;/&lt;agent&gt;.sh</code>. The
VM inherits <code className={styles["inlineCode"]}>THEGRID_API_KEY</code> and OpenAI-compatible base URLs
targeting the Grid API.
</p>
</section>

Expand All @@ -141,8 +136,8 @@ export default function HowItWorksPage() {
<strong>Open Dashboard</strong> for Hermes / OpenClaw UIs
</li>
<li>
<code className={styles["inlineCode"]}>agentsea &lt;agent&gt; &lt;cloud&gt;</code> — provision a
fresh environment with Grid credentials wired
<code className={styles["inlineCode"]}>agentsea &lt;agent&gt; &lt;cloud&gt;</code> — provision a fresh
environment with Grid credentials wired
</li>
<li>
<code className={styles["inlineCode"]}>THEGRID_API_KEY</code> — consumption key from{" "}
Expand Down
45 changes: 19 additions & 26 deletions packages/ui/src/app/landing-from-manifest.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
import type { Metadata } from "next";
import type { AgentSortMode, Manifest } from "@agentsea/sdk";
import {
agentKeys,
allAgentKeys,
cloudKeys,
DEFAULT_AGENT_SORT_MODE,
matrixStatus,
} from "@agentsea/sdk";
import { agentKeys, allAgentKeys, cloudKeys, DEFAULT_AGENT_SORT_MODE, matrixStatus } from "@agentsea/sdk";

import {
CHAT_VERIFIED_AGENT_SLUGS,
HOME_CLOUD_COMING_SOON,
HOME_CLOUD_SLUGS,
LINODE_PLACEHOLDER,
type HomeCloudSlug,
} from "./home-public-constants";

const CHAT_VERIFIED_ORDER = new Map<string, number>(
CHAT_VERIFIED_AGENT_SLUGS.map((slug, i) => [slug, i]),
);
const CHAT_VERIFIED_ORDER = new Map<string, number>(CHAT_VERIFIED_AGENT_SLUGS.map((slug, i) => [slug, i]));

export { DEFAULT_AGENT_SORT_MODE };
export type { AgentSortMode };
Expand All @@ -42,16 +35,8 @@ export function isCloudImplementedForAgent(m: Manifest, cloud: string, agentSlug
return matrixStatus(m, cloud, agentSlug) === "implemented";
}

/** Cloud slugs included in sitemap and static `/{agent}/{cloud}` routes. */
export const INDEXED_CLOUD_SLUGS = [
"local",
"digitalocean",
"hetzner",
"aws",
"gcp",
"daytona",
"sprite",
] as const;
/** Cloud slugs supported by static `/{agent}/{cloud}` routes, including CLI-only providers. */
export const ROUTABLE_CLOUD_SLUGS = ["local", "digitalocean", "hetzner", "aws", "gcp", "daytona", "sprite"] as const;

export function agentCloudPath(agentSlug: string, cloudSlug: string): string {
return `/${agentSlug}/${cloudSlug}`;
Expand All @@ -67,7 +52,7 @@ export function displayCloudName(cloudSlug: string, cloudName: string): string {
export function implementedAgentCloudPairs(m: Manifest): Array<{ agent: string; cloud: string }> {
const pairs: Array<{ agent: string; cloud: string }> = [];
for (const agentSlug of agentKeys(m)) {
for (const cloudSlug of INDEXED_CLOUD_SLUGS) {
for (const cloudSlug of ROUTABLE_CLOUD_SLUGS) {
if (isCloudImplementedForAgent(m, cloudSlug, agentSlug)) {
pairs.push({ agent: agentSlug, cloud: cloudSlug });
}
Expand All @@ -76,8 +61,19 @@ export function implementedAgentCloudPairs(m: Manifest): Array<{ agent: string;
return pairs;
}

/** Implemented pairs exposed in the homepage UX and therefore appropriate for the public sitemap. */
export function publiclyDiscoverableAgentCloudPairs(m: Manifest): Array<{ agent: string; cloud: string }> {
return implementedAgentCloudPairs(m).filter(({ agent, cloud }) => {
return (
CHAT_VERIFIED_ORDER.has(agent) &&
HOME_CLOUD_SLUGS.includes(cloud as HomeCloudSlug) &&
!HOME_CLOUD_COMING_SOON.has(cloud)
);
});
}

function publicOriginBase(): string {
return process.env.NEXT_PUBLIC_AGENTSEA_PUBLIC_ORIGIN?.replace(/\/+$/, "") ?? "https://spawn.thegrid.ai";
return process.env.NEXT_PUBLIC_AGENTSEA_PUBLIC_ORIGIN?.replace(/\/+$/, "") ?? "https://agentsea.thegrid.ai";
}

/** Per-route title, description, canonical URL, and Open Graph / Twitter tags for launch pages. */
Expand Down Expand Up @@ -245,10 +241,7 @@ export function sortHomeAgents(agents: readonly HomeAgentVm[], mode: AgentSortMo
});
}

export function homeAgentsFromManifest(
m: Manifest,
mode: AgentSortMode = DEFAULT_AGENT_SORT_MODE,
): HomeAgentVm[] {
export function homeAgentsFromManifest(m: Manifest, mode: AgentSortMode = DEFAULT_AGENT_SORT_MODE): HomeAgentVm[] {
const rows: HomeAgentVm[] = [];

for (const slug of allAgentKeys(m, mode)) {
Expand Down
2 changes: 2 additions & 0 deletions packages/ui/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const dmMono = DM_Mono({
});

export const metadata: Metadata = {
metadataBase: new URL("https://agentsea.thegrid.ai"),
title: "AgentSea — AI agents on any cloud | The Grid",
description:
"Pick an agent, pick a cloud, one CLI. Provision VMs, Grid API key, browser terminal — AgentSea for The Grid.",
Expand All @@ -29,6 +30,7 @@ export const metadata: Metadata = {
title: "AgentSea — AI agents on any cloud",
description: "Pick an agent, pick a cloud, one CLI. Provision VMs wired to The Grid API.",
type: "website",
url: "https://agentsea.thegrid.ai/",
},
};

Expand Down
23 changes: 19 additions & 4 deletions packages/ui/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
import type { Metadata } from "next";
import Link from "next/link";
import { Suspense } from "react";

import { HomeAgentGridStatic } from "./home-agent-grid-static";
import { HomeLaunchFlow } from "./home-launch-flow";
import { THE_GRID_EXTERNAL_URL } from "./home-public-constants";
import { homeAgentCloudAvailability, homeAgentsFromManifest, homeCloudOptionsFromManifest } from "./landing-from-manifest";
import {
homeAgentCloudAvailability,
homeAgentsFromManifest,
homeCloudOptionsFromManifest,
} from "./landing-from-manifest";
import { SiteHeader } from "./site-header";
import styles from "./page.module.scss";

import { loadManifest } from "@agentsea/sdk/node";

export const metadata: Metadata = {
alternates: { canonical: "https://agentsea.thegrid.ai/" },
};

export default async function HomePage() {
const manifest = await loadManifest(false);
const agents = homeAgentsFromManifest(manifest);
Expand All @@ -24,9 +33,7 @@ export default async function HomePage() {
<h1 id="hero-title" className={styles["hero__title"]}>
Launch AI agents locally or on the cloud
</h1>
<p className={styles["hero__tagline"]}>
Any agent, on your infrastructure — wired to The Grid API.
</p>
<p className={styles["hero__tagline"]}>Any agent, on your infrastructure — wired to The Grid API.</p>
</section>

<Suspense fallback={<HomeAgentGridStatic agents={agents} />}>
Expand All @@ -53,6 +60,14 @@ export default async function HomePage() {
How it works
</Link>
<span className={styles["footer__sep"]}>·</span>
<Link href="/openclaw/local" className={styles["footer__link"]}>
OpenClaw guide
</Link>
<span className={styles["footer__sep"]}>·</span>
<Link href="/hermes/local" className={styles["footer__link"]}>
Hermes guide
</Link>
<span className={styles["footer__sep"]}>·</span>
<a href={THE_GRID_EXTERNAL_URL} rel="noopener noreferrer" className={styles["footer__link"]}>
The Grid
</a>
Expand Down
27 changes: 27 additions & 0 deletions packages/ui/src/app/robots.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { MetadataRoute } from "next";

const PUBLIC_ORIGIN = "https://agentsea.thegrid.ai";

export default function robots(): MetadataRoute.Robots {
const allowedBots = [
"*",
"Googlebot",
"Bingbot",
"Applebot",
"OAI-SearchBot",
"ChatGPT-User",
"Claude-SearchBot",
"Claude-User",
"PerplexityBot",
"Perplexity-User",
"ExaSearchBot",
"ShapBot",
"FirecrawlAgent",
];

return {
rules: allowedBots.map((userAgent) => ({ userAgent, allow: "/" })),
sitemap: `${PUBLIC_ORIGIN}/sitemap.xml`,
host: PUBLIC_ORIGIN,
};
}
15 changes: 7 additions & 8 deletions packages/ui/src/app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
import type { MetadataRoute } from "next";

import { implementedAgentCloudPairs, agentCloudPath } from "./landing-from-manifest";
import { agentCloudPath, publiclyDiscoverableAgentCloudPairs } from "./landing-from-manifest";

import { loadManifest } from "@agentsea/sdk/node";

function publicOriginBase(): string {
return process.env.NEXT_PUBLIC_AGENTSEA_PUBLIC_ORIGIN?.replace(/\/+$/, "") ?? "https://spawn.thegrid.ai";
return process.env.NEXT_PUBLIC_AGENTSEA_PUBLIC_ORIGIN?.replace(/\/+$/, "") ?? "https://agentsea.thegrid.ai";
}

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const manifest = await loadManifest(false);
const base = publicOriginBase();
const entries: MetadataRoute.Sitemap = [
{ url: base, lastModified: new Date() },
{ url: `${base}/cli`, lastModified: new Date() },
{ url: `${base}/why-agentsea`, lastModified: new Date() },
{ url: `${base}/how-it-works`, lastModified: new Date() },
{ url: `${base}/` },
{ url: `${base}/cli` },
{ url: `${base}/why-agentsea` },
{ url: `${base}/how-it-works` },
];

for (const { agent, cloud } of implementedAgentCloudPairs(manifest)) {
for (const { agent, cloud } of publiclyDiscoverableAgentCloudPairs(manifest)) {
entries.push({
url: `${base}${agentCloudPath(agent, cloud)}`,
lastModified: new Date(),
});
}

Expand Down
5 changes: 3 additions & 2 deletions packages/ui/src/app/why-agentsea/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const metadata: Metadata = {
title: "Why AgentSea",
description:
"AgentSea is the fastest way to deploy Grid-backed AI agents on infrastructure you control — agent-agnostic, bring your own cloud, fully sandboxed.",
alternates: { canonical: "https://agentsea.thegrid.ai/why-agentsea" },
openGraph: {
title: "Why AgentSea",
description:
Expand All @@ -33,8 +34,8 @@ export default function WhyAgentSeaPage() {
<header className={styles["referenceHero"]}>
<h1 className={styles["referenceHero__title"]}>Why AgentSea?</h1>
<p className={styles["referenceHero__p"]}>
The fastest way to deploy Grid-backed agents on infrastructure you control. Pick an agent and
environment on the{" "}
The fastest way to deploy Grid-backed agents on infrastructure you control. Pick an agent and environment
on the{" "}
<Link href="/" className={styles["fallback__link"]}>
homepage
</Link>{" "}
Expand Down
Loading