Skip to content
Draft
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
105 changes: 105 additions & 0 deletions web/app/about/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import type { Metadata } from 'next';
import Link from 'next/link';

import { SiteFooter } from '../../components/SiteFooter';
import { SiteNav } from '../../components/SiteNav';
import { HOME_OG_IMAGE_PATH, ogImage } from '../../lib/og-meta';
import { absoluteUrl } from '../../lib/site';
import s from '../landing.module.css';

export const metadata: Metadata = {
title: 'About Agent Relay',
description: 'Agent Relay exists for an agent-centered future where software works through coordinated agents.',
alternates: {
canonical: absoluteUrl('/about'),
},
openGraph: {
title: 'About Agent Relay',
description: 'Agent Relay exists for an agent-centered future where software works through coordinated agents.',
url: absoluteUrl('/about'),
type: 'website',
images: [ogImage(HOME_OG_IMAGE_PATH, 'About Agent Relay')],
},
twitter: {
card: 'summary_large_image',
title: 'About Agent Relay',
description: 'Agent Relay exists for an agent-centered future where software works through coordinated agents.',
images: [absoluteUrl(HOME_OG_IMAGE_PATH)],
},
};

export default function AboutPage() {
const navGetStartedLink = (
<Link href="/docs" className={`${s.ctaPrimary} ${s.homeNavAction}`}>
Get Started
</Link>
);
const mobileGetStartedLink = (
<Link href="/docs" className={`${s.ctaPrimary} ${s.homeNavAction}`}>
Get Started
</Link>
);

return (
<div className={`${s.page} ${s.homePage} ${s.aboutPage}`}>
<SiteNav actions={navGetStartedLink} mobileMenuContent={mobileGetStartedLink} hideLinks />
Comment on lines +32 to +45

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is redundant code duplication where navGetStartedLink and mobileGetStartedLink are defined as two separate but completely identical JSX elements. We can consolidate them into a single getStartedLink variable and pass it to both props in <SiteNav />. This simplifies the component and improves maintainability.

  const getStartedLink = (
    <Link href="/docs" className={`${s.ctaPrimary} ${s.homeNavAction}`}>
      Get Started
    </Link>
  );

  return (
    <div className={`${s.page} ${s.homePage} ${s.aboutPage}`}>
      <SiteNav actions={getStartedLink} mobileMenuContent={getStartedLink} hideLinks />


<main className={s.aboutMain}>
<section className={s.aboutHero} aria-labelledby="about-title">
<div className={s.aboutHeroCopy}>
<h1 id="about-title" className={s.aboutTitle}>
The future is <span className={s.aboutNoBreak}>agent-centered.</span>
</h1>
<p className={s.aboutLead}>
Software is becoming a network of agents that work with people, share context, and move work
forward.
</p>
</div>

<div className={s.aboutOrbit} role="img" aria-label="Agent Relay at the center of agent work">
<span className={`${s.aboutOrbitRing} ${s.aboutOrbitRingOuter}`} />
<span className={`${s.aboutOrbitRing} ${s.aboutOrbitRingInner}`} />
<span className={`${s.aboutOrbitNode} ${s.aboutOrbitNodeTop}`}>People</span>
<span className={`${s.aboutOrbitNode} ${s.aboutOrbitNodeRight}`}>Tools</span>
<span className={`${s.aboutOrbitNode} ${s.aboutOrbitNodeBottom}`}>Memory</span>
<span className={`${s.aboutOrbitNode} ${s.aboutOrbitNodeLeft}`}>Files</span>
<span className={s.aboutOrbitCore}>
<img src="/brand-kit/agent-relay-mark-transparent.png" alt="" className={s.aboutOrbitMark} />

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using a native <img> element in Next.js can trigger the @next/next/no-img-element ESLint warning/error and bypass Next.js's automatic image optimization features (such as layout shifting prevention, resizing, and modern format serving). Consider importing and using the Next.js <Image> component from 'next/image' instead.

</span>
</div>
</section>

<section className={s.aboutBeliefs} aria-labelledby="belief-title">
<div className={s.aboutBeliefIntro}>
<h2 id="belief-title">We are building for the next center of work.</h2>
<p>
Agents need the same primitives teams rely on: identity, communication, files, memory, and
permissions.
</p>
</div>

<div className={s.aboutBeliefList}>
<article className={s.aboutBeliefItem}>
<h3>Agents become participants.</h3>
<p>They should join workspaces, understand context, and coordinate without brittle glue.</p>
</article>
<article className={s.aboutBeliefItem}>
<h3>Context becomes infrastructure.</h3>
<p>The history of work should be shared, searchable, durable, and easy to inspect.</p>
</article>
<article className={s.aboutBeliefItem}>
<h3>Humans stay in charge.</h3>
<p>Agent systems should make decisions visible and give people clear control points.</p>
</article>
</div>
</section>

<section className={s.aboutClosing} aria-label="Agent Relay purpose">
<p>Agent Relay exists to make that future reliable, open, and understandable.</p>
</section>
</main>

<SiteFooter />
</div>
);
}
14 changes: 12 additions & 2 deletions web/app/blog/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import remarkGfm from 'remark-gfm';
import { BlogTableOfContents } from '../../../components/blog/BlogTableOfContents';
import styles from '../../../components/blog/blog.module.css';
import { HighlightedPre } from '../../../components/docs/HighlightedCode';
import { GitHubStarsBadge } from '../../../components/GitHubStars';
import { Waitlist } from '../../../components/home';
import { SiteFooter } from '../../../components/SiteFooter';
import { SiteNav } from '../../../components/SiteNav';
import { getAllPosts, getPost, slugifyHeading } from '../../../lib/blog';
import { getAuthorInitials, getBlogAuthor } from '../../../lib/blog-authors';
import { OG_IMAGE_HEIGHT, OG_IMAGE_WIDTH } from '../../../lib/og-meta';
import { absoluteUrl, SITE_NAME, SITE_URL } from '../../../lib/site';
import landingStyles from '../../landing.module.css';

type PageProps = {
params: Promise<{ slug: string }>;
Expand Down Expand Up @@ -133,6 +133,16 @@ export default async function BlogPostPage({ params }: PageProps) {
.slice(0, 4);
const postUrl = absoluteUrl(`/blog/${slug}`);
const imageUrl = post.frontmatter.coverImage || absoluteUrl(`/blog/${slug}/og.png`);
const navGetStartedLink = (
<Link href="/docs" className={`${landingStyles.ctaPrimary} ${landingStyles.homeNavAction}`}>
Get Started
</Link>
);
const mobileGetStartedLink = (
<Link href="/docs" className={`${landingStyles.ctaPrimary} ${landingStyles.homeNavAction}`}>
Get Started
</Link>
);
const structuredData = {
'@context': 'https://schema.org',
'@type': 'BlogPosting',
Expand Down Expand Up @@ -253,7 +263,7 @@ export default async function BlogPostPage({ params }: PageProps) {

return (
<div className={styles.blogPage}>
<SiteNav actions={<GitHubStarsBadge />} />
<SiteNav actions={navGetStartedLink} mobileMenuContent={mobileGetStartedLink} hideLinks />

<section className={styles.postHero}>
<div className={styles.postHeroInner}>
Expand Down
14 changes: 12 additions & 2 deletions web/app/blog/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import Link from 'next/link';
import { Rss } from 'lucide-react';

import styles from '../../components/blog/blog.module.css';
import { GitHubStarsBadge } from '../../components/GitHubStars';
import { SiteFooter } from '../../components/SiteFooter';
import { SiteNav } from '../../components/SiteNav';
import { getAllPosts } from '../../lib/blog';
import { getAuthorInitials, getBlogAuthor } from '../../lib/blog-authors';
import { defaultOgImage } from '../../lib/og-meta';
import { absoluteUrl, SITE_NAME, SITE_URL } from '../../lib/site';
import landingStyles from '../landing.module.css';

export const metadata: Metadata = {
title: { absolute: 'Agent Relay Blog — Multi-Agent Systems & AI Coordination' },
Expand Down Expand Up @@ -46,6 +46,16 @@ function formatDate(dateStr: string): string {
export default function BlogIndexPage() {
const posts = getAllPosts();
const allPosts = posts;
const navGetStartedLink = (
<Link href="/docs" className={`${landingStyles.ctaPrimary} ${landingStyles.homeNavAction}`}>
Get Started
</Link>
);
const mobileGetStartedLink = (
<Link href="/docs" className={`${landingStyles.ctaPrimary} ${landingStyles.homeNavAction}`}>
Get Started
</Link>
);
const structuredData = {
'@context': 'https://schema.org',
'@type': 'CollectionPage',
Expand All @@ -66,7 +76,7 @@ export default function BlogIndexPage() {

return (
<div className={styles.blogPage}>
<SiteNav actions={<GitHubStarsBadge />} />
<SiteNav actions={navGetStartedLink} mobileMenuContent={mobileGetStartedLink} hideLinks />

<main className={styles.blogMain}>
<script
Expand Down
52 changes: 52 additions & 0 deletions web/app/careers/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import type { Metadata } from 'next';
import Link from 'next/link';

import { SiteFooter } from '../../components/SiteFooter';
import { SiteNav } from '../../components/SiteNav';
import { HOME_OG_IMAGE_PATH, ogImage } from '../../lib/og-meta';
import { absoluteUrl } from '../../lib/site';
import s from '../landing.module.css';

export const metadata: Metadata = {
title: 'Careers',
description: 'Careers at Agent Relay.',
alternates: {
canonical: absoluteUrl('/careers'),
},
openGraph: {
title: 'Careers',
description: 'Careers at Agent Relay.',
url: absoluteUrl('/careers'),
type: 'website',
images: [ogImage(HOME_OG_IMAGE_PATH, 'Careers')],
},
twitter: {
card: 'summary_large_image',
title: 'Careers',
description: 'Careers at Agent Relay.',
images: [absoluteUrl(HOME_OG_IMAGE_PATH)],
},
};

export default function CareersPage() {
const navGetStartedLink = (
<Link href="/docs" className={`${s.ctaPrimary} ${s.homeNavAction}`}>
Get Started
</Link>
);
const mobileGetStartedLink = (
<Link href="/docs" className={`${s.ctaPrimary} ${s.homeNavAction}`}>
Get Started
</Link>
);

return (
<div className={`${s.page} ${s.homePage}`}>
<SiteNav actions={navGetStartedLink} mobileMenuContent={mobileGetStartedLink} hideLinks />

<main className={s.homeMain} />

<SiteFooter />
</div>
);
}
42 changes: 42 additions & 0 deletions web/app/docs/agents/[slug]/og.png/route.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { ImageResponse } from 'next/og';
import { notFound } from 'next/navigation';

import { DefaultVariant, loadBrandFonts, OG_SIZE } from '../../../../../lib/og/template';
import { getProductDoc, getProductDocSlugs } from '../../../../../lib/product-docs';
import { agentsSection } from '../../../../../lib/product-docs-nav';

export const runtime = 'nodejs';
export const dynamic = 'force-static';

type RouteContext = {
params: Promise<{ slug: string }>;
};

export function generateStaticParams() {
return getProductDocSlugs(agentsSection).map((slug) => ({ slug }));
}

export async function GET(_request: Request, { params }: RouteContext) {
const { slug } = await params;
const doc = getProductDoc(agentsSection.id, slug);

if (!doc) {
notFound();
}

const { fonts, headingFamily, bodyFamily } = await loadBrandFonts();

return new ImageResponse(
<DefaultVariant
headingFamily={headingFamily}
bodyFamily={bodyFamily}
eyebrow={agentsSection.label}
title={doc.frontmatter.title}
subtitle={doc.frontmatter.description}
/>,
{
...OG_SIZE,
...(fonts.length > 0 ? { fonts } : {}),
}
);
}
59 changes: 59 additions & 0 deletions web/app/docs/agents/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import type { Metadata } from 'next';

import { ProductDocPage } from '../../../../components/docs/ProductDocPage';
import { ogImage } from '../../../../lib/og-meta';
import {
agentsSection,
getProductDoc,
getProductDocMarkdownUrl,
getProductDocSlugs,
} from '../../../../lib/product-docs';
import { absoluteUrl } from '../../../../lib/site';

const SECTION_ID = agentsSection.id;

type PageProps = {
params: Promise<{ slug: string }>;
};

export function generateStaticParams() {
return getProductDocSlugs(agentsSection).map((slug) => ({ slug }));
}

export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
const { slug } = await params;
const doc = getProductDoc(SECTION_ID, slug);

if (!doc) {
return { title: 'Not Found' };
}

const ogPath = `/docs/${SECTION_ID}/${slug}/og.png`;

return {
title: `${doc.frontmatter.title} — Agents`,
description: doc.frontmatter.description,
alternates: {
canonical: absoluteUrl(`/docs/${SECTION_ID}/${slug}`),
types: { 'text/markdown': getProductDocMarkdownUrl(SECTION_ID, slug) },
},
openGraph: {
title: `${doc.frontmatter.title} — Agents`,
description: doc.frontmatter.description,
url: absoluteUrl(`/docs/${SECTION_ID}/${slug}`),
type: 'article',
images: [ogImage(ogPath, `${doc.frontmatter.title} — Agents docs`)],
},
twitter: {
card: 'summary_large_image',
title: `${doc.frontmatter.title} — Agents`,
description: doc.frontmatter.description,
images: [absoluteUrl(ogPath)],
},
};
}

export default async function AgentsDocPage({ params }: PageProps) {
const { slug } = await params;
return <ProductDocPage sectionId={SECTION_ID} slug={slug} />;
}
30 changes: 30 additions & 0 deletions web/app/docs/agents/markdown/[slug]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { agentsSection, getProductDocMarkdown, getProductDocSlugs } from '../../../../../lib/product-docs';

export const revalidate = 86400;
export const dynamicParams = false;

export function generateStaticParams() {
return getProductDocSlugs(agentsSection).map((slug) => ({ slug: `${slug}.md` }));
}

type RouteProps = {
params: Promise<{ slug: string }>;
};

export async function GET(_request: Request, { params }: RouteProps) {
const { slug: rawSlug } = await params;
const slug = rawSlug.replace(/\.md$/, '');

const doc = getProductDocMarkdown(agentsSection.id, slug);

if (!doc) {
return new Response('Not found', { status: 404 });
}

return new Response(doc.markdown, {
headers: {
'Content-Type': 'text/markdown; charset=utf-8',
'Cache-Control': 'public, max-age=86400',
},
});
}
5 changes: 5 additions & 0 deletions web/app/docs/agents/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { redirect } from 'next/navigation';

export default function AgentsDocsIndexPage() {
redirect('/docs/agents/introduction');
}
Loading
Loading