Sześć praktycznych ruchów, by serwis obsługiwał zarówno ludzi, jak i agentów AI, z gotową checklistą
Przez ostatnie cztery dni razem z Claude Code przerobiliśmy smarts.md z serwisu dokumentacji smart kontraktów zbudowanego dla ludzi w serwis zbudowany dla agentów AI.
Brzmi jak to samo. Nie jest. Serwis dla ludzi optymalizuje czytelność, wyszukiwanie i czas ładowania. Serwis dla agentów AI musi odpowiadać na inne pytania:
robots.txt zamyka im drzwi?Oto sześć rzeczy, które kazałem Claude zbudować. Każda jest użyteczna samodzielnie i możesz ją przenieść do swojego serwisu osobno.
robots.txtWiększość serwisów dziedziczy robots.txt po jakimś starym szablonie, który domyślnie blokuje każdego nieznanego User-Agenta. Ale po 2025 roku wiele crawlerów AI to nowe User-Agenty — GPTBot, ClaudeBot, PerplexityBot, Applebot-Extended, Google-Extended, CCBot, meta-externalagent i inni. Jeśli chcesz ich wpuścić, musisz jawnie dać Allow.
robots.txt w smarts zaczyna się notatką polityki, a dalej wymienia User-agent + Allow: / dla 12 crawlerów obejmujących OpenAI, Anthropic, Perplexity, Google Gemini, Apple, Common Crawl, Meta i Cohere. Stanowisko jest proste: ten serwis istnieje po to, by czytały go AI.
llms.txt — menu dla LLM-ówllms.txt to konwencja zaproponowana przez llmstxt.org: wrzucasz zwięzły Markdown w korzeniu serwisu, który mówi LLM-owi, czym jest ten serwis, jak go używać i gdzie są kluczowe punkty wejścia. To elevator pitch twojego serwisu.
llms.txt w smarts ma około 60 linii:
/{chain}/{address} vs krótki slug)Kluczowa myśl: LLM-y płacą tokenami za czytanie dokumentacji, więc nie przeglądają całego serwisu. Podaj im destylowany indeks — trafialność wyraźnie rośnie.
.well-known/mcp.json — wczesny zakładProtokół MCP nie znormalizował jeszcze konwencji autowykrywania w stylu /.well-known/openid-configuration. Dziś żaden publiczny klient nie przeszukuje stałej ścieżki well-known.
Ale publikacja manifestu to 30 linii:
def well_known_mcp
response.set_header("Cache-Control", "public, max-age=3600")
response.set_header("Access-Control-Allow-Origin", "*")
render json: {
name: "smarts",
version: "0.1.0",
description: "...",
protocol_version: "2024-11-05",
transports: [{ type: "sse", endpoint: "https://smarts.md/mcp/sse" }],
capabilities: { tools: true, resources: false, prompts: false },
tools: MCP_TOOLS.map { |t| { name: t[:name], description: t[:blurb] } }
}
end
W chwili, gdy konwencja wykrywania się pojawi, nie muszę ruszać ani linii. A poza tym to samodokumentacja dla deweloperów — kto ciekaw mojego MCP, po prostu robi curl smarts.md/.well-known/mcp.json.
Myk: tablica tools wywodzi się ze stałej MCP_TOOLS, jedno źródło prawdy. Istniejący strukturalny test wymusza, żeby każdy app/tools/*_tool.rb pojawiał się w tej stałej, więc manifest darmo dziedziczy gwarancję „żaden nowy tool się nie zgubi".
.md: destylacja przyjazna WebFetch dla każdej stronyMój ulubiony. Narzędzie WebFetch w Claude Code musi samo czyścić i wyciągać treść z dowolnego HTML-a — drogo tokenowo i zawodnie. A co, jeśli od razu podajemy .md?
respond_to w Railsach wspiera to natywnie:
# config/routes.rb
get ":slug(.:format)", to: "contracts#show",
constraints: { slug: ContractSlugs::ROUTE_PATTERN, format: /html|md/ }
https://smarts.md/usdc-eth zwraca HTML; https://smarts.md/usdc-eth.md zwraca 40 linii Markdowna — adres, sieć, klasyfikacja, endpoint MCP, jak odpytać przez agenta AI, linki źródłowe.
# USD Coin on Ethereum
- **Address:** `0xa0b8...`
- **Chain:** Ethereum
- **Classification:** ERC-20 Token
## Query via AI agent
- **MCP endpoint:** `https://smarts.md/mcp/sse`
- **Reference:** `usdc-eth`
- **Sample prompt:** "Tell me the current state of usdc-eth"
Jeden fetch — cała strukturyzowana treść, której chce agent AI, jest w środku, bez potrzeby parsera DOM. Claude zrobił to szybko — jeden controller, dwa szablony .md.erb, (.:format) w routes, gotowe.
To odwrotne wykrywanie: część moich gości używa już Claude Code / Cursor / Windsurf. Lądują na stronie kontraktu, a kolejny odruch brzmi „niech moje AI na to zerknie".
Dlatego każda strona kontraktu renderuje kartę z:
usdc-eth) albo chain/address, z przyciskiem Kopiujmcp.smarts.md (setup w jednej linijce)Między „patrzę na ten kontrakt" a „pytam swoje AI" zostaje jedno kliknięcie tarcia. Karta używa card z DaisyUI i ogólnego Stimulus-controllera copy — 50 linii erb. Test regresji blokuje atrybuty data-copy-text-value, żeby przyszły refactor po cichu nie wkleił użytkownikom złego ciągu znaków do schowka.
OpenGraph, Twitter Card, JSON-LD — tradycyjna warstwa wyszukiwania i kart społecznościowych. Warto, bo crawlery AI też to czytają.
Ciekawy wybór to, jak JSON-LD powinien opisać smart kontrakt. Claude zdecydował się na WebPage opakowujący SoftwareApplication:
{
"@type": "WebPage",
"about": {
"@type": "SoftwareApplication",
"name": "USD Coin",
"applicationCategory": "SmartContract",
"operatingSystem": "Ethereum",
"identifier": "0xa0b8..."
}
}
operatingSystem dostaje nazwę sieci, identifier adres, additionalType klasyfikację (np. „Uniswap V3 Pool"). schema.org nie ma dedykowanego typu SmartContract, ale SoftwareApplication plus te pola wystarcza, by LLM zrozumiał „to jest kontrakt na Ethereum o konkretnym adresie".
Obraz OG to summary_large_image 1200×630; Twitter Card, breadcrumbs, softwareVersion i license dopełniają całość.
Sześć punktów wyżej wyszło z siedmiu PR-ów w cztery dni:
| PR | Pliki | Rozmiar |
|---|---|---|
feat/ai-crawler-discovery |
2 | ~126 loc |
feat/well-known-mcp-manifest |
4 | ~129 loc |
feat/markdown-contract-pages |
6 | ~298 loc |
feat/contract-mcp-card |
3 | ~126 loc |
feat/seo-meta-tags |
8 | ~292 loc |
feat/seo-enrichments |
8 | ~189 loc |
feat/og-card |
— | — |
Każdy to niezależny PR z własnymi testami i komunikatem commita. Ten rytm drobnego cięcia to najcenniejsza rzecz we współpracy z Claude — każdy PR jest na tyle mały, by przejrzeć diff jednym spojrzeniem, ale poukładane razem pokazują, że serwisowi wyrosła kompletna powierzchnia AI.
Jeśli masz serwis treściowy i chcesz, by był AI-przyjazny, rób to w takiej kolejności:
robots.txt jawnie Allow głównych crawlerów AI/llms.txt (destylowane menu).md do głównych stron treści/.well-known/mcp.jsonPierwszych pięciu nie powie ci większość inżynierów SEO — nie ma ich w klasycznym playbooku. Ale z czterech dni danych po mojej stronie krzywa ruchu AI i krzywa ruchu ludzkiego to dwa kompletnie niezależne szeregi. Trzeba obsługiwać oba.