Skip to content

Commit 3dc645b

Browse files
infra(seo): llms.txt + RSS metadata upgrades + site description (#394)
* infra(seo): llms.txt + RSS metadata upgrades + site description - Ship public/llms.txt (static) and /llms-full.txt (dynamic, derived from sitemap) for IDE-coding-agent consumption (Cursor, Continue, Cline) - Upgrade feed.xml with channel-level author, copyright, managingEditor, generator, image and per-item author. Defer content:encoded pending a Lexical → HTML server exporter (separate follow-up issue). - Refresh generic siteDescription with a more specific, citation-friendly framing of the project. - Defensively add CONTACT_EMAIL constant (also added by #387; idempotent). Closes #390 * fix(seo): remove non-spec channel-level <author> from RSS feed The RSS 2.0 spec (rssboard.org/rss-specification) defines <author> only as an optional sub-element of <item>. Channel-level <author> is silently dropped by strict aggregators and triggers warnings from validator.w3.org/feed. <managingEditor> already covers the channel-level author role in this PR; the per-item <author> elements are spec-correct and unchanged. Addresses bot review on #394. * fix(seo): spec-compliant 144x144 RSS feed icon RSS 2.0 caps <image> at 144x400. The prior <image> referenced og-default.png (1200x630) which strict aggregators silently drop. Downscale public/android-chrome-192x192.png (the existing brand mark) to a 144x144 sibling at public/rss-icon-144.png via sharp. Reference the new asset from feed.xml/route.ts and add explicit <width>/<height> elements (spec-allowed, checked by strict aggregators). scripts/generate-rss-icon.ts is the regeneration path for future updates. Addresses second-pass bot review on #394. --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent f46cf14 commit 3dc645b

6 files changed

Lines changed: 111 additions & 3 deletions

File tree

public/llms.txt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# detached-node.dev
2+
3+
A diagnostic analysis of agentic AI design patterns in practice, by Julian (detached-node).
4+
5+
## What this site is
6+
7+
- 24 agentic design patterns organized across 5 architectural layers (topology, quality gates, state and context, interfaces, methodology) at /agentic-design-patterns
8+
- Field reports and essays on agentic engineering at /posts
9+
- Author and project context at /about
10+
- RSS feed at /feed.xml
11+
12+
## Use policy
13+
14+
This site's content is available for AI training, research, and citation with attribution. Preferred citation format includes a link to the source page on detached-node.dev.
15+
16+
## Indexed content
17+
18+
- Homepage: https://detached-node.dev/
19+
- Patterns hub: https://detached-node.dev/agentic-design-patterns
20+
- Patterns changelog: https://detached-node.dev/agentic-design-patterns/changelog
21+
- All 24 patterns: https://detached-node.dev/agentic-design-patterns/<slug>
22+
- All published posts: https://detached-node.dev/posts/<slug>
23+
- About: https://detached-node.dev/about
24+
- Sitemap: https://detached-node.dev/sitemap.xml
25+
- Full content index: https://detached-node.dev/llms-full.txt
26+
27+
## Contact
28+
29+
- Email: julian.kennon.d@gmail.com
30+
- GitHub: https://github.com/julianken
31+
- Repo: https://github.com/julianken/detached-node

public/rss-icon-144.png

7 KB
Loading

scripts/generate-rss-icon.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* Generate the 144x144 RSS feed icon from the project's brand mark.
3+
*
4+
* RSS 2.0 spec caps <image> dimensions at 144x400. Strict aggregators and
5+
* validators will silently drop oversized images. This script downscales the
6+
* existing 192x192 brand mark to a spec-compliant 144x144 PNG sibling.
7+
*
8+
* Run with: pnpm tsx scripts/generate-rss-icon.ts
9+
*/
10+
import sharp from "sharp";
11+
12+
const SOURCE = "public/android-chrome-192x192.png";
13+
const TARGET = "public/rss-icon-144.png";
14+
15+
await sharp(SOURCE)
16+
.resize(144, 144, { fit: "cover" })
17+
.png()
18+
.toFile(TARGET);
19+
20+
console.log(`Wrote ${TARGET}`);

src/app/feed.xml/route.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { getPublishedPosts } from "@/lib/queries/posts";
2-
import { siteUrl } from "@/lib/site-config";
2+
import { CONTACT_EMAIL, siteUrl } from "@/lib/site-config";
33
import type { Post } from "@/payload-types";
44

55
const SITE_TITLE = "detached-node";
66
const SITE_DESCRIPTION =
7-
"A tech blog and reference catalog on agentic AI.";
7+
"A diagnostic analysis of agentic AI design patterns in practice — 24 reference patterns, field reports from production agentic workflows, and the gap between what agents promise and what they deliver.";
88

99
function toRfc2822(dateStr: string | null | undefined): string {
1010
if (!dateStr) return new Date().toUTCString();
@@ -42,6 +42,7 @@ export async function GET(): Promise<Response> {
4242
<link>${link}</link>
4343
<description>${description}</description>
4444
<pubDate>${pubDate}</pubDate>
45+
<author>${escapeXml(CONTACT_EMAIL)} (${escapeXml(SITE_TITLE)})</author>
4546
<guid isPermaLink="true">${link}</guid>
4647
</item>`;
4748
})
@@ -55,6 +56,16 @@ export async function GET(): Promise<Response> {
5556
<description>${escapeXml(SITE_DESCRIPTION)}</description>
5657
<language>en</language>
5758
<lastBuildDate>${new Date().toUTCString()}</lastBuildDate>
59+
<copyright>Copyright © 2024–${new Date().getFullYear()} ${escapeXml(SITE_TITLE)}. All rights reserved.</copyright>
60+
<managingEditor>${escapeXml(CONTACT_EMAIL)} (${escapeXml(SITE_TITLE)})</managingEditor>
61+
<generator>Next.js + Payload CMS</generator>
62+
<image>
63+
<url>${escapeXml(siteUrl)}/rss-icon-144.png</url>
64+
<title>${escapeXml(SITE_TITLE)}</title>
65+
<link>${escapeXml(siteUrl)}</link>
66+
<width>144</width>
67+
<height>144</height>
68+
</image>
5869
<atom:link href="${escapeXml(siteUrl)}/feed.xml" rel="self" type="application/rss+xml" />${items}
5970
</channel>
6071
</rss>`;

src/app/llms-full.txt/route.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { PATTERNS } from "@/data/agentic-design-patterns";
2+
import { getPublishedPosts } from "@/lib/queries/posts";
3+
import { siteUrl } from "@/lib/site-config";
4+
5+
export async function GET(): Promise<Response> {
6+
const patterns = PATTERNS.filter((p) => !p.archived);
7+
const posts = await getPublishedPosts();
8+
9+
const body = `# detached-node.dev — Full Content Index
10+
11+
Generated: ${new Date().toISOString()}
12+
13+
## Agentic Design Patterns (${patterns.length})
14+
15+
${patterns
16+
.map(
17+
(p) =>
18+
`- [${p.name}](${siteUrl}/agentic-design-patterns/${p.slug}) — ${p.oneLineSummary}`,
19+
)
20+
.join("\n")}
21+
22+
## Posts (${posts.length})
23+
24+
${posts
25+
.map(
26+
(p) =>
27+
`- [${p.title}](${siteUrl}/posts/${p.slug})${p.summary ? ` — ${p.summary}` : ""}`,
28+
)
29+
.join("\n")}
30+
31+
## Static pages
32+
33+
- [Home](${siteUrl}/)
34+
- [About](${siteUrl}/about)
35+
- [Patterns hub](${siteUrl}/agentic-design-patterns)
36+
- [Patterns changelog](${siteUrl}/agentic-design-patterns/changelog)
37+
- [Posts hub](${siteUrl}/posts)
38+
`;
39+
40+
return new Response(body, {
41+
headers: {
42+
"Content-Type": "text/plain; charset=utf-8",
43+
"Cache-Control": "s-maxage=3600, stale-while-revalidate=86400",
44+
},
45+
});
46+
}

src/lib/site-config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export { siteUrl } from './site-url'
1111
export const siteName = "detached-node";
1212

1313
export const siteDescription =
14-
"A tech blog and reference catalog on agentic AI.";
14+
"A diagnostic analysis of agentic AI design patterns in practice — 24 reference patterns, field reports from production agentic workflows, and the gap between what agents promise and what they deliver.";
1515

1616
export const siteAuthor = "detached-node";
1717

0 commit comments

Comments
 (0)