Files
zeekay 0910c3cc68 agents: a start page for AI agents, and the site describes itself to them
/agents is where an agent lands: get a key (device flow or HTTP sign-up),
the free tier as /v1/billing/plans states it, a first call, the MCP server
for Claude Code, Codex, Cursor and Zed, Kai and its harness, a campaign
draft, and how an owner pays and bounds spend. The Agents SDK page moves
to /agents/sdk.

The prompt an agent pastes is lib/agents.ts, drawn on /agents and written
into llms.txt, which now keeps every hand-written section. robots.txt names
the AI crawlers; JSON-LD carries the positioning, 2014, the founders as
/about names them, and drops a SearchAction /search never answered;
/.well-known/api-catalog points at the OpenAPI document. /about gains a
track-record band, each line beside its source.

Claude-Session: https://claude.ai/code/session_017vrVus6PPBgP5YRzKV1iqW
2026-10-26 11:45:15 -07:00

50 lines
1.7 KiB
TypeScript

import type { MetadataRoute } from 'next'
import { DISALLOW } from '@/lib/publish'
// Static export: emits /robots.txt at build.
export const dynamic = 'force-static'
/**
* The AI crawlers, named so that reading this file answers whether each one is
* welcome rather than leaving it to inference from `*`. A crawler that finds a
* group with its own name obeys that group alone (RFC 9309 §2.2.1), so each
* named group carries the same Disallow lines as `*`; written once, here.
*
* Bytespider is not named: whether it is welcome is the owner's decision, and
* until it is made it reads the `*` group like any other crawler.
*/
const AGENTS = [
'GPTBot',
'OAI-SearchBot',
'ChatGPT-User',
'ClaudeBot',
'Claude-User',
'Claude-SearchBot',
'anthropic-ai',
'PerplexityBot',
'Perplexity-User',
'Google-Extended',
'CCBot',
'Applebot-Extended',
]
export default function robots(): MetadataRoute.Robots {
return {
// DISALLOW, not the route prefixes: lib/publish turns one prefix into the
// pair of RFC 9309 patterns that mean it, and this surface cannot spell a
// bare prefix. `Disallow: /auth` reads as a string and takes /authz with
// it; `/auth$` + `/auth/` is the same segment written in the crawler's own
// grammar.
//
// Private routes only. An unapproved route is deliberately fetchable, so
// that the `noindex` it carries is read — a Disallow here would be the one
// thing that prevents it.
rules: [
{ userAgent: '*', allow: '/', disallow: [...DISALLOW] },
{ userAgent: AGENTS, allow: '/', disallow: [...DISALLOW] },
],
sitemap: 'https://hanzo.ai/sitemap.xml',
host: 'https://hanzo.ai',
}
}