Skip to content

feat: add llms.txt and LLM-friendly markdown docs generation#497

Open
takaebato wants to merge 2 commits intoapache:masterfrom
takaebato:add-llms-txt
Open

feat: add llms.txt and LLM-friendly markdown docs generation#497
takaebato wants to merge 2 commits intoapache:masterfrom
takaebato:add-llms-txt

Conversation

@takaebato
Copy link

@takaebato takaebato commented Mar 1, 2026

Summary

Add llms.txt and LLM-friendly markdown documentation generation to the ECharts doc build pipeline. Since the current SPA-based docs are difficult for AI agents to access via web fetch, this provides static Markdown alternatives.

  • Add build/build-llms.js that mechanically converts documents/*-parts/*.json to llms-documents/*-parts/*.md by converting HTML descriptions to Markdown via turndown, with type/default info extracted from full schema JSONs (option.json, api.json, etc.)
  • Integrate into the existing build pipeline via build/build-doc.js (runs after main doc build)
  • Generate llms.txt index file per language (en/zh) listing all available documentation
  • Add turndown and turndown-plugin-gfm as dependencies

Output structure

  en/
  ├── llms.txt
  └── llms-documents/
      ├── option-parts/     (55 files)
      ├── option-gl-parts/  (18 files)
      ├── api-parts/        (5 files)
      └── tutorial-parts/   (1 file)
  zh/ (same structure)

Output examples

en/llms.txt
# Apache ECharts Documentation

> Apache ECharts is a free, powerful charting and visualization library offering easy ways to add intuitive, interactive, and highly customizable charts to your commercial products.

## API

- [api.action](llms-documents/api-parts/api.action.md)
- [api.echarts](llms-documents/api-parts/api.echarts.md)
- [api.echartsInstance](llms-documents/api-parts/api.echartsInstance.md)
- [api.events](llms-documents/api-parts/api.events.md)
- [api](llms-documents/api-parts/api.md)

## Option GL

- [option-gl.geo3D](llms-documents/option-gl-parts/option-gl.geo3D.md)
- [option-gl.globe](llms-documents/option-gl-parts/option-gl.globe.md)
- [option-gl.grid3D](llms-documents/option-gl-parts/option-gl.grid3D.md)
- [option-gl.mapbox3D](llms-documents/option-gl-parts/option-gl.mapbox3D.md)
- [option-gl](llms-documents/option-gl-parts/option-gl.md)
- [option-gl.series-bar3D](llms-documents/option-gl-parts/option-gl.series-bar3D.md)
- [option-gl.series-flowGL](llms-documents/option-gl-parts/option-gl.series-flowGL.md)
- [option-gl.series-graphGL](llms-documents/option-gl-parts/option-gl.series-graphGL.md)
- [option-gl.series-line3D](llms-documents/option-gl-parts/option-gl.series-line3D.md)
- [option-gl.series-lines3D](llms-documents/option-gl-parts/option-gl.series-lines3D.md)
- [option-gl.series-map3D](llms-documents/option-gl-parts/option-gl.series-map3D.md)
- [option-gl.series-polygons3D](llms-documents/option-gl-parts/option-gl.series-polygons3D.md)
- [option-gl.series-scatter3D](llms-documents/option-gl-parts/option-gl.series-scatter3D.md)
- [option-gl.series-scatterGL](llms-documents/option-gl-parts/option-gl.series-scatterGL.md)
- [option-gl.series-surface](llms-documents/option-gl-parts/option-gl.series-surface.md)
- [option-gl.xAxis3D](llms-documents/option-gl-parts/option-gl.xAxis3D.md)
- [option-gl.yAxis3D](llms-documents/option-gl-parts/option-gl.yAxis3D.md)
- [option-gl.zAxis3D](llms-documents/option-gl-parts/option-gl.zAxis3D.md)

## Option

- [option.angleAxis](llms-documents/option-parts/option.angleAxis.md)
- [option.aria](llms-documents/option-parts/option.aria.md)
- [option.axisPointer](llms-documents/option-parts/option.axisPointer.md)
- [option.brush](llms-documents/option-parts/option.brush.md)
- [option.calendar](llms-documents/option-parts/option.calendar.md)
- [option.dataset](llms-documents/option-parts/option.dataset.md)
- [option.dataZoom-inside](llms-documents/option-parts/option.dataZoom-inside.md)
- [option.dataZoom-slider](llms-documents/option-parts/option.dataZoom-slider.md)
- [option.geo](llms-documents/option-parts/option.geo.md)
- [option.graphic](llms-documents/option-parts/option.graphic.md)
- [option.grid](llms-documents/option-parts/option.grid.md)
- [option.legend](llms-documents/option-parts/option.legend.md)
- [option.matrix](llms-documents/option-parts/option.matrix.md)
- [option](llms-documents/option-parts/option.md)
- [option.media](llms-documents/option-parts/option.media.md)
- [option.parallel](llms-documents/option-parts/option.parallel.md)
- [option.parallelAxis](llms-documents/option-parts/option.parallelAxis.md)
- [option.polar](llms-documents/option-parts/option.polar.md)
- [option.radar](llms-documents/option-parts/option.radar.md)
- [option.radiusAxis](llms-documents/option-parts/option.radiusAxis.md)
- [option.series-bar](llms-documents/option-parts/option.series-bar.md)
- [option.series-boxplot](llms-documents/option-parts/option.series-boxplot.md)
- [option.series-candlestick](llms-documents/option-parts/option.series-candlestick.md)
- [option.series-chord](llms-documents/option-parts/option.series-chord.md)
- [option.series-custom](llms-documents/option-parts/option.series-custom.md)
- [option.series-effectScatter](llms-documents/option-parts/option.series-effectScatter.md)
- [option.series-funnel](llms-documents/option-parts/option.series-funnel.md)
- [option.series-gauge](llms-documents/option-parts/option.series-gauge.md)
- [option.series-graph](llms-documents/option-parts/option.series-graph.md)
- [option.series-heatmap](llms-documents/option-parts/option.series-heatmap.md)
- [option.series-line](llms-documents/option-parts/option.series-line.md)
- [option.series-lines](llms-documents/option-parts/option.series-lines.md)
- [option.series-map](llms-documents/option-parts/option.series-map.md)
- [option.series-parallel](llms-documents/option-parts/option.series-parallel.md)
- [option.series-pictorialBar](llms-documents/option-parts/option.series-pictorialBar.md)
- [option.series-pie](llms-documents/option-parts/option.series-pie.md)
- [option.series-radar](llms-documents/option-parts/option.series-radar.md)
- [option.series-sankey](llms-documents/option-parts/option.series-sankey.md)
- [option.series-scatter](llms-documents/option-parts/option.series-scatter.md)
- [option.series-sunburst](llms-documents/option-parts/option.series-sunburst.md)
- [option.series-themeRiver](llms-documents/option-parts/option.series-themeRiver.md)
- [option.series-tree](llms-documents/option-parts/option.series-tree.md)
- [option.series-treemap](llms-documents/option-parts/option.series-treemap.md)
- [option.singleAxis](llms-documents/option-parts/option.singleAxis.md)
- [option.stateAnimation](llms-documents/option-parts/option.stateAnimation.md)
- [option.textStyle](llms-documents/option-parts/option.textStyle.md)
- [option.thumbnail](llms-documents/option-parts/option.thumbnail.md)
- [option.timeline](llms-documents/option-parts/option.timeline.md)
- [option.title](llms-documents/option-parts/option.title.md)
- [option.toolbox](llms-documents/option-parts/option.toolbox.md)
- [option.tooltip](llms-documents/option-parts/option.tooltip.md)
- [option.visualMap-continuous](llms-documents/option-parts/option.visualMap-continuous.md)
- [option.visualMap-piecewise](llms-documents/option-parts/option.visualMap-piecewise.md)
- [option.xAxis](llms-documents/option-parts/option.xAxis.md)
- [option.yAxis](llms-documents/option-parts/option.yAxis.md)

## Tutorial

- [tutorial](llms-documents/tutorial-parts/tutorial.md)

llms-documents/option-parts/option.title.md (excerpt)
# option.title

## id
- **Type**: `string`

Component ID, not specified by default. If specified, it can be used to refer the component in option or API.

## show
- **Type**: `boolean`
- **Default**: `true`

Set this to `false` to prevent the title from showing

## text
- **Type**: `string`
- **Default**: `''`

The main title text, supporting for `\n` for newlines.

\[WARNING\]: When enabling [toolbox.feature.saveAsImage](option.toolbox.md#feature.saveAsImage), and [toolbox.feature.saveAsImage.name](option.toolbox.md#feature.saveAsImage.name) is not provided, it has historically been using `title[0].text` instead. This usage is not recommended -- [toolbox.feature.saveAsImage.name](option.toolbox.md#feature.saveAsImage.name) should always be specified explicitly; otherwise, **correctness** and **security risks** for a filename have to be considered in this `title.text` option. See document ["Security Guidelines"](http://localhost/echarts-website/handbook/en/best-practices/security) for recommendations on safe usage.

## link
- **Type**: `string`
- **Default**: `''`

The hyper link of main title text.

\[WARNING\]: This URL string is accepted directly without any internal sanitization. **Security risks** must be considered if it comes from untrusted sources. See document ["Security Guidelines"](http://localhost/echarts-website/handbook/en/best-practices/security) for recommendations on safe usage.

## target
- **Type**: `string`
- **Default**: `'blank'`

Open the hyper link of main title in specified tab.

**options:**

*   `'self'` opening it in current tab
    
*   `'blank'` opening it in a new tab

### textStyle.color
- **Type**: `Color`
- **Default**: `'#333'`

main title text color.

### textStyle.fontStyle
- **Type**: `string`
- **Default**: `'normal'`

main title font style.

Options are:

*   `'normal'`
*   `'italic'`
*   `'oblique'`

### textStyle.fontWeight
- **Type**: `string|number`
- **Default**: `'bolder'`

main title font thick weight.

Options are:

*   `'normal'`
*   `'bold'`
*   `'bolder'`
*   `'lighter'`
*   100 | 200 | 300 | 400...

### textStyle.fontFamily
- **Type**: `string`
- **Default**: `'sans-serif'`

main title font family.

Can also be 'serif' , 'monospace', ...

### textStyle.fontSize
- **Type**: `number`
- **Default**: `18`

main title font size.

Link resolution

Internal links in HTML (href="#property.path" and href="(option|api|tutorial).html#...") are resolved to relative .md file paths before turndown conversion on a best-effort basis.
Out of ~22,600 total links in the source, ~12,000 internal links are resolved to .md file paths (~99%), ~10,600 external links are preserved as-is, and ~50 links with non-standard formats (e.g. missing # prefix) are left unresolved.

@takaebato takaebato marked this pull request as ready for review March 1, 2026 11:09
@takaebato takaebato marked this pull request as draft March 1, 2026 13:18
@takaebato takaebato marked this pull request as ready for review March 1, 2026 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant