Holocron is a Mintlify-compatible docs site generator and Vite plugin. Use this skill when creating, migrating, customizing, or deploying a Holocron documentation site. Also load when writing index.mdx, page titles, hideTitle, Above heroes, or homepage SEO for Google brand ranking.
44 stars
0 votes
0 copies
0 views
Added November 7, 2026
devopstypescriptgobashnodegitapidocumentation
Works with
cli
api
mcp
Security analysis
A92/100
mediumUses curl or wget to download content
mediumInstalls packages at runtime which could introduce malicious dependencies
Installs into .claude/skills of the current project.
Are you the author of Holocron?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/remorses-holocron)
---
name: holocron
repo: https://github.com/remorses/holocron
description: >
Holocron is a Mintlify-compatible docs site generator and Vite plugin.
Use this skill when creating, migrating, customizing, or deploying a
Holocron documentation site. Also load when writing index.mdx, page
titles, hideTitle, Above heroes, or homepage SEO for Google brand ranking.
---
# Holocron
Holocron documentation changes fast. Do not rely on stale training data or
repository-relative source paths. Fetch the public docs first, then search them.
## Relevant docs pages
Fetch `https://holocron.so/sitemap.xml` to see all available pages. Append `.md` to any page URL
to get raw markdown. Never pipe curl output through `head`, `tail`, `sed -n`, or any truncation
command. Read the full output every time.
```bash
curl -s https://holocron.so/sitemap.xml
curl -s https://holocron.so/docs/quickstart.md
```
When the user asks about a specific workflow, fetch the matching page directly:
- **Overview**: https://holocron.so/llms.txt
- **Quickstart**: https://holocron.so/docs/quickstart.md
- **What Holocron is**: https://holocron.so/docs/what-is-holocron.md
- **Create pages**: https://holocron.so/docs/create/pages.md
- **MDX syntax**: https://holocron.so/docs/create/mdx.md
- **Local imports**: https://holocron.so/docs/create/local-imports.md
- **Redirects**: https://holocron.so/docs/create/redirects.md
- **`docs.json` config**: https://holocron.so/docs/organize/docs-json.md
- **Config schema**: https://holocron.so/docs.json
- **Navigation**: https://holocron.so/docs/organize/navigation.md
- **Theme customization**: https://holocron.so/docs/customize/theme.md
- **Icons**: https://holocron.so/docs/customize/icons.md
- **Custom entry (Spiceflow)**: https://holocron.so/docs/custom-entry.md
- **Spiceflow integration**: https://holocron.so/docs/spiceflow.md
- **Cloudflare deploy**: https://holocron.so/docs/deploy/cloudflare.md
- **Node deploy**: https://holocron.so/docs/deploy/node.md
- **Holocron deploy**: https://holocron.so/docs/deploy/holocron.md
- **AI assistant docs**: https://holocron.so/docs/ai/assistant.md
- **Bleed**: https://holocron.so/docs/customize/bleed.md
- **Layout and page modes**: https://holocron.so/docs/customize/layout.md
```bash
curl -fsSL https://holocron.so/docs/quickstart.md
curl -fsSL https://holocron.so/docs/organize/docs-json.md
```
## Scaffolding a new project
Use the CLI to create a new docs site with a working template:
```bash
npx -y "@holocron.so/cli" create --name "My Docs" my-docs --skip-auth
```
The `--skip-auth` flag skips cloud setup & AI chat setup (suitable for agents and local-only
usage). The template includes `vite.config.ts`, `docs.jsonc`, sample pages,
navigation with tabs, anchors, and icons.
After scaffolding, start the dev server:
```bash
cd my-docs
pnpm install
pnpm dev
```
## `docs.json` basics
Holocron reads `docs.json`, `docs.jsonc`, or `holocron.jsonc`. Prefer
`docs.jsonc` when writing by hand because comments and trailing commas make it
easier to maintain.
Always fetch the schema before adding uncommon config fields:
```bash
curl -fsSL https://holocron.so/docs.json
```
Simple `docs.jsonc`:
```jsonc
{
"$schema": "https://holocron.so/docs.json",
"name": "Acme",
"description": "Documentation for Acme.",
"colors": { "primary": "#6366f1" },
"icons": { "library": "lucide" },
"navigation": {
"groups": [
{
"group": "Getting Started",
"icon": "lucide:rocket",
"pages": ["index", "docs/quickstart"]
},
{
"group": "Guides",
"icon": "lucide:map",
"pages": ["docs/install", "docs/deploy"]
}
],
"global": {
"anchors": [
{ "anchor": "GitHub", "href": "https://github.com/example/docs", "icon": "lucide:github" },
{ "anchor": "Changelog", "href": "https://github.com/example/docs/releases", "icon": "lucide:newspaper" }
]
}
}
}
```
Page slugs in `navigation.pages` map to MDX files. `docs/quickstart` loads
`docs/quickstart.mdx`, and `docs/install` loads `docs/install.mdx`.
### Navbar links and CTA
App routes (login, dashboard, signup) go in `navbar`, and in `knownPaths` so the link check passes:
```jsonc
"navbar": {
"links": [{ "label": "Log in", "href": "/login" }, { "label": "Dashboard", "href": "/dashboard" }],
"primary": { "type": "button", "label": "Start free trial", "href": "/signup" }
},
"knownPaths": ["/login", "/signup", "/dashboard"]
```
## Keep slugs short. Put docs under `/docs`
**Prefer short slugs.** Do not nest pages to match every sidebar group.
Put **info docs** under a **`docs/`** parent so later landing pages, tools, and
products can live at the root without competing with docs URLs.
```diagram
URL file
/ ► index.mdx (home, product, landing)
/pricing ► pricing.mdx (not a docs page)
/docs/quickstart ► docs/quickstart.mdx
/docs/sdk ► docs/sdk.mdx
/docs/cli/query ► docs/cli/query.mdx (max extra folder)
```
Rules:
- **Home stays at the root.** `index.mdx` is `/`.
- **Docs pages use `/docs/...`.** `docs/quickstart.mdx` is `/docs/quickstart`.
Do not put guides at `/quickstart` or `/guides/quickstart`.
- **Max nesting is `docs/<folder>/<page>`.** One subdirectory under `docs` is
the limit (`docs/cli/query.mdx`). Never `docs/cli/analytics/pages.mdx`.
- **Never name a page `README.md` or `README.mdx`.** Either filename becomes
`/README` or `/docs/README`. Use a real slug (`docs/sdk.mdx`) and import
the shared markdown.
- **Keep `index` only for home or a section hub.** Do not use `README` as the
hub filename.
- **Moving a page changes its URL.** Add a redirect from the old slug. Update
`navigation.pages` and relative links. The build's broken-link check catches
links you miss.
**Anchors** in `navigation.global.anchors` are persistent sidebar links visible
across all tabs. Use them for GitHub, Changelog, Discord, or other external
links.
**Progressive disclosure in navigation.** Order groups, pages, and tabs the way
a reader would read them top-to-bottom. Start with introductory content (getting
started, quickstart), then core concepts and guides, then advanced topics and
reference material last. The reader should never need to jump ahead to
understand the current section.
**Tab order.** In `navigation.tabs`, list documentation and guides first, then
API reference, then changelog. Tabs that link out to external URLs (`href`) go
last. This guides the reader from concepts to reference.
## Icons
Use **prefixed icon names** so the source library is explicit:
```jsonc
"icon": "lucide:rocket"
"icon": "fontawesome:brands:github"
```
Plain names resolve against the configured library. See
https://holocron.so/docs/customize/icons.md for the full reference.
If a group has an icon, do not use the same icon on the first page in that
group. It looks like a duplicate in the navigation tree.
## Local imports
MDX pages can import `.md`, `.mdx`, `.tsx`, or `.ts` files. Prefer **relative
imports** (`./` or `../`) over absolute `/` imports.
**Reuse shared markdown with a wrapper page.** Keep `README.md`, `MCP.md`, or
an SDK markdown file outside `pagesDir` for GitHub. Do **not** put those files
in `pagesDir` as `README.md` or `README.mdx`. The Holocron slug is the file
path, so `sdk/README.mdx` becomes `/sdk/README`.
The wrapper inside `pagesDir` owns the public slug:
```
repo/
README.md
MCP.md
website/src/pages/
index.mdx
docs/sdk.mdx → /docs/sdk
docs/mcp-setup.mdx → /docs/mcp-setup
```
```mdx
---
$schema: https://holocron.so/frontmatter.json
title: "MCP Setup"
sidebarTitle: MCP
---
import SharedDocs from '../../../../MCP.md'
<SharedDocs />
```
File: `docs/mcp-setup.mdx`. Nav slug: `"docs/mcp-setup"`. URL: `/docs/mcp-setup`.
If an old `/README` or `/sdk/README` URL exists, add a redirect:
```jsonc
"redirects": [
{ "source": "/sdk/README", "destination": "/docs/sdk", "permanent": true }
]
```
See https://holocron.so/docs/create/local-imports.md for details.
## Linking between pages
> [!IMPORTANT]
> **Internal links must ALWAYS be relative (`./` or `../`). NEVER use an
> absolute link starting with `/`.**
Every internal link from one page to another must:
1. **Start with `./` or `../`** — a relative path from the current file. **Never
start a link with `/`.**
2. **Point at the real target file on disk** — the actual `.md`/`.mdx` file, not
a route or slug.
3. **Keep the `.md`/`.mdx` extension.**
```mdx
✅ [SDK reference](./sdk.mdx)
✅ [Browser Analytics](./browser-analytics.mdx)
✅ [Quickstart](./quickstart.mdx)
❌ [SDK reference](/sdk/README)
❌ [Browser Analytics](/docs/browser-analytics)
❌ [Quickstart](/quickstart)
```
The reason: an absolute `/slug` link hardcodes the route, which depends on
`pagesDir`. The same file produces different slugs across projects
(`pagesDir: './src'` vs `pagesDir: './src/pages'`), so absolute links are
fragile and break when `pagesDir` or the folder layout changes. A relative path
to the real file is `pagesDir`-independent: Holocron resolves it to the right
route and strips the extension, and the link also opens the real file on GitHub.
**Never reason about slugs or `pagesDir` when writing a link.** Write the
relative path to the actual file on disk, the way you would for GitHub. Holocron
does the rest. The only links that may start with `/` are external full URLs
(`https://...`) and `knownPaths` entries declared in `docs.json`.
## Importing a README that also renders on GitHub
A common pattern is importing a repo `README.md` as the docs index page so the
same file renders on **both GitHub and the Holocron site**. The README links to
other docs (pricing, guides, reference), and those links must work in both
places.
The rule is simple: **always link to the real target file with a correct
relative path, ending in `.md` or `.mdx`.** Do not reason about slugs, `pagesDir`,
or where `/` ends up. Write the link the way you would for GitHub: a relative
path from the README to the actual file on disk.
Holocron does the rest. When it inlines an imported file, it **recomputes every
relative link to be correct relative to the importing page**, then **strips the
`.md`/`.mdx` extension**. So a README link to a real file lands on that file's
page automatically, with no per-environment guessing.
### Rules
1. **Link to the real file.** The target must be an actual `.md`/`.mdx` file on
disk at the relative path you write. This is what makes GitHub work, and it is
what Holocron rewrites. If the file does not exist, GitHub 404s and Holocron's
broken-link check warns.
2. **Always use a relative path** (`./` or `../`), never absolute. The README is
rendered from different base directories on GitHub vs Holocron, so an absolute
`/docs/x` or a guessed path breaks in one of them. A relative path to the real
file works in both because Holocron recomputes it.
3. **Keep the `.md`/`.mdx` extension.** GitHub needs it to open the file;
Holocron strips it automatically so the link resolves to the rendered page.
4. **The target file must be a page inside `pagesDir`.** Holocron only maps
links to files under `pagesDir`. Importing a shared markdown file does **not**
give that file a route. From imported markdown, link to the **wrapper `.mdx`**
inside `pagesDir`, not to `README.md` / `MCP.md`.
`[README.md](./README.md)` becomes `/README`. Use
`[quick start](./website/src/pages/docs/quick-start.mdx)` instead.
```diagram
README.md [pricing](./docs/pricing.md) ◄── correct relative path to a real file
│
├──────────────────────► GitHub opens ./docs/pricing.md
│
▼ imported into the index page
Holocron recomputes the relative path ──► strips .md ──► lands on the page that renders pricing
│
▼
/docs/pricing ◄── resolves as long as a page renders that file and it is in docs.json
```
If the rewritten slug has no matching page, the build prints a broken-link
warning pointing at the README line. Fix it by creating the page at
`<pagesDir>/<slug>.mdx` (or a wrapper importing the shared `.md`) and adding its
slug to `docs.json` navigation.
## MDX JSX in README files
Do **not** use MDX JSX components (like `<Aside>`, `<Note>`, `<CardGroup>`,
`<Card>`, etc.) inside `README.md`. GitHub does not render markdown inside
unknown HTML tags; content inside them appears as raw unformatted text.
The README should use only standard markdown. MDX-specific components belong in
the `.mdx` file that imports the README, not in the README itself.
## Page frontmatter
Every MDX page can include YAML frontmatter. See
https://holocron.so/docs/create/pages.md for the full fields reference.
```mdx
---
$schema: https://holocron.so/frontmatter.json
title: Quickstart
description: Build and deploy your first Holocron docs site.
icon: lucide:rocket
tag: NEW
prompt: |
Write the Quickstart from @/cli/src/create.ts.
---
```
### Record the generation prompt
Every documentation page you create must include a **`prompt`** field that
records the instruction and sources used to generate that page. When editing an
older page without one, add it when you can identify the real sources. Write the
original generation recipe, not a maintenance instruction.
Use **`@/path`** for source files and folders from the **repository root**.
Use `@./path` or `@../path` only when the source sits next to the MDX page.
Prefix remote sources with **`@https://`**. Bare URLs are not references. Do
not invent sources, and update the prompt when source locations or page scope
change.
```yaml
---
$schema: https://holocron.so/frontmatter.json
title: Authentication
prompt: |
Write the authentication guide from @/src/auth/ and
@/src/middleware/session.ts.
Use @https://github.com/example/project/releases for recent behavior.
Explain sessions, API keys, and GitHub Actions OIDC.
Include a complete TypeScript example for every method.
---
```
Holocron Maintain extracts these references and reruns the generation prompt
when a source changes. A folder reference matches changes to any tracked file
inside that folder.
### Migrating an existing docs site
When moving a docs site to Holocron, write each `prompt` as if the page was
authored from scratch. Keep it a short summary of what the page documents.
Do not mention migration, recreation, or the old docs URL. Do not add
`@https://old-site/...` references. The source site is going away after the
move unless the user says otherwise.
```yaml
prompt: |
Document connecting the first integration, role access, and chat validation.
```
**Title** should be **50-60 characters** max. It appears in the OG image at large
font size, in the browser tab, and in search results. Keep it concise and
descriptive.
**Sidebar title** — if `title` is longer than **30 characters**, add a
`sidebarTitle` field in frontmatter with a shorter label (under 30 chars). The
left nav is only 230px wide; long titles wrap to multiple lines and break the
visual rhythm. The `sidebarTitle` replaces the title only in sidebar navigation;
the full title still appears in the page heading, browser tab, and OG image.
```mdx
---
$schema: https://holocron.so/frontmatter.json
title: Configuring Authentication Providers
sidebarTitle: Auth Providers
---
```
**Description** should be **120-150 characters**. It appears in the OG image
below the title and in search engine snippets. Write a single sentence that
summarizes the page content. Longer descriptions get truncated with an ellipsis.
## Page titles and SEO (MUST follow)
Google title links and snippets come from on-page title, H1, and description.
See [title links](https://developers.google.com/search/docs/appearance/title-link)
and [snippets](https://developers.google.com/search/docs/appearance/snippet).
Holocron already appends the site name. `buildPageTitle` renders
`{page title} — {site name}` unless `title` already starts with the site name.
**Do not put the site name in `title` or in the H1.** That doubles the brand
(`Kimaki: … — Kimaki`). Write the ranking keywords only. Let Holocron add
` — {site name}`.
Two frontmatter fields:
- **`title`** — browser tab, Google title link, OG image, and the injected H1. Write for SEO. Put the keywords this page should rank for.
- **`sidebarTitle`** — sidebar only. Short label, under 30 characters.
**Always set both.** Without `sidebarTitle`, the long SEO title wraps in the 230px sidebar.
**Always quote frontmatter strings.** YAML treats `:` as a map. `title: Kimaki: AI agents` is nested YAML. Holocron then drops all frontmatter, and the browser title becomes the first body heading. Quote `title` and `description`. Holocron warns when an unquoted value contains `:`, and when a parsed key contains a space and `:`.
```mdx
---
$schema: https://holocron.so/frontmatter.json
title: "Open-source browser automation"
sidebarTitle: Home
description: "Automate any browser with a TypeScript API. Control Chrome from a CLI or agent."
---
```
Browser tab: `Open-source browser automation — Playwriter`
Injected H1: `Open-source browser automation`
Sidebar: `Home`
On most pages Holocron injects `title` as the only H1, so **title and H1 are the same**. Keep it that way. Do not add another `#` or `<h1>` in the body.
**Title rules:**
- **Put ranking keywords in `title`.** The homepage title is the most important. Docs pages use the topic keywords (`Subscriptions`, `Worktrees`), not `Introduction` or `Overview`.
- **Never start `title` with the site name.** Holocron already appends ` — {site name}`.
- **Never set `title` identical to the site name.** A title of `Playwriter` becomes `Playwriter — Playwriter`.
- **Every `title` MUST be unique, descriptive, and concise.** Google truncates long titles. Avoid keyword stuffing and boilerplate that only changes one word.
- **`index.mdx` MUST use `sidebarTitle: Home`** (or `Overview`). See Homepage SEO below.
**H1 rules:**
- **One H1 per page.** It must contain the same ranking keywords as `title`. Prefer the exact `title` text. Holocron does this automatically when it injects the title.
- Google uses the first prominent H1 as a title-link source. Extra H1s with the same weight can steal the tab title (`Quick Start — Site`). Heading count is not a ranking penalty. A clear main title is.
**Description rules:**
`description` becomes `<meta name="description">`. Google may use it as the snippet when it describes the page better than on-page text.
- **Unique per page.** Site-wide copy on every page is useless in search results.
- **Summarize this page**, in one or two sentences. Not a keyword list.
- **Include ranking keywords naturally.** Do not stuff. Do not repeat the site name just because the title suffix already has it. The homepage may name the product once if that is the summary.
- **Be specific.** Length has no hard cap. Google truncates to the device width. Aim for a short pitch, about 120 to 160 characters.
- Quote the YAML string.
```yaml
description: "Run AI coding agents from Discord. Each channel is a project, each thread is a session."
```
## Homepage SEO
The homepage title is the strongest brand query signal. Put the keywords people search in `title` and H1. Let Holocron append the site name.
```mdx
---
$schema: https://holocron.so/frontmatter.json
title: "AI coding agents from Discord"
sidebarTitle: Home
description: "Run AI coding agents from Discord. Each channel is a project, each thread is a session."
---
```
Browser tab: `AI coding agents from Discord — Kimaki`
H1: `AI coding agents from Discord`
**One H1, same keywords as `title`.** Holocron injects that H1 unless the page has `<Above>` or `hideTitle: true`. A custom hero that also renders `<h1>` next to an injected title creates two H1s.
**If the page has `<Above>`, that hero owns the H1.** Holocron skips the injected title. Set the hero H1 to the same text as `title`. Do not put the site name in the hero H1. Never write `#` or `<h1>` in the MDX body below it. The first body section must be `##`. Extra H1s are demoted to H2.
```mdx
---
title: "AI coding agents from Discord"
sidebarTitle: Home
description: "Run AI coding agents from Discord. Each channel is a project, each thread is a session."
---
<Above>
<HeroSection />
</Above>
```
```tsx
<h1>
<span>AI coding agents</span>
<span>from Discord.</span>
</h1>
```
If there is no custom hero, do **not** set `hideTitle`. Let Holocron inject `title` as the only H1.
**Do not make `/` a clone of GitHub.** Importing `README.md` under the hero is fine. The homepage still needs its own title, H1, and description. If `/` is the same text as GitHub, Google prefers GitHub plus a unique inner docs page.
A **logo link to `/`** is weak. Fix title, H1, and description first.
After deploy, fetch the live HTML and check:
```bash
curl -sL -A 'Mozilla/5.0 (compatible; Googlebot/2.1)' 'https://example.com/' -o /tmp/home.html
```
Confirm **exactly one `<h1>`**, that H1 text matches `title`, and `<title>` is `{title} — {site name}` with the site name only at the end. Rank will not move until Google recrawls.
## Readable text over hero backgrounds
Text over a `VideoBackgroundShader` hero is hard to see: the animated glyphs
fight with the letters. Always add contrast layers.
**Heading and CTAs:** add a radial scrim that fades the background in the
center, behind the content (`z-[1]`, below the text at `z-[2]`):
```tsx
<div
aria-hidden
className='absolute inset-0 z-[1] pointer-events-none'
style={{
background:
'radial-gradient(ellipse 45% 40% at 50% 42%, color-mix(in srgb, var(--background) 85%, transparent) 0%, color-mix(in srgb, var(--background) 60%, transparent) 50%, transparent 100%)',
}}
/>
```
**Subheading and small text:** give it a blurred, semi-transparent pill. Small
muted text is unreadable over glyphs without it:
```tsx
<p className='rounded-xl bg-background/50 px-3 py-1.5 text-sm text-muted-foreground backdrop-blur-md'>
Paste the prompt into your agent
</p>
```
Also keep `dotColor` close to the page background so the title keeps contrast.
## Page modes — hiding sidebars
Set **`mode`** in frontmatter to hide sidebars. Use for landing pages, tool pages, or pages that should not show left nav or AI chat. See https://holocron.so/docs/customize/layout.md for details.
- **`center`** — hides the left nav, centers content. Right aside still works.
- **`custom`** — hides both sidebars and the editorial grid. Only navbar, tab bar, and footer remain. See `example/src/landing.mdx` for a full example.
In both modes the content can feel too wide. Use **`maxWidth`** to constrain it:
```yaml
---
$schema: https://holocron.so/frontmatter.json
mode: "custom"
maxWidth: 700
---
```
## Custom entry (mounting docs inside a Spiceflow app)
When the site mounts Holocron inside an existing **Spiceflow** app (the `entry`
option in the Vite plugin), always fetch the custom entry docs first. This page
covers middleware order, the shared theme cookie, Tailwind `@reference` rules,
and how to keep docs (including OpenAPI and Changelog tabs) under a `/docs/*`
namespace so they never collide with app routes like `/api`:
```bash
curl -fsSL https://holocron.so/docs/custom-entry.md
```
## Redirects
When restructuring docs, add redirects in `docs.json`. See
https://holocron.so/docs/create/redirects.md for the full reference.
## Broken link detection
Holocron **fails production builds** when internal links point to non-existent
pages. Dev still warns. Links in MDX, **footer**, **navbar**, and **anchors**
are all checked. Links to redirect sources and static files (`.json`, `.pdf`,
etc.) are not flagged. The warning includes the **source**, **line number**,
and the broken href so you can find and fix it quickly.
Do **not** put a path in `knownPaths` unless that route actually exists at
runtime. `knownPaths` only silences the check; it does not create a page.
### Suppressing false positives with `knownPaths`
When docs are mounted alongside other routes (API endpoints, dashboards, blogs),
internal links to those non-MDX paths trigger false broken-link warnings. Use
the **`knownPaths`** field in `docs.json` to tell Holocron these paths are valid:
```jsonc
{
"knownPaths": ["/api/*", "/dashboard", "/blog/*"]
}
```
**Supported patterns:**
- **Exact paths** — `"/dashboard"` matches only `/dashboard`.
- **Wildcard prefixes** — `"/api/*"` matches `/api/users`, `/api/v2/health`,
and any other path starting with `/api/`.
Wildcards only work as a trailing `/*` suffix. Glob patterns like `/api/*/users`
are not supported.
## Vertical spacing inside wrappers
When wrapping MDX content in a `<div>` or custom component, add
`flex flex-col gap-(--prose-gap)` so children get correct vertical spacing.
Without it, elements collapse together. Add `no-bleed` too if the wrapper
contains images or code blocks that shouldn't escape its bounds.
```mdx
<div className='no-bleed flex flex-col gap-(--prose-gap)'>
First paragraph.
Second paragraph with correct spacing above.
</div>
```
## MDX container components
Always use multi-line form for container components like `Callout`, `Note`,
`Warning`, `Info`, `Tip`, `Check`, `Danger`, `Aside`, `Accordion`, `Steps`,
`Card`, `Expandable`, `Panel`, `Frame`, and `Prompt`.
```mdx
<Note>
Use `Note` for neutral supporting information.
</Note>
```
Single-line form can produce bare phrasing children without paragraph wrapping,
which changes styling.
Native headings (`h1`-`h6`) are auto-fixed; Holocron unwraps the paragraph
wrapper regardless of form. For other leaf-like elements (`<span>`, `<div>`,
or custom uppercase components), use **single-line form** to avoid the wrapper.
```mdx
<MyBanner className='text-xl'>Short announcement text</MyBanner>
```
## Aside content
`Aside` is positioning-only and has no visual frame. Always wrap visible content
inside `Note`, `Tip`, `Info`, `Warning`, `Callout`, or another framed component.
```mdx
<Aside>
<Note>
This appears in the sidebar with a proper callout frame.
</Note>
</Aside>
```
Exception: `Aside full` can contain `TableOfContentsPanel` directly.
**Only use `<Aside>` in sections with enough content.** A non-full Aside shares
its vertical space with the section it belongs to (the content between two
headings). If the aside is taller than the section text, extra whitespace appears
below the main content to accommodate the aside height. Keep aside callouts
short, and only place them in sections that have at least a few paragraphs of
body text.
## Moving or renaming a page
When moving or renaming a page, **always add a redirect** from the old path to
the new one so old URLs and bookmarks keep working. Update internal links in
other pages and the slug in `docs.json` navigation to match.
Add the redirect to the `redirects` array in `docs.json`:
```jsonc
{
"redirects": [
{ "source": "/old-page", "destination": "/new-page" },
{ "source": "/guides/setup", "destination": "/docs/setup", "permanent": true },
// wildcard: redirect a whole moved folder (:splat = matched suffix)
{ "source": "/v1/*", "destination": "/v2/:splat" }
]
}
```
`source` and `destination` are **absolute paths** (leading `/`, no extension).
Add `"permanent": true` for a 301 (default is 302). See
https://holocron.so/docs/create/redirects.md for the full reference.
## New pages and navigation
After creating a new `.mdx` or `.md` page, add its slug to `docs.jsonc`
navigation. Pages not in the navigation tree will not appear in the sidebar
and return 404.
Read the existing navigation structure first, then place the page in the best
tab, group, and reading order.
### Legal and support pages: hidden group plus footer
Privacy policy, terms of service, support and similar pages are **not interesting
for readers**. Never show them in the sidebar. Put them in a group with
`"hidden": true` (still served and indexed) and link them from `footer.links`:
```jsonc
{
"navigation": {
"groups": [
// ...real docs groups
{
"group": "Legal",
"hidden": true,
"pages": ["docs/privacy", "docs/terms", "docs/support"]
}
]
},
"footer": {
"links": [
{
"header": "Legal",
"items": [
{ "label": "Privacy", "href": "/docs/privacy" },
{ "label": "Terms", "href": "/docs/terms" },
{ "label": "Support", "href": "/docs/support" }
]
}
]
}
}
```
Use the group `hidden` flag, not `hidden: true` in page frontmatter: frontmatter
`hidden` also adds `noindex`. Add `"redirects"` from the standard short paths
(`/privacy`, `/terms`, `/support`) with `"permanent": true`, because app stores
and OAuth consent screens often expect them.
### Where to put new content
The real docs live in **`website/src/pages/docs/`**, not `example/src/`. The `example/`
folder is a demo fixture, not the published docs site.
Before adding or editing docs content, **always read `website/docs.json`** first
to see the full navigation tree and existing pages. Then decide:
1. Does an existing page already cover this topic? Add a section there.
2. Is the topic distinct enough for its own page? Create a new `.mdx` file and
add it to the best group in `website/docs.json`.
Never append unrelated sections to a page just because it was the last file you
had open. Match the topic to the right page or create a new one.
## Feedback loop
After editing MDX pages, `docs.json` navigation, or frontmatter, always **build the site** to
catch issues early. The build surfaces broken internal links, MDX parsing errors, missing pages
referenced in navigation, and rendering problems that the dev server may not show until a page
is visited.
```bash
pnpm build
```
Fix any warnings or errors before considering the changes done. Common issues:
- **Broken links** — an internal `[link](/some-page)` pointing to a slug not in navigation.
- **MDX parse errors** — malformed JSX, unclosed tags, or invalid frontmatter YAML.
- **Missing pages** — a slug listed in `docs.json` navigation but no matching `.mdx` file exists.
- **Rendering errors** — components used incorrectly (e.g. wrong props, missing children).
If the build warns about links to paths that are **not MDX pages but do exist** at runtime (API
routes, external apps mounted alongside docs, dashboard pages), suppress those warnings with
the `knownPaths` field in `docs.json`. See the [Broken link detection](#broken-link-detection)
section above.
## CLI overview
Run `--help` to see all available commands. Never truncate the output.
```bash
npx -y "@holocron.so/cli" --help
```
Key commands: `login`, `logout`, `whoami`, `deploy`, `projects list`,
`projects create`, `keys list`, `keys create`, `keys delete`, `create`.
Before logging in, always check if the user is already authenticated:
```bash
npx -y "@holocron.so/cli" whoami
```
If `whoami` succeeds and shows user, orgs, and projects, skip login. Only run
`npx -y "@holocron.so/cli" login` if `whoami` fails.
## Deploy
When the user asks to "deploy the site", they may mean deploying with their own
script and platform (Cloudflare Workers, a Node server, CI pipeline), not
`holocron deploy`. Check `package.json` scripts first: if there is a `deploy`,
`deployment`, or similar script (e.g. wrangler deploy), use that instead of the
Holocron CLI. Only use `holocron deploy` when the project has no own deploy
script or the user explicitly asks for holocron.so hosting.
`holocron deploy` builds the docs site and uploads it to holocron.so hosting.
It is the fastest way to publish without managing your own server.
```bash
npx -y "@holocron.so/cli" deploy
```
The command runs the build, uploads only changed files, finalizes the deployment,
and prints the live URL. Use `--project prj_xxx` if the account has multiple
projects and you are using session auth. Use `--branch <name>` to override
branch detection for preview deploys.
**Auth priority:** `HOLOCRON_KEY` env var > session token from `holocron login` >
GitHub Actions OIDC token (automatic in GitHub Actions with `id-token: write`).
See https://holocron.so/docs/deploy/holocron.md for the full reference including
deployment URLs, GitHub Actions OIDC setup, and org/project resolution.
Always deploy preview before production. If preview fails, stop.
## Icon consistency
When adding icons to any element in `docs.json` or MDX frontmatter, apply them **consistently across all siblings** at the same level. Inconsistent icon usage looks unfinished and breaks visual rhythm.
**Rules:**
- **Tabs**: if one tab has an icon, every tab must have an icon.
- **Groups**: if one sidebar group has an icon, every sibling group in the same tab should have one.
- **Anchors**: if one anchor in `navigation.global.anchors` has an icon, all anchors must.
- **Pages**: if one page in a group has a frontmatter `icon`, all pages in that group should. Exception: a group with only 1-2 pages where icons add no navigational value.
- **Cards / CardGroup**: if one `<Card>` in a `<CardGroup>` has an `icon` prop, every card in that group must.
- **Accordion / AccordionGroup**: same rule. Either all items have icons or none do.
When reviewing or creating navigation and MDX content, scan siblings and fill in missing icons before finishing. Pick icons from the same library (usually Lucide) and choose semantically distinct icons for each item.
## Writing style for MDX pages
### Bold keywords for skimmability
Every section and every paragraph must have at least **one bold keyword or phrase**. Readers skim docs pages; they do not read every word. Bold text acts as anchor points that let the eye jump to the relevant paragraph.
Pick the word or phrase that captures the core idea. Do not bold entire sentences or generic filler words. Bold the specific term, API name, or concept that a reader would scan for.
### Use Aside frequently for side content
Use `<Aside>` often to place supplementary content in the right sidebar column. Asides break the monotony of a single-column text flow and give readers contextual notes exactly where they are relevant. A page with zero asides looks flat and underuses the layout.
Good candidates for Aside content:
- **Tips and gotchas** that relate to the current section but are not part of the main narrative
- **Version notes** or compatibility warnings
- **Links to related pages** or external references
- **Short code snippets** showing an alternative approach or edge case
- **Definitions or clarifications** of a term introduced in the main text
Always wrap Aside content in a framed component (`Note`, `Tip`, `Info`, `Warning`, `Callout`).
```mdx
## Authentication
The deploy command authenticates via **GitHub Actions OIDC** when running in CI.
<Aside>
<Info>
If OIDC is not available, fall back to a **`HOLOCRON_KEY`** environment variable
or a session token from `holocron login`.
</Info>
</Aside>
```
Aim for roughly **one Aside per major section** (per `##` heading). Not every section needs one, but if a page has more than three `##` sections without a single Aside, look for opportunities.
**Avoid asides in short sections.** A non-full Aside shares vertical space with its section (the text between two headings). If the aside callout is taller than the section body, empty whitespace fills the gap below the main content. Only add asides to sections with enough prose to match or exceed the aside height. Keep aside callouts concise (1-2 sentences).
### Use diagrams to explain architecture and flows
Use ASCII diagrams frequently in MDX pages. Always use the **`diagram`** language hint on the code fence. Holocron renders `diagram` fences with special styling; Unicode box-drawing characters and arrows get colored differently from labels.
**Layout rules:**
- Diagrams should try to cover the **full width of the content column**, roughly **94 characters** wide.
- Never exceed 94 characters per line.
- Prefer a **varied, organic layout**. Mix plain text labels, boxes for major components, and directional arrows.
- All connections must use **directional arrows**. Never use plain lines without an arrowhead.
- Verify alignment by running `npx -y "@holocron.so/cli" diagrams fix <file>` (see dedicated section below).
````mdx
```diagram
┌───────────────┐
docs.jsonc ───►│ Vite Plugin │──────► Build Output
└───────┬───────┘
│
┌───────▼───────┐
│ sync.ts │ MDX files ──► parsed sections
│ (walk nav) │ git SHA diff ──► cache hit/miss
└───────┬───────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
navigation page cache virtual modules
tree.json holocron-mdx holocron-pages
holocron-config holocron-config
```
````
## Always run `diagrams fix` after editing diagrams or tables
LLMs cannot count characters or pad table columns reliably. Every time you create or edit a **diagram** or a **GFM table** in an MDX page, you **must** run the fixer before committing. This is not optional.
```bash
npx -y "@holocron.so/cli" diagrams fix path/to/file.mdx
```
The command:
- Fixes box-drawing diagram alignment (padding, border widths, junctions) in-place
- Formats GFM tables (column padding, aligned pipes, blank lines above/below)
- Reports how many lines were changed
- Exits with code 1 if any diagram lines exceed max width (94 cols by default) or tables still need formatting (`--check`)
If the output says "No changes", the file was already correct. If it reports width violations, shorten the offending diagram lines manually and re-run.
**Do not skip this step.** Even if a diagram or table looks fine in your editor, run the command. Off-by-one padding and uneven table columns are invisible to LLMs but obvious to humans in monospace fonts.
## OpenAPI summaries
OpenAPI operation `summary` fields become sidebar titles. The sidebar is only
230px wide, so summaries must be **short**: 2-3 words, ideally under 20
characters. Use the same concise style as page `sidebarTitle` fields.
- **Verb + noun** pattern: `List users`, `Create order`, `Get me`, `Upload files`.
- Drop qualifiers, parentheticals, and implementation details. `Upload deployment files (zip batch)` becomes `Upload files`.
- Never repeat the tag/group name in the summary. If the tag is `Deploy`, the summary should not start with "Deploy".
- If the summary reads well as a sidebar label at 230px, it is short enough.
## Bleed — extending content past the prose column
Always wrap **YouTube embeds, videos, and large images** in `<div className='bleed'>`
so they extend into both page margins instead of sitting at narrow prose width.
`<Frame>` also accepts `className='bleed'`. Containers like Callout, Card, and
Accordion apply `no-bleed` automatically to keep descendants inside their frame.
See https://holocron.so/docs/customize/bleed.md for the full reference.
## Custom CSS — prefer CSS variables over class selectors
When customizing the look of a Holocron site, **always use CSS variable overrides** in `:root` instead of targeting internal class names, DOM structure, or aria labels. Holocron exposes a set of documented CSS variables for colors, typography, spacing, code blocks, blockquotes, and sidebar navigation. These are stable across Holocron updates; internal markup is not.
```css
/* style.css */
:root {
--weight-heading: 700;
--code-block-background: var(--muted);
--code-block-border: 1px solid var(--border-subtle);
--sidebar-link-radius: var(--radius-sm);
--blockquote-border-color: var(--border-subtle);
}
```
Fetch the full list of available tokens:
```bash
curl -fsSL https://holocron.so/docs/customize/theme.md
```
If a user wants to customize something that has no CSS variable, **do not hack it with fragile selectors**. Instead, open an issue on the Holocron repo (https://github.com/remorses/holocron/issues) requesting a new CSS variable for that use case. Holocron actively adds new variables based on user needs. Internal selectors like `.slot-sidebar-left nav > div:first-child > a` or `figure[class~='group/code'] button[aria-label='Copy code']` will break on any refactor and should never be used.
## Agent rules
- **Always place MDX pages inside the Holocron `pagesDir`.** Before creating or
editing any docs page, read the project's `vite.config.ts` (or `vite.config.mts`)
to find the `pagesDir` option passed to the Holocron plugin. If `pagesDir` is not
set, it defaults to the project root. All `.mdx` and `.md` page files must live
inside that directory; files outside it are invisible to the navigation and build.
- Prefer the latest fetched docs over anything remembered from previous sessions.
- Keep rule-like project behavior in this skill so agents see it even before
fetching the full docs.
- All ASCII diagrams in MDX pages must use the `diagram` language hint on the
code fence (` ```diagram `). This renders them with proper styling on the
website instead of plain monospace.
- After creating or editing any diagram or GFM table, run
`npx -y "@holocron.so/cli" diagrams fix <file>` to auto-fix diagram
alignment and table column padding. LLMs cannot count characters or pad
columns reliably.
- Never pipe curl or `--help` output through `head`, `tail`, or any truncation
command. Always read the full output.