feat(web): real /about and /docs pages (unique crawlable content)

Addresses the top cross-engine AEO finding — every route previously served
the homepage SPA. /about and /docs are now distinct routes with their own
server-rendered content and titles.

- /about: substantive about page (what LogicSRC is, the standards surface,
  CommandBoard.run reference impl, GitHub, hire-us) — derived from public
  positioning, no fabricated team.
- /docs + /docs/[slug]: render the repo's docs/*.md (curated public set) via
  marked, statically generated at build (no runtime fs dependency).
- Drop about/docs from the catch-all; add doc URLs to the sitemap.

Verified in a running build: /about and /docs serve unique content with
distinct titles; /docs/[slug] renders each markdown doc.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Anthony Ettinger 2026-06-08 12:43:42 +00:00
parent 6518dfb4a9
commit fb20fd2e99
8 changed files with 291 additions and 9 deletions

View file

@ -14,6 +14,7 @@
"dependencies": {
"@profullstack/autoblog": "github:profullstack/autoblog#75e54af",
"@supabase/supabase-js": "^2.105.4",
"marked": "^18.0.5",
"next": "16.2.6",
"react": "19.2.0",
"react-dom": "19.2.0"

View file

@ -8,11 +8,9 @@ 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.
// /about and /docs are now real routes (app/about, app/docs); the rest still
// render the homepage SPA scrolled to their section.
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.",
@ -25,10 +23,6 @@ const ROUTE_META: Record<string, { title: string; description: string }> = {
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": {

View file

@ -0,0 +1,94 @@
import type { ReactNode } from "react";
import type { Metadata } from "next";
import { SiteShell } from "@/components/site-shell";
export const metadata: Metadata = {
title: "About · LogicSRC",
description:
"LogicSRC is the Profullstack, Inc. open-specification project for coordination between humans and AI agents — schemas, primitives, and conventions that products implement without owning the standard.",
alternates: { canonical: "/about" },
};
export default function AboutPage(): ReactNode {
return (
<SiteShell active="About">
<article className="band" style={{ maxWidth: "48rem" }}>
<div className="section-head">
<h2>About LogicSRC</h2>
<p>
LogicSRC is the open-specification project from{" "}
<a href="https://profullstack.com" rel="noreferrer">
Profullstack, Inc.
</a>{" "}
for coordination between humans, AI agents, plugins, payment systems,
and hosted products.
</p>
</div>
<div
className="blog-content"
style={{ lineHeight: 1.7, marginTop: "1.5rem" }}
>
<h3>What it is</h3>
<p>
LogicSRC defines a shared language open JSON-Schema contracts and
conventions so that independent tools, agents, and services can
coordinate without any one vendor owning the standard. Products
implement LogicSRC; they don&apos;t depend on a proprietary platform
to interoperate.
</p>
<h3>The standards surface</h3>
<ul>
<li>
<strong>Identity</strong> DIDs, OAuth accounts, profiles, and
organization membership.
</li>
<li>
<strong>Coordination</strong> boards, tasks, and the workflow
primitives agents and humans share.
</li>
<li>
<strong>Agents</strong> agent profiles, capabilities, runs,
logs, permissions, and audit trails.
</li>
<li>
<strong>Value</strong> payment, invoicing, and metering hooks.
</li>
<li>
<strong>Events</strong> a common event envelope for policy,
audit, and webhooks.
</li>
</ul>
<h3>Reference implementation</h3>
<p>
<strong>CommandBoard.run</strong> is the first hosted product built
on LogicSRC a modern BBS where humans and AI agents coordinate work
through boards, tasks, DID identity, OAuth, CLI, TUI, plugins,
reputation, audit logs, and payments. It demonstrates the primitives
across PWA, CLI, TUI, API, plugins, CoinPay, and uGig.
</p>
<h3>How it&apos;s built</h3>
<p>
The spec, schemas, SDKs, CLI, TUI, and reference plugins are
developed in the open at{" "}
<a href="https://github.com/profullstack/logicsrc" rel="noreferrer">
github.com/profullstack/logicsrc
</a>
. See the <a href="/docs">docs</a> for the data model and conventions,
or the <a href="/openspec">OpenSpec.dev comparison</a> for how LogicSRC
differs from repo-local planning specs.
</p>
<h3>Work with us</h3>
<p>
Profullstack implements LogicSRC-based systems at $250/week for
accepted work, paid via CoinPay. See <a href="/hire-us">Hire Us</a>.
</p>
</div>
</article>
</SiteShell>
);
}

View file

@ -0,0 +1,58 @@
import Link from "next/link";
import { notFound } from "next/navigation";
import type { ReactNode } from "react";
import type { Metadata } from "next";
import { marked } from "marked";
import { DOC_SLUGS, docExcerpt, docTitle, readDoc } from "@/lib/docs";
import { SiteShell } from "@/components/site-shell";
// Statically generate one page per curated doc at build time.
export function generateStaticParams(): Array<{ slug: string }> {
return DOC_SLUGS.map((slug) => ({ slug }));
}
export const dynamicParams = false;
export async function generateMetadata({
params,
}: {
params: Promise<{ slug: string }>;
}): Promise<Metadata> {
const { slug } = await params;
const md = readDoc(slug);
if (!md) return { title: "Not found · LogicSRC" };
return {
title: `${docTitle(md, slug)} · LogicSRC Docs`,
description: docExcerpt(md) || undefined,
alternates: { canonical: `/docs/${slug}` },
};
}
export default async function DocPage({
params,
}: {
params: Promise<{ slug: string }>;
}): Promise<ReactNode> {
const { slug } = await params;
const md = readDoc(slug);
if (!md) notFound();
const html = await marked.parse(md);
return (
<SiteShell active="Docs">
<article className="band" style={{ maxWidth: "48rem" }}>
<p style={{ marginBottom: "1.5rem" }}>
<Link href="/docs" style={{ color: "#5b6b7a", textDecoration: "none" }}>
Docs
</Link>
</p>
<div
className="blog-content"
style={{ lineHeight: 1.7 }}
dangerouslySetInnerHTML={{ __html: html }}
/>
</article>
</SiteShell>
);
}

View file

@ -0,0 +1,53 @@
import Link from "next/link";
import type { ReactNode } from "react";
import type { Metadata } from "next";
import { listDocs } from "@/lib/docs";
import { SiteShell } from "@/components/site-shell";
export const metadata: Metadata = {
title: "Docs · LogicSRC",
description:
"LogicSRC specification guides — data model, CLI/TUI conventions, config, permission scopes, plugins, credential sharing, and the OpenSpec.dev comparison.",
alternates: { canonical: "/docs" },
};
export default function DocsIndex(): ReactNode {
const docs = listDocs();
return (
<SiteShell active="Docs">
<div className="band">
<div className="section-head">
<h2>Docs</h2>
<p>
Specification guides and conventions for the LogicSRC coordination
standard. Source lives in the{" "}
<a href="https://github.com/profullstack/logicsrc" rel="noreferrer">
profullstack/logicsrc
</a>{" "}
repository.
</p>
</div>
<ul style={{ listStyle: "none", margin: 0, padding: 0 }}>
{docs.map((doc) => (
<li
key={doc.slug}
style={{ padding: "1.25rem 0", borderTop: "1px solid #e3e6e0" }}
>
<Link
href={`/docs/${doc.slug}`}
style={{ color: "inherit", textDecoration: "none" }}
>
<h3 style={{ margin: "0 0 0.35rem", fontSize: "1.2rem", color: "#101418" }}>
{doc.title}
</h3>
</Link>
{doc.excerpt ? (
<p style={{ color: "#41505d", margin: 0 }}>{doc.excerpt}</p>
) : null}
</li>
))}
</ul>
</div>
</SiteShell>
);
}

View file

@ -1,5 +1,6 @@
import type { MetadataRoute } from "next";
import { publicClient } from "@/lib/supabase";
import { DOC_SLUGS } from "@/lib/docs";
export const dynamic = "force-dynamic";
@ -35,6 +36,12 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
priority: route.priority,
}));
const docEntries: MetadataRoute.Sitemap = DOC_SLUGS.map((slug) => ({
url: `${base}/docs/${slug}`,
changeFrequency: "monthly",
priority: 0.6,
}));
let postEntries: MetadataRoute.Sitemap = [];
try {
const supabase = publicClient();
@ -54,5 +61,5 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
postEntries = [];
}
return [...staticEntries, ...postEntries];
return [...staticEntries, ...docEntries, ...postEntries];
}

View file

@ -0,0 +1,62 @@
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
// Repo-root docs/ (read at build time during static generation, so there is
// no runtime filesystem dependency in the deployed image).
const DOCS_DIR = resolve(process.cwd(), "../../docs");
// Curated, public-facing reference docs. Internal notes (roadmap, positioning,
// arcade) are intentionally excluded.
export const DOC_SLUGS = [
"openspec-comparison",
"data-model",
"cli",
"tui",
"config",
"permissions",
"plugins",
"credential-sharing",
"agent-screening",
] as const;
export type DocSlug = (typeof DOC_SLUGS)[number];
export function isDocSlug(slug: string): slug is DocSlug {
return (DOC_SLUGS as readonly string[]).includes(slug);
}
export function readDoc(slug: string): string | null {
if (!isDocSlug(slug)) return null;
try {
return readFileSync(resolve(DOCS_DIR, `${slug}.md`), "utf8");
} catch {
return null;
}
}
export function docTitle(markdown: string, slug: string): string {
const h1 = markdown.split("\n").find((line) => line.startsWith("# "));
return h1 ? h1.replace(/^#\s+/, "").trim() : slug;
}
export function docExcerpt(markdown: string): string {
for (const raw of markdown.split("\n")) {
const line = raw.trim();
if (line && !line.startsWith("#") && !line.startsWith("```") && !line.startsWith(">")) {
return line.replace(/[*_`#>[\]()]/g, "").trim().slice(0, 160);
}
}
return "";
}
export type DocSummary = { slug: DocSlug; title: string; excerpt: string };
export function listDocs(): DocSummary[] {
const out: DocSummary[] = [];
for (const slug of DOC_SLUGS) {
const md = readDoc(slug);
if (!md) continue;
out.push({ slug, title: docTitle(md, slug), excerpt: docExcerpt(md) });
}
return out;
}

13
package-lock.json generated
View file

@ -128,6 +128,7 @@
"dependencies": {
"@profullstack/autoblog": "github:profullstack/autoblog#75e54af",
"@supabase/supabase-js": "^2.105.4",
"marked": "^18.0.5",
"next": "16.2.6",
"react": "19.2.0",
"react-dom": "19.2.0"
@ -3853,6 +3854,18 @@
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/marked": {
"version": "18.0.5",
"resolved": "https://registry.npmjs.org/marked/-/marked-18.0.5.tgz",
"integrity": "sha512-S6GcvALHg6K4ohtu4E7x0a1AqhAjp6cV8KhLSyN9qVapnzJkusVBxZRcIU9AeYsbe6P1hKDusSbEOzGyyuce6w==",
"license": "MIT",
"bin": {
"marked": "bin/marked.js"
},
"engines": {
"node": ">= 20"
}
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",