Payload Markdown Docs
@valkyrianlabs/payload-markdown-docs turns a repo-local /docs tree into Payload-native documentation that AI can generate, humans can review, CI can publish, and your Next/Payload site can render.
No hosted docs platform lock-in.
No AI-generated Markdown sludge with no structure.
No babysitting a CMS every time the code changes.
Just plain Markdown docs, native agent skills, trusted publishing, and Payload-owned output.
1pnpm add @valkyrianlabs/payload-markdown-docs @valkyrianlabs/payload-markdownPayload Markdown Docs is the delivery pipeline for teams who want documentation to move as fast as the code it describes. AI gets the speed. Humans keep the control. Payload owns the output.
Documentation that lives with the code
Most documentation systems eventually drift into one of three bad worlds:
Manual docs rot
The code changes. The docs do not. Eventually the documentation becomes archaeological evidence instead of operational truth.
AI slop
Agents can generate Markdown quickly, but without structure, validation, route rules, and renderer guidance, the output becomes a pile of plausible nonsense.
Hosted platform gravity
External docs platforms can be convenient, but they pull your content, routes, rendering, auth, publishing, and ownership away from your app.
payload-markdown-docs takes the fourth path:
1analyze codebase2 -> generate docs with repo-local AI skills3 -> write plain Markdown into /docs4 -> validate and plan the docs tree5 -> publish through GitHub OIDC or Ed255196 -> render inside your Payload/Next site
The docs stay in your repo. The CLI validates them. CI publishes them. Payload stores them. Your site renders them.
What you get
Repo-local Markdown source
Keep human documentation in /docs as plain Markdown files that can be reviewed, edited, versioned, and generated like normal source.
Native AI skill installer
Install Codex and Claude workflow packs so agents know your docs structure, frontmatter rules, validation flow, and renderer syntax.
Payload-native docs records
Sync documentation into Payload collections for docs sets, groups, access records, keys, assets, and rendered content.
Trusted publishing
Publish through GitHub Actions OIDC or Ed25519 signed local pushes with branch, owner, repository, and docs-set validation.
Next.js rendering helpers
Resolve docs routes, render docs pages, build nav trees, generate metadata, and integrate docs into your app frontend.
AI discovery routes
Generate and serve llms.txt, llms-full.txt, docs-set AI files, and native agent skill artifacts from synced docs and skills.
Docs navigation
Use drop-in nav components or headless builders for docs sets, docs groups, and custom site headers.
Validation and planning
Validate docs, generate manifests, preview sync plans, and catch problems before publishing into Payload.
Renderer powered by Payload Markdown
Render structured Markdown through @valkyrianlabs/payload-markdown for cards, callouts, buttons, tabs, steps, code blocks, and docs layouts.
AI-first, not AI-only
This plugin is built for AI-assisted documentation from the ground up.
Give agents a real workflow
Install native skill packs into the repo so Codex and Claude know how to generate docs for your actual pipeline instead of freestyle hallucinating a docs structure.
1pnpm exec payload-markdown-docs install skill --agent codex2pnpm exec payload-markdown-docs install skill --agent claudeKeep humans in command
AI can create the first pass, maintain large sections, and keep documentation moving with the codebase.
Humans still review, edit, tune, and ship plain Markdown like any other source-controlled project asset.
The AI does not just write random docs. It writes docs for a known renderer, known route model, known frontmatter format, known CLI, and known publishing pipeline.
A typical agent prompt after installing the skill:
1Use the installed payload-markdown-docs skill.2 3Analyze this repository and generate a complete documentation tree under /docs.4Use route-aware frontmatter and payload-markdown-compatible Markdown. Validate5the tree with the payload-markdown-docs CLI when finished.
The workflow
1 Generate or edit docs in the repo
Write documentation by hand or ask an agent to generate a complete tree under
/docs.2 Validate before publishing
Run the CLI locally or in CI to validate docs structure, metadata, routes, assets, and sync behavior.
3 Publish through a trusted channel
Use GitHub Actions OIDC for normal CI publishing or Ed25519 signed pushes for local/operator workflows.
4 Store and render in Payload
Payload receives the docs, stores the records, resolves docs sets and groups, and exposes renderable content to your Next app.
5 Serve human and AI-facing routes
Render human docs pages while also serving AI-readable
llms.txt, docs-set discovery files, and native skill artifacts.
Install
Install the plugin and its renderer dependency:
1pnpm add @valkyrianlabs/payload-markdown-docs @valkyrianlabs/payload-markdownInstall the CLI package in repositories that publish documentation:
1pnpm add -D @valkyrianlabs/payload-markdown-docsConfigure Payload
Add the plugin to your Payload config:
1import { payloadMarkdownDocs } from '@valkyrianlabs/payload-markdown-docs'2import { buildConfig } from 'payload'3 4export default buildConfig({5 plugins: [6 payloadMarkdownDocs({7 auth: {8 githubOidc: true,9 },10 target: {11 enableDrafts: true,12 },13 sync: {14 allowWrites: true,15 allowPublish: true,16 },17 }),18 ],19})
This adds the docs admin surface, sync endpoint, publishing controls, and Payload-native records needed to receive documentation from your repo.
Public API surface
Use the root package for Payload plugin configuration:
1import { payloadMarkdownDocs } from '@valkyrianlabs/payload-markdown-docs'This surface is for Payload config and server-side plugin setup.
Use /next for frontend docs rendering, route resolution, metadata, sitemap generation, nav helpers, and asset route helpers:
1import {2 PayloadMarkdownDocsPage,3 resolvePayloadMarkdownDocsRoute,4} from '@valkyrianlabs/payload-markdown-docs/next'Use /admin for Payload admin import map helpers such as DocsSetManager:
1import { DocsSetManager } from '@valkyrianlabs/payload-markdown-docs/admin'Use /blocks for optional Payload block schemas and field helpers:
1import {2 DocsCTABlock,3 DocsPreviewBlock,4} from '@valkyrianlabs/payload-markdown-docs/blocks'Create your docs model
Create a docs set in Payload Admin:
1title: Payload Markdown Docs2slug: payload-markdown-docs3branch: main4group: plugins
With the plugins group, the generated route becomes:
1/plugins/payload-markdown-docs
Create a trusted GitHub owner:
1owner: valkyrianlabs2limitRepos: false
When limitRepos is disabled, any repository owned by that GitHub owner can publish to a matching docs set from the configured branch.
Enable limitRepos when you want explicit repository allowlists.
Create a docs tree
A minimal project can look like this:
1docs/2 index.md3 getting-started/4 quick-start.md5 configuration/6 plugin-config.md7 workflow/8 ci-github-actions.md9 reference/10 cli.md11skills/12 payload-markdown-docs/13 codex/14 SKILL.md15 claude/16 SKILL.md
/docs contains human documentation. /skills contains agent-native workflow packages. The plugin syncs both, but treats them as different kinds of source material.
Generated llms.txt, llms-full.txt, and docs-set AI files are built from synced docs, docs set metadata, dependencies, and skills.
You do not need generated-only docs, hidden storage, or a hosted documentation service.
Validate locally
Before publishing, validate the docs tree:
1pnpm exec payload-markdown-docs validate --source payload-markdown-docs
Generate a manifest:
1pnpm exec payload-markdown-docs manifest \2 --source payload-markdown-docs \3 --pretty
Preview the sync plan:
1pnpm exec payload-markdown-docs plan --source payload-markdown-docs
From this package source checkout, use the local source CLI instead:
1pnpm cli validate --source payload-markdown-docs
In GitHub Actions, --source can be omitted when the docs set slug matches the repository name. The CLI can infer it from GITHUB_REPOSITORY.
Publish from GitHub Actions
GitHub Actions is the standard publishing path.
GitHub signs the publish request with OIDC. Payload verifies the trusted owner, repository, branch, and docs set before accepting the sync.
1permissions:2 contents: read3 id-token: write4 5steps:6 - uses: actions/checkout@v47 8 - uses: pnpm/action-setup@v49 10 - uses: actions/setup-node@v411 with:12 node-version: 2213 cache: pnpm14 15 - run: pnpm install --frozen-lockfile16 17 - run: pnpm exec payload-markdown-docs validate --source payload-markdown-docs18 19 - run: |20 pnpm exec payload-markdown-docs push \21 --endpoint "$DOCS_SYNC_ENDPOINT" \22 --repository "$GITHUB_REPOSITORY" \23 --branch "$GITHUB_REF_NAME" \24 --commit "$GITHUB_SHA" \25 --github-oidc \26 --publish
Sync writes require:
1sync: {2 allowWrites: true,3}
Publishing also requires:
1sync: {2 allowPublish: true,3},4target: {5 enableDrafts: true,6}
That is the normal docs CI path:
1commit docs2 -> validate docs3 -> push docs4 -> publish docs
Push locally with Ed25519
For advanced operator workflows, use Ed25519 signed pushes from your editor, local machine, internal tooling, or non-GitHub environments.
Generate a keypair:
1pnpm exec payload-markdown-docs keygen --out .docs-sync
Add the public key in Payload Admin:
1Docs Globals > Access
Push with the private key:
1pnpm exec payload-markdown-docs push \2 --endpoint "$DOCS_SYNC_ENDPOINT" \3 --source payload-markdown-docs \4 --key-id local-docs \5 --private-key-file .docs-sync/docs-sync-private.pem
For immediate publishing:
1pnpm exec payload-markdown-docs push \2 --endpoint "$DOCS_SYNC_ENDPOINT" \3 --source payload-markdown-docs \4 --key-id local-docs \5 --private-key-file .docs-sync/docs-sync-private.pem \6 --publish
Edit locally, validate locally, push directly, and review the rendered docs on your Payload site.
Render docs in Next
The plugin does not mutate your Pages collection and does not register public frontend routes for you.
Add route handlers where you want docs to render:
1import config from '@payload-config'2import {3 PayloadMarkdownDocsPage,4 resolvePayloadMarkdownDocsRoute,5} from '@valkyrianlabs/payload-markdown-docs/next'6import { notFound } from 'next/navigation'7import { getPayload } from 'payload'8 9export default async function Page({ params }: { params: Promise<{ slug?: string[] }> }) {10 const { slug } = await params11 const payload = await getPayload({ config })12 13 const resolved = await resolvePayloadMarkdownDocsRoute({14 payload,15 slug,16 })17 18 if (resolved) {19 return <PayloadMarkdownDocsPage resolved={resolved} />20 }21 22 notFound()23}
Your app decides where documentation lives. The plugin handles route resolution and rendering.
Navigation that fits your site
Drop-in navbar
Use PayloadMarkdownDocsNavbar when you want the plugin to own the docs menu UI.
Header adapter
Append docs groups and docs sets to an existing site header without rewriting your navigation model.
Headless nav builder
Use getPayloadMarkdownDocsNavItems when you want full control over rendering, routing, analytics, and layout.
Drop-in navbar example:
1import { PayloadMarkdownDocsNavbar } from '@valkyrianlabs/payload-markdown-docs/next'2import type { Payload } from 'payload'3 4export async function HeaderDocsNav({ payload }: { payload: Payload }) {5 return (6 <PayloadMarkdownDocsNavbar currentPath="/plugins/payload-markdown-docs" payload={payload} />7 )8}
Header adapter example:
1import { appendPayloadMarkdownDocsHeaderNavItems } from '@valkyrianlabs/payload-markdown-docs/next'2 3const navItems = await appendPayloadMarkdownDocsHeaderNavItems({4 existingItems: header.navItems ?? [],5 maxItems: headerNavItemsMaxRows,6 payload,7})
Headless nav example:
1import { getPayloadMarkdownDocsNavItems } from '@valkyrianlabs/payload-markdown-docs/next'2 3const docsNav = await getPayloadMarkdownDocsNavItems({4 availableSlots: 4,5 payload,6})
Serve raw AI assets
The canonical agent artifacts are normal files under skills/.
push syncs them as raw asset records by convention. Skill files are not docs records and do not need docs frontmatter.
Payload owns the asset storage and handlers, but a Next App Router site still needs route files so public root URLs reach those handlers instead of being swallowed by the frontend catch-all.
Install public Next route files once:
1pnpm exec payload-markdown-docs install routes --payload-app "src/app/(payload)"
Use this for apps without src/:
1pnpm exec payload-markdown-docs install routes --payload-app "app/(payload)"
Useful stable paths include:
1/llms.txt2/llms-full.txt3/plugins/payload-markdown-docs/llms.txt4/plugins/payload-markdown-docs/llms-full.txt5/plugins/payload-markdown-docs/skills/codex6/plugins/payload-markdown-docs/skills/codex/SKILL.md7/plugins/payload-markdown-docs/skills/claude8/plugins/payload-markdown-docs/skills/claude/SKILL.md9/plugins/payload-markdown-docs/skills/codex/reference/workflow.md
sitemap.xml is crawler discovery. llms.txt is an AI-readable entrypoint. Skills are native agent workflow artifacts. Keep those surfaces separate on purpose.
Advanced security
You do not need advanced workflow restrictions for normal docs publishing.
Each docs set can optionally enforce exact GitHub workflow refs.
Leave it disabled to allow any workflow from a trusted owner/repository on the configured branch.
When enabled, add every allowed workflow ref explicitly. An empty list rejects all workflow publishing for that docs set.
Built on Payload Markdown
payload-markdown-docs depends on @valkyrianlabs/payload-markdown for structured Markdown rendering.
That means your generated documentation can use the same directive system as the rest of your Payload Markdown content:
Callouts
Highlight warnings, tips, notes, and important documentation context.
Cards and grids
Create feature grids, reference groups, and landing-page style documentation sections.
Buttons and CTAs
Link readers to install guides, repositories, examples, and related pages.
Tabs and steps
Document multi-path workflows, setup flows, and progressive implementation guides.
Code blocks
Render technical examples through the same Shiki-powered code pipeline.
AI-friendly source
Let agents edit readable Markdown instead of opaque CMS state.
Philosophy
The repo is the source of truth
Documentation should live next to the code it explains.
AI should have rules
Agents should receive repo-local instructions, renderer syntax, validation expectations, and publishing constraints.
Humans should keep control
Generated docs should still be plain Markdown that developers can review, edit, and own.
Publishing should be trusted
CI and local pushes should prove who they are before Payload accepts documentation writes.
Payload should own the output
Your app should control routes, rendering, navigation, metadata, and final presentation.
Docs should move with code
A docs pipeline should make maintenance faster, not add another side quest to every release.
Payload Markdown Docs is for teams that want AI-accelerated documentation without giving up plain Markdown, source control, trusted publishing, or ownership of the rendered site.