Skip to content

Add llms.txt and llms-all.txt endpoints for LLM-friendly content#474

Open
SohamJuneja wants to merge 15 commits intojenkinsci:masterfrom
SohamJuneja:llms-txt-support
Open

Add llms.txt and llms-all.txt endpoints for LLM-friendly content#474
SohamJuneja wants to merge 15 commits intojenkinsci:masterfrom
SohamJuneja:llms-txt-support

Conversation

@SohamJuneja
Copy link
Copy Markdown
Contributor

Adds dynamically generated LLM-friendly endpoints to the Design Library, following the llms.txt convention:

  • /design-library/llms.txt — markdown index listing all components with links to individual .md pages
  • /design-library/llms-all.txt — all component documentation concatenated into a single file
  • /design-library/{component}.md — per-component markdown (e.g. /design-library/buttons.md)

Content is generated at runtime from the existing UISample extension list, so new components are automatically included with no extra work.

Fixes #473

Testing done

  • Added LlmContentTest.java with 5 integration tests covering all three endpoints, 404 handling, and backwards compatibility
  • Full test suite passes: 195 tests, 0 failures
  • Spotless formatting passes
  • Existing component pages are unaffected (getDynamic is unchanged)

Submitter checklist

  • Make sure you are opening from a topic/feature/bugfix branch (right side) and not your main branch!
  • Ensure that the pull request title represents the desired changelog entry
  • Please describe what you did
  • Link to relevant issues in GitHub or Jira
  • Ensure you have provided tests that demonstrate the feature works or the issue is fixed

@SohamJuneja SohamJuneja requested a review from a team as a code owner April 6, 2026 22:13
* <li>{@code {component}.md} - documentation for a single component</li>
* </ul>
*/
public void doDynamic(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
* <li>{@code {component}.md} - documentation for a single component</li>
* </ul>
*/
public void doDynamic(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
@janfaracik
Copy link
Copy Markdown
Member

Thanks for this.

Liking the llms.txt - seems reasonable. The *.md on the other hand I'm not sure provides much value:

# App bars

> Frames your page and contains your most important actions.

**Category:** Components

It's not showing any content not already available in llms.txt

@janfaracik
Copy link
Copy Markdown
Member

I've added a link on the homepage to this and the IntelilJ plugin as part of your branch:

image

@SohamJuneja
Copy link
Copy Markdown
Contributor Author

Thanks for the feedback and the homepage additions! Removed the per-component .md endpoints as llms.txt and llms-all.txt cover everything needed.

@janfaracik
Copy link
Copy Markdown
Member

It'd be good to get some advice on this @SohamJuneja @timja - should llms.txt still link to the individual pages? And, with the Markdown version removed, should we kill llms-all.txt?

@SohamJuneja
Copy link
Copy Markdown
Contributor Author

I think llms-all.txt is worth keeping though, it's the file that contains the actual code snippets (Jelly/Java) from each component, which is what an LLM needs to generate correct Jenkins UI code. llms.txt alone is just a table of contents. This follows the llms.txt convention of having an index + a full content file. Waiting for your insights too!!

Copy link
Copy Markdown
Member

@timja timja left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I doing something wrong?

llms.txt isn't linking to individual files.
llms-all.txt doesn't have all the content about the design library

This should load all the content from the files and ideally examples into something the llm can use.

I can't find how to load an individual component.

e.g. http://localhost:8080/jenkins/design-library/banner.md returns a 404

llms.txt

# Jenkins Design Library

> A reference library of UI components and patterns for building Jenkins plugin interfaces.

## Components
- App bars: Frames your page and contains your most important actions.
- Banner: Banners are a handy way to display small snippets of text and actions.
- Buttons: Triggers specific actions with a click or tap.
- Cards: Use cards to surface related information and controls to users.
- Checkboxes: Allows users to select one or more items from a list.
- Dialogs: Displays overlay windows for additional information or user input without navigating away.
- Empty States: For when there is no data, no configuration or no plugins installed that support the required feature an empty state can be provided instead.
- File: Enables file upload functionality.
- Inputs: Captures user input through various text or data entry formats.
- Menu: Menus allow you to group similar controls under one roof. They're an effective way to de-clutter your page whilst offering users the actions they need.
- Notifications: Jenkins can display in-page notifications with a simple-to-use JavaScript API.
- Progress: Indicates the completion status of a task or operation.
- Radios: Allows users to select a single option from a group.
- Repeatable list: Displays lists with varying content types within the same container.
- Select: Provides a dropdown for choosing one option from a predefined list.
- Symbols: Jenkins Symbols are an extensive and consistent collection of icons for use in Jenkins and plugins.
- Table: Displays structured data in rows and columns, with support for sorting and badges.
- Toggle switch: Enables users to switch between two states, such as on or off.
- Tooltips: Offers brief, contextual information when hovering over an element.

## Patterns
- Colors: Defines the palette for consistent use of color.
- JavaScript Proxy: Export arbitrary server-side Java object to JavaScript and invoke their methods from JavaScript.
- Layouts: Predefined layout structures and patterns to organize page content.
- Links: Creates navigational connections to internal or external destinations.
- Localization: Ensures texts can be displayed in the user's language.
- Spacing: Defines consistent padding, margins, and gaps between elements.
- Stylesheets: Provides reusable stylesheet principles and standards for maintaining consistency.
- Validation: Ensures user inputs meet specified criteria or rules before submission.

llms-all.txt

# Jenkins Design Library

> A reference library of UI components and patterns for building Jenkins plugin interfaces.

## Components

# App bars

> Frames your page and contains your most important actions.

**Category:** Components


---

# Banner

> Banners are a handy way to display small snippets of text and actions.

**Category:** Components


---

# Buttons

> Triggers specific actions with a click or tap.

**Category:** Components


---

# Cards

> Use cards to surface related information and controls to users.

**Category:** Components
**Since:** 2.479.1


---

# Checkboxes

> Allows users to select one or more items from a list.

**Category:** Components


---

# Dialogs

> Displays overlay windows for additional information or user input without navigating away.

**Category:** Components
**Since:** 2.426.1


---

# Empty States

> For when there is no data, no configuration or no plugins installed that support the required feature an empty state can be provided instead.

**Category:** Components


---

# File

> Enables file upload functionality.

**Category:** Components


---

# Inputs

> Captures user input through various text or data entry formats.

**Category:** Components


---

# Menu

> Menus allow you to group similar controls under one roof. They're an effective way to de-clutter your page whilst offering users the actions they need.

**Category:** Components
**Since:** 2.452.1


---

# Notifications

> Jenkins can display in-page notifications with a simple-to-use JavaScript API.

**Category:** Components


---

# Progress

> Indicates the completion status of a task or operation.

**Category:** Components


---

# Radios

> Allows users to select a single option from a group.

**Category:** Components


---

# Repeatable list

> Displays lists with varying content types within the same container.

**Category:** Components


---

# Select

> Provides a dropdown for choosing one option from a predefined list.

**Category:** Components


---

# Symbols

> Jenkins Symbols are an extensive and consistent collection of icons for use in Jenkins and plugins.

**Category:** Components


---

# Table

> Displays structured data in rows and columns, with support for sorting and badges.

**Category:** Components


---

# Toggle switch

> Enables users to switch between two states, such as on or off.

**Category:** Components


---

# Tooltips

> Offers brief, contextual information when hovering over an element.

**Category:** Components


---

## Patterns

# Colors

> Defines the palette for consistent use of color.

**Category:** Patterns


---

# JavaScript Proxy

> Export arbitrary server-side Java object to JavaScript and invoke their methods from JavaScript.

**Category:** Patterns


---

# Layouts

> Predefined layout structures and patterns to organize page content.

**Category:** Patterns


---

# Links

> Creates navigational connections to internal or external destinations.

**Category:** Patterns


---

# Localization

> Ensures texts can be displayed in the user's language.

**Category:** Patterns


---

# Spacing

> Defines consistent padding, margins, and gaps between elements.

**Category:** Patterns


---

# Stylesheets

> Provides reusable stylesheet principles and standards for maintaining consistency.

**Category:** Patterns


---

# Validation

> Ensures user inputs meet specified criteria or rules before submission.

**Category:** Patterns


---

@SohamJuneja
Copy link
Copy Markdown
Contributor Author

The issue was that code example files are split between the webapp directory and the classpath, and the original implementation only checked one location. readResource now checks both, so llms-all.txt and the per-component .md pages include the actual Jelly/Java code examples.

@timja
Copy link
Copy Markdown
Member

timja commented Apr 9, 2026

Better, llms.txt now loads to the individual markdown page.

But only a couple of them are actually loading content / example above their description.

Dialogs, tables and radios have a little bit

generally the rest is missing, e.g. cards

@SohamJuneja
Copy link
Copy Markdown
Contributor Author

The root cause was in how the resource URL was constructed, new URL(base, relPath) uses relative URL resolution which breaks silently for jar: scheme URLs. For components like Cards and Buttons whose snippet files live only in src/main/webapp/, this caused every lookup to fail and fall through to a classpath-only search that could never find them. The fix uses explicit string concatenation instead: new URL(base + componentName + "/" + filename), which works correctly for both file: and jar: scheme URLs. A classloader-root fallback is also added as a safety net.

@timja
Copy link
Copy Markdown
Member

timja commented Apr 14, 2026

build is failing

@krisstern
Copy link
Copy Markdown
Member

It looks like we will need to run mvn spotless:apply to fix some Spoteless bugs before the CI/CD checks will pass

@timja
Copy link
Copy Markdown
Member

timja commented Apr 14, 2026

Are you actually testing this? (it has improved since the last iteration there is a lot more content though)

go through each page and make sure at least the majority of the content is there. I got as far as the first page before I found missing content: http://localhost:8080/jenkins/design-library/app-bars.md

All the do and don't are missing

@SohamJuneja
Copy link
Copy Markdown
Contributor Author

This time I tested every single one of the 27 component pages locally by running Jenkins via mvn clean hpi:run -Dskip.npm -Dport=8090 and checking each .md endpoint individually.
I've now added:

  1. Parsing of <s:dos-donts> blocks with i18n key resolution from index.properties files
  2. Extraction of inline code snippets (e.g. used in Notifications and Symbols)

@timja
Copy link
Copy Markdown
Member

timja commented Apr 16, 2026

  1. I'd expect llms-all.txt to be linked in llms.txt, for all components you can fetch llms-all.txt or something like that.
  2. app-bar is missing the content for each example, e.g. top app-bar:

Top app bar provides the page heading as well as important actions.

  1. Banners is missing the warning:

Since 2.459. The css classes have the jenkins- prefix. Older versions should use the non prefixed form which interfere with classes defined in bootstrap.

  1. Buttons is missing the content under each example e.g.:

Tertiary buttons should be used for buttons which have minimal interaction or for those where a background creates too much visual clutter.


Can you compare more carefully please? - each iteration is getting better but I don't get past the first page without finding important missing content.

import org.kohsuke.accmod.restrictions.NoExternalUse;

@Restricted(NoExternalUse.class)
class LlmContent {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't workable, better to just commit markdown files.

@janfaracik think its worth trying to generate jelly from markdown or just keep a markdown copy and a jelly version?

Copy link
Copy Markdown
Contributor Author

@SohamJuneja SohamJuneja Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's fair, the Jelly-parsing approach technically works but it's fragile. Any new pattern someone adds to a component Jelly file would need another special case in the parser.

Even just building this I ran into a bunch of edge cases while manually checking each page, things like half-encoded tag names in property values, 'br' inside i18n strings causing two sentences to run together, Java generics inside code container spans getting stripped by the tag cleaner, and Colors using j:forEach which makes the Jelly basically unparseable statically. Each one took a while to track down. So I get why this isn't the right long-term approach.

One option, we could use the current implementation as a one-time generation tool to get all the content out, then delete LlmContent.java entirely and just commit the generated .md files directly. That way the content isn't lost but there's no fragile parser living in the codebase.

What do you think?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah give it a go, will need to run it past others of whether we want:

  • both committed
  • markdown as the master and then generate jelly from it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Where should the .md files live? Either alongside each component's existing resources (src/main/resources/.../AppBars/index.md) or in a dedicated top-level folder like docs/llms/app-bars.md?

  2. Should the HTTP endpoints still work and serve these files, or are the committed files enough? If the URLs need to keep working, we still need some Java code.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. alongside the jelly files I think
  2. not sure what you mean, the markdown files need to be served

return null;
}

private java.net.URL getPluginResourceBase() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import

Copy link
Copy Markdown
Member

@timja timja left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes themself look good, I've not reviewed every page but I checked a few.

@janfaracik any thoughts on this?

not ideal to have to duplicate it, might be possible to generate the jelly as an alternative?

@janfaracik
Copy link
Copy Markdown
Member

Yeah not ideal. I'll have a play around and see how easy it is to generate Markdown from Jelly.

@SohamJuneja
Copy link
Copy Markdown
Contributor Author

One thing that might be worth exploring, instead of parsing Jelly source directly, we could fetch the already-rendered HTML of each component page and extract content from that using something like Jsoup with CSS selectors. The tradeoff is it would need a running Jenkins instance to generate the files, but that could be a build step?

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.

Publish llms.txt

5 participants