2026-05-11 16:40:34 -07:00
import { source } from "@/lib/source" ;
const siteOrigin = "https://ktx.dev" ;
export type LlmDocsPage = {
title : string ;
description? : string ;
url : string ;
markdownUrl : string ;
slug : string [ ] ;
getMarkdown : ( ) = > Promise < string > ;
} ;
export function getLlmDocsPages ( ) : LlmDocsPage [ ] {
return source . getPages ( ) . map ( toLlmDocsPage ) ;
}
export function getLlmDocsPage ( slug : string [ ] | undefined ) {
const page = source . getPage ( slug ) ;
return page ? toLlmDocsPage ( page ) : null ;
}
export async function getPageMarkdown ( page : LlmDocsPage ) {
const description = page . description ? ` \ n \ n> ${ page . description } ` : "" ;
const body = await page . getMarkdown ( ) ;
return normalizeMarkdown ( ` # ${ page . title } ${ description }
Canonical URL : $ { page . url }
Markdown URL : $ { page . markdownUrl }
$ { body }
` );
}
export function buildLlmsTxt() {
const pages = getLlmDocsPages ( ) ;
const byUrl = new Map ( pages . map ( ( page ) = > [ page . url , page ] ) ) ;
const link = ( url : string , label : string , fallbackDescription : string ) = > {
const page = byUrl . get ( url ) ;
const description = page ? . description ? ? fallbackDescription ;
2026-05-11 17:20:11 -07:00
const markdownUrl = page ? . markdownUrl ? ? ` ${ url } .md ` ;
return ` - [ ${ label } ]( ${ markdownUrl } ): ${ description } ` ;
2026-05-11 16:40:34 -07:00
} ;
return ` # KTX
> Agent - native context layer for analytics engineering and database agents .
KTX provides semantic - layer files , warehouse scans , knowledge pages , provenance , and agent - facing tools that help coding agents answer analytics questions without inventing metrics or joins .
2026-05-11 17:20:11 -07:00
# # Agent Entry Points
$ { link ( "/docs/ai-resources" , "AI Resources" , "Machine-readable docs, prompt recipes, and agent setup paths" ) }
$ { link ( "/docs/ai-resources/agent-quickstart" , "Agent Quickstart" , "Task-first route for coding assistants using KTX" ) }
2026-05-11 19:35:46 -07:00
$ { link ( "/docs/ai-resources/markdown-access" , "Markdown Access" , "Fetch KTX docs as llms.txt, llms-full.txt, or per-page Markdown" ) }
$ { link ( "/docs/ai-resources/agent-instructions" , "Agent Instructions" , "Suggested instructions for coding assistants that need to read and cite KTX docs" ) }
2026-05-11 17:20:11 -07:00
2026-05-11 16:40:34 -07:00
# # Start Here
$ { link ( "/docs/getting-started/introduction" , "Introduction" , "What KTX is and who it is for" ) }
$ { link ( "/docs/getting-started/quickstart" , "Quickstart" , "Set up KTX and build your first context" ) }
$ { link ( "/docs/guides/writing-context" , "Writing Context" , "Write semantic sources and knowledge pages" ) }
# # Machine - Readable Documentation
- [ Full documentation ] ( / l l m s - f u l l . t x t ) : A l l d o c s p a g e s i n o n e p l a i n - t e x t m a r k d o w n r e s p o n s e
2026-05-11 17:20:11 -07:00
- [ Markdown access guide ] ( / d o c s / a i - r e s o u r c e s / m a r k d o w n - a c c e s s . m d ) : H o w t o f e t c h l l m s . t x t , l l m s - f u l l . t x t , a n d p e r - p a g e M a r k d o w n
- [ Quickstart markdown ] ( / d o c s / g e t t i n g - s t a r t e d / q u i c k s t a r t . m d ) : H u m a n s e t u p w a l k t h r o u g h
- [ Agent CLI markdown ] ( / d o c s / c l i - r e f e r e n c e / k t x - a g e n t . m d ) : M a c h i n e - r e a d a b l e a g e n t c o m m a n d s
2026-05-11 16:40:34 -07:00
# # CLI Reference
$ { link ( "/docs/cli-reference/ktx-setup" , "ktx setup" , "Interactive project setup" ) }
$ { link ( "/docs/cli-reference/ktx-agent" , "ktx agent" , "Machine-readable commands for coding agents" ) }
$ { link ( "/docs/cli-reference/ktx-sl" , "ktx sl" , "Semantic-layer commands" ) }
$ { link ( "/docs/cli-reference/ktx-wiki" , "ktx wiki" , "Knowledge page commands" ) }
$ { link ( "/docs/cli-reference/ktx-connection" , "ktx connection" , "Connection management commands" ) }
# # Integrations
$ { link ( "/docs/integrations/primary-sources" , "Primary Sources" , "Connect KTX to databases and warehouses" ) }
$ { link ( "/docs/integrations/context-sources" , "Context Sources" , "Ingest dbt, LookML, Metabase, Looker, MetricFlow, and Notion" ) }
2026-05-11 17:20:11 -07:00
# # All Documentation
$ { buildPageIndex ( pages ) }
2026-05-11 16:40:34 -07:00
` ;
}
export async function buildLlmsFullTxt() {
const rendered = await Promise . all ( getLlmDocsPages ( ) . map ( getPageMarkdown ) ) ;
return [ ` # KTX Full Documentation ` , ` Source: ${ siteOrigin } ` , . . . rendered ] . join (
"\n\n---\n\n" ,
) ;
}
function toLlmDocsPage ( page : ReturnType < typeof source.getPages > [ number ] ) {
return {
title : page.data.title ,
description : page.data.description ,
url : page.url ,
markdownUrl : ` ${ page . url } .md ` ,
slug : page.slugs ,
getMarkdown : async ( ) = > normalizeMarkdown ( page . data . content ) ,
} satisfies LlmDocsPage ;
}
function normalizeMarkdown ( markdown : string ) {
2026-05-11 16:42:08 -07:00
return markdown
. trim ( )
. replace ( /^---\n[\s\S]*?\n---\n?/ , "" )
. trim ( )
. replace ( /\n{3,}/g , "\n\n" ) ;
2026-05-11 16:40:34 -07:00
}
2026-05-11 17:20:11 -07:00
function buildPageIndex ( pages : LlmDocsPage [ ] ) {
const grouped = new Map < string , LlmDocsPage [ ] > ( ) ;
for ( const page of pages ) {
const category = page . slug [ 0 ] ? ? "general" ;
grouped . set ( category , [ . . . ( grouped . get ( category ) ? ? [ ] ) , page ] ) ;
}
return [ . . . grouped . entries ( ) ]
. map ( ( [ category , categoryPages ] ) = > {
const links = categoryPages
. map ( ( page ) = > {
const description = page . description ? ` : ${ page . description } ` : "" ;
return ` - [ ${ page . title } ]( ${ page . markdownUrl } ) ${ description } ` ;
} )
. join ( "\n" ) ;
return ` ### ${ formatCategoryName ( category ) }
$ { links } ` ;
} )
. join ( "\n\n" ) ;
}
function formatCategoryName ( category : string ) {
const labels : Record < string , string > = {
"ai-resources" : "AI Resources" ,
"cli-reference" : "CLI Reference" ,
} ;
if ( labels [ category ] ) {
return labels [ category ] ;
}
return category
. split ( "-" )
. map ( ( word ) = > word . charAt ( 0 ) . toUpperCase ( ) + word . slice ( 1 ) )
. join ( " " ) ;
}