Skip to content

Commit ad12ed9

Browse files
Add combined compacted llms-full.txt; make llms.txt a product directory
- New build_llms_full.py aggregates every product's source into one compacted, well-structured /llms-full.txt (navigation boilerplate stripped; signatures, summaries, and member/parameter tables kept). ~28 MB / ~3 MB gz. - Site-root llms.txt is now a per-product directory (the format previously used by llms-full.txt) with a pointer to the combined file. - Home build no longer emits llms-full.txt; build_llms_full.py owns the bucket-root /llms-full.txt, built and deployed by deploy_all and the content refresher (refresh_search_index.yml -> "Refresh Root Aggregates"). - All page links in llms.txt / llms-full.txt now target the Markdown (.md) rendition instead of the HTML page, for LLM/agent consumption. - Docs updated: README, CLAUDE.md, CHANGELOG.md.
1 parent 4515a39 commit ad12ed9

13 files changed

Lines changed: 437 additions & 36 deletions

File tree

.github/workflows/deploy_all.yml

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,9 @@ jobs:
5858
environment: ${{ github.event_name == 'workflow_dispatch' && inputs.environment || (github.ref_name == 'production' && 'production' || 'staging') }}
5959
secrets: inherit
6060

61-
# Rebuild the root /search-index.json (the 404 live search source) from every product's
62-
# source front matter — no per-product build artifacts needed. Same job runs standalone in
61+
# Rebuild the bucket-root aggregates from every product's SOURCE — no per-product build
62+
# artifacts needed: the 404 live-search index (/search-index.json) and the combined,
63+
# compacted whole-reference file (/llms-full.txt). Same job runs standalone in
6364
# refresh_search_index.yml on content pushes.
6465
search-index:
6566
if: ${{ !cancelled() }}
@@ -80,11 +81,25 @@ jobs:
8081
AWS_ACCESS_KEY_ID: ${{ secrets.ACCESS_KEY }}
8182
AWS_SECRET_ACCESS_KEY: ${{ secrets.SECRET_ACCESS }}
8283

84+
- name: Build llms-full.txt from source
85+
run: |
86+
BASE=${{ env.ENVIRONMENT == 'production' && 'https://reference.groupdocs.com' || 'https://reference2.groupdocs.com' }}
87+
python3 build_llms_full.py --source content/sites/groupdocs --base-url "$BASE" --out llms-full.txt
88+
89+
- name: Deploy llms-full.txt to bucket root
90+
run: |
91+
BUCKET=${{ env.ENVIRONMENT == 'production' && 'reference.groupdocs.com' || 'reference2.groupdocs.com' }}
92+
aws s3 cp llms-full.txt "s3://$BUCKET/llms-full.txt" \
93+
--content-type "text/plain; charset=utf-8" --region us-west-2
94+
env:
95+
AWS_ACCESS_KEY_ID: ${{ secrets.ACCESS_KEY }}
96+
AWS_SECRET_ACCESS_KEY: ${{ secrets.SECRET_ACCESS }}
97+
8398
- name: Invalidate CloudFront
8499
uses: chetan/invalidate-cloudfront-action@v2
85100
env:
86101
DISTRIBUTION: ${{ env.ENVIRONMENT == 'production' && secrets.AWS_DISTRIBUTION_PROD || secrets.AWS_DISTRIBUTION }}
87-
PATHS: '/search-index.json'
102+
PATHS: '/search-index.json /llms-full.txt'
88103
AWS_REGION: 'us-west-2'
89104
AWS_ACCESS_KEY_ID: ${{ secrets.ACCESS_KEY }}
90105
AWS_SECRET_ACCESS_KEY: ${{ secrets.SECRET_ACCESS }}

.github/workflows/refresh_search_index.yml

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
name: Refresh Search Index
1+
name: Refresh Root Aggregates
22

3-
# Lightweight: rebuild the root /search-index.json (the 404 live search source) from product
4-
# source front matter — no Hugo build. Runs on any content push so the index stays current
5-
# between full Deploy All runs. Branch mapping: production -> production, main -> staging.
3+
# Lightweight: rebuild the bucket-root aggregates from product SOURCE — no Hugo build:
4+
# /search-index.json (the 404 live search source) and /llms-full.txt (the combined, compacted
5+
# whole-reference file). Runs on any content push so both stay current between full Deploy All
6+
# runs. Branch mapping: production -> production, main -> staging.
67
on:
78
workflow_dispatch:
89
inputs:
@@ -44,11 +45,25 @@ jobs:
4445
AWS_ACCESS_KEY_ID: ${{ secrets.ACCESS_KEY }}
4546
AWS_SECRET_ACCESS_KEY: ${{ secrets.SECRET_ACCESS }}
4647

48+
- name: Build llms-full.txt from source
49+
run: |
50+
BASE=${{ env.ENVIRONMENT == 'production' && 'https://reference.groupdocs.com' || 'https://reference2.groupdocs.com' }}
51+
python3 build_llms_full.py --source content/sites/groupdocs --base-url "$BASE" --out llms-full.txt
52+
53+
- name: Deploy llms-full.txt to bucket root
54+
run: |
55+
BUCKET=${{ env.ENVIRONMENT == 'production' && 'reference.groupdocs.com' || 'reference2.groupdocs.com' }}
56+
aws s3 cp llms-full.txt "s3://$BUCKET/llms-full.txt" \
57+
--content-type "text/plain; charset=utf-8" --region us-west-2
58+
env:
59+
AWS_ACCESS_KEY_ID: ${{ secrets.ACCESS_KEY }}
60+
AWS_SECRET_ACCESS_KEY: ${{ secrets.SECRET_ACCESS }}
61+
4762
- name: Invalidate CloudFront
4863
uses: chetan/invalidate-cloudfront-action@v2
4964
env:
5065
DISTRIBUTION: ${{ env.ENVIRONMENT == 'production' && secrets.AWS_DISTRIBUTION_PROD || secrets.AWS_DISTRIBUTION }}
51-
PATHS: '/search-index.json'
66+
PATHS: '/search-index.json /llms-full.txt'
5267
AWS_REGION: 'us-west-2'
5368
AWS_ACCESS_KEY_ID: ${{ secrets.ACCESS_KEY }}
5469
AWS_SECRET_ACCESS_KEY: ${{ secrets.SECRET_ACCESS }}

CHANGELOG.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ tags), so changes accumulate under **[Unreleased]**.
1010
## [Unreleased]
1111

1212
### Added
13+
- **Combined, compacted `llms-full.txt`** at the site root — the entire API reference for all 15
14+
products in one well-structured file. Built from source by `build_llms_full.py` (navigation
15+
boilerplate stripped: `See Also` footers, `Learn more` blocks, internal link URLs, front matter,
16+
heading anchors, Java separators; signatures, summaries, and member/parameter tables kept).
17+
~28 MB (~3 MB gzipped). Deployed to the bucket root by `deploy_all` + the content-push refresher.
1318
- **Live search on the 404 page** — type-ahead over a combined `/search-index.json` (all 15 products,
1419
~37k symbols): kind badges, namespace paths, platform pills, keyboard navigation.
1520
- **Cross-product search index** `/search-index.json`, built from product source front matter by
@@ -31,8 +36,15 @@ tags), so changes accumulate under **[Unreleased]**.
3136
`deploy_home.yml`), Hugo 0.101.0, AWS S3 + CloudFront.
3237
- Home page: product grid driven by `data/products.toml`; **AI Agents & LLM section** refocused on this
3338
site's machine-readable indexes (`/llms.txt`, `/llms-full.txt`, `.md`) with clearer FontAwesome icons.
34-
- Site-root `llms.txt`/`llms-full.txt` and home `index.md` emit **absolute URLs** (host baseURL per env);
35-
site-root `llms-full.txt` is a directory of per-product `llms-full.txt`.
39+
- Site-root `llms.txt`/`llms-full.txt` and home `index.md` emit **absolute URLs** (host baseURL per env).
40+
- **All page links in `llms.txt` / `llms-full.txt` now point to the Markdown (`.md`) rendition, not the
41+
HTML page** — these files are for LLMs/agents (e.g. `…/annotator/text/``…/annotator/text.md`).
42+
Applies to the combined `/llms-full.txt` (`Path:` lines) and the per-product Hugo `llms.txt`/`llms-full.txt`.
43+
- **Site-root `llms.txt` is now a per-product directory** (full-reference / section-index / Markdown
44+
links per product, plus a pointer to the combined `/llms-full.txt`) — the format previously used by
45+
`llms-full.txt`. The home build no longer emits `llms-full.txt`; the source-built combined file owns
46+
`/llms-full.txt`. `refresh_search_index.yml` (now "Refresh Root Aggregates") rebuilds both
47+
`/search-index.json` and `/llms-full.txt` on content pushes.
3648

3749
### Fixed
3850
- Family-page "Browse API reference" links now include the product path prefix.

CLAUDE.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ obvious from the code.
2929
`hugo deploy` → CloudFront invalidate**.
3030
- `deploy_<product>.yml` (×15) — triggers on `content/sites/groupdocs/<product>/**` push; calls the reusable one.
3131
- `deploy_home.yml``content/sites/groupdocs/home/**`; invalidates `/index.html /index.md /llms.txt /llms-full.txt /404.html`; `maxDeletes 0`.
32-
- `deploy_all.yml``themes/**` push or manual; home → products matrix → **`search-index`** job (rebuilds `/search-index.json` from source).
33-
- `refresh_search_index.yml``content/sites/groupdocs/**` push or manual; rebuilds `/search-index.json` from source (lightweight, no Hugo), concurrency-coalesced.
32+
- `deploy_all.yml``themes/**` push or manual; home → products matrix → **aggregates** job (`search-index`)
33+
that rebuilds the bucket-root `/search-index.json` **and** `/llms-full.txt` from source.
34+
- `refresh_search_index.yml` ("Refresh Root Aggregates") — `content/sites/groupdocs/**` push or manual;
35+
rebuilds `/search-index.json` **and** `/llms-full.txt` from source (lightweight, no Hugo), concurrency-coalesced.
3436
- Secrets: `ACCESS_KEY`/`SECRET_ACCESS` (S3), `AWS_DISTRIBUTION_PROD` (prod) / `AWS_DISTRIBUTION` (staging) CloudFront.
3537

3638
## Content model
@@ -58,8 +60,15 @@ obvious from the code.
5860
**absolute links**, **ugly URLs**. Family page `.md` is served at **`/<product>.md`** (bucket root), not `/<product>/index.md`.
5961
- `partials/md/abs-content.txt`: emits `.RawContent`, absolutizes root-relative links, strips a leading
6062
front-matter block for empty-body pages (CRLF-tolerant).
61-
- llms: `index.llmstxt.txt` (home lists products from `data/products.toml` with `.md` links),
62-
`index.llmsfull.txt` (product build inlines all pages; site-root = directory of per-product `llms-full.txt`).
63+
- llms (per-build, Hugo): `index.llmstxt.txt`**site-root** `llms.txt` is a per-product **directory**
64+
(full-reference / section-index / Markdown links per product, from `data/products.toml`); a product
65+
build's `llms.txt` lists its platforms/namespaces. `index.llmsfull.txt` — a **product** build inlines
66+
all its pages into `/<product>/llms-full.txt`. The **site-root** build no longer emits `llms-full.txt`.
67+
- **Combined `/llms-full.txt`** (bucket root): the entire reference for all 15 products in one compacted,
68+
well-structured file, built from source by `build_llms_full.py` (no Hugo — each product is a separate
69+
build, so Hugo can't aggregate). It strips nav boilerplate (`See Also`, `Learn more`, internal link
70+
URLs, front matter, anchors, Java separators) and keeps signatures + summaries + member/parameter
71+
tables. Produced & deployed by the `deploy_all` aggregates job and `refresh_search_index.yml`.
6372
- **Search index** `/search-index.json` (bucket root, ~37k entries, all products) powers the **404 live search**.
6473
Built by `build_search_index.py --source content/sites/groupdocs` (parses front matter `title`+`url`, no Hugo).
6574
- Serving: `.md`/`.txt`/`.html` get `charset=utf-8` via `[[deployment.matchers]]`; CloudFront auto-gzips.
@@ -69,6 +78,8 @@ obvious from the code.
6978
- `resolve_md_links.py <dir> --base-url <BASE>` — resolve relative `.md` links to absolute (per page URL);
7079
`surrogateescape` for non-UTF-8 bytes. Must run **before** the ugly-URL rename.
7180
- `build_search_index.py --source content/sites/groupdocs --out search-index.json` — combined index (source mode).
81+
- `build_llms_full.py --source content/sites/groupdocs --base-url <BASE> --out llms-full.txt` — combined,
82+
compacted whole-reference file (source mode; `--only a,b` limits products for fast local preview).
7283
- `build-local.sh [products…]` — builds home + listed products into `./public-local/` (runs resolver + ugly rename +
7384
family-md-to-root + search index). Default product: annotation.
7485
- `serve-local.py [port]` — static server for `./public-local` that sends `charset=utf-8` for text (plain

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ Alongside HTML, every page emits a **Markdown (`.md`)** rendition, and each buil
5353
consumption. Configured per product in `config/sites/groupdocs/<product>/_default/config.toml`
5454
(`[outputFormats.MD|LLMSTXT|LLMSFULL]`, `[outputs]`).
5555

56+
At the **site root**, `llms.txt` is a **per-product directory** (each product's full-reference,
57+
section-index, and Markdown links), and `/llms-full.txt` is the **entire API reference for all 15
58+
products in one compacted file**. Because each product is a separate Hugo build, Hugo can't
59+
aggregate them — so [`build_llms_full.py`](build_llms_full.py) builds `/llms-full.txt` from source
60+
(stripping navigation boilerplate, keeping signatures + summaries + member/parameter tables) and CI
61+
uploads it to the bucket root (`deploy_all` + `refresh_search_index.yml`).
62+
5663
The `.md` files are post-processed so they're clean and portable:
5764

5865
1. **No front matter, real Markdown**`single.md` / `list.md` emit `.RawContent` (Hugo strips

build-local.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ done
4343
# Combined cross-product search index for the 404 live search (built from the merged tree).
4444
python build_search_index.py "$OUT" --out "$OUT/search-index.json"
4545

46+
# Combined, compacted llms-full.txt (whole API reference, built from source). --only limits it
47+
# to the products built locally so the preview is quick; production builds all 15.
48+
python build_llms_full.py --source content/sites/groupdocs --base-url "http://localhost:$PORT" \
49+
--only "$(IFS=,; echo "${PRODUCTS[*]}")" --out "$OUT/llms-full.txt"
50+
4651
echo
4752
echo "Built ${#PRODUCTS[@]} product(s) + home into ./$OUT"
4853
echo "Serve with: python serve-local.py $PORT # UTF-8 charset, matches production"

0 commit comments

Comments
 (0)