CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history
seo.ts
Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.
| 5618f9a | 1 | /** |
| a0071d7 | 2 | * SEO + agent-discovery routes: robots.txt, sitemap.xml, llms.txt. |
| 5618f9a | 3 | * |
| 4 | * robots.txt — allow crawlers on public surfaces, disallow admin/settings | |
| 5 | * and API write paths. | |
| 6 | * sitemap.xml — lists the stable public URLs (landing, explore, status, | |
| 7 | * marketplace, graphql explorer, shortcuts, terms). Public repo URLs are | |
| 8 | * not enumerated here — those live behind /explore which crawlers follow. | |
| a0071d7 | 9 | * llms.txt — the llmstxt.org convention: a curated map of the platform for |
| 10 | * AI agents, pointing at the MCP endpoint, API docs, and OAuth discovery so | |
| 11 | * any LLM/agent can orient itself and connect. | |
| 5618f9a | 12 | */ |
| 13 | ||
| 14 | import { Hono } from "hono"; | |
| a0071d7 | 15 | import { config } from "../lib/config"; |
| 5618f9a | 16 | |
| 17 | const seo = new Hono(); | |
| 18 | ||
| 19 | const ROBOTS = `User-agent: * | |
| 20 | Allow: / | |
| 21 | Disallow: /admin | |
| 22 | Disallow: /settings | |
| 23 | Disallow: /api/ | |
| 24 | Disallow: /login | |
| 25 | Disallow: /register | |
| 26 | Disallow: /logout | |
| 27 | Disallow: /oauth/ | |
| 28 | Disallow: /*/settings | |
| 29 | Disallow: /*.git/ | |
| 30 | ||
| 31 | Sitemap: /sitemap.xml | |
| 32 | `; | |
| a0071d7 | 33 | // Note: /llms.txt is intentionally allowed (agent-facing map, public). |
| 5618f9a | 34 | |
| 35 | seo.get("/robots.txt", (c) => { | |
| 36 | c.header("Content-Type", "text/plain; charset=utf-8"); | |
| 37 | c.header("Cache-Control", "public, max-age=3600"); | |
| 38 | return c.body(ROBOTS); | |
| 39 | }); | |
| 40 | ||
| a0071d7 | 41 | /** |
| 42 | * llms.txt (llmstxt.org) — a curated, agent-facing map of the platform. | |
| 43 | * Served at both /llms.txt and /.well-known/llms.txt. Built from the live | |
| 44 | * base URL so links are always absolute + correct for this deployment. | |
| 45 | */ | |
| 46 | function buildLlmsTxt(): string { | |
| 47 | const b = config.appBaseUrl; | |
| 48 | return `# Gluecron | |
| 49 | ||
| 50 | > AI-native git hosting. Git over HTTPS + SSH, issues, pull requests with AI | |
| 51 | > code review and gated auto-merge, CI workflows, package + container | |
| 52 | > registries, and a Model Context Protocol (MCP) server so any LLM/agent can | |
| 53 | > read and drive repositories directly. Self-hosted-friendly and MCP-native. | |
| 54 | ||
| 55 | ## For AI agents | |
| 56 | ||
| 57 | - [MCP server](${b}/mcp): Model Context Protocol endpoint (JSON-RPC 2.0 over HTTP). GET for discovery, POST to call tools. Read tools work anonymously on public repos; write tools require an OAuth/PAT bearer token. | |
| 58 | - [OAuth authorization server metadata](${b}/.well-known/oauth-authorization-server): RFC 8414 — how to authenticate (authorize/token endpoints, PKCE S256, scopes). | |
| 59 | - [OAuth protected resource metadata](${b}/.well-known/oauth-protected-resource): RFC 9728 — which authorization server guards the MCP resource. | |
| 60 | ||
| 61 | ## API | |
| 62 | ||
| 63 | - [REST + GraphQL API docs](${b}/api/docs): endpoints, authentication, and scopes for programmatic access. | |
| 64 | - [GraphQL explorer](${b}/api/graphql): read queries over repos, users, issues, and search. | |
| 65 | ||
| 66 | ## Get started | |
| 67 | ||
| 68 | - [Sign up](${b}/register): create an account. | |
| 69 | - [Explore public repos](${b}/explore): browse what's hosted here. | |
| 70 | - [Import from GitHub](${b}/import): mirror an existing repo in one step. | |
| 71 | - [Install script](${b}/install): one-line setup for the CLI + Claude Desktop MCP config. | |
| 72 | ||
| 73 | ## Conventions | |
| 74 | ||
| 75 | - Personal access tokens are prefixed \`glc_\`; OAuth access tokens \`glct_\`. Pass either as \`Authorization: Bearer <token>\`. | |
| 76 | - Repos are addressed as \`${b}/<owner>/<repo>\`; clone over HTTPS at \`${b}/<owner>/<repo>.git\`. | |
| 77 | `; | |
| 78 | } | |
| 79 | ||
| 80 | seo.get("/llms.txt", (c) => { | |
| 81 | c.header("Content-Type", "text/plain; charset=utf-8"); | |
| 82 | c.header("Cache-Control", "public, max-age=3600"); | |
| 83 | return c.body(buildLlmsTxt()); | |
| 84 | }); | |
| 85 | ||
| 86 | seo.get("/.well-known/llms.txt", (c) => { | |
| 87 | c.header("Content-Type", "text/plain; charset=utf-8"); | |
| 88 | c.header("Cache-Control", "public, max-age=3600"); | |
| 89 | return c.body(buildLlmsTxt()); | |
| 90 | }); | |
| 91 | ||
| 5618f9a | 92 | const STATIC_PATHS = [ |
| 93 | "/", | |
| 94 | "/explore", | |
| 95 | "/marketplace", | |
| 96 | "/status", | |
| 80bed05 | 97 | "/help", |
| 5618f9a | 98 | "/shortcuts", |
| 99 | "/api/graphql", | |
| 100 | "/terms", | |
| 101 | "/privacy", | |
| 102 | "/acceptable-use", | |
| 103 | ]; | |
| 104 | ||
| 105 | seo.get("/sitemap.xml", (c) => { | |
| 106 | const origin = new URL(c.req.url).origin; | |
| 107 | const lastmod = new Date().toISOString().slice(0, 10); | |
| 108 | const urls = STATIC_PATHS.map( | |
| 109 | (p) => | |
| 110 | `<url><loc>${origin}${p}</loc><lastmod>${lastmod}</lastmod></url>` | |
| 111 | ).join("\n "); | |
| 112 | const body = `<?xml version="1.0" encoding="UTF-8"?> | |
| 113 | <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> | |
| 114 | ${urls} | |
| 115 | </urlset> | |
| 116 | `; | |
| 117 | c.header("Content-Type", "application/xml; charset=utf-8"); | |
| 118 | c.header("Cache-Control", "public, max-age=3600"); | |
| 119 | return c.body(body); | |
| 120 | }); | |
| 121 | ||
| 122 | export default seo; |