@stritti/vitepress-plugin-openspec
v0.7.0
Published
A VitePress plugin that integrates OpenSpec documentation into your VitePress site
Downloads
1,085
Maintainers
Readme
@stritti/vitepress-plugin-openspec
A VitePress plugin that renders your project's OpenSpec folder as structured documentation pages — specs, changes, and artifacts — with sidebar and nav integration.
Installation
npm install @stritti/vitepress-plugin-openspec
# or with bun:
bun add @stritti/vitepress-plugin-openspecUsage
Add the following to your .vitepress/config.ts:
import { defineConfig } from 'vitepress'
import { withOpenSpec } from '@stritti/vitepress-plugin-openspec'
export default defineConfig(
withOpenSpec({
// your regular VitePress config
themeConfig: {
nav: [{ text: 'Home', link: '/' }],
sidebar: {},
},
})
)withOpenSpec handles everything in one call: page generation, the Vite plugin for live reload, the nav entry, and the sidebar section. All fields are optional — it works with an empty config object and sensible defaults.
Other Vite plugins go into vite.plugins as usual — withOpenSpec appends to the array without replacing it:
import { defineConfig } from 'vitepress'
import { withOpenSpec } from '@stritti/vitepress-plugin-openspec'
import myOtherPlugin from 'vitepress-plugin-something'
export default defineConfig(
withOpenSpec(
{
vite: { plugins: [myOtherPlugin()] }, // preserved alongside openspec
themeConfig: { nav: [], sidebar: {} },
},
{ specDir: '../openspec', outDir: 'openspec' } // options (all optional)
)
)Options
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| specDir | string | './openspec' | Path to your project's openspec/ directory. Can be an absolute path or relative to the working directory — use path.resolve(__dirname, '../../openspec') when config.ts lives in docs/.vitepress/. |
| outDir | string | 'openspec' | Output directory relative to VitePress srcDir |
| srcDir | string | process.cwd() | VitePress source directory (the docs/ folder) |
| nav | boolean | true | Whether to prepend an openspec entry to themeConfig.nav |
| sidebar | boolean | true | Whether to inject the openspec sidebar section into themeConfig.sidebar |
Missing directory — if
specDirdoes not exist the plugin emits aconsole.warnand skips page generation, nav, and sidebar. No error is thrown and your VitePress build continues normally. This is intentional for projects that haven't set up anopenspec/folder yet.
Advanced / manual setup
If you need full control over each integration point, you can wire up the lower-level APIs individually:
import { defineConfig } from 'vitepress'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import openspec, {
generateOpenSpecPages,
generateOpenSpecSidebar,
openspecNav,
} from '@stritti/vitepress-plugin-openspec'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const specDir = path.resolve(__dirname, '../openspec')
// Must be called before defineConfig so pages exist when VitePress scans for routes.
generateOpenSpecPages({
specDir,
outDir: 'openspec',
srcDir: path.resolve(__dirname, '..'),
})
export default defineConfig({
vite: {
plugins: [openspec({ specDir, outDir: 'openspec' })],
},
themeConfig: {
nav: [openspecNav(specDir, { outDir: 'openspec', text: 'Docs' })],
sidebar: {
'/openspec/': generateOpenSpecSidebar(specDir, { outDir: 'openspec' }),
},
},
})Output Structure
The plugin reads your openspec/ folder and generates:
openspec/ ← your source (not committed if used as output)
├── specs/
│ └── <capability>/
│ └── spec.md
└── changes/
├── <change-name>/
│ ├── .openspec.yaml
│ ├── proposal.md
│ ├── design.md
│ └── tasks.md
└── archive/
└── YYYY-MM-DD-<change-name>/
docs/openspec/ ← generated by the plugin (automatically gitignored)
├── index.md
├── specs/
│ ├── index.md
│ └── <capability>/
│ └── index.md
└── changes/
├── index.md
├── <change-name>/
│ ├── index.md
│ ├── proposal.md
│ └── tasks.md
└── archive/
└── YYYY-MM-DD-<change-name>/
└── ...The plugin automatically writes a .gitignore into the output directory that excludes all generated files from version control. No manual .gitignore entry is needed.
How It Works
VitePress scans srcDir for .md files before any Vite plugin hooks run. The plugin solves this with two complementary mechanisms:
generateOpenSpecPages()— called synchronously at the top ofconfig.ts, beforedefineConfig(). Ensures all pages exist when VitePress scans for routes (critical for first builds and CI).openspec()Vite plugin — callsgenerateOpenSpecPages()again on every config reload duringvitepress dev, keeping pages in sync with your source files.
Development
bun install # Install dependencies
bun run build # Build the plugin
bun run dev # Watch mode
bun test # Run tests
bun run lint # Type checkLicense
MIT
