feat: make the bundled docs agent-readable - #8781
Merged
Merged
Conversation
🦋 Changeset detectedLatest commit: 913679d The changes in this PR will be included in the next version bump. This PR includes changesets to release 119 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
✅ Deploy Preview for modernjs-byted ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Contributor
Rsdoctor Bundle Diff Analysis📊 Quick Summary
Generated by Rsdoctor GitHub Action |
keepview
force-pushed
the
feat/agents-md-only-flag
branch
from
July 30, 2026 14:10
1d87450 to
dcf6c54
Compare
zllkjc
previously approved these changes
Aug 5, 2026
keepview
enabled auto-merge (squash)
August 5, 2026 13:34
…ommand The `create agents-md` subcommand overloaded the project-name positional: it reserved "agents-md" as a name and behaved differently depending on argument position. Replace it with an `--agents-md-only` flag, which can never collide with a project name and is position-independent. It updates the agent files in the current directory only, and is mutually exclusive with a project name and with `--no-agents-md` (guarded with a clear error). Updates the docs and adds tests for the guards and for "agents-md" now being a valid project name again. Co-Authored-By: Riff
The bundle was copied from the MDX sources, which are the docs site's input rather than something an agent can read: components are not rendered and shared fragments are not inlined. A quarter of the pages got their actual content from components whose data never ships with the package — configure/app/tools/ postcss.mdx, for example, was 38 lines with the type and defaults left to a component, so an agent reading it learned nothing. Copy from the docs site build output (packages/document/doc_build) instead. Those pages are self-contained: components are rendered and fragments inlined, so agents no longer need to follow cross-file references. Also ship llms.txt as a local index, and stop trimming sections — the full bundle is 906KB, roughly half of what the MDX bundle cost. Order is guaranteed via an nx dependsOn so the docs site builds first; when its output is absent the copy step warns and skips rather than blocking everyday builds, and check-doc-bundle.mjs is the gate that keeps a release from shipping without the docs. Co-Authored-By: Riff
EdenX and PIA need the same capability — version-matched bundled docs plus an
idempotently generated AGENTS.md — but both pieces were private to Modern.js:
the copy script had its paths hardcoded, and the agent-file writer lived inside
@modern-js/create with the marker name, block content and target baked in.
Reimplementing them downstream would fork the idempotency rules.
Make both reusable instead:
- Rename copy-main-doc.mjs to copy-docs.mjs (the source is no longer the
main-doc package, so "main" meant nothing) and parameterize it as
`bundleDocs({source, target, indexFile, excludedDirs})`, exposed via a
`modern-bundle-docs` bin. Modern.js's own call keeps the previous defaults.
- Extract the AGENTS.md/CLAUDE.md writer into agent-files.mjs, parameterized by
marker name, managed block and target directory, exported as
`@modern-js/create/agent-files`. The create command now calls it too, so the
rules stay in one place.
Co-Authored-By: Riff
…kage Review found four ways the new APIs work in the repo but break once published: - `modern-bundle-docs` could not run. The script had no shebang, so the shell read `import` as a command; and the direct-invocation check compared the module path against argv[1], which is a symlink under `.bin`, so even with a shebang it would exit silently. Add the shebang and compare realpaths. - `bundleDocs()` was exported but unreachable: nothing in the exports map pointed at it, so importing from a real tarball raised ERR_PACKAGE_PATH_NOT_EXPORTED. Add a `./bundle-docs` subpath. - Docs could be published stale. `@modern-js/main-doc:build` neither hashed `docs/**` nor declared `doc_build` as an output, so editing a page hit the cache and the bundle silently kept the old content. Declare both, and run check-doc-bundle from `release` so a bad bundle fails the publish instead of shipping. - `@modern-js/create/agent-files` had no types, degrading the public API to `any` for strict consumers. Ship a `.d.mts` and add `types` conditions. Verified against the failure modes: invoking through a `.bin` symlink now works, the subpath imports, editing a doc rebuilds instead of hitting cache, deleting doc_build restores it from cache, and the release gate fails when the docs site has not been built. create tests still 14/14. Co-Authored-By: Riff
…ered components Two more issues the previous round's checks could not see: - The `.d.mts` files were unreachable for consumers on `moduleResolution: node`, which is what this repo itself uses — classic resolution ignores the exports map, so both subpaths raised TS2307. Add `typesVersions` entries; verified by typechecking a consumer under both node and nodenext. - `<ReleaseNote />` and `<PackageManagerTabs />` in upgrade.mdx were indented inside a list item, so MDX treated them as text and the release notes and install commands never reached the bundled docs. Un-indent them, matching how the same components are used elsewhere, and extend check-doc-bundle to flag component tags that survive the build — the existing import check could not, since the build strips imports either way. The component check matches only self-closing or attributed tags: a bare `<Name>` also shows up in type signatures such as `Promise<RsbuildConfig>`, which is prose rather than an unrendered component. Verified: the install commands now appear as real code blocks in the bundle, check-doc-bundle passes, create tests 14/14. Co-Authored-By: Riff
…ists The bundle gate had two blind spots that let non-self-contained pages through: the import check only accepted single quotes, while the docs use both (e.g. `import EnableBFFCaution from "@site-docs-en/..."`), and the component check enumerated five names, so anything outside that list — EnableBFFCaution, Badge — passed silently. Match both structurally: accept either quote style, and treat any capitalized self-closing tag as an unrendered component rather than maintaining a list. Fixing the detection surfaced a third bug in the code-stripping: fences indented inside a list item were not stripped, so JSX in sample code read as a leftover component. Move the rules into scripts/doc-bundle-rules.mjs so they can be tested without triggering a docs build, add negative tests for each blind spot, and run them in CI — the previous rules would have passed a test suite that only used the cases they already handled. Co-Authored-By: Riff
The gate tried to infer whether a page had rendered completely by scanning its text for leftover imports and component tags. Each round of review found another case it got wrong — quote styles, component names, tilde fences, doubled backticks, paired tags — and each fix only moved the blind spot. Doing it properly means parsing the full MDX surface, which is the docs site's job, not a downstream packaging check's. Keep what can be verified deterministically: the tarball has the pages, the page count matches the docs site output, llms.txt ships, and the bundle stays under the size limit. Stop claiming "all pages self-contained" in the success log, since that is no longer checked. Pages that fail to render are fixed at the source instead — the upgrade.mdx indentation fix earlier in this branch is one such case. Co-Authored-By: Riff
AGENTS.md asserted `node_modules/@modern-js/app-tools/docs/` unconditionally. No released version ships that directory yet, and versions before 3.8.0 never will, so `--agents-md-only` on any existing project wrote a path that does not resolve — while printing that agents would read the bundled docs. An agent following it wastes a turn and concludes it has consulted the documentation. Resolve the location from the version instead, and write one address: major <= 2 -> https://modernjs.dev/v2/llms.txt >= 3.8.0 -> node_modules/@modern-js/app-tools/docs/ current major, older -> https://modernjs.dev/llms.txt canary / workspace links -> bundled (trunk builds always carry them) The version comes from node_modules when installed and from the declared range otherwise, so it works in the two entry points where nothing is installed yet. Deciding here rather than leaving the agent an "if the directory exists" rule is deliberate: the file is written once and read on every turn. Also refuses to write into a directory that declares no @modern-js dependency — it would point that project's agent at a framework it does not use — and the completion message now names the location it actually wrote. Drops the v3 essentials list. It duplicated what the docs say, in the block that costs context on every turn.
ut-windows failed on the check that keeps template/AGENTS.md in step with the generated block. The repo has no .gitattributes rule for text, so the template checks out with CRLF on the Windows runner while the block is always joined with \n — the assertion compared line endings, which was never its point.
Four entries described one capability from four angles, which reads as four features in the release notes. One entry, one paragraph per language. Drops the note about re-exporting `build` and `closeServer` — that change was reverted; feat/export-modern-app-tools-dev exposes the same API properly. Also corrects the pending entry from #8774: it still tells existing projects to run `create agents-md`, the subcommand this PR replaced with a flag. Both ship in the same release, so the notes would have contradicted each other.
The hand-written .mjs + .d.mts pair existed for one consumer: EdenX's generator imported it through the `./agent-files` export. That generator now ships its own copy so the two release independently, which leaves this package as the only user — so the module moves into src as TypeScript, the export, the typesVersions mapping and the hand-maintained declaration file all go, and the types come from the compiler.
copy-docs.mjs was hand-written JS with a hand-maintained .d.mts beside it — the declaration existed only because the module was not TypeScript. It now lives in src/bundleDocs.ts and comes out of the normal rslib build, so the types are generated and the pair of loose files under scripts/ goes away. The three consumers keep their contracts: - the `modern-bundle-docs` bin becomes a two-line CommonJS shim that dynamic- imports the compiled ESM and passes the package root in — the compiled module cannot know that path portably across output formats, and the shim keeps the shebang without needing a loader on user machines - the `./bundle-docs` export points at the compiled ESM with generated types - the package's own build runs the shim after rslib, same as before The former direct-invocation realpath check is gone with the file: the CLI only runs when the shim calls it, so import-vs-execute no longer needs detecting. The root gate keeps calling the bin; scripts/ at the repo root stays plain node — that is its convention (check-dependencies.js, skipCI.js, sync-skills.mjs), unlike EdenX's script workspaces.
check-doc-bundle sat at the top of scripts/ as a loose .mjs, next to four script workspaces that all run TypeScript through tsx — check-changeset, lint-package-json, release-note, release-version. Nothing about this one justified the exception; it now has the same shape, and the root script enters it the same way the others are entered. Unlike its siblings it also declares typescript, so its `build` script — the type check — actually runs; theirs reference tsc without depending on it.
Multi-paragraph headers shrink to what a reader needs, and references to downstream consumers by name go — which frameworks reuse these entry points is their business, not this repo's. No behavior change; the full suite and the release gate pass unchanged.
The version decides everything. At or past 3.8.0 — and on trunk builds — the managed block names the bundled docs, exactly as before. Below that, the command now creates and modifies nothing: it prints where the online index lives and how to move forward, instead of writing a block that points there. Writing the online index ourselves is retired because it produced a file the tool half-manages on versions it cannot serve — one that would need migrating again right after the upgrade it is nudging the user toward. The superseded- major index table goes with it: its only purpose was choosing which online address to write. Scaffolding is unaffected — a new project pins the version of the create package itself, which ships the docs.
keepview
force-pushed
the
feat/agents-md-only-flag
branch
from
August 5, 2026 13:41
d31c019 to
d13f60e
Compare
The rebase onto main merged main's lockfile over the entry for the new script workspace, so CI's frozen install refused it.
zllkjc
approved these changes
Aug 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

What
Two follow-ups to #8774, both about how agents actually consume the bundled docs:
llms.txtships alongside as a local index, and the bundle no longer trims sections (it's about half the size of the old one).create agents-mdsubcommand with a--agents-md-onlyflag. The subcommand reservedagents-mdas a project name and changed meaning depending on argument position. A flag has neither problem.Test
createunit tests pass (14).node scripts/check-doc-bundle.mjspasses: the tarball has the expected page count plusllms.txt, within the size limit.pnpm pack --ignore-scriptsconfirms the docs andllms.txtare in the tarball.