Skip to content

Agent-friendly documentation: .md companions, llms.txt, coding-agent guide (HF-154)#1703

Open
marcin-kordas-hoc wants to merge 46 commits into
developfrom
feat/hf-154-agent-friendly-docs
Open

Agent-friendly documentation: .md companions, llms.txt, coding-agent guide (HF-154)#1703
marcin-kordas-hoc wants to merge 46 commits into
developfrom
feat/hf-154-agent-friendly-docs

Conversation

@marcin-kordas-hoc

@marcin-kordas-hoc marcin-kordas-hoc commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Context

HF-154 — make the HyperFormula docs friendlier to coding agents and LLMs. On top of the existing VuePress portal this adds:

  • Per-page .md companions — every doc page is also served as clean, VuePress-stripped Markdown (a build-time md-companions plugin), plus an aggregate llms-full.txt. Both are also mirrored to the site root so /llms.txt and /llms-full.txt resolve on GitHub Pages (prod) and the Netlify preview.
  • llms.txt — a top-level index pointing agents at the Markdown sources.
  • Copy-Markdown-link button (CopyMarkdownButton.vue) — copies the page's .md URL for pasting into an agent.
  • Coding-agent setup guide (docs/guide/setup-coding-agent.md) plus a CodingAgentWizard.vue helper.
  • context7.json so agent doc-access tooling (Context7 / GitMCP) can discover the sources.

The Markdown stripper (md-companions/strip.js) is the fidelity-critical piece: it turns VuePress-flavoured Markdown (::: containers, <script>/Vue components, [[toc]], {{ }} bindings, Vue-bound <a :href>/<img :src>, live :::example demos, nested code fences) into clean Markdown.

How did you test your changes?

  • Unit specs under test/docs/ (26 assertions, all passing): md-companions-strip.spec.js covers the stripper's transforms and edge cases; md-companions-generated.spec.js covers the generated() hook (per-page writes, root mirror, per-page error isolation, empty content, URL/base construction) with fs stubbed. Both are .js Jest specs (Karma globs only .spec.ts, so they stay out of the browser bundle).
  • npm run lint clean (an ESLint override for **/test/**/*.spec.js allows the plain-Node specs).
  • The full corpus was sanity-checked against the Netlify deploy-preview build (llms-full.txt populated, per-page .md clean, no leaked components).

Types of changes

  • New feature or improvement (a non-breaking change that adds functionality)
  • Change to the documentation

Related issues:

  1. HF-154

Checklist:

  • I have reviewed the guidelines about Contributing to HyperFormula and I confirm that my code follows the code style of this project.
  • I described my changes in the CHANGELOG.md file.

Notes


Note

Low Risk
Docs-site and build-plugin changes only; no HyperFormula engine or runtime API changes. Stripper/link logic is the main fidelity risk but is scoped to static doc output.

Overview
Adds LLM- and agent-friendly documentation outputs on top of the existing VuePress site: a build-time md-companions plugin writes VuePress-stripped per-page .md companions and llms-full.txt, rebases root links for /docs/ base, and mirrors llms.txt / llms-full.txt to the site root for GitHub Pages.

Site UX: global CopyMarkdownButton copies the current page’s .md URL; new guide setup-coding-agent.md with CodingAgentWizard for Claude Code, Cursor, Copilot, and corpus fetch; sidebar entry under Getting started. llms.txt index in public/; Netlify redirects root /llms.txt and /llms-full.txt; Node 22 for docs builds.

Authoring & discovery: new DOCS_CONTENT_GUIDE.md (RAG-oriented writing rules); DEV_DOCS.md links it; context7.json for Context7 indexing of docs/. Minor .eslintrc.js syntax fix in overrides.

Reviewed by Cursor Bugbot for commit 765a5a5. Bugbot is set up for automated code reviews on this repo. Configure here.

marcin-kordas-hoc and others added 18 commits May 28, 2026 10:12
…cking

Used by the prep-flip T2.5 tier to extract the HyperFormula public API
surface at a given git ref and compare between develop and PR HEAD to
detect breaking API changes (constructor arg additions, removed exports,
lint-scope drift).
…int config

Add scripts/*.js override to .eslintrc.js enabling node env and
disabling TypeScript-specific rules that do not apply to CJS scripts.
Auto-fix semicolons (project enforces no-semicolons style), rename
lint_scope variable to lintScope (naming-convention), and add missing
JSDoc param/returns descriptions.
Five-component design: VuePress md-companions plugin, Copy Markdown
button, static setup-coding-agent page, interactive wizard, and
llms.txt/robots.txt updates.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Address 5 findings grounded in VuePress core verification:
- respect base '/docs/' and DOCS_DEST in all 5 components
- compute Copy Markdown URL from $page.path, not window.location
- forbid invented install commands; trace to published skill
- token-aware container stripping with code-fence fixture test
- flag robots.txt root-vs-/docs/ placement for confirmation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Six tasks: md-companions plugin (C1), Copy Markdown button (C2),
setup-coding-agent page (C3), interactive wizard (C4), llms.txt/robots
(C5), and config.js integration. Install commands traced to the
published handsontable/handsontable-skills repo; code-fence stripping
fixture test included.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Install commands traced to handsontable/handsontable-skills; no invented commands.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…mpanions

Strip.js regex was limited to tip|warning|danger|details. The ::: example
container (live code runner) leaked into companion .md files. Broadened
match to \w+ and strip example containers entirely (they are demo markup,
not prose). Added 8th assertion to the test fixture.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…p page

- require md-companions plugin, register with DOCS_HOSTNAME
- globalUIComponents: ['CopyMarkdownButton']
- add 'Set up your coding agent' to Getting started sidebar

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
strip.js:
- track full fence marker length (CommonMark); inner ``` no longer closes ````
- bail out verbatim on unclosed ::: container (no silent page truncation)
- 9th test assertion for nested fence lengths

index.js:
- wrap per-page work in try/catch; one bad page warns and continues
- substitute real base/hostname in corpus header (was literal <base>)

CopyMarkdownButton.vue + CodingAgentWizard.vue:
- clipboard fallback via document.execCommand for non-HTTPS contexts
- isSecureContext guard + .catch() on Clipboard API promise
- null-guard on this.current in wizard copy()

setup-coding-agent.md:
- relative links to llms-full.txt (../llms-full.txt) to survive any
  base-path edge cases in static-file link resolution

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The md-companions markdown stripper is the acceptance gate for the
agent-friendly docs (per-page .md companions + llms.txt), but its test
lived at docs/.vuepress/plugins/md-companions/strip.test.js — a path and
suffix Jest's testMatch (`test/**/*spec.(ts|js)`) never discovers, so it
never ran in CI.

- Move the assertions into test/docs/md-companions-strip.spec.js as a
  Jest spec, where the default glob picks them up. The file is `.js`, so
  Karma's `.spec.ts`-only require.context skips it (the stripper is plain
  Node code, not part of the browser bundle).
- Add an ESLint override for `**/test/**/*.spec.js` mirroring the existing
  `scripts/*.js` relaxations (node env, allow require of untyped modules).
- Remove the orphan strip.test.js.
- CHANGELOG: note the agent-friendly docs under [Unreleased] > Added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
These are internal implementation planning docs, not user-facing
documentation. VuePress builds every file under docs/ into the public
site (and the md-companions plugin would emit .md + llms.txt for them),
so they must not live in the public repo. They belong in the internal
dev-skills workspace instead.
…rve-out

scripts/extract-public-api.js was an internal helper for the prep-flip
review harness (per its own header), has no consumer anywhere in this
repo, and is out of scope for an agent-friendly-docs PR. Removing it also
resolves the two outstanding review threads it was the sole source of:
the CodeQL 'indirect uncontrolled command line' alert (execSync git show)
and Cursor's regex finding in extractHyperFormulaExports.

The scripts/*.js ESLint override existed only to lint this file, so it is
removed too; the **/test/**/*.spec.js override stays (needed by the
md-companions strip spec).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@qunabu

qunabu commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Task linked: HF-154 Agent-friendly docs

@netlify

netlify Bot commented Jul 9, 2026

Copy link
Copy Markdown

Deploy Preview for hyperformula-dev-docs ready!

Name Link
🔨 Latest commit 765a5a5
🔍 Latest deploy log https://app.netlify.com/projects/hyperformula-dev-docs/deploys/6a5774fe8bc762000830b298
😎 Deploy Preview https://deploy-preview-1703--hyperformula-dev-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

marcin-kordas-hoc added a commit that referenced this pull request Jul 9, 2026
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@marcin-kordas-hoc marcin-kordas-hoc force-pushed the feat/hf-154-agent-friendly-docs branch from e79f1a8 to ddfa8f0 Compare July 9, 2026 05:59
Comment thread docs/.vuepress/plugins/md-companions/index.js Outdated
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

Performance comparison of head (765a5a5) vs base (e0e1261)

                                     testName |   base |   head | change
------------------------------------------------------------------------
                                      Sheet A |  502.3 | 502.33 | +0.01%
                                      Sheet B | 165.79 | 166.98 | +0.72%
                                      Sheet T | 142.63 | 140.48 | -1.51%
                                Column ranges | 535.68 | 528.25 | -1.39%
Sheet A:  change value, add/remove row/column |  16.42 |  17.46 | +6.33%
 Sheet B: change value, add/remove row/column | 138.33 | 150.08 | +8.49%
                   Column ranges - add column | 160.34 | 160.04 | -0.19%
                Column ranges - without batch | 498.22 | 489.89 | -1.67%
                        Column ranges - batch | 131.63 | 125.83 | -4.41%

marcin-kordas-hoc and others added 3 commits July 9, 2026 07:50
The docs build (`npm run docs:build`) is validated in CI on Node 22
(the build-docs workflow), but Netlify built the deploy preview on Node
18, where the build errored. Aligning the deploy runtime with the
validated CI runtime.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ents

- CopyMarkdownButton copies the page's .md URL (per its tooltip), so the
  label now reads 'Copy Markdown link' instead of 'Copy Markdown', which
  implied it copied the markdown content. Guide reference updated to match.
- Removed the two 'AI/LLM agent index' comment lines from robots.txt:
  crawlers ignore comments, so they provided no machine-discoverability.
  llms.txt is discoverable at its well-known path; the Sitemap directive
  stays.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Verified the deploy-preview build output: llms-full.txt is populated
(1.3 MB, page content present) and guide pages strip cleanly, but the
typedoc API pages leaked ~638 inline `<Badge text="Class"/>` tags —
the stripper only dropped component tags that occupied a whole line, not
inline ones after heading text. Now strips inline self-closing
capitalized components too; the [A-Z] guard leaves plain HTML (<br/>)
alone and code fences are still preserved. +3 spec assertions (12 total).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread docs/.vuepress/components/CopyMarkdownButton.vue Outdated
…ent tags

- Extract the shared Clipboard-API-with-textarea-fallback logic from
  CopyMarkdownButton.vue and CodingAgentWizard.vue into a single
  components/clipboard.js (copyToClipboard); both now import it.
- strip.js: also drop a whole-line closing tag of a paired block
  component (</Foo>); the opening tag and inner content were already
  handled, only the stray closing tag leaked. +1 spec assertion (13).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
marcin-kordas-hoc and others added 2 commits July 12, 2026 14:50
Cursor Bugbot flagged that stripping {{ … }} drops meaningful inline values
(e.g. a function count) — worse than shipping the literal token. Leave them
as-is; full expansion needs rendered-HTML extraction (follow-up). The
Vue-bound <a :href>/<img :src> stripping (no info loss) stays.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread context7.json Outdated
Bugbot: context7.json only excluded docs/.vuepress/dist, so Context7 would
index the VuePress source (config, plugins, .vue components) as if it were
HyperFormula documentation. Exclude the whole docs/.vuepress; the actual
guide content lives under docs/guide/ and docs/*.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread docs/.vuepress/plugins/md-companions/strip.js
Bugbot: the [[toc]] removal only matched whole-line markers, so inline forms
like '**Contents:** [[toc]]' (custom-functions.md) leaked into companions.
Now stripped anywhere. +1 spec assertion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread docs/.vuepress/public/llms.txt Outdated
marcin-kordas-hoc and others added 6 commits July 12, 2026 19:45
Bugbot: /docs/guide/ has no static index (client-side Vue Router only), so
raw fetches 404 for non-JS agents. Point the Guide entry at the docs root
/docs/ (returns 200), which is stable across page renames.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The snippet box inherited a near-invisible light text colour on its light
background. Set explicit dark text (#2c3e50, VuePress $textColor), reset the
inner <code> colour/background, and wrap long URLs (word-break) so the full
llms-full.txt link is visible instead of overflowing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ompanions

Reviewing the live basic-usage.md companion: the '## Demo' heading dangled at
EOF because its :::example live-demo was (correctly) stripped, leaving an empty
trailing section; and a whitespace-only source line surfaced as literal spaces.
Now: trailing heading(s) with no body are dropped (guarded by a hasProse check
so a title-only page like '# AbsoluteCellRange' is never wiped), and
whitespace-only lines are normalised to clean blanks. +2 spec assertions (29).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stratified whole-page fixtures (one per real docs category: guide+tip+demo,
integration with {{ }}+Vue anchor, branding image, API page with <Badge>,
fence-preservation, title-only) run through the stripper with 'clean companion'
invariants — no VuePress/Vue leaks outside fences, no dangling empty heading.
Encodes the bug classes found on the live preview as regressions. 35 assertions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The wizard snippet used a light box while the rest of the docs' code blocks
are dark ($codeBgColor #282c34), so it looked inconsistent on the same page
(visible on the Set-up-your-coding-agent page). Match the fenced-code-block
style: dark bg + light text.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…cs folder)

Independent review flagged the 'both read this site's llms.txt' line as
imprecise: GitMCP serves the GitHub repository's docs (not the deployed site),
and Context7 indexes the repo's docs/ folder per context7.json (not the
deployed llms.txt/llms-full.txt). Reworded to match the actual mechanisms.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread docs/.vuepress/plugins/md-companions/index.js
Comment thread docs/.vuepress/plugins/md-companions/strip.js Outdated
Two Cursor Bugbot findings:
- index.js: root-relative Markdown links (](/guide/…), ](/api/…)) are now
  rewritten to include the base (/docs/), so companions resolved from the site
  origin don't 404. Protocol/absolute/anchor/relative links untouched. (Medium)
- strip.js: the ::: container body scan is now fence-aware — a bare ::: inside a
  fenced code block in the body no longer closes the container early / leaks. (Low)
+2 spec assertions (37).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread docs/.vuepress/plugins/md-companions/index.js
Bugbot: rebaseRootLinks rewrote ](/…) everywhere, including inside fenced code
blocks, which could corrupt link-shaped text in code examples. Now fence-aware
(mirrors the stripper's contract) — only prose links are rebased. +1 spec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread docs/.vuepress/plugins/md-companions/index.js Outdated
Bugbot (Medium): the corpus aggregates every page into one file at
/docs/llms-full.txt, so page-relative links (](basic-usage.md), ](../api/x.md))
resolved against the corpus URL and 404'd — and the corpus is the surface
Cursor/Copilot are pointed at. Corpus entries now resolve every link to an
absolute URL relative to the source page's URL (fence-aware; per-page .md keeps
relative links, which resolve within the companion tree). +1 spec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ba78f3f. Configure here.

Comment thread docs/.vuepress/plugins/md-companions/strip.js
marcin-kordas-hoc and others added 6 commits July 13, 2026 03:49
Bugbot (Medium): ::: tip/warning bodies were blockquoted and pushed without the
inline Vue-markup cleanup normal prose gets, so [[toc]], Vue-bound :href/:src
and inline <Badge/> inside a container leaked into companions. Extracted the
cleanup into cleanInlineMarkup() and apply it to container bodies as well as
plain lines (also de-duplicates the rule set). +1 spec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@@ -0,0 +1,10 @@
# HyperFormula

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does it make sense to put llms.txt at https://hyperformula.handsontable.com/docs/llms.txt? We already have https://hyperformula.handsontable.com/LLMs.txt. Suppose an agent visits our docs - will it look for https://hyperformula.handsontable.com/docs/llms.txt or https://hyperformula.handsontable.com/llms.txt?

v-if="mdUrl"
class="copy-md-button"
type="button"
:title="'Copy this page as Markdown URL for LLMs'"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Instedy of button "copy as markdown" I'd prefer "view as markdown" on top of each documentation page. I think agent will more likely click a link and read the clipboard content and then navigate to it.


/**
* VuePress plugin: after build, write a clean `.md` companion next to each
* rendered `.html`, plus an aggregate `llms-full.txt`. Respects ctx.outDir

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I like the idea of llms-full.txt

import { copyToClipboard } from './clipboard';

export default {
name: 'CodingAgentWizard',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good idea with this wizzard

Comment thread netlify.toml
# expects the index at the domain root. Rewrite the well-known root paths to
# the built files so agents probing `/llms.txt` (and the full corpus) resolve.
[[redirects]]
from = "/llms.txt"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not sure this redirect is good idea. https://hyperformula.handsontable.com/LLMs.txt contains more info than just about the docs

Comment thread docs/.vuepress/config.js
exclude: ['/404.html'],
changefreq: 'weekly'
}],
[mdCompanions, { hostname: DOCS_HOSTNAME }],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All changes from this PR ("viev as markdown", setup-agent-wizard etc) should be described in docs/README.md. Particullary we need to make it clear that the final build result now contains both html and md versions for all pages as well as llm-full.txt with everything joind into a single long file.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

While you're at it, please check if the content of docs/README.md is up to date


- [Official skill repository](https://github.com/handsontable/handsontable-skills)
- [`llms-full.txt`](../llms-full.txt)
- [API reference](/api/)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

A general question: Did you look at Exa's docs and find anything there that could be an inspiration to us? Another good inspiration is https://resend.com/docs/introduction

@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.16%. Comparing base (e0e1261) to head (765a5a5).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##           develop    #1703   +/-   ##
========================================
  Coverage    97.16%   97.16%           
========================================
  Files          176      176           
  Lines        15450    15450           
  Branches      3417     3417           
========================================
  Hits         15012    15012           
  Misses         438      438           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants