AI tools read Markdown better than HTML. bongo can write a Markdown copy of each page next to its HTML, such as /config.md for /config/. This site does it: open the Copy page menu at the top of this page.
Make a copy of each page
Put a <bongo:alternate> element of type text/markdown in the <head> of your layout:
<head>
<meta charset="utf-8"/>
<title>{{ $page.title }}</title>
<bongo:alternate type="text/markdown" />
</head>For each page from a Markdown file, bongo:
- writes the copy at the route of the page plus
.md:/config/gives/config.md, and/gives/index.md. - puts
<link rel="alternate" type="text/markdown" href="/config.md"/>in place of the element, so that tools find the copy.
The element can also link other versions of a page, such as a feed. See Alternates.
What a copy holds
A copy holds the title and the summary from the frontmatter, then the Markdown of the page as you wrote it:
# Config
> The fields of bongo.config.ts, and how plugins merge into the config.
The config file, `bongo.config.ts`, sets the site metadata, …bongo reads the source file again when it writes the copy, so a build does not keep every page's Markdown in memory. bongo dev makes a copy the first time that you open it.
Choose the pages
- A page from an
.htmlor.hbsfile has no Markdown to copy. It gets no copy and no<link>, so one layout can serve every page. - To make copies for some Markdown pages only, put the element in the layout of their folder, or in an
{{#if}}block. - Two pages that name the same copy, or a copy that lands on another file of the site, fail the build.
Add Copy page and View as Markdown
A page cannot read its own alternates, because bongo finds the element only after the layouts render. $utils.url.ext() gives the same URL that the element uses:
{{#var md = $utils.url.ext($page.path, 'md')}}
<a href="{{ md }}" target="_blank">View as Markdown</a>
<button type="button" data-copy-page="{{ md }}">Copy page</button>document.addEventListener('click', event => {
let button = event.target instanceof Element && event.target.closest<HTMLElement>('[data-copy-page]');
if (!button) return;
let text = fetch(button.dataset.copyPage ?? '')
.then(res => res.text())
.then(text => new Blob([text], { type: 'text/plain' }));
navigator.clipboard.write([new ClipboardItem({ 'text/plain': text })]);
});Safari allows a write to the clipboard only while the click is current. Thus the script gives ClipboardItem the fetch as a promise, and does not wait for the fetch first.
Check it
bongo devserves each copy. Open one, such as/config.md.bongo buildwrites each copy topublic/, next to the HTML of its page.
To list every copy in one file for AI tools, see Create an llms.txt.