feat(web): AEO foundation — robots, JSON-LD, meta, llms.txt, security headers

Implements the high-signal, content-independent fixes flagged across the
multi-engine AEO audit:

- robots.txt (app/robots.ts): allow mainstream + AI crawlers (GPTBot,
  ClaudeBot, PerplexityBot, Google-Extended, …), disallow /api, link sitemap.
- Organization + WebSite JSON-LD on the root layout; BlogPosting JSON-LD on
  /blog/[slug].
- Richer metadata: descriptive default title, Open Graph + Twitter cards,
  canonical, icons, metadataBase.
- Per-route titles/descriptions for catch-all routes (docs, about, hire-us,
  agent-swarm, …) instead of the generic "LogicSRC".
- /llms.txt (llmstxt.org) and /skill.md capability manifest.
- /.well-known/security.txt (RFC 9116).
- Security headers via next.config: HSTS, X-Content-Type-Options,
  X-Frame-Options, Referrer-Policy, Permissions-Policy (CSP intentionally
  deferred to avoid breaking inline/stats/CoinPay scripts).

Verified in a running build: all routes serve correctly and headers are set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Anthony Ettinger 2026-06-08 12:38:27 +00:00
parent ce79f02211
commit 6518dfb4a9
8 changed files with 285 additions and 19 deletions

View file

@ -6,7 +6,19 @@ import type { NextConfig } from "next";
// webhooks) are filesystem routes and match before these afterFiles rewrites.
const commandboardApiUrl = process.env.COMMANDBOARD_API_URL;
const securityHeaders = [
// HSTS — site is HTTPS-only behind Railway. No `preload` (irreversible).
{ key: "Strict-Transport-Security", value: "max-age=31536000; includeSubDomains" },
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "X-Frame-Options", value: "SAMEORIGIN" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
{ key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=()" },
];
const nextConfig: NextConfig = {
async headers() {
return [{ source: "/:path*", headers: securityHeaders }];
},
async rewrites() {
if (!commandboardApiUrl) return [];
const base = commandboardApiUrl.replace(/\/$/, "");

View file

@ -0,0 +1,17 @@
const SITE_URL = (process.env.PUBLIC_URL ?? "https://logicsrc.com").replace(/\/$/, "");
// GET /.well-known/security.txt (RFC 9116).
export function GET(): Response {
const expires = new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString();
const body = `Contact: mailto:security@profullstack.com
Expires: ${expires}
Preferred-Languages: en
Canonical: ${SITE_URL}/.well-known/security.txt
`;
return new Response(body, {
headers: {
"content-type": "text/plain; charset=utf-8",
"cache-control": "public, max-age=86400",
},
});
}

View file

@ -1,4 +1,5 @@
import { notFound } from "next/navigation";
import type { Metadata } from "next";
import type { ReactNode } from "react";
import { renderPageMarkup } from "@/lib/page-markup";
import { HomeInteractivity } from "@/components/home-interactivity";
@ -7,18 +8,57 @@ import { HomeInteractivity } from "@/components/home-interactivity";
// scrolled to the matching section. We preserve those URLs (they are canonical
// in sitemap.xml) by rendering the same page for each known route and 404ing
// anything else.
const KNOWN_ROUTES = new Set([
"docs",
"blog",
"openspec",
"credential-sharing",
"hire-us",
"about",
"terms",
"privacy",
"agent-swarm",
"agentbyte"
]);
const ROUTE_META: Record<string, { title: string; description: string }> = {
docs: {
title: "Docs · LogicSRC",
description: "LogicSRC specification guides, schemas, and CLI conventions for humanAI agent coordination.",
},
openspec: {
title: "LogicSRC vs OpenSpec.dev · LogicSRC",
description: "How LogicSRC's coordination standard compares with OpenSpec.dev, including MCP and agent support.",
},
"credential-sharing": {
title: "Credential Sharing · LogicSRC",
description: "Source/target credential diffs, approval, sync, rollback, and audit across .env, Doppler, Railway, and GitHub Secrets.",
},
"hire-us": {
title: "Hire Us · LogicSRC",
description: "Implementation help for LogicSRC, AgentSwarm, and Credential Sharing at $250/week for accepted work, paid via CoinPay.",
},
about: {
title: "About · LogicSRC",
description: "LogicSRC is the Profullstack, Inc. open-specification project for human and AI agent coordination.",
},
terms: { title: "Terms · LogicSRC", description: "LogicSRC terms of use." },
privacy: { title: "Privacy · LogicSRC", description: "LogicSRC privacy notes." },
"agent-swarm": {
title: "AgentSwarm · LogicSRC",
description: "Provider-neutral agent orchestration with model routing, cost controls, and GitHub integration.",
},
agentbyte: {
title: "AgentByte · LogicSRC",
description: "Agent screening sessions, AI-assisted humans, policy events, and APIs.",
},
};
const KNOWN_ROUTES = new Set(Object.keys(ROUTE_META));
export async function generateMetadata({
params,
}: {
params: Promise<{ slug?: string[] }>;
}): Promise<Metadata> {
const { slug } = await params;
const key = slug?.[0];
if (key && ROUTE_META[key]) {
return {
title: ROUTE_META[key].title,
description: ROUTE_META[key].description,
alternates: { canonical: `/${key}` },
};
}
return {};
}
export default async function Page({
params

View file

@ -14,13 +14,16 @@ type PostRow = {
html: string;
featured_image: { url?: string } | null;
published_at: string;
updated_at: string;
};
const SITE_URL = (process.env.PUBLIC_URL ?? "https://logicsrc.com").replace(/\/$/, "");
async function loadPost(slug: string): Promise<PostRow | null> {
const supabase = publicClient();
const { data } = await supabase
.from("blog_posts")
.select("slug, title, excerpt, html, featured_image, published_at")
.select("slug, title, excerpt, html, featured_image, published_at, updated_at")
.eq("slug", slug)
.eq("status", "published")
.maybeSingle();
@ -65,8 +68,25 @@ export default async function BlogPostPage({
const post = await loadPost(slug);
if (!post) notFound();
const jsonLd = {
"@context": "https://schema.org",
"@type": "BlogPosting",
headline: post.title,
description: post.excerpt ?? undefined,
image: post.featured_image?.url ? [post.featured_image.url] : undefined,
datePublished: post.published_at,
dateModified: post.updated_at,
url: `${SITE_URL}/blog/${post.slug}`,
mainEntityOfPage: `${SITE_URL}/blog/${post.slug}`,
publisher: { "@id": `${SITE_URL}/#organization` },
};
return (
<SiteShell active="Blog">
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<article className="band" style={{ maxWidth: "48rem" }}>
<p style={{ marginBottom: "1.5rem" }}>
<Link href="/blog" style={{ color: "#5b6b7a", textDecoration: "none" }}>

View file

@ -3,23 +3,91 @@ import type { ReactNode } from "react";
import "../styles.css";
import Script from "next/script";
const SITE_URL = (process.env.PUBLIC_URL ?? "https://logicsrc.com").replace(/\/$/, "");
const DESCRIPTION =
"Open schemas, primitives, and conventions for coordination between humans, AI agents, plugins, payment systems, and hosted products.";
export const metadata: Metadata = {
title: "LogicSRC",
description:
"Open schemas, primitives, and conventions for coordination between humans, AI agents, plugins, payment systems, and hosted products.",
manifest: "/manifest.webmanifest"
metadataBase: new URL(SITE_URL),
title: "LogicSRC — Open Coordination Standards for Humans & AI Agents",
description: DESCRIPTION,
applicationName: "LogicSRC",
manifest: "/manifest.webmanifest",
alternates: { canonical: "/" },
icons: {
icon: [{ url: "/icon.svg", type: "image/svg+xml" }],
apple: "/icon.svg",
},
openGraph: {
type: "website",
siteName: "LogicSRC",
url: SITE_URL,
title: "LogicSRC — Open Coordination Standards for Humans & AI Agents",
description: DESCRIPTION,
images: ["/icon.svg"],
},
twitter: {
card: "summary",
title: "LogicSRC — Open Coordination Standards",
description: DESCRIPTION,
images: ["/icon.svg"],
},
};
export const viewport: Viewport = {
themeColor: "#101418",
width: "device-width",
initialScale: 1
initialScale: 1,
};
// Organization + WebSite JSON-LD so answer engines can resolve LogicSRC as a
// distinct entity without guessing.
const jsonLd = {
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"@id": `${SITE_URL}/#organization`,
name: "LogicSRC",
url: SITE_URL,
logo: `${SITE_URL}/icon.svg`,
description: DESCRIPTION,
parentOrganization: {
"@type": "Organization",
name: "Profullstack, Inc.",
url: "https://profullstack.com",
},
sameAs: [
"https://github.com/profullstack/logicsrc",
"https://profullstack.com",
],
},
{
"@type": "WebSite",
"@id": `${SITE_URL}/#website`,
url: SITE_URL,
name: "LogicSRC",
description: DESCRIPTION,
inLanguage: "en",
publisher: { "@id": `${SITE_URL}/#organization` },
},
],
};
export default function RootLayout({ children }: { children: ReactNode }): ReactNode {
return (
<html lang="en">
<body>{children} <Script data-site="56a0c760-e6cb-4875-844e-8b8aaa80b59b" src="https://crawlproof.com/stats.js" strategy="afterInteractive" />
<body>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
{children}
<Script
data-site="56a0c760-e6cb-4875-844e-8b8aaa80b59b"
src="https://crawlproof.com/stats.js"
strategy="afterInteractive"
/>
</body>
</html>
);

View file

@ -0,0 +1,37 @@
const SITE_URL = (process.env.PUBLIC_URL ?? "https://logicsrc.com").replace(/\/$/, "");
// GET /llms.txt — concise, link-rich orientation for LLM crawlers
// (https://llmstxt.org spec).
export function GET(): Response {
const body = `# LogicSRC
> Open schemas, primitives, and conventions for coordination between humans, AI agents, plugins, payment systems, and hosted products. LogicSRC defines the shared language; products can implement it without owning the standard. A Profullstack, Inc. open-specification project.
## Core
- [Home](${SITE_URL}/): Overview, standards surface, schemas, CLI, and reference implementations.
- [Docs](${SITE_URL}/docs): Specification guides and conventions.
- [OpenSpec](${SITE_URL}/openspec): LogicSRC vs OpenSpec.dev comparison and compatibility mode.
- [Blog](${SITE_URL}/blog): Project notes and release announcements.
- [Blog RSS](${SITE_URL}/blog/rss.xml): Machine-readable feed of posts.
## Standards & products
- [AgentSwarm](${SITE_URL}/agent-swarm): Provider-neutral agent orchestration, model routing, and cost controls.
- [AgentByte](${SITE_URL}/agentbyte): Agent screening sessions, policy events, and APIs.
- [Credential Sharing](${SITE_URL}/credential-sharing): Source/target credential diffs, approval, sync, rollback, and audit.
## Company & legal
- [About](${SITE_URL}/about): What LogicSRC is and who maintains it (Profullstack, Inc.).
- [Hire Us](${SITE_URL}/hire-us): Implementation help at $250/week for accepted LogicSRC work.
- [Terms](${SITE_URL}/terms)
- [Privacy](${SITE_URL}/privacy)
`;
return new Response(body, {
headers: {
"content-type": "text/plain; charset=utf-8",
"cache-control": "public, max-age=3600",
},
});
}

View file

@ -0,0 +1,30 @@
import type { MetadataRoute } from "next";
const SITE_URL = (process.env.PUBLIC_URL ?? "https://logicsrc.com").replace(/\/$/, "");
// Welcome mainstream + AI crawlers; keep them out of the API surface.
export default function robots(): MetadataRoute.Robots {
return {
rules: [
{
userAgent: [
"*",
"GPTBot",
"OAI-SearchBot",
"ChatGPT-User",
"ClaudeBot",
"Claude-Web",
"anthropic-ai",
"PerplexityBot",
"Google-Extended",
"Applebot-Extended",
"CCBot",
],
allow: "/",
disallow: ["/api/", "/health"],
},
],
sitemap: `${SITE_URL}/sitemap.xml`,
host: SITE_URL,
};
}

View file

@ -0,0 +1,42 @@
const SITE_URL = (process.env.PUBLIC_URL ?? "https://logicsrc.com").replace(/\/$/, "");
// GET /skill.md — capability manifest for agents discovering what this site
// exposes.
export function GET(): Response {
const body = `# LogicSRC Skill
LogicSRC publishes open coordination standards (schemas, primitives, and
conventions) for humans, AI agents, plugins, payment systems, and hosted
products. CommandBoard.run is the reference implementation.
Base URL: ${SITE_URL}
## Resources
- Specification & docs: ${SITE_URL}/docs
- OpenSpec comparison: ${SITE_URL}/openspec
- Schemas, CLI, SDK, TUI, and reference implementations: ${SITE_URL}/
- Blog feed: ${SITE_URL}/blog/rss.xml
- Sitemap: ${SITE_URL}/sitemap.xml
- LLM orientation: ${SITE_URL}/llms.txt
## What you can do here
- Read the LogicSRC coordination schemas and conventions.
- Compare LogicSRC with OpenSpec.dev.
- Request paid implementation help via the Hire Us flow (${SITE_URL}/hire-us),
billed at $250/week for accepted work and paid through CoinPay.
## Notes
- Public marketing/spec content is open to crawl. The /api/ surface is for
application use, not crawling.
- Contact: implementation requests via the Hire Us form at ${SITE_URL}/hire-us.
`;
return new Response(body, {
headers: {
"content-type": "text/markdown; charset=utf-8",
"cache-control": "public, max-age=3600",
},
});
}