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
12 changes: 12 additions & 0 deletions app/AGENTS.md/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// ABOUTME: Serves the /AGENTS.md agent guide as markdown.
// ABOUTME: Content is the shared AGENT_INSTRUCTIONS block with the llms.txt index pointer.
import { AGENT_INSTRUCTIONS } from '@/lib/agent-instructions';
import { LLMS_INDEX_POINTER } from '@/lib/get-llm-text';

export const revalidate = false;

export async function GET() {
return new Response(`${LLMS_INDEX_POINTER}\n\n${AGENT_INSTRUCTIONS}`, {
headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
});
}
4 changes: 2 additions & 2 deletions lib/agent-instructions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// ABOUTME: Quick reference and gotchas prepended to the agent-facing markdown
// ABOUTME: bundles, shared by public/llms.txt generation and the /llms-full.txt route.
// ABOUTME: Quick reference and gotchas served to agents via the /llms.txt index,
// ABOUTME: the /llms-full.txt bundle, and the /AGENTS.md route.

export const AGENT_INSTRUCTIONS = `# Steel Documentation

Expand Down
2 changes: 2 additions & 0 deletions lib/markdown-negotiation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const MARKDOWN_VARY_HEADERS = ['Accept', 'User-Agent'];

const EXCLUDED_EXACT_PATHS = new Set([
'/.well-known/llms.txt',
'/AGENTS',
'/AGENTS.md',
'/favicon.ico',
'/llms-full.txt',
'/llms.txt',
Expand Down
5 changes: 5 additions & 0 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ const config = {
destination: "/llms.txt",
permanent: true, // 301 redirect - tells crawlers this is the canonical location
},
{
source: "/.well-known/agents.md",
destination: "/AGENTS.md",
permanent: true,
},
{
source: "/overview/llms-full.txt",
destination: "/llms-full.txt",
Expand Down
20 changes: 20 additions & 0 deletions tests/e2e/llm-endpoints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,26 @@ describe('.md suffix end-to-end', () => {
expect(body).not.toContain(':::callout');
});

test('serves /AGENTS.md as markdown with install, auth, and the index pointer', async () => {
const response = await fetch(`${BASE_URL}/AGENTS.md`, { headers: BROWSER_HEADERS });
expect(response.status).toBe(200);
expect(response.headers.get('content-type')).toStartWith('text/markdown');
const body = await response.text();
expect(body).toStartWith('> Full docs index: https://docs.steel.dev/llms.txt');
expect(body).toContain('npm install steel-sdk');
expect(body).toContain('STEEL_API_KEY');
});

test('redirects /.well-known/agents.md to /AGENTS.md', async () => {
const response = await fetch(`${BASE_URL}/.well-known/agents.md`, {
headers: BROWSER_HEADERS,
redirect: 'manual',
});
// Next.js renders permanent config redirects as 308.
expect(response.status).toBe(308);
expect(response.headers.get('location')).toBe('/AGENTS.md');
});

test('llms-full.txt does not repeat the index pointer', async () => {
const response = await fetch(`${BASE_URL}/llms-full.txt`, { headers: BROWSER_HEADERS });
expect(response.status).toBe(200);
Expand Down
4 changes: 4 additions & 0 deletions tests/markdown-negotiation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ describe('resolveMarkdownPath', () => {
expect(resolveMarkdownPath('/llms.txt.md')).toBeNull();
});

test('returns null for /AGENTS.md so its route handler owns the request', () => {
expect(resolveMarkdownPath('/AGENTS.md')).toBeNull();
});

test('returns null when the stripped path is under an excluded prefix', () => {
expect(resolveMarkdownPath('/llms.mdx/overview.md')).toBeNull();
expect(resolveMarkdownPath('/api/search.md')).toBeNull();
Expand Down
11 changes: 11 additions & 0 deletions tests/middleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,15 @@ describe('middleware .md suffix handling', () => {
const response = middleware(browserRequest('http://localhost/llms-full.txt.md'));
expect(response.headers.get('x-middleware-rewrite')).toBeNull();
});

test('does not rewrite /AGENTS.md, even for markdown user agents', () => {
const browser = middleware(browserRequest('http://localhost/AGENTS.md'));
expect(browser.headers.get('x-middleware-rewrite')).toBeNull();
const agent = middleware(
new NextRequest('http://localhost/AGENTS.md', {
headers: { 'user-agent': 'claude-code/1.0' },
}),
);
expect(agent.headers.get('x-middleware-rewrite')).toBeNull();
});
});
Loading