feat: make shared chat links agent-friendly - #213
Merged
Conversation
Serve /shared/:token with server-rendered share metadata and a no-JS transcript fallback so a shared link is both human-friendly and readable by agents/crawlers that do not execute JavaScript.
yongkangc
enabled auto-merge (squash)
June 24, 2026 02:49
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A shared chat link (
/shared/:token) served only the SvelteKit SPA shell — the transcript loaded client-side via a follow-up/api/v1/sharedfetch. Agents and crawlers that do not execute JavaScript (most HTTP fetchers, link unfurlers, LLM web-fetch tools) saw an empty shell with a generic<title>Garcon</title>and no conversation content. The agent-readable plain-text endpoint (/shared/llm/:token) existed but was undiscoverable from the human URL.Solution
Serve
/shared/:tokenfrom a dynamic handler that enriches the SPA shell server-side: Open Graph/Twitter metadata, a discoverable<link rel="alternate">to the plain-text transcript, and a no-JS transcript fallback embedded in the HTML. An inline script removes the fallback the instant JS runs, so browser users get the normal hydrated app while JS-less agents read the full transcript straight from the markup. All snapshot content is HTML-escaped.Changes
server/chats/share-page.tswith pure render helpers (injectSharedChatContext,renderStandaloneSharedHtml) that inject share metadata and the escaped transcript fallback (reusingrenderSharedChatText)./shared/:tokenfrom the static route map to a dynamic handler inserver/routes/shares.ts; unknown tokens fall through to the SPA shell with no transcript leak.loadStaticTextfromserver/routes/static.tsto read the SPA shell; remove the static/shared/:tokenroute.Expected Impact
A shared link is now both human-friendly and agent-scrapable: fetching
/shared/:tokenreturns the full conversation in the HTML with no JS engine or second request needed, and link unfurls show the chat title/snippet. Note: branded AI crawler user-agents (GPTBot, ClaudeBot) are still blocked by Cloudflare bot protection at the edge; allowing them through for/shared/*is a separate infra change.