---
title: "Developer Information"
manual: "LLMs.txt Generator"
version: "1.0"
permalink: "https://docs.typo3.org/permalink/rtfirst/llms-txt:developer@1.0"
source: "Developer.rst"
rendered: "2026-09-28T14:13:24+00:00"
---

# Developer Information {#developer}

This chapter provides technical details for developers and integrators.

## Architecture {#developer-architecture}

The extension uses three PSR-15 middlewares:

1.  **UrlSuffixMiddleware** \- Detects `.md` suffix and rewrites URLs
1.  **LlmsTxtMiddleware** \- Serves the `/llms.txt` endpoint
1.  **ContentFormatMiddleware** \- Transforms HTML to Markdown

### Middleware Chain {#developer-middlewares}

```text
Request: /about.md
   │
   ▼
UrlSuffixMiddleware (before site resolver)
   │  Strips .md suffix
   │  Sets request attribute 'llms_txt_format' = 'md'
   │  Rewrites URI to /about
   ▼
TYPO3 Site Resolver
   │
   ▼
LlmsTxtMiddleware (after site, before page resolver)
   │  Handles /llms.txt requests
   ▼
TYPO3 Page Resolver & Frontend
   │
   ▼
ContentFormatMiddleware (after content-length-headers)
   │  Checks for 'llms_txt_format' attribute
   │  Converts HTML response to Markdown
   ▼
Response: Markdown with YAML frontmatter
```

## Services {#developer-services}

### PageTreeService {#pagetreeservice}

`RTfirst\LlmsTxt\Service\PageTreeService`

Traverses the TYPO3 page tree and collects page data for llms.txt generation.

-   Supports multi-language sites
-   Respects page exclusion settings
-   Handles translated pages with fallback

### MarkdownConverterService {#markdownconverterservice}

`RTfirst\LlmsTxt\Service\MarkdownConverterService`

Orchestrates content element to Markdown conversion using registered converters.

### LlmsTxtGeneratorService {#llmstxtgeneratorservice}

`RTfirst\LlmsTxt\Service\LlmsTxtGeneratorService`

Generates the llms.txt content for a site.

## Content Converters {#developer-converters}

The extension uses a converter pattern for content element to Markdown conversion.
Each converter implements `ContentConverterInterface`:

```php
interface ContentConverterInterface
{
    public function supports(string $cType): bool;
    public function convert(array $record, string $baseUrl): string;
}
```

### Built-in Converters {#built-in-converters}

| Converter | Supported CTypes | Description |
| --- | --- | --- |
| HeaderConverter | `header` | Converts header elements |
| TextConverter | `text`, `textpic`, `textmedia` | Converts text and text+media |
| ImageConverter | `image` | Converts image galleries |
| BulletsConverter | `bullets` | Converts bullet lists |
| TableConverter | `table` | Converts tables |
| MenuConverter | `menu_*` | Converts menu elements |
| HtmlConverter | `html` | Converts raw HTML |
| DefaultConverter | (fallback) | HTML-to-Markdown fallback |

### Creating Custom Converters {#developer-custom-converter}

1.  Create a class implementing `ContentConverterInterface`:

```php
<?php
declare(strict_types=1);

namespace Vendor\MyExtension\Converter;

use RTfirst\LlmsTxt\Converter\ContentConverterInterface;

class MyCustomConverter implements ContentConverterInterface
{
    public function supports(string $cType): bool
    {
        return $cType === 'my_custom_element';
    }

    public function convert(array $record, string $baseUrl): string
    {
        $header = $record['header'] ?? '';
        $bodytext = $record['bodytext'] ?? '';

        return "## {$header}\n\n{$bodytext}";
    }
}
```

1.  Register the converter in `Services.yaml`:

```yaml
services:
  Vendor\MyExtension\Converter\MyCustomConverter:
    tags:
      - name: 'llms_txt.content_converter'
        priority: 100
```

Higher priority converters are checked first.

## Event Listeners {#developer-events}

### CacheFlushEventListener {#cacheflusheventlistener}

Invalidates llms.txt cache when TYPO3 caches are flushed.

### HeaderLinkEventListener {#headerlinkeventlistener}

Injects the `<link rel="alternate">` tag into HTML responses.

### BackendNotificationEventListener {#backendnotificationeventlistener}

Shows a notification in the Backend if robots.txt lacks llms.txt reference.

## Caching {#developer-caching}

The extension uses two cache layers:

1.  **llms.txt Index Cache** (`cache_pages`)

    -   Stores generated llms.txt content per site
    -   Invalidated on cache flush
1.  **Format Output Cache** (`llms_txt_format`)

    -   Stores Markdown output per page/language
    -   24-hour default lifetime
    -   Part of the `pages` cache group

## Database Schema {#developer-database}

The extension adds fields to the `pages` table:

| Field | Type | Description |
| --- | --- | --- |
| tx_llmstxt_description | text | LLM-specific page description |
| tx_llmstxt_summary | text | Extended page summary |
| tx_llmstxt_keywords | varchar(255) | Comma-separated keywords |
| tx_llmstxt_exclude | tinyint(1) | Exclude from llms.txt |
| tx_llmstxt_priority | int(11) | Priority (0-100) for sorting |

## Code Quality {#developer-code-quality}

The extension maintains high code quality standards:

-   **PHPStan Level 8** compliant
-   **PSR-12** code style (php-cs-fixer)
-   **Unit tests** for converters and services

Run quality checks:

```bash
# Static analysis
vendor/bin/phpstan analyse packages/llms_txt --level=8

# Code style check
vendor/bin/php-cs-fixer fix packages/llms_txt --dry-run

# Fix code style
vendor/bin/php-cs-fixer fix packages/llms_txt

# Run tests
vendor/bin/phpunit -c packages/llms_txt/phpunit.xml
```

## Dependencies {#developer-dependencies}

-   **league/html-to-markdown** (^5.1) - HTML to Markdown conversion
-   **typo3/cms-core** (^13.0 || ^14.0)
-   **typo3/cms-frontend** (^13.0 || ^14.0)
