Overhaul docs IA, ship AGENTS.md for bundled docs, add eval harness#13
Conversation
- Redirect / to /docs via beforeLoad and remove the Home dashboard - Add a robot-icon "View as Markdown" toggle in the header that opens the agent-friendly .md variant of the current docs page - Wire pipeline:convert into dev/build so leadtype's convertAllMdx populates apps/example/public/docs/**/*.md before vite starts - Add a Vite middleware that negotiates Accept: text/markdown on /docs/* URLs so agents can hit canonical URLs with the right header - Render Mermaid client-side with @streamdown/mermaid; flatten the inner Streamdown chart wrapper so it shows as a single card - Restructure /docs/components into one section per component (description + usage + live example) so the page is a real reference and dogfoods the renderer + remark conversion at once - Wire the NotFound component into router + root route, and update it to point users back to /docs
Full rewrite of /docs into Get Started → Authoring → Build → Reference. Adds quickstart, how-it-works, frontmatter, validate-in-ci, and CLI reference pages. Every page leads with the problem it solves; mermaid diagrams carry the conceptual load (headline flow, pipeline internals, group resolution, plugin order, both build journeys). READMEs aligned with the new narrative. Anchor `build` in .gitignore to repo root so docs/build/ and route build/ directories aren't shadowed by the generic build-output rule. Updates CLI integration tests to match the new IA (build/ replaces guides/).
Vite served .md files as `text/markdown` with no charset, so browsers defaulted to Latin-1 and rendered UTF-8 box-drawing as mojibake (├── as ├──). The middleware now patches setHeader on every response to append `; charset=utf-8` to text/markdown and text/plain when the charset is missing. Covers both negotiated /docs/foo and direct /docs/foo.md paths.
Adds a Callout warning to the content-negotiation section calling out that static handlers default to no charset, which makes browsers fall back to Latin-1 and render UTF-8 as mojibake. Verify step now checks for charset=utf-8 explicitly.
Agents reading bundled docs (via npm install or llms.txt) can't follow links to apps/example/* on GitHub, so every "see this file" reference became a dead end. The connect-docs-site, bundle-package-docs, cli, llm, remark, components, and quickstart pages now contain the actual copyable code (mdx-convert script, full vite middleware with charset patch, generate-docs script, navigation write helpers) rather than GitHub-link breadcrumbs.
leadtype's bundled docs (inside the published tarball) were emitting website-shaped artifacts: llms.txt with absolute URLs, llms-full.txt, search-index.json — none of which made sense at node_modules/<pkg>/. The llms.txt spec is for hosted websites; agents don't auto-discover node_modules/<pkg>/llms.txt. The actual filesystem convention is AGENTS.md, supported by 25+ coding agents (Claude Code, Codex, Cursor, Copilot, Aider, etc.). Changes: - New `generateAgentsMd` in leadtype/llm — same shape as generateLlmsTxt but emits Markdown with relative ./docs/<topic>.md paths so the file works inside an installed npm package. - New `--bundle` flag on `leadtype generate`. Emits AGENTS.md + docs/*.md and skips llms.txt, llms-full*, and search artifacts. Website mode is unchanged. - packages/leadtype now uses --bundle for its own published tarball. AGENTS.md added to package.json#files. - Docs rewritten across index, how-it-works, quickstart, the bundle guide, both READMEs, and the cli + llm references. The "agents read llms.txt from node_modules" claim is replaced everywhere with the correct AGENTS.md flow plus the Next.js consuming-project pattern. - New evals/ directory using @vercel/agent-eval to measure discoverability empirically: paired bundled-docs vs bundled-docs-control experiments across four fixtures (wire-content-negotiation, validate-in-ci, explain-cli-flag, bundle-own-docs). Pass-rate delta = the value of shipping AGENTS.md. - New `--bundle` integration test in cli.test.ts asserts AGENTS.md is written, llms.txt is NOT, and docs/*.md still ship. Existing tests unchanged. 98/98 pass. Tarball check (`npm pack --dry-run`): - AGENTS.md (3.6kB) at root ✓ - docs/**/*.md (15 files) ✓ - no llms.txt, no llms-full, no search-index.json ✓
agent-eval's Docker sandboxes were unworkable here: every fresh node:24-slim container ran apt-get update + apt-get install -y ca-certificates git before the agent could start, and the framework's hardcoded image meant we couldn't skip it. With multiple containers spinning up concurrently apt-get saturated bandwidth and routinely ran past the 300s timeout. We watched 48 sandboxes hit timeout with zero transcripts produced and 35+ stuck containers. The whole isolation layer was overkill for our threat model — these are our own fixtures. Switched to a custom harness on the AI SDK that: - Uses Vercel AI Gateway (single AI_GATEWAY_API_KEY for all providers) - Spins up an OS tempdir per (fixture × mode), no Docker - Defines six AI SDK tools — read/write/list/glob/grep + a narrow npm with subcommand allowlist (pack/install only) and scrubbed env. No `bash` tool. Every tool path-scopes via resolveScoped() at the JS level — no shell parsing, no command substitution, no env-var leak - Records every tool call into a transcript JSON the EVAL.ts files read via TRANSCRIPT_PATH env var - Archives transcripts + modified files to evals/results/<fixture>/<mode>/ for debugging Smoke run on wire-content-negotiation with claude-haiku-4-5 confirms the harness works end-to-end: agent runs in 246s, makes 49 tool calls, reads node_modules/leadtype/AGENTS.md and follows it to write a correct vite.config.ts. The harness correctly catches that Haiku didn't navigate from AGENTS.md to the connect-docs-site topic — it skipped to quickstart.md and improvised. That's the kind of measurement we wanted. Path-escape unit tests (lib/tools.test.ts) verify resolveScoped rejects ../../../etc/passwd, /etc/passwd, and subdir/../.. — 9/9 pass.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📜 Recent review details🧰 Additional context used🔍 Remote MCP Context7Summary of additional factual context useful for reviewing the PR
Tools/sources used
🔇 Additional comments (1)
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis PR restructures leadtype's documentation pipeline and example app to support offline agent bundles via a new ChangesBundle Mode & Agent Documentation
Content Negotiation & Markdown Serving
Documentation Restructuring & Routing
UI Components & Styling
Agent Evaluation Framework
Configuration & Documentation
Sequence Diagram(s)sequenceDiagram
participant Agent as Coding Agent
participant Pkg as npm Package
participant Vite as Vite Dev Server
participant FS as Filesystem
Agent->>Pkg: Read AGENTS.md
Agent->>Pkg: Follow relative links to docs
Agent->>Vite: GET /docs/quickstart (markdown accept)
Vite->>Vite: markdownNegotiation() intercepts
Vite->>FS: Rewrite to /docs/quickstart.md
FS-->>Vite: Return markdown content
Vite->>Vite: Inject charset UTF-8
Vite-->>Agent: markdown content
Agent->>FS: Modify package.json
Agent->>FS: Create docs directory
sequenceDiagram
participant CLI as leadtype CLI
participant LLM as LLM Module
participant FS as Filesystem
CLI->>CLI: Parse --bundle flag
alt Bundle Mode
CLI->>LLM: generateAgentsMd(config)
LLM->>FS: Read source docs frontmatter
LLM->>LLM: Build group membership
LLM->>FS: Write AGENTS.md at root
FS-->>LLM: output path
LLM-->>CLI: bundle result
else Site Mode
CLI->>LLM: generateLlmsTxt and search
LLM-->>CLI: site result
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: be8b4a6f22
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "scripts": { | ||
| "evals": "bun run run-eval.ts", | ||
| "test": "vitest run lib", | ||
| "pack-leadtype": "mkdir -p .tarballs && cd ../packages/leadtype && npm pack --pack-destination ../../evals/.tarballs" |
There was a problem hiding this comment.
Build the package before packing it for evals
When someone follows evals/README.md from a clean checkout and runs bun run pack-leadtype, this script calls npm pack without first running the leadtype build/docs generation. packages/leadtype/docs/ is gitignored and not present in the repo, so the tarball installed by the treatment harness contains AGENTS.md with links to ./docs/... but no bundled docs for agents to read, causing the AGENTS.md discovery evals that assert topic reads to fail unless the developer happened to build the package manually beforehand.
Useful? React with 👍 / 👎.
| const matches = await fg(pattern, { | ||
| cwd: tempDir, | ||
| absolute: false, |
There was a problem hiding this comment.
Scope glob patterns before running fast-glob
The harness claims every tool path-scopes through resolveScoped, but the glob tool passes the model-controlled pattern directly to fast-glob. For patterns that include parent segments or absolute roots, this bypasses the tempdir check used by read, write, list, and grep, so an agent can enumerate paths outside the sandbox even though the eval README says it cannot see outside the tempdir.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 17
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/example/src/components/site-header.tsx`:
- Around line 34-45: The markdownHrefForPath helper incorrectly maps "/docs/" to
"/docs.md" because it checks for the root "/docs" before normalizing trailing
slashes; fix by normalizing the pathname up front (use TRAILING_SLASH_PATTERN to
strip trailing slash into a local variable, e.g., normalized) and then perform
the checks against normalized: if normalized is not under "/docs" return null,
if normalized endsWith(".md") return null, if normalized === "/docs" return
"/docs/index.md", otherwise return `${normalized}.md`. Update all references in
markdownHrefForPath to use the normalized variable.
In `@apps/example/vite.config.ts`:
- Around line 65-79: The monkeypatch in forceUtf8OnTextResponses currently binds
res.setHeader to original and assumes string arguments; update the patch to
preserve all overloads and this context by capturing the original as done
(original = res.setHeader.bind(res)) but implement the wrapper using a rest-args
signature (e.g., (...args)) and call the original via Reflect.apply(original,
res, args) so return value and this are preserved; additionally, handle
non-string/array header values safely by checking types before modifying value
(only modify when name is a string equal to "content-type" and value is a string
matching TEXT_CONTENT_TYPE_PATTERN without CHARSET_PATTERN), otherwise delegate
to original unchanged.
In `@biome.jsonc`:
- Around line 39-42: Update the stale rationale comment that references
"@vercel/agent-eval" so it accurately describes the current eval architecture:
replace the mention of `@vercel/agent-eval` with the "custom AI SDK harness" and
keep the guidance about fixture naming (EVAL.ts and PROMPT.md) and lint
decisions (useTopLevelRegex / useConsistentTypeDefinitions) intact; specifically
edit the comment containing the string "@vercel/agent-eval" and the lines
referencing "EVAL.ts", "PROMPT.md", and "useTopLevelRegex /
useConsistentTypeDefinitions" to reflect the new harness and avoid confusion.
In `@docs/build/connect-docs-site.mdx`:
- Line 184: Update the prose around the CLI flag so the platform name is
correctly capitalized: keep the flag text exactly as `--format github` but
change the surrounding plain-text reference to the platform to “GitHub” (capital
H) in the sentence that currently reads "Use `--format github` in CI to get
inline annotations on the PR."
In `@docs/how-it-works.mdx`:
- Around line 144-150: The documentation for the leadtype generate command
currently describes mode-specific outputs as if they always occur (it hardcodes
the converted output path `public/docs/` and implies LLM bundle/search
generation always runs); update the step list under the "leadtype generate"
command to be mode-agnostic by: (1) changing the fixed `public/docs/` reference
to a conditional phrase like "site output (e.g. public/docs/) when running site
mode", (2) clarifying that "Generate LLM bundles" and "Build the search index"
only run when the corresponding flags/modes (e.g. `--bundle` / bundle or search
mode) are enabled, and (3) mention the flag names (`--bundle`) and/or mode names
so readers know these steps are conditional rather than universal.
In `@evals/evals/explain-cli-flag/EVAL.ts`:
- Around line 11-13: The code uses a type assertion (c.args.path as string) when
building reads from transcript.toolCalls; instead, narrow the type by checking
that c.args && typeof c.args.path === "string" (or by filtering entries where
typeof c.args?.path === "string") before mapping, so reads only contains actual
strings and you can remove the unsafe as string assertion while keeping the
fallback logic for missing values; update the filter/map on transcript.toolCalls
(the reads assignment) to perform this runtime type check.
In `@evals/evals/explain-cli-flag/PROMPT.md`:
- Line 1: Add a top-level H1 heading as the first line of PROMPT.md to satisfy
markdownlint MD041; prepend a concise H1 (e.g., "# Explanation of --enrich-git")
above the existing paragraph so the file begins with an H1 and then the current
instruction sentence remains unchanged.
In `@evals/evals/validate-in-ci/PROMPT.md`:
- Line 1: The file PROMPT.md triggers MD041 because it starts with body text;
add a top-level H1 heading at the top of PROMPT.md (for example, "# Prompt" or a
concise title relevant to the content) so the file begins with an H1 line and
the existing content follows; this will satisfy the markdownlint rule without
changing the rest of the text.
In `@evals/evals/wire-content-negotiation/EVAL.ts`:
- Around line 40-55: Both tests duplicate reading vite.config.ts; extract a
helper (e.g., getViteConfigSource) at the top of the describe block that builds
viteConfigPath using projectRoot, asserts existsSync(viteConfigPath) and returns
readFileSync(viteConfigPath, "utf-8"), then replace the inline file-read logic
in the "middleware sets charset=utf-8" and "middleware rewrites /docs/* paths to
.md" tests to call getViteConfigSource() and run the same expect assertions
against its returned string.
In `@evals/evals/wire-content-negotiation/PROMPT.md`:
- Line 1: Add a top-level H1 as the very first line of PROMPT.md to satisfy
markdown linting (MD041); insert a single heading like "# Title" or a brief
descriptive H1 above the existing content so the file begins with an H1 and the
markdown linter stops flagging the prompt.
In `@evals/lib/sandbox.ts`:
- Around line 45-51: The cp call inside createSandbox can fail
(permissions/symlinks); wrap the cp(fixtureDir, tempDir, ...) invocation in a
try/catch, catch the error, and augment it with a clear diagnostic message that
includes fixtureDir and tempDir (or log via the existing logger) before
rethrowing or throwing a new Error that preserves the original error/stack; this
will make failures in cp easier to diagnose while still letting callers handle
the error.
In `@evals/run-eval.ts`:
- Around line 51-53: The CLI parsing for "--runs" currently sets args.runs =
Number.parseInt(...) without validating, allowing 0 or NaN; update the parsing
logic (the argv handling where args.runs is assigned and the other similar
occurrences around lines referencing args.runs) to verify the parsed value is an
integer > 0 (e.g., Number.isFinite and Number.isInteger checks and > 0), and if
invalid print a clear error to stderr and exit with a non-zero code (or default
to 1 explicitly), ensuring downstream summary math never runs with 0 or NaN
runs.
- Around line 274-291: The promise returned by runVitest can hang if spawn fails
or the child emits an 'error' event; update the code around the spawn call (the
proc variable created by spawn in runVitest) to (1) wrap spawn in try/catch and
immediately resolveSpawn with { passed: false, output: err.message } if spawn
throws, and (2) attach an 'error' listener on proc that resolves (or rejects)
the Promise with a failure result and include the error message in output;
ensure you still only resolve once (use a flag or remove other listeners) and
keep the existing stdout/stderr and 'close' handling intact.
- Around line 185-220: Wrap the main run logic (including the call to runVitest,
processing of evalResult, printing output, and the await archiveTranscript call)
in a try block and move the sandbox.cleanup() call into a finally block so
cleanup always runs even if runVitest or archiveTranscript throws; specifically,
keep await archiveTranscript({...}) inside the try but ensure finally { await
sandbox.cleanup(); } is present, referencing the existing runVitest,
archiveTranscript, and sandbox.cleanup symbols.
In `@packages/leadtype/README.md`:
- Around line 39-45: Replace the placeholder docs domain
"https://docs.example.com" used across the README: update the five links in the
docs list (the Quickstart, How it works, Build a docs site, Bundle docs into a
package, and CLI reference) and also update the example command that references
the example docs URL (the example command on line 13) to the real production
docs domain once it's available; search for the string "docs.example.com" in the
README and substitute the canonical production docs hostname so all links point
to the live documentation.
In `@packages/leadtype/src/cli.test.ts`:
- Around line 387-390: The bundle-mode test in cli.test.ts currently only
asserts that "search-index.json" is not emitted; update the test to also assert
that "search-content.json" is not emitted by adding a second expectation using
the same pattern (use existsSync and path.join with outDir and "docs" to check
"search-content.json") and assert toBe(false) so regressions that emit the full
search content will fail; locate the check near the existing
expect(existsSync(path.join(outDir, "docs", "search-index.json"))).toBe(false)
and add the analogous assertion for "search-content.json".
In `@README.md`:
- Around line 30-63: Replace the placeholder docs host
"https://docs.example.com" used across the README (including the 30-second
example commands and links to Quickstart, How it works, Frontmatter, CLI
reference, Methodology, and the two example outputs like AGENTS.md/llms.txt)
with the real documentation origin or repository-relative paths; update the npx
generate examples to use the real --base-url or remove the host so they work
locally, and ensure all user-facing links point to live docs or relative URLs
before merging.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: f68611d3-0753-45a2-8470-381e0dbad623
⛔ Files ignored due to path filters (5)
apps/example/src/generated/docs-nav.jsonis excluded by!**/generated/**apps/example/src/generated/docs-search-content.jsonis excluded by!**/generated/**apps/example/src/generated/docs-search-index.jsonis excluded by!**/generated/**bun.lockis excluded by!**/*.lockevals/bun.lockis excluded by!**/*.lock
📒 Files selected for processing (84)
.gitignoreREADME.mdapps/example/package.jsonapps/example/playwright.config.tsapps/example/src/components/docs-mdx/command-tabs.tsxapps/example/src/components/docs-mdx/mermaid.tsxapps/example/src/components/not-found.tsxapps/example/src/components/site-footer.tsxapps/example/src/components/site-header.tsxapps/example/src/lib/docs.tsapps/example/src/routeTree.gen.tsapps/example/src/router.tsxapps/example/src/routes/__root.tsxapps/example/src/routes/docs/authoring/components.tsxapps/example/src/routes/docs/authoring/frontmatter.tsxapps/example/src/routes/docs/build/bundle-package-docs.tsxapps/example/src/routes/docs/build/connect-docs-site.tsxapps/example/src/routes/docs/build/validate-in-ci.tsxapps/example/src/routes/docs/how-it-works.tsxapps/example/src/routes/docs/quickstart.tsxapps/example/src/routes/docs/reference/cli.tsxapps/example/src/routes/docs/reference/convert.tsxapps/example/src/routes/docs/reference/lint.tsxapps/example/src/routes/docs/reference/llm.tsxapps/example/src/routes/docs/reference/remark.tsxapps/example/src/routes/docs/reference/search.tsxapps/example/src/routes/docs/search.tsxapps/example/src/routes/index.tsxapps/example/src/styles.cssapps/example/vite.config.tsbiome.jsoncdocs/authoring/components.mdxdocs/authoring/frontmatter.mdxdocs/build/bundle-package-docs.mdxdocs/build/connect-docs-site.mdxdocs/build/validate-in-ci.mdxdocs/components.mdxdocs/convert.mdxdocs/docs.config.tsdocs/guides/bundle-package-docs.mdxdocs/guides/connect-docs-site.mdxdocs/how-it-works.mdxdocs/index.mdxdocs/lint.mdxdocs/llm.mdxdocs/methodology.mdxdocs/quickstart.mdxdocs/reference/cli.mdxdocs/reference/convert.mdxdocs/reference/lint.mdxdocs/reference/llm.mdxdocs/reference/remark.mdxdocs/reference/search.mdxdocs/remark.mdxdocs/search.mdxevals/.env.exampleevals/README.mdevals/evals/bundle-own-docs/EVAL.tsevals/evals/bundle-own-docs/PROMPT.mdevals/evals/bundle-own-docs/package.jsonevals/evals/explain-cli-flag/EVAL.tsevals/evals/explain-cli-flag/PROMPT.mdevals/evals/explain-cli-flag/package.jsonevals/evals/validate-in-ci/EVAL.tsevals/evals/validate-in-ci/PROMPT.mdevals/evals/validate-in-ci/package.jsonevals/evals/wire-content-negotiation/EVAL.tsevals/evals/wire-content-negotiation/PROMPT.mdevals/evals/wire-content-negotiation/package.jsonevals/evals/wire-content-negotiation/vite.config.tsevals/lib/sandbox.tsevals/lib/tools.test.tsevals/lib/tools.tsevals/lib/transcript.tsevals/package.jsonevals/run-eval.tspackages/leadtype/AGENTS.mdpackages/leadtype/README.mdpackages/leadtype/package.jsonpackages/leadtype/scripts/generate-docs.tspackages/leadtype/src/cli.test.tspackages/leadtype/src/cli/generate.tspackages/leadtype/src/llm/index.tspackages/leadtype/src/llm/llm.ts
💤 Files with no reviewable changes (11)
- apps/example/src/routes/docs/search.tsx
- docs/llm.mdx
- apps/example/src/lib/docs.ts
- docs/lint.mdx
- docs/guides/bundle-package-docs.mdx
- docs/remark.mdx
- docs/convert.mdx
- docs/guides/connect-docs-site.mdx
- docs/components.mdx
- apps/example/src/components/docs-mdx/command-tabs.tsx
- docs/search.mdx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Preferunknownoveranywhen the type is genuinely unknown
Use const assertions (as const) for immutable values and literal types
Leverage TypeScript's type narrowing instead of type assertions
Files:
apps/example/src/routes/docs/reference/convert.tsxapps/example/src/routes/docs/reference/remark.tsxapps/example/playwright.config.tsapps/example/src/routes/docs/authoring/frontmatter.tsxapps/example/src/routes/docs/reference/llm.tsxapps/example/src/components/site-footer.tsxapps/example/src/routes/docs/build/connect-docs-site.tsxapps/example/src/routes/docs/authoring/components.tsxevals/evals/wire-content-negotiation/vite.config.tsapps/example/src/routes/docs/build/bundle-package-docs.tsxapps/example/src/routes/docs/quickstart.tsxapps/example/src/routes/__root.tsxevals/evals/validate-in-ci/EVAL.tspackages/leadtype/src/llm/index.tsapps/example/src/components/not-found.tsxapps/example/src/routes/docs/reference/cli.tsxevals/evals/explain-cli-flag/EVAL.tsapps/example/src/routes/docs/build/validate-in-ci.tsxapps/example/vite.config.tsevals/lib/transcript.tsapps/example/src/routes/docs/reference/search.tsxevals/lib/sandbox.tsevals/lib/tools.test.tsdocs/docs.config.tsapps/example/src/components/site-header.tsxevals/evals/bundle-own-docs/EVAL.tsapps/example/src/routes/index.tsxpackages/leadtype/src/llm/llm.tsevals/lib/tools.tsapps/example/src/routes/docs/how-it-works.tsxapps/example/src/routes/docs/reference/lint.tsxevals/run-eval.tsevals/evals/wire-content-negotiation/EVAL.tsapps/example/src/router.tsxapps/example/src/routeTree.gen.tspackages/leadtype/scripts/generate-docs.tsapps/example/src/components/docs-mdx/mermaid.tsxpackages/leadtype/src/cli/generate.tspackages/leadtype/src/cli.test.ts
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions
Preferfor...ofloops over.forEach()and indexedforloops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Useconstby default,letonly when reassignment is needed, nevervar
Alwaysawaitpromises in async functions - don't forget to use the return value
Useasync/awaitsyntax instead of promise chains for better readability
Handle errors appropriately in async code with try-catch blocks
Don't use async functions as Promise executors
Removeconsole.log,debugger, andalertstatements from production code
ThrowErrorobjects with descriptive messages, not strings or other values
Usetry-catchblocks meaningfully - don't catch errors just to rethrow them
Prefer early returns over nested conditionals for error cases
Extract complex conditions into well-named boolean variables
Use early returns to reduce nesting
Prefer simple conditionals over nested ternary operators
Don't useeval()or assign directly todocument.cookie
Avoid spread syntax in accumulators within loops
Use top-level regex literals instead of creating them in loops
Prefer specific imports over namespace imports
Use descriptive names for functions, variables, and types for meaningful naming
Add comments for complex logic, but prefer self-documenting code
Files:
apps/example/src/routes/docs/reference/convert.tsxapps/example/src/routes/docs/reference/remark.tsxapps/example/playwright.config.tsapps/example/src/routes/docs/authoring/frontmatter.tsxapps/example/src/routes/docs/reference/llm.tsxapps/example/src/components/site-footer.tsxapps/example/src/routes/docs/build/connect-docs-site.tsxapps/example/src/routes/docs/authoring/components.tsxevals/evals/wire-content-negotiation/vite.config.tsapps/example/src/routes/docs/build/bundle-package-docs.tsxapps/example/src/routes/docs/quickstart.tsxapps/example/src/routes/__root.tsxevals/evals/validate-in-ci/EVAL.tspackages/leadtype/src/llm/index.tsapps/example/src/components/not-found.tsxapps/example/src/routes/docs/reference/cli.tsxevals/evals/explain-cli-flag/EVAL.tsapps/example/src/routes/docs/build/validate-in-ci.tsxapps/example/vite.config.tsevals/lib/transcript.tsapps/example/src/routes/docs/reference/search.tsxevals/lib/sandbox.tsevals/lib/tools.test.tsdocs/docs.config.tsapps/example/src/components/site-header.tsxevals/evals/bundle-own-docs/EVAL.tsapps/example/src/routes/index.tsxpackages/leadtype/src/llm/llm.tsevals/lib/tools.tsapps/example/src/routes/docs/how-it-works.tsxapps/example/src/routes/docs/reference/lint.tsxevals/run-eval.tsevals/evals/wire-content-negotiation/EVAL.tsapps/example/src/router.tsxapps/example/src/routeTree.gen.tspackages/leadtype/scripts/generate-docs.tsapps/example/src/components/docs-mdx/mermaid.tsxpackages/leadtype/src/cli/generate.tspackages/leadtype/src/cli.test.ts
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{jsx,tsx}: Use function components over class components in React
Call hooks at the top level only, never conditionally
Specify all dependencies in hook dependency arrays correctly
Use thekeyprop for elements in iterables (prefer unique IDs over array indices)
Nest children between opening and closing tags instead of passing as props
Don't define components inside other components
AvoiddangerouslySetInnerHTMLunless absolutely necessary
Use proper image components (e.g., Next.js<Image>) over<img>tags
Use Next.js<Image>component for images
Usenext/heador App Router metadata API for head elements in Next.js
Use Server Components for async data fetching instead of async Client Components in Next.js
Use ref as a prop instead ofReact.forwardRefin React 19+
Files:
apps/example/src/routes/docs/reference/convert.tsxapps/example/src/routes/docs/reference/remark.tsxapps/example/src/routes/docs/authoring/frontmatter.tsxapps/example/src/routes/docs/reference/llm.tsxapps/example/src/components/site-footer.tsxapps/example/src/routes/docs/build/connect-docs-site.tsxapps/example/src/routes/docs/authoring/components.tsxapps/example/src/routes/docs/build/bundle-package-docs.tsxapps/example/src/routes/docs/quickstart.tsxapps/example/src/routes/__root.tsxapps/example/src/components/not-found.tsxapps/example/src/routes/docs/reference/cli.tsxapps/example/src/routes/docs/build/validate-in-ci.tsxapps/example/src/routes/docs/reference/search.tsxapps/example/src/components/site-header.tsxapps/example/src/routes/index.tsxapps/example/src/routes/docs/how-it-works.tsxapps/example/src/routes/docs/reference/lint.tsxapps/example/src/router.tsxapps/example/src/components/docs-mdx/mermaid.tsx
**/*.{jsx,tsx,html}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{jsx,tsx,html}: Use semantic HTML and ARIA attributes for accessibility: provide meaningful alt text for images, use proper heading hierarchy, add labels for form inputs, include keyboard event handlers alongside mouse events, use semantic elements instead of divs with roles
Addrel="noopener"when usingtarget="_blank"on links
Files:
apps/example/src/routes/docs/reference/convert.tsxapps/example/src/routes/docs/reference/remark.tsxapps/example/src/routes/docs/authoring/frontmatter.tsxapps/example/src/routes/docs/reference/llm.tsxapps/example/src/components/site-footer.tsxapps/example/src/routes/docs/build/connect-docs-site.tsxapps/example/src/routes/docs/authoring/components.tsxapps/example/src/routes/docs/build/bundle-package-docs.tsxapps/example/src/routes/docs/quickstart.tsxapps/example/src/routes/__root.tsxapps/example/src/components/not-found.tsxapps/example/src/routes/docs/reference/cli.tsxapps/example/src/routes/docs/build/validate-in-ci.tsxapps/example/src/routes/docs/reference/search.tsxapps/example/src/components/site-header.tsxapps/example/src/routes/index.tsxapps/example/src/routes/docs/how-it-works.tsxapps/example/src/routes/docs/reference/lint.tsxapps/example/src/router.tsxapps/example/src/components/docs-mdx/mermaid.tsx
**/index.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Avoid barrel files (index files that re-export everything)
Files:
packages/leadtype/src/llm/index.tsapps/example/src/routes/index.tsx
**/*.{test,spec}.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{test,spec}.{js,ts,jsx,tsx}: Write assertions insideit()ortest()blocks
Avoid done callbacks in async tests - use async/await instead
Don't use.onlyor.skipin committed code
Keep test suites reasonably flat - avoid excessivedescribenesting
Files:
evals/lib/tools.test.tspackages/leadtype/src/cli.test.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: inthhq/leadtype
Timestamp: 2026-05-09T16:25:33.574Z
Learning: Leadtype converts a single MDX source into four artifacts: a website for humans, llms.txt for agents, topic-scoped full-context bundles, and a static search index
Learnt from: CR
Repo: inthhq/leadtype
Timestamp: 2026-05-09T16:25:33.574Z
Learning: Validate frontmatter, navigation structure, and internal links before publishing using leadtype lint
Learnt from: CR
Repo: inthhq/leadtype
Timestamp: 2026-05-09T16:25:33.574Z
Learning: Ship agent-readable docs inside npm packages so IDEs and coding agents can read documentation offline
Learnt from: CR
Repo: inthhq/leadtype
Timestamp: 2026-05-09T16:25:33.574Z
Learning: Use the remark plugin stack to flatten MDX components into markdown that agents can process
🪛 ast-grep (0.42.1)
evals/lib/tools.ts
[warning] 85-85: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(pattern, flags)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
🪛 LanguageTool
evals/evals/validate-in-ci/PROMPT.md
[uncategorized] ~1-~1: The official name of this software platform is spelled with a capital “H”.
Context: Add a GitHub Actions workflow at .github/workflows/lint-docs.yml that runs `lea...
(GITHUB)
packages/leadtype/AGENTS.md
[uncategorized] ~54-~54: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...stack that flattens MDX components into markdown. - Search...
(MARKDOWN_NNP)
evals/README.md
[grammar] ~21-~21: Ensure spelling is correct
Context: ... call into a transcript JSON. 6. Spawns vitest against the fixture's EVAL.ts, which ...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[grammar] ~23-~23: Ensure spelling is correct
Context: ...terally cannot see anything outside the tempdir. ## Setup ```bash cd evals cp .env.example ...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
docs/how-it-works.mdx
[uncategorized] ~33-~33: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...old headings, a <TypeTable> becomes a markdown table. The flattened markdown is what e...
(MARKDOWN_NNP)
[style] ~73-~73: Consider a different adjective to strengthen your wording.
Context: ...t over HTTP and follow absolute URLs to deeper context. Useless inside an npm tarball,...
(DEEP_PROFOUND)
docs/reference/lint.mdx
[uncategorized] ~164-~164: The official name of this software platform is spelled with a capital “H”.
Context: ...ateso content errors fail fast. - Use--format githubin GitHub Actions and--format json` ...
(GITHUB)
docs/authoring/components.mdx
[uncategorized] ~9-~9: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...ipeline can flatten each component into markdown for agents, search, and `llms-full/*.tx...
(MARKDOWN_NNP)
[uncategorized] ~17-~17: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...ne per tab. - A <TypeTable> becomes a markdown table. - A <Mermaid> becomes a fenced...
(MARKDOWN_NNP)
[uncategorized] ~125-~125: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ... install or run commands. Flattens to a markdown table with one row per manager. Use `m...
(MARKDOWN_NNP)
docs/build/bundle-package-docs.mdx
[style] ~77-~77: The double modal “needs shared” is nonstandard (only accepted in certain dialects). Consider “to be shared”.
Context: ...ters are explicit. If the package needs shared overview pages, list them too. `--exclu...
(NEEDS_FIXED)
docs/reference/remark.mdx
[uncategorized] ~51-~51: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...mandTabsToMarkdown—→ markdown table. 10.remarkStepsToMarkdown—<...
(MARKDOWN_NNP)
[uncategorized] ~54-~54: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...ypeTable>and→ markdown table. 13.remarkAccordionToMarkdown` ...
(MARKDOWN_NNP)
[uncategorized] ~102-~102: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...file, finds the named type, and emits a markdown table with one row per property. The re...
(MARKDOWN_NNP)
[style] ~109-~109: ‘almost never’ might be wordy. Consider a shorter alternative.
Context: ...d the converted .md first. The fix is almost never reordering — it's usually a custom plug...
(EN_WORDINESS_PREMIUM_ALMOST_NEVER)
docs/reference/cli.mdx
[uncategorized] ~109-~109: The official name of this software platform is spelled with a capital “H”.
Context: ...fmt>|pretty|pretty, json, or github(annotation format). | |--ignore <gl...
(GITHUB)
docs/build/validate-in-ci.mdx
[uncategorized] ~24-~24: The official name of this software platform is spelled with a capital “H”.
Context: ...end the schema. ## GitHub Actions Use --format github so violations render as inline annotat...
(GITHUB)
[style] ~79-~79: Consider using a synonym to be more concise.
Context: ... ## What to fix first When CI fails on a lot of violations, fix them in this order: 1....
(A_LOT_OF)
docs/build/connect-docs-site.mdx
[uncategorized] ~184-~184: The official name of this software platform is spelled with a capital “H”.
Context: ...fore the converter writes anything. Use --format github in CI to get inline annotations on the...
(GITHUB)
docs/reference/llm.mdx
[style] ~32-~32: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...ened into one file. Use for agents with very large context windows. | | `/docs/llms-f...
(EN_WEAK_ADJECTIVE)
docs/methodology.mdx
[style] ~20-~20: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...sted platform when you want zero infra. Use leadtype when you want to **own the doc...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
🪛 markdownlint-cli2 (0.22.1)
evals/evals/validate-in-ci/PROMPT.md
[warning] 1-1: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
evals/evals/explain-cli-flag/PROMPT.md
[warning] 1-1: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
evals/evals/bundle-own-docs/PROMPT.md
[warning] 1-1: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
evals/evals/wire-content-negotiation/PROMPT.md
[warning] 1-1: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
evals/README.md
[warning] 68-68: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 89-89: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔍 Remote MCP Context7
Perfect! Now I have the documentation context. Let me compile a concise summary of the relevant findings for PR review.
Additional Context for PR Review
Based on documentation review of the key libraries used in this PR, here's the relevant validation context:
1. Vite Plugin & Middleware Configuration
The PR's custom leadtype:markdown-negotiation Vite plugin using the configureServer hook follows the documented pattern. According to Vite v7 documentation:
- The
configureServerhook correctly provides access to the dev server instance for custom middleware injection - The plugin can return a post-hook that runs after internal middlewares are installed, which is appropriate for intercepting and modifying responses
- Using
server.middlewares.use()to add custom middleware that manipulates response headers (thecharset=utf-8append) is the standard pattern
Key validation: The implementation approach of checking Accept headers and rewriting paths in middleware aligns with Vite's recommended patterns for content negotiation.
2. TanStack Router Routing Structure
The PR restructures routes using createFileRoute with nested paths. Documentation confirms:
- File-based routing with
createFileRoute('/path')({ component: ... })is the standard pattern - NotFound handling: The pattern of setting
notFoundComponenton both root route (__root.tsx) and router-leveldefaultNotFoundComponentmatches the documented best practice for not-found errors - The PR adds both: a dedicated
NotFoundcomponent at__root.tsxand a router-leveldefaultNotFoundComponent: NotFoundinrouter.tsx
Key validation: This dual-layer approach provides proper fallback coverage and aligns with Tanstack Router's documented guidance: "If no suitable handler is found, the root route will handle it with a basic default component. It is highly recommended to configure a notFoundComponent for the root route or a router-wide defaultNotFoundComponent."
3. Vercel AI SDK Tools & Schemas
The PR's eval harness implements scoped tools using the AI SDK's tool system. Documentation confirms the correct pattern:
- Tools are defined with
tool()helper from theaipackage - Zod schemas are used to validate tool inputs (
z.object()with.describe()for field descriptions) - The
executefunction pattern is standard for tool implementation - The tools in
evals/lib/tools.ts(read, write, list, glob, grep, npm) follow the documented schema and execute function pattern
Key validation: The scoped tool implementation using zod schemas and async execute functions matches the documented Vercel AI SDK approach. The pattern of providing descriptive field descriptions helps guide model behavior—important for agent instructions.
Summary
The PR's implementation of three major components (Vite middleware, TanStack Router structure, and AI SDK tools) all follow documented best practices from their respective libraries:
- ✅ Vite plugin middleware approach for content negotiation is correct
- ✅ NotFound component routing pattern provides proper error boundary coverage
- ✅ Scoped tools implementation with Zod schemas matches AI SDK documentation
🔇 Additional comments (73)
.gitignore (2)
27-27: LGTM: Anchored build pattern improves specificity.Changing
buildto/buildrestricts the ignore to the root-level build directory only, preventing unintended matches in nested paths. This aligns with the PR objectives.
41-45: LGTM: Comprehensive eval artifact exclusion.The patterns correctly exclude eval harness outputs (tarballs, results, and agent eval directories). Using both
evals/__agent_eval__/andevals/**/__agent_eval__/provides clarity even though the globstar pattern covers both cases.apps/example/src/components/site-footer.tsx (1)
3-3: GitHub footer link update looks correct.This aligns the footer target with the Leadtype repository and preserves the existing external-link safety behavior.
evals/.env.example (1)
1-5: Env template addition is clear and appropriate.The new key placeholder and comments are concise and useful for harness setup.
evals/package.json (1)
1-18: Eval package manifest is well-structured.Scripts and dev dependencies are coherent with the custom eval harness workflow.
apps/example/src/routes/docs/reference/llm.tsx (1)
4-7: Route path and MDX source move are correctly aligned.The updated route target and document import are consistent with the new docs IA location.
docs/build/validate-in-ci.mdx (1)
1-86: Strong CI guidance and clear failure triage flow.The page is practical, concrete, and gives a clean lint-first workflow for teams.
packages/leadtype/AGENTS.md (1)
1-56: AGENTS.md structure is clear and agent-friendly.The sectioning and relative topic links make offline navigation straightforward.
apps/example/src/routes/docs/build/validate-in-ci.tsx (1)
1-12: Looks good — route registration and MDX rendering are correctly wired.evals/evals/validate-in-ci/package.json (1)
1-11: Fixture manifest is clean and fit-for-purpose.docs/authoring/frontmatter.mdx (1)
1-109: Excellent addition — clear, comprehensive frontmatter and linting guidance.apps/example/src/routes/docs/authoring/frontmatter.tsx (1)
1-12: Route setup is correct and consistent with the docs IA structure.evals/evals/explain-cli-flag/package.json (1)
1-11: This fixture package config looks solid.evals/evals/bundle-own-docs/package.json (1)
1-15: Package fixture configuration is appropriate for the eval scenario.evals/evals/wire-content-negotiation/package.json (1)
1-12: This fixture manifest is correctly structured for the test harness.docs/docs.config.ts (1)
3-50: Config rewrite looks consistent with the new IA and artifact narrative.The updated
productcopy and top-levelgroupsstructure are coherent and release-ready.apps/example/src/components/not-found.tsx (1)
5-28: 404 component is clean and well integrated.Layout composition and recovery path back to docs are solid.
docs/reference/lint.mdx (1)
1-169: Comprehensive lint reference—scope and structure are strong.Rules, API surface, result schema, and CI guidance are clear and actionable.
apps/example/src/routes/docs/reference/lint.tsx (1)
4-8: Route migration is consistent and correctly wired.The new path and MDX source update match the IA move.
docs/methodology.mdx (1)
9-41: Positioning rewrite is clear and effective.The ownership boundaries and pairing guidance are easy to follow.
docs/authoring/components.mdx (1)
22-247: Great component-contract documentation depth.This gives authors a practical, implementation-ready map of flattening behavior.
apps/example/src/routes/docs/authoring/components.tsx (1)
4-8: Authoring route move is correctly implemented.Path and source doc updates are aligned with the IA restructure.
apps/example/src/routes/docs/how-it-works.tsx (1)
3-12: Route wiring looks goodThe new
/docs/how-it-worksroute cleanly maps to the MDX page and follows the existing route-module pattern.docs/build/bundle-package-docs.mdx (1)
28-165: Solid bundle-mode documentationThis is clear, actionable, and covers both producer and consumer sides of the
AGENTS.mdworkflow well.apps/example/src/routes/docs/build/bundle-package-docs.tsx (1)
4-8: Import/path migration is correctThe route now points at the new docs location and stays aligned with the restructured IA.
docs/reference/cli.mdx (1)
23-143: CLI reference is thorough and well-structuredThe page clearly distinguishes site vs bundle output, documents exit codes, and gives useful JSON-mode behavior details.
apps/example/src/routes/docs/reference/cli.tsx (1)
3-12: Route addition is clean
/docs/reference/cliis wired correctly and renders the new MDX page as expected.docs/reference/search.mdx (1)
17-153: Search reference is strongGreat coverage of the end-to-end flow (indexing, querying, retrieval helpers, streaming, and guardrails) with practical code examples.
apps/example/src/routes/docs/reference/search.tsx (1)
3-12: Route wiring looks correct and clean.MDX import, path registration, and route component rendering are all consistent with the docs IA move.
docs/build/connect-docs-site.mdx (1)
8-211: Strong end-to-end build guide.The flow, middleware example, and verification checklist are clear and actionable.
apps/example/src/routes/docs/build/connect-docs-site.tsx (1)
4-12: Path and import updates are consistent with the new IA.This correctly re-points both the route and MDX source to the
build/section.docs/quickstart.mdx (1)
44-87: Quickstart narrative is clear and correctly distinguishes site vs bundle outputs.The examples and artifact expectations are easy to follow for first-time setup.
apps/example/src/routes/docs/quickstart.tsx (1)
3-12: Route setup is good.This cleanly exposes the new quickstart page under
/docs/quickstart.packages/leadtype/package.json (1)
62-67: Publishing whitelist update is correct.Including
AGENTS.mdinfilesaligns the npm tarball with the new bundle discovery flow.evals/evals/wire-content-negotiation/vite.config.ts (1)
1-8: Fixture scaffold is appropriate for the eval scenario.The minimal config and explicit placeholder make the expected agent edit target clear.
apps/example/src/router.tsx (1)
2-11: Default not-found fallback is a solid addition.
defaultNotFoundComponentwiring is clean and improves global unmatched-route handling.apps/example/src/routes/__root.tsx (1)
34-34: Explicit rootnotFoundComponentwiring looks good.This keeps unmatched-route rendering deterministic at the route definition point.
packages/leadtype/src/llm/index.ts (1)
2-3: Public export surface update is clean and consistent.Re-exporting
generateAgentsMdwith its config/result types makes the bundle API discoverable from the module entrypoint.Also applies to: 11-11
apps/example/src/routes/docs/reference/convert.tsx (1)
4-4: Route path and MDX source relocation are correctly aligned.This matches the new
/docs/reference/*structure without introducing behavior regressions.Also applies to: 6-6
apps/example/src/routes/docs/reference/remark.tsx (1)
4-4:remarkdoc route migration is consistent with the new IA.Import target and route id now match the
referencenamespace.Also applies to: 6-6
docs/reference/convert.mdx (1)
21-42: API coverage and plugin-order guidance are clear and implementation-aligned.The page cleanly documents
convertAllMdxoptions and correctly emphasizesremarkIncludeordering.Also applies to: 81-92
evals/README.md (2)
68-81: 💤 Low valueAdd language specifier to fenced code blocks.
The directory layout and results table code blocks should have a language specifier like
textorplaintextfor consistency and to satisfy linting.
1-103: LGTM!The README provides comprehensive documentation of the eval harness, clearly explaining the treatment vs control methodology, setup steps, CLI flags, and how to interpret results. The technical terms flagged by static analysis (vitest, tempdir) are correct.
apps/example/src/components/docs-mdx/mermaid.tsx (1)
1-20: LGTM!The refactor from a static placeholder to Streamdown-based rendering is clean. The client component correctly uses the mermaid plugin, and the fallback to empty string for non-string children handles edge cases gracefully.
evals/evals/bundle-own-docs/PROMPT.md (1)
1-11: LGTM!The eval prompt is clear and actionable with well-structured steps. The missing top-level heading flagged by markdownlint is appropriate here—this is an agent task description, not documentation requiring formal structure.
apps/example/playwright.config.ts (1)
7-27: LGTM!The
PORTLESS_HTTP_PORTconstant and explicit env overrides ensure consistent configuration between Playwright and the dev scripts. Spreadingprocess.envpreserves the existing environment while overriding the specificportlesssettings.apps/example/src/routes/index.tsx (1)
1-7: LGTM!The redirect pattern using
throw redirect({ to: "/docs" })inbeforeLoadfollows TanStack Router's documented approach for route-level redirects. Clean and minimal.docs/reference/remark.mdx (1)
1-109: LGTM!Comprehensive documentation of the remark plugin stack. The Mermaid diagram clearly illustrates the processing order, and the code examples demonstrate both basic usage and advanced patterns like plugin replacement with options.
packages/leadtype/scripts/generate-docs.ts (1)
1-55: LGTM!Clean migration from the
llms.txtflow toAGENTS.md. The script properly:
- Cleans up legacy artifacts (
llms.txt,llms-full.txt)- Validates navigation groups with fail-fast behavior
- Emits
AGENTS.mdat the package root for agent discoveryThe validation step at lines 31-42 is a good safety net that catches config typos before they ship.
evals/evals/wire-content-negotiation/EVAL.ts (1)
6-11: TheprojectRootresolution is correct. TRANSCRIPT_PATH is set to<tempDir>/__transcript__/transcript.json, andresolve(dirname(process.env.TRANSCRIPT_PATH), "..")correctly resolves to<tempDir>(the project root), which matches the comment's description.docs/index.mdx (1)
13-67: Landing page restructuring is coherent and well-scoped.The new “choose your path” + “what you get” flow reads clearly and matches the bundle/site split introduced in this PR.
evals/evals/bundle-own-docs/EVAL.ts (1)
17-63: Good coverage for the bundle workflow transcript checks.These assertions directly validate the AGENTS.md discovery path, bundle guide read, and
npm pack --dry-runbehavior end-to-end.apps/example/package.json (1)
7-9: Script and dependency updates look consistent with the docs pipeline changes.The pre-convert step before dev/build and the Mermaid package addition align with the new docs rendering flow.
Also applies to: 34-45
evals/evals/validate-in-ci/EVAL.ts (1)
15-54: CI fixture assertions are well targeted.This validates both discovery (
AGENTS.md/docs reads) and concrete workflow output (lint-docs.ymlflags), which is the right contract for this eval.evals/lib/transcript.ts (1)
29-56: Transcript helper API is clean and cohesive.
transcriptPathFor,writeTranscript, andreadTranscriptare straightforward and match the harness/test integration points.evals/lib/tools.test.ts (1)
18-100: Great baseline coverage for scoped path safety.The escape-path rejection cases plus transcript assertions give strong confidence in the tool sandbox boundaries.
apps/example/src/routeTree.gen.ts (1)
1-9: Auto-generated file - no review needed.This file is auto-generated by TanStack Router as indicated by the header comments. The changes correctly reflect the new route structure (
/docs/quickstart,/docs/how-it-works,/docs/reference/*,/docs/build/*,/docs/authoring/*).apps/example/vite.config.ts (3)
23-28: LGTM! Precompiled regex patterns at module level.Good practice extracting these patterns as top-level constants—avoids recreating them on each request. As per coding guidelines: "Use top-level regex literals instead of creating them in loops."
30-58: LGTM! Clean URL rewriting logic.The function correctly handles edge cases: missing accept header, already-
.mdURLs, non-docs paths, and browser requests that includetext/html. The query string preservation on line 55-57 is a nice touch.
81-114: LGTM! Middleware plugin follows Vite patterns.The plugin correctly hooks both
configureServerandconfigurePreviewServer, and the middleware properly callsnext()in all paths. The external tools context confirms this matches Vite's documentedconfigureServerhook pattern.evals/lib/sandbox.ts (2)
11-25: LGTM! Clear tarball discovery with helpful error messages.The function provides actionable guidance when the tarball is missing, directing users to run the prerequisite command.
74-97: LGTM! Well-isolated npm subprocess.Setting
HOME: tempDirprevents npm from polluting the user's cache, andNPM_CONFIG_LOGLEVEL: "error"reduces noise. The error message correctly includes both exit code and stderr.packages/leadtype/src/llm/llm.ts (2)
826-843: LGTM! Well-defined configuration types.The
AgentsMdConfigtype clearly documents each field with JSDoc comments, and the optionaldocsSubdirwith a sensible default provides flexibility without complexity.
864-948: LGTM! Clean AGENTS.md generation with proper edge case handling.The function correctly:
- Skips
bestStartingPointsentries that don't exist in source docs (lines 897-901) rather than emitting broken links- Documents why
agentGuidanceis intentionally omitted (lines 938-941)- Uses consistent relative path format (
./docs/<path>.md)Based on learnings: "Ship agent-readable docs inside npm packages so IDEs and coding agents can read documentation offline."
docs/reference/llm.mdx (2)
1-5: LGTM! Proper frontmatter with group assignment.The page correctly declares
group: referencewhich will place it in the reference section of the navigation.
104-129: LGTM! Clear API documentation with practical options table.The
generateAgentsMdsection clearly explains the difference fromgenerateLlmsTxt(relative paths vs absolute URLs), and line 125 correctly notes thatagentGuidanceis intentionally ignored for offline agents.packages/leadtype/src/cli/generate.ts (2)
59-76: LGTM! Well-structured discriminated result type.The
mode: "site" | "bundle"field combined with optional file paths creates a clear discriminated union pattern. Consumers can checkmodeto know whichfilesproperties will be populated.
392-448: LGTM! Clean branching between site and bundle modes.The implementation correctly:
- Runs
convertAllMdxin both modes (line 385-390)- Generates
AGENTS.mdonly in bundle mode- Skips
llms.txt,llms-full, and search artifacts in bundle mode- Populates mode-appropriate result fields
evals/lib/tools.ts (3)
17-29: LGTM! Solid path sandboxing implementation.The function correctly:
- Strips leading slashes so absolute-looking paths become relative (line 21)
- Uses
path.resolveto normalize traversal attempts like../..- Validates the resolved path starts with
root + path.septo prevent escapesThe check on line 25 (
resolved !== root && !resolved.startsWith(root + path.sep)) properly handles both exact root matches and subdirectories.
140-185: LGTM! Read and write tools properly sandboxed.Both tools:
- Use
resolveScopedto validate paths- Record operations to transcript with timing
- The write tool correctly creates parent directories and tracks modified files
277-340: LGTM! npm tool has appropriate restrictions.The implementation correctly:
- Allowlists only
packandinstallsubcommands (line 297)- Requires all args to start with
-(flag-form only) to prevent arbitrary file/package injection (lines 300-305)- Isolates npm with restricted env (PATH, HOME, NPM_CONFIG_LOGLEVEL)
This prevents agents from running dangerous commands like
npm publishor installing arbitrary packages by name.apps/example/src/styles.css (2)
253-287: LGTM! Clean CSS-only step numbering with visual connectors.The implementation uses:
- CSS counters for automatic numbering (lines 254, 259, 264)
- Pseudo-elements for the numbered circle and vertical connector line
- Proper spacing with
pb-8andpl-12for the step layout:last-childhandling to avoid trailing connector (line 268)This is a solid approach that keeps the markup simple while achieving the connected-steps visual.
421-433: LGTM! Mermaid container styling updates.The nested selector targeting
[data-streamdown="mermaid-block"]removes conflicting styles from the Streamdown wrapper, allowing the mermaid diagram to render cleanly.
| function forceUtf8OnTextResponses(res: Res) { | ||
| const original = res.setHeader.bind(res); | ||
| res.setHeader = (name, value) => { | ||
| if ( | ||
| typeof name === "string" && | ||
| name.toLowerCase() === "content-type" && | ||
| typeof value === "string" && | ||
| TEXT_CONTENT_TYPE_PATTERN.test(value) && | ||
| !CHARSET_PATTERN.test(value) | ||
| ) { | ||
| return original(name, `${value}; charset=utf-8`); | ||
| } | ||
| return original(name, value); | ||
| }; | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | 💤 Low value
Potential issue: original setHeader binding may not preserve all overloads.
The monkeypatch approach works but res.setHeader in Node's HTTP API can accept arrays and has specific return type expectations. The current implementation handles the common case but consider whether the original function's this context is correctly preserved for all call patterns.
That said, .bind(res) on line 66 should handle this correctly, and the patched function delegates to original for non-matching cases.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/example/vite.config.ts` around lines 65 - 79, The monkeypatch in
forceUtf8OnTextResponses currently binds res.setHeader to original and assumes
string arguments; update the patch to preserve all overloads and this context by
capturing the original as done (original = res.setHeader.bind(res)) but
implement the wrapper using a rest-args signature (e.g., (...args)) and call the
original via Reflect.apply(original, res, args) so return value and this are
preserved; additionally, handle non-string/array header values safely by
checking types before modifying value (only modify when name is a string equal
to "content-type" and value is a string matching TEXT_CONTENT_TYPE_PATTERN
without CHARSET_PATTERN), otherwise delegate to original unchanged.
| npm run build | ||
| ``` | ||
|
|
||
| Run lint first so missing or malformed frontmatter fails before the converter writes anything. Use `--format github` in CI to get inline annotations on the PR. Use `--json` on `generate` so automation can read the resolved groups and search index stats. |
There was a problem hiding this comment.
Capitalize product name in prose at Line 184.
Keep the CLI flag as --format github, but in surrounding text use “GitHub” (capital H) for the platform name.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~184-~184: The official name of this software platform is spelled with a capital “H”.
Context: ...fore the converter writes anything. Use --format github in CI to get inline annotations on the...
(GITHUB)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/build/connect-docs-site.mdx` at line 184, Update the prose around the
CLI flag so the platform name is correctly capitalized: keep the flag text
exactly as `--format github` but change the surrounding plain-text reference to
the platform to “GitHub” (capital H) in the sentence that currently reads "Use
`--format github` in CI to get inline annotations on the PR."
| Full docs at [docs.example.com](https://docs.example.com/docs). Highlights: | ||
|
|
||
| - `docs/llms.txt` | ||
| - `docs/components.md` | ||
| - `docs/convert.md` | ||
| - `docs/remark.md` | ||
| - `docs/llm.md` | ||
| - `docs/search.md` | ||
| - `docs/lint.md` | ||
| - [Quickstart](https://docs.example.com/docs/quickstart) — five-minute happy path. | ||
| - [How it works](https://docs.example.com/docs/how-it-works) — the mental model. | ||
| - [Build a docs site](https://docs.example.com/docs/build/connect-docs-site) — wire into your build. | ||
| - [Bundle docs into a package](https://docs.example.com/docs/build/bundle-package-docs) — ship docs inside an npm tarball. | ||
| - [CLI reference](https://docs.example.com/docs/reference/cli) — every flag. |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
for p in quickstart how-it-works build/connect-docs-site build/bundle-package-docs reference/cli; do
url="https://docs.example.com/docs/$p"
code=$(curl -s -o /dev/null -w "%{http_code}" "$url" || true)
echo "$code $url"
doneRepository: inthhq/leadtype
Length of output: 322
🏁 Script executed:
cat packages/leadtype/README.md | head -50Repository: inthhq/leadtype
Length of output: 1949
🏁 Script executed:
grep -r "docs.example.com" packages/leadtype/Repository: inthhq/leadtype
Length of output: 3022
🏁 Script executed:
grep -r "https://" packages/leadtype/README.md | head -20Repository: inthhq/leadtype
Length of output: 1112
🏁 Script executed:
fd -e md packages/leadtype/ -exec grep -l "docs\|documentation" {} \;Repository: inthhq/leadtype
Length of output: 314
🏁 Script executed:
cat packages/leadtype/package.json | jq '.homepage, .repository, .bugs' 2>/dev/null || cat packages/leadtype/package.json | grep -E "homepage|repository|bugs|url" | head -10Repository: inthhq/leadtype
Length of output: 74
🏁 Script executed:
find packages/leadtype -type d -name "docs" -o -name "doc" 2>/dev/nullRepository: inthhq/leadtype
Length of output: 41
🏁 Script executed:
grep -r "github.com\|leadtype" packages/leadtype/package.json | head -5Repository: inthhq/leadtype
Length of output: 81
🏁 Script executed:
cat packages/leadtype/package.jsonRepository: inthhq/leadtype
Length of output: 3638
🌐 Web query:
leadtype documentation site npm package
💡 Result:
No npm package named "leadtype" exists based on searches across npm registry, GitHub, and general web. The closest match is "leadconduit-types", a Node.js module for parsing lead data by type (e.g., phone, email, street) used in LeadConduit by ActiveProspect. Its documentation is on the npm page, GitHub repo (https://github.com/activeprospect/leadconduit-types#readme), and LeadConduit API docs (https://activeprospect.redoc.ly/docs/leadconduit/api/tag/Types/), listing supported types like phone, email, url, ssn, state, etc., with parsing examples such as types.phone.parse('(512) 789-1111'). Latest version 4.23.2 published Nov 2024, 935 weekly downloads.[1][2][3] Other lead-related packages include @leadcms/sdk (LeadCMS SDK/CLI),[4] @leadpipe/client (Leadpipe intent APIs client).[5] No dedicated documentation site for a "leadtype" package was found; queries returned lead management docs from unrelated services like Serviceform, EASI'R, LeadExec.[6][7][8]
Citations:
- 1: https://registry.npmjs.org/leadconduit-types
- 2: https://www.npmjs.com/package/leadconduit-types
- 3: https://activeprospect.redoc.ly/docs/leadconduit/api/tag/Types/
- 4: https://registry.npmjs.org/@leadcms/sdk
- 5: https://registry.npmjs.org/@leadpipe/client
- 6: https://docs.serviceform.com/lead-type?ab-redirect-url=&docAnchorId=undefined&docId=-qzjebFe3w3-ufx6QcS_a&hostName=docs.serviceform.com&queryTemplate=&title=Dynamic+forms
- 7: https://easir.io/endpoints/lead-types/index.html
- 8: https://leadexechelp.clickpointsoftware.com/en/articles/6136809-lead-type-settings-creating-lead-types
🏁 Script executed:
grep -r "homepage\|docs" . --include="*.json" --include="*.md" --exclude-dir=node_modules --exclude-dir=dist | grep -v "example.com" | grep -v ".test." | head -10Repository: inthhq/leadtype
Length of output: 1206
🏁 Script executed:
cat packages/leadtype/scripts/generate-docs.ts 2>/dev/null || echo "Script not found or unreadable"Repository: inthhq/leadtype
Length of output: 2220
🏁 Script executed:
cat README.md 2>/dev/null | head -30Repository: inthhq/leadtype
Length of output: 1429
🏁 Script executed:
ls -la | head -20Repository: inthhq/leadtype
Length of output: 1211
🏁 Script executed:
find . -maxdepth 2 -name "*.config.*" -o -name ".github" -type d | head -10Repository: inthhq/leadtype
Length of output: 91
🏁 Script executed:
cat docs/docs.config.tsRepository: inthhq/leadtype
Length of output: 1718
🏁 Script executed:
cat .github/workflows/*.yml 2>/dev/null | grep -E "deploy|docs|url" | head -20Repository: inthhq/leadtype
Length of output: 130
🏁 Script executed:
find .github -type f -name "*.yml" -o -name "*.yaml" | xargs ls -laRepository: inthhq/leadtype
Length of output: 215
Replace placeholder docs URLs before package publication.
The README links point to https://docs.example.com/docs/..., which is inaccessible (HTTP connection fails). These placeholders must be replaced with the actual production docs URL before the package is published, or users will encounter broken links. Update the 5 doc links (lines 39–45) and the example command (line 13) with the real docs domain once it's deployed.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/leadtype/README.md` around lines 39 - 45, Replace the placeholder
docs domain "https://docs.example.com" used across the README: update the five
links in the docs list (the Quickstart, How it works, Build a docs site, Bundle
docs into a package, and CLI reference) and also update the example command that
references the example docs URL (the example command on line 13) to the real
production docs domain once it's available; search for the string
"docs.example.com" in the README and substitute the canonical production docs
hostname so all links point to the live documentation.
| - **[Build a docs site](https://docs.example.com/docs/build/connect-docs-site)** — wire leadtype into your build to convert MDX, index search, and serve markdown to agents. | ||
| - **[Bundle docs into your package](https://docs.example.com/docs/build/bundle-package-docs)** — ship `AGENTS.md` plus topic markdown inside the npm tarball so coding agents auto-discover them from `node_modules/<your-package>/AGENTS.md`. | ||
|
|
||
| ## Install | ||
|
|
||
| ```bash | ||
| pnpm add leadtype | ||
| ``` | ||
|
|
||
| ## Basic Usage | ||
|
|
||
| ### Own MDX components in your app | ||
|
|
||
| `leadtype` does not export prebuilt React, Vue, Nuxt, Svelte, or Astro components. Define the MDX component map in the docs app that renders your pages. | ||
|
|
||
| ## Live Example App | ||
| ## 30-second example | ||
|
|
||
| The repo includes a canonical consumer demo at `apps/example`. | ||
|
|
||
| - Renders real `.mdx` fixture files through app-owned `mdxComponents`. | ||
| - Uses TanStack Start for SSR and hydration coverage. | ||
| - Shows extracted `ExtractedTypeTable` output while keeping pipeline fixtures in the validation path. | ||
|
|
||
| Local workflow: | ||
| For a hosted docs site: | ||
|
|
||
| ```bash | ||
| bun install | ||
| bun run dev | ||
| npx leadtype generate --src . --out public --base-url https://docs.example.com | ||
| ``` | ||
|
|
||
| Pipeline and browser checks: | ||
| For an npm-bundled doc set: | ||
|
|
||
| ```bash | ||
| bun run --filter example pipeline:build | ||
| bun run --filter example pipeline:test | ||
| bun run --filter example test:e2e | ||
| npx leadtype generate --bundle --src . --out packages/my-package | ||
| ``` | ||
|
|
||
| Validation layers: | ||
|
|
||
| - Package unit tests in `packages/leadtype/src/**/*.test.ts*` cover framework-neutral conversion, search, linting, and generated docs behavior. | ||
| - Pipeline fixtures in `apps/example/scripts` and `apps/example/content` cover MDX conversion, LLM generation, and `ExtractedTypeTable`. | ||
| - The TanStack Start demo app in `apps/example/src` covers real browser rendering and hydration. | ||
|
|
||
| ## Where This Fits | ||
| The first produces `public/llms.txt`, `public/docs/llms-full/*.txt`, `public/docs/search-index.json`, and `public/docs/*.md`. The second produces `packages/my-package/AGENTS.md` and `packages/my-package/docs/*.md` — auto-discoverable by [25+ coding agents](https://agents.md) once the package is installed. | ||
|
|
||
| `leadtype` is not a hosted docs platform or a complete docs-site framework. Use tools such as Mintlify, Fumadocs, or Starlight when the primary job is shipping a polished docs website quickly. | ||
| ## Documentation | ||
|
|
||
| Use this package when the primary job is shared docs infrastructure: MDX-to-markdown conversion, LLM bundles, linting, static search artifacts, answer helpers, and agent-facing docs output that can feed multiple apps and tools. | ||
| Full docs at [docs.example.com](https://docs.example.com/docs): | ||
|
|
||
| The pipeline entry points are framework-neutral. React, Vue, Nuxt, Svelte, Astro, and other stacks can use conversion, LLM, lint, and search APIs while owning their own runtime component rendering. | ||
| - [Quickstart](https://docs.example.com/docs/quickstart) | ||
| - [How it works](https://docs.example.com/docs/how-it-works) | ||
| - [Frontmatter](https://docs.example.com/docs/authoring/frontmatter) | ||
| - [CLI reference](https://docs.example.com/docs/reference/cli) | ||
| - [Methodology](https://docs.example.com/docs/methodology) — how leadtype differs from Fumadocs, Starlight, and Mintlify |
There was a problem hiding this comment.
Replace placeholder docs host in user-facing links
Lines 30-63 use https://docs.example.com/... as primary documentation links. If that host isn’t live for this project, users will hit dead links from the README.
Use the real docs origin (or repository-relative links) before merge so the README remains navigable.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@README.md` around lines 30 - 63, Replace the placeholder docs host
"https://docs.example.com" used across the README (including the 30-second
example commands and links to Quickstart, How it works, Frontmatter, CLI
reference, Methodology, and the two example outputs like AGENTS.md/llms.txt)
with the real documentation origin or repository-relative paths; update the npx
generate examples to use the real --base-url or remove the host so they work
locally, and ensure all user-facing links point to live docs or relative URLs
before merging.
- site-header markdownHrefForPath: normalize trailing slash before checking
the /docs root so /docs/ resolves to /docs/index.md instead of /docs.md.
- biome.jsonc: refresh stale @vercel/agent-eval comment to reflect the
custom AI SDK harness that replaced it.
- how-it-works "What runs when": rewrite the step list to be mode-agnostic.
Site mode emits llms.txt + llms-full + search index; --bundle emits
AGENTS.md instead. Output dir is conditional on mode, not hardcoded to
public/docs/.
- 4 EVAL.ts files: replace `c.args.path as string ?? ""` with a runtime
typeof guard in the filter so reads only contains real strings.
- wire-content-negotiation/EVAL.ts: extract getViteConfigSource helper to
DRY up two tests that read vite.config.ts the same way.
- evals/lib/sandbox.ts: wrap the cp call in try/catch so failures include
fixtureDir → tempDir context with the original error as cause.
- evals/run-eval.ts (three sub-fixes):
- --runs validates positive integer (extracted parsePositiveInt helper);
--runs 0 / --runs notanumber now error clearly instead of producing
NaN summary math.
- runVitest gains a settle-once guard, an error listener on the spawn,
and a try/catch around spawn() so the promise can't hang on launch
failure.
- sandbox.cleanup() moved into a finally block so the tempdir is removed
even if runVitest or archiveTranscript throws.
- cli.test.ts bundle-mode test: also assert search-content.json is absent
alongside the existing search-index.json check.
Skipped 5 review findings with reasons (see plan file): vite.config.ts
setHeader patch (already correct — bind preserves this, return value
preserved, types narrowed before mutation), connect-docs-site.mdx "github"
capitalization (no plain-text reference exists; only the literal flag
value), PROMPT.md MD041 H1 headings (markdownlint not enforced; would
mutate agent input for no benefit), and two README docs.example.com
placeholders (no production domain registered yet).
Verified: 98/98 leadtype tests pass, 9/9 eval unit tests pass, ultracite
clean, typecheck clean.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@evals/run-eval.ts`:
- Around line 260-280: Replace the dynamic import of node:fs/promises inside
archiveTranscript with top-level named imports for mkdir and writeFile (add
mkdir and writeFile to the existing readFile import), remove the await
import(...) and the local fs binding, and update calls from fs.mkdir(...) and
fs.writeFile(...) to direct mkdir(...) and writeFile(...); keep readFile(...)
usage as-is and ensure path.join(dir, "files", rel) and any mkdir calls still
use path.dirname(dest) where appropriate.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: c2235bd5-7a91-42c5-99aa-75a27b1955b3
📒 Files selected for processing (10)
apps/example/src/components/site-header.tsxbiome.jsoncdocs/how-it-works.mdxevals/evals/bundle-own-docs/EVAL.tsevals/evals/explain-cli-flag/EVAL.tsevals/evals/validate-in-ci/EVAL.tsevals/evals/wire-content-negotiation/EVAL.tsevals/lib/sandbox.tsevals/run-eval.tspackages/leadtype/src/cli.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Preferunknownoveranywhen the type is genuinely unknown
Use const assertions (as const) for immutable values and literal types
Leverage TypeScript's type narrowing instead of type assertions
Files:
evals/evals/bundle-own-docs/EVAL.tsevals/lib/sandbox.tsevals/evals/wire-content-negotiation/EVAL.tsevals/evals/explain-cli-flag/EVAL.tspackages/leadtype/src/cli.test.tsevals/evals/validate-in-ci/EVAL.tsevals/run-eval.tsapps/example/src/components/site-header.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions
Preferfor...ofloops over.forEach()and indexedforloops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Useconstby default,letonly when reassignment is needed, nevervar
Alwaysawaitpromises in async functions - don't forget to use the return value
Useasync/awaitsyntax instead of promise chains for better readability
Handle errors appropriately in async code with try-catch blocks
Don't use async functions as Promise executors
Removeconsole.log,debugger, andalertstatements from production code
ThrowErrorobjects with descriptive messages, not strings or other values
Usetry-catchblocks meaningfully - don't catch errors just to rethrow them
Prefer early returns over nested conditionals for error cases
Extract complex conditions into well-named boolean variables
Use early returns to reduce nesting
Prefer simple conditionals over nested ternary operators
Don't useeval()or assign directly todocument.cookie
Avoid spread syntax in accumulators within loops
Use top-level regex literals instead of creating them in loops
Prefer specific imports over namespace imports
Use descriptive names for functions, variables, and types for meaningful naming
Add comments for complex logic, but prefer self-documenting code
Files:
evals/evals/bundle-own-docs/EVAL.tsevals/lib/sandbox.tsevals/evals/wire-content-negotiation/EVAL.tsevals/evals/explain-cli-flag/EVAL.tspackages/leadtype/src/cli.test.tsevals/evals/validate-in-ci/EVAL.tsevals/run-eval.tsapps/example/src/components/site-header.tsx
**/*.{test,spec}.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{test,spec}.{js,ts,jsx,tsx}: Write assertions insideit()ortest()blocks
Avoid done callbacks in async tests - use async/await instead
Don't use.onlyor.skipin committed code
Keep test suites reasonably flat - avoid excessivedescribenesting
Files:
packages/leadtype/src/cli.test.ts
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{jsx,tsx}: Use function components over class components in React
Call hooks at the top level only, never conditionally
Specify all dependencies in hook dependency arrays correctly
Use thekeyprop for elements in iterables (prefer unique IDs over array indices)
Nest children between opening and closing tags instead of passing as props
Don't define components inside other components
AvoiddangerouslySetInnerHTMLunless absolutely necessary
Use proper image components (e.g., Next.js<Image>) over<img>tags
Use Next.js<Image>component for images
Usenext/heador App Router metadata API for head elements in Next.js
Use Server Components for async data fetching instead of async Client Components in Next.js
Use ref as a prop instead ofReact.forwardRefin React 19+
Files:
apps/example/src/components/site-header.tsx
**/*.{jsx,tsx,html}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{jsx,tsx,html}: Use semantic HTML and ARIA attributes for accessibility: provide meaningful alt text for images, use proper heading hierarchy, add labels for form inputs, include keyboard event handlers alongside mouse events, use semantic elements instead of divs with roles
Addrel="noopener"when usingtarget="_blank"on links
Files:
apps/example/src/components/site-header.tsx
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: inthhq/leadtype
Timestamp: 2026-05-09T16:51:58.518Z
Learning: Convert MDX into clean markdown that agents and tools can read
Learnt from: CR
Repo: inthhq/leadtype
Timestamp: 2026-05-09T16:51:58.518Z
Learning: Validate frontmatter, navigation, and internal links before publish using leadtype lint
Learnt from: CR
Repo: inthhq/leadtype
Timestamp: 2026-05-09T16:51:58.518Z
Learning: Ship agent-readable docs inside npm packages so IDEs and coding agents can read them offline
Learnt from: CR
Repo: inthhq/leadtype
Timestamp: 2026-05-09T16:51:58.518Z
Learning: Generate llms.txt and topic-scoped full-context bundles from a single MDX source for LLM consumption
Learnt from: CR
Repo: inthhq/leadtype
Timestamp: 2026-05-09T16:51:58.518Z
Learning: Wire leadtype into a docs site build to serve humans, agents, and search from one source
Learnt from: CR
Repo: inthhq/leadtype
Timestamp: 2026-05-09T16:51:58.518Z
Learning: Use a remark plugin stack to flatten MDX components into markdown during conversion
🪛 LanguageTool
docs/how-it-works.mdx
[uncategorized] ~33-~33: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...old headings, a <TypeTable> becomes a markdown table. The flattened markdown is what e...
(MARKDOWN_NNP)
[style] ~73-~73: Consider a different adjective to strengthen your wording.
Context: ...t over HTTP and follow absolute URLs to deeper context. Useless inside an npm tarball,...
(DEEP_PROFOUND)
🔍 Remote MCP Context7
Additional factual context for reviewing this PR
-
Vite plugin middleware lifecycle
- configureServer receives the ViteDevServer and is used to add custom middleware via server.middlewares.use; returning a function from configureServer registers middleware that runs after Vite’s internal middlewares (so both pre- and post-injection patterns shown are supported). This validates the plugin pattern used for content-negotiation and header modification (append charset).
-
Vite middleware examples / guidance
- Examples show using server.middlewares.use(...) to intercept/modify requests and responses in both dev and preview servers; configurePreviewServer exists for preview-specific middleware. This supports the PR’s adding middleware to dev + preview and manipulating response Content-Type.
-
TanStack Router not-found and file-route patterns
- createFileRoute / createRootRoute file-based routing conventions and examples are documented; root-level notFoundComponent is recommended and createRouter supports defaultNotFoundComponent for a router-wide fallback. Using both a NotFound component on the root route and setting defaultNotFoundComponent on the router (as this PR does) matches documented patterns for providing consistent 404 handling. Also, createFileRoute examples show how to throw notFound() from loaders and supply per-route notFoundComponent.
-
Vercel AI SDK tool helper and Zod schemas
- The recommended pattern for defining callable tools is tool({ description, inputSchema: z.object(...), execute: async (...) => ... }), which performs input validation and provides a typed execute. The PR’s scoped tools using tool() + zod input schemas and execute functions align with examples in the SDK docs.
Sources consulted (Context7 MCP):
- Vite plugin/middleware docs and examples — Context7 query on Vite configureServer and plugin hooks.
- TanStack Router file-route and not-found handling docs.
- Vercel AI SDK tool() + Zod tool-calling examples.
🔇 Additional comments (16)
docs/how-it-works.mdx (1)
146-150: Execution-order section is now mode-accurate and clear.This now correctly distinguishes default site outputs from
--bundleoutputs and removes the earlier ambiguity.biome.jsonc (1)
39-54: Scoped Biome override is appropriate for eval fixtures and harness tests.The rationale and rule exemptions are aligned with the new custom eval harness and are correctly limited to
evals/**.packages/leadtype/src/cli.test.ts (3)
118-119: Build-path and group-slug migration checks look correct.These assertions correctly enforce the
docs/build/*output and"build"group slug contract.Also applies to: 172-172
188-205: Include/exclude glob behavior is validated cleanly for the new IA.The updated glob expectations and emitted/omitted file assertions are coherent and precise.
Also applies to: 221-234
346-398:--bundlecoverage is strong and aligns with the new artifact contract.Great test scope here: mode verification,
AGENTS.mdemission, relative-link sanity, omission of llms/search artifacts (includingsearch-content.json), and retained markdown outputs.apps/example/src/components/site-header.tsx (3)
8-30:RobotIconimplementation looks good.Clean SVG component, and
aria-hidden="true"avoids redundant screen-reader noise for the decorative icon.
34-47:markdownHrefForPathnormalization logic is correct.The trailing-slash normalization and
/docs→/docs/index.mdmapping now handle the docs root and nested routes safely.
67-79: External markdown link is safely and conditionally rendered.Good use of
target="_blank"withrel="noopener", and rendering only when a valid markdown href is available.evals/evals/explain-cli-flag/EVAL.ts (1)
11-13: Type narrowing addressed, residual assertion is safe.The previous review about type narrowing has been addressed: the filter now includes
typeof c.args.path === "string". Theas stringon line 13 is technically redundant since TypeScript's control flow doesn't narrow acrossfilter→mapboundaries, but it's safe given the runtime check. No action needed.evals/evals/wire-content-negotiation/EVAL.ts (1)
17-23: Helper extraction addresses previous feedback.The
getViteConfigSource()helper properly consolidates the duplicated file-reading logic from the previous review. Good refactor.evals/run-eval.ts (3)
35-41: Previous feedback on--runsvalidation has been addressed.The
parsePositiveInthelper correctly validates that--runsis a positive integer and throws a clear error message for invalid values.Also applies to: 62-63
196-243: Sandbox cleanup now infinallyblock — previous feedback addressed.The
sandbox.cleanup()call is correctly placed in afinallyblock (line 241-243), ensuring temp directories are cleaned up even ifrunVitestorarchiveTranscriptthrows.
288-331: Spawn error handling properly implemented.The
runVitestfunction now handles spawn errors correctly:
- Uses a
settledflag to prevent multiple resolves- Wraps
spawnin try-catch for synchronous failures- Attaches an
errorevent listener for async spawn failuresThis addresses the previous review feedback.
evals/lib/sandbox.ts (1)
1-105: LGTM!The sandbox implementation is well-structured with proper error handling. The
cpoperation is now wrapped in try-catch with a clear diagnostic message (addressing the past review comment), andnpmInstallcorrectly captures stderr and surfaces failures with exit codes.evals/evals/bundle-own-docs/EVAL.ts (1)
1-63: LGTM!The test suite properly validates the agent's bundle-own-docs behavior: checking AGENTS.md discovery, package.json configuration with
--bundlein prepack, and npm pack verification. The type checking patterns are consistent with other eval files.evals/evals/validate-in-ci/EVAL.ts (1)
1-54: LGTM!The test suite validates the CI workflow generation comprehensively: checking AGENTS.md discovery, documentation reads, workflow file creation, and correct flags usage. Pattern is consistent with other eval files.
Summary
Three big strands shipped together over this branch.
1. Docs IA rewrite (Get Started → Authoring → Build → Reference)
Full rewrite of
/docs/*.mdxwith two hero paths called out from the landing page (build a docs site / bundle docs into a package), seven mermaid diagrams carrying the conceptual load, and tighter prose throughout. Companion changes:quickstart.mdx,how-it-works.mdx,authoring/frontmatter.mdx,build/validate-in-ci.mdx,reference/cli.mdx.authoring/,build/,reference/subdirs.apps/exampleroute files moved to mirror the new IA.README.mdandpackages/leadtype/README.mdaligned with the new narrative.vite.config.tspatchessetHeaderto append; charset=utf-8totext/markdownresponses (fixes UTF-8 mojibake on .md pages).2. AGENTS.md instead of llms.txt for npm-bundled docs
llms.txtis a website spec — it assumes a hosted root and absolute URLs. Inside an npm tarball it's the wrong shape: every link is useless offline, and no major coding agent looks fornode_modules/<pkg>/llms.txt. The actual filesystem convention isAGENTS.md, supported by 25+ tools (Claude Code, Codex, Cursor, Copilot, Aider, etc.).generateAgentsMdAPI inleadtype/llm— same shape asgenerateLlmsTxtbut emits Markdown with relative./docs/<topic>.mdpaths.--bundleflag onleadtype generate— producesAGENTS.md+docs/*.md, skipsllms.txt/llms-full*/ search artifacts.packages/leadtype/AGENTS.mdships in the published tarball.AGENTS.mdpoints atnode_modules/<pkg>/AGENTS.md, à la Next.js).--bundleintegration test incli.test.ts. Existing 96 tests unchanged. 98/98 pass.3. Custom AI SDK eval harness for AGENTS.md discoverability
We tried
@vercel/agent-evalfirst; its hardcoded Docker image runsapt-get update && apt-get install ca-certificates gitper fresh container, which routinely blows past the 300s timeout under concurrent load. Pivoted to a custom harness on the AI SDK that:AI_GATEWAY_API_KEYonly — no separate provider keys).read,write,list,glob,grep, plus a narrownpm(subcommand allowlist:pack,install; flag-form args only; scrubbed env). Nobashtool. Every tool path-scopes viaresolveScopedat the JS level — no shell parsing, no command substitution, no env-var leak.evals/results/<fixture>/<mode>/<timestamp>-runN/for debugging.resolveScopedrejects..-style escapes and absolute paths.wire-content-negotiation/treatment withclaude-haiku-4-5confirmed the harness works end-to-end (49 tool calls, agent readsAGENTS.md).Test plan
bun test— all 98 leadtype tests pass.bun run --filter leadtype build— clean. AGENTS.md generated at package root.npm pack --dry-runfrompackages/leadtype/— tarball includesAGENTS.mdand everydocs/**/*.md. Nollms.txt, nollms-full*, nosearch-*.json.bun --cwd apps/example run check-types— clean.bun --cwd apps/example run pipeline:build— website mode unchanged, producespublic/llms.txt,public/docs/llms-full/*.txt,public/docs/search-index.json, etc.node packages/leadtype/dist/cli.js lint docs --error-unknown— all 15 files pass.bun x ultracite check— clean across the repo.cd evals && bun test lib— 9/9 path-escape and tool unit tests pass.cd evals && bun run evals -- --fixture wire-content-negotiation --mode treatment --runs 1— harness completes end-to-end.🤖 Generated with Claude Code