dogsbay 0.2.0-beta.2 → 0.2.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/agent.js +305 -0
- package/dist/commands/site-build.js +66 -15
- package/dist/commands/site-dev.js +181 -23
- package/dist/commands/site-init.js +193 -32
- package/dist/config/defaults.js +8 -1
- package/dist/config/load.js +6 -32
- package/dist/config/to-astro-options.js +1 -0
- package/dist/import-content.js +13 -12
- package/dist/index.js +19 -4
- package/dist/passthrough-astro.js +152 -0
- package/dist/registry.js +8 -0
- package/package.json +11 -9
- package/skills/platform/agent-readiness/SKILL.md +262 -0
- package/skills/platform/cli-commands/SKILL.md +205 -0
- package/skills/platform/config-yml/SKILL.md +219 -0
- package/skills/platform/frontmatter-fields/SKILL.md +310 -0
- package/skills/platform/markdown-directives/SKILL.md +329 -0
- package/skills/platform/multi-source/SKILL.md +294 -0
- package/skills/platform/nav-file/SKILL.md +107 -0
- package/skills/platform/openapi-source/SKILL.md +237 -0
- package/skills/platform/plugin-api/SKILL.md +280 -0
- package/skills/platform/project-anatomy/SKILL.md +156 -0
- package/skills/platform/taxonomy-config/SKILL.md +392 -0
- package/skills/platform/theme-tokens/SKILL.md +276 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dogsbay:multi-source
|
|
3
|
+
description: How sources[] aggregation works in Dogsbay — multiple content sources with locale, version, and namespace axes producing unified URLs and per-source nav. Use when configuring multi-source sites, multi-version setups, or i18n.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Multi-source aggregation
|
|
7
|
+
|
|
8
|
+
Dogsbay treats versioning, i18n, and multi-repo aggregation as
|
|
9
|
+
the **same problem with different metadata keys**. One mechanism
|
|
10
|
+
solves all three: each entry in `content.sources[]` carries
|
|
11
|
+
optional `name`, `version`, `locale` metadata, and the
|
|
12
|
+
aggregator activates a URL axis when ≥2 sources have distinct
|
|
13
|
+
values.
|
|
14
|
+
|
|
15
|
+
## Three axes, one URL convention
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
/<basePath>/<locale>/<version>/<namespace>/<page-slug>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Each axis is **omitted from URLs when not in use**. The base
|
|
22
|
+
case (single locale, version, namespace) keeps URLs flat:
|
|
23
|
+
`/docs/intro`. Add axes by configuring sources; the URL grows
|
|
24
|
+
left-to-right in canonical order.
|
|
25
|
+
|
|
26
|
+
| Configuration | URL example |
|
|
27
|
+
|---|---|
|
|
28
|
+
| Single source, no axis metadata | `/docs/intro` |
|
|
29
|
+
| i18n only | `/docs/en/intro`, `/docs/fr/intro` |
|
|
30
|
+
| Versioning only | `/docs/v1/intro`, `/docs/latest/intro` |
|
|
31
|
+
| Locale + version | `/docs/en/v2/intro`, `/docs/fr/latest/intro` |
|
|
32
|
+
| Multi-namespace | `/docs/api-reference/intro`, `/docs/handbook/intro` |
|
|
33
|
+
| All three | `/docs/en/v2/api-reference/intro` |
|
|
34
|
+
|
|
35
|
+
Order: locale → version → namespace. Locale outermost matches
|
|
36
|
+
universal convention (Mintlify, Starlight, Cloudflare Docs).
|
|
37
|
+
Version inside locale because each locale has its own version
|
|
38
|
+
cadence.
|
|
39
|
+
|
|
40
|
+
## When does an axis activate?
|
|
41
|
+
|
|
42
|
+
The aggregator inspects the configured sources at build time:
|
|
43
|
+
|
|
44
|
+
- **Locale axis** active when ≥2 distinct `locale:` values appear
|
|
45
|
+
- **Version axis** active when ≥2 distinct `version:` values appear
|
|
46
|
+
- **Namespace axis** active when ≥2 distinct `name:` values appear
|
|
47
|
+
|
|
48
|
+
`undefined` counts as a distinct bucket. So:
|
|
49
|
+
|
|
50
|
+
- One source with `locale: en`, one with no `locale:` → locale
|
|
51
|
+
axis IS active. The unspecified source's pages stay flat
|
|
52
|
+
(`/docs/page`); the `en:` source's pages get `/docs/en/page`.
|
|
53
|
+
- Five sources all with `locale: en` → locale axis is NOT active.
|
|
54
|
+
The metadata is uniform; no prefix needed.
|
|
55
|
+
|
|
56
|
+
This produces the "current + archived" / "default + i18n" patterns
|
|
57
|
+
naturally. Adding versioning to one source never silently
|
|
58
|
+
rewrites URLs in the unversioned baseline.
|
|
59
|
+
|
|
60
|
+
## Source descriptor
|
|
61
|
+
|
|
62
|
+
```yaml
|
|
63
|
+
content:
|
|
64
|
+
sources:
|
|
65
|
+
# Local filesystem
|
|
66
|
+
- name: docs
|
|
67
|
+
path: ./content/v1
|
|
68
|
+
version: v1
|
|
69
|
+
locale: en
|
|
70
|
+
from: dogsbay-md
|
|
71
|
+
primary: true
|
|
72
|
+
|
|
73
|
+
# Git checkout — fetched at build time
|
|
74
|
+
- name: api-reference
|
|
75
|
+
git: https://github.com/acme/api-docs.git
|
|
76
|
+
ref: v1.0
|
|
77
|
+
subdir: docs # optional path within the repo
|
|
78
|
+
version: v1
|
|
79
|
+
|
|
80
|
+
# Same source as a different version
|
|
81
|
+
- name: docs
|
|
82
|
+
path: ./content/v2
|
|
83
|
+
version: v2
|
|
84
|
+
locale: en
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
| Field | Required | Notes |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `path` OR `git` | yes (exactly one) | Origin |
|
|
90
|
+
| `ref` | required when `git:` is set | Branch / tag / sha |
|
|
91
|
+
| `subdir` | no | Subdirectory within resolved source |
|
|
92
|
+
| `name` | no | Namespace key |
|
|
93
|
+
| `version` | no | Version label |
|
|
94
|
+
| `locale` | no | BCP-47 locale tag |
|
|
95
|
+
| `from` | no | One of `auto`, `dogsbay-md`, `mkdocs`, `obsidian`, `starlight`, `mdx`, `openapi` |
|
|
96
|
+
| `nav` | no | Path to explicit nav file |
|
|
97
|
+
| `primary` | no | Marks this source for primary build mode |
|
|
98
|
+
|
|
99
|
+
## Single canonical shape — `sources[]` only
|
|
100
|
+
|
|
101
|
+
Even one source uses the array. There is no `content.source:`
|
|
102
|
+
shorthand. Single-source pays one extra YAML line; in exchange
|
|
103
|
+
the schema, loader, and docs stay simple.
|
|
104
|
+
|
|
105
|
+
```yaml
|
|
106
|
+
content:
|
|
107
|
+
sources:
|
|
108
|
+
- path: ./content
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Defaults for missing axis metadata
|
|
112
|
+
|
|
113
|
+
When an axis IS active but a source omits the key:
|
|
114
|
+
|
|
115
|
+
| Axis | Default |
|
|
116
|
+
|---|---|
|
|
117
|
+
| `locale` | falls back to `defaultLocale` if declared, else `undefined` (no segment) |
|
|
118
|
+
| `version` | falls back to `defaultVersion` if declared, else `undefined` (no segment) |
|
|
119
|
+
| `namespace` | `undefined` — no segment, even when other sources have names |
|
|
120
|
+
|
|
121
|
+
The `undefined`-as-distinct-bucket semantics let users mix
|
|
122
|
+
"current" + "archived" sources without explicit metadata on the
|
|
123
|
+
current one.
|
|
124
|
+
|
|
125
|
+
## Build modes — `all` (default) vs `primary-only`
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
dogsbay site build # all sources (default — full matrix)
|
|
129
|
+
dogsbay site build --primary-only # only sources marked primary: true
|
|
130
|
+
dogsbay site dev # primary-only (fast iteration)
|
|
131
|
+
dogsbay site dev --full # all sources (preview switcher chrome)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`dogsbay site build` defaults to **publish mode** — every declared
|
|
135
|
+
source builds. Declaring `locales:`, `versions:`, or multiple
|
|
136
|
+
sources in config is a strong signal you want them all in
|
|
137
|
+
production; a writer who runs `site build` after declaring a
|
|
138
|
+
French locale should see French in the output, not silently dropped.
|
|
139
|
+
|
|
140
|
+
`--primary-only` is the opt-out for fast-iteration CI lint jobs
|
|
141
|
+
that don't need the full matrix (rare). When ≥1 source has
|
|
142
|
+
`primary: true`, primary-only loads just those. If NO source has
|
|
143
|
+
`primary: true`, the filter is inert (every source loads).
|
|
144
|
+
|
|
145
|
+
`dogsbay site dev` is the writer's iteration loop and defaults to
|
|
146
|
+
`primary-only` for speed. Use `--full` to preview the version /
|
|
147
|
+
locale switcher chrome locally.
|
|
148
|
+
|
|
149
|
+
The legacy `--publish` flag is kept as a deprecated no-op for
|
|
150
|
+
older scripts; publish IS the default now.
|
|
151
|
+
|
|
152
|
+
## Namespace nav merging
|
|
153
|
+
|
|
154
|
+
Each source's nav becomes a top-level group in the unified
|
|
155
|
+
sidebar:
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
Sidebar:
|
|
159
|
+
Docs ← namespace "docs" group
|
|
160
|
+
Getting started
|
|
161
|
+
Concepts
|
|
162
|
+
…
|
|
163
|
+
API reference ← namespace "api-reference" group
|
|
164
|
+
Authentication
|
|
165
|
+
Endpoints
|
|
166
|
+
…
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Sources without an explicit `name:` contribute their nav flat
|
|
170
|
+
(no group wrapper).
|
|
171
|
+
|
|
172
|
+
## Per-page axis metadata
|
|
173
|
+
|
|
174
|
+
When ANY axis is active, every imported page gets
|
|
175
|
+
`page.multiSource` populated:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
{
|
|
179
|
+
namespace?: string; // when namespace axis active
|
|
180
|
+
version?: string; // when version axis active
|
|
181
|
+
locale?: string; // when locale axis active
|
|
182
|
+
originalSlug: string; // slug as the importer produced it
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Used by:
|
|
187
|
+
|
|
188
|
+
- The version-switcher UI (cross-version equivalents)
|
|
189
|
+
- The locale-switcher UI (translated equivalents)
|
|
190
|
+
- Hreflang / canonical tag emission
|
|
191
|
+
- The agent-readiness `.md` mirror with axis context
|
|
192
|
+
|
|
193
|
+
## Common patterns
|
|
194
|
+
|
|
195
|
+
### Versioning markdown sources
|
|
196
|
+
|
|
197
|
+
```yaml
|
|
198
|
+
content:
|
|
199
|
+
sources:
|
|
200
|
+
- path: ./content # current — flat URLs
|
|
201
|
+
from: dogsbay-md
|
|
202
|
+
primary: true
|
|
203
|
+
|
|
204
|
+
- path: ./archive/v1
|
|
205
|
+
from: dogsbay-md
|
|
206
|
+
version: v1 # archived — /docs/v1/...
|
|
207
|
+
|
|
208
|
+
- path: ./archive/v0
|
|
209
|
+
from: dogsbay-md
|
|
210
|
+
version: v0 # archived — /docs/v0/...
|
|
211
|
+
|
|
212
|
+
versions:
|
|
213
|
+
- id: latest
|
|
214
|
+
label: Latest
|
|
215
|
+
default: true
|
|
216
|
+
- id: v1
|
|
217
|
+
label: v1
|
|
218
|
+
- id: v0
|
|
219
|
+
label: v0 (legacy)
|
|
220
|
+
eol: 2025-12-31 # tombstones in switcher
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Mixed prose + API ref with independent versions
|
|
224
|
+
|
|
225
|
+
```yaml
|
|
226
|
+
content:
|
|
227
|
+
sources:
|
|
228
|
+
# Evergreen prose
|
|
229
|
+
- path: ./content
|
|
230
|
+
from: dogsbay-md
|
|
231
|
+
|
|
232
|
+
# API ref — date-pinned
|
|
233
|
+
- name: api
|
|
234
|
+
path: ./openapi/2024-04-10.yaml
|
|
235
|
+
from: openapi
|
|
236
|
+
version: "2024-04-10"
|
|
237
|
+
primary: true
|
|
238
|
+
|
|
239
|
+
- name: api
|
|
240
|
+
path: ./openapi/2023-12-01.yaml
|
|
241
|
+
from: openapi
|
|
242
|
+
version: "2023-12-01"
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
URLs:
|
|
246
|
+
```
|
|
247
|
+
/docs/ ← prose, versionless
|
|
248
|
+
/docs/api/2024-04-10/ ← API root, latest spec
|
|
249
|
+
/docs/api/2024-04-10/pets/list-pets ← operation
|
|
250
|
+
/docs/api/2023-12-01/pets/list-pets ← same op, prior version
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Multi-locale with git origin
|
|
254
|
+
|
|
255
|
+
```yaml
|
|
256
|
+
content:
|
|
257
|
+
sources:
|
|
258
|
+
- path: ./content
|
|
259
|
+
locale: en
|
|
260
|
+
primary: true
|
|
261
|
+
|
|
262
|
+
- git: https://github.com/acme/docs-fr.git
|
|
263
|
+
ref: main
|
|
264
|
+
locale: fr
|
|
265
|
+
|
|
266
|
+
- git: https://github.com/acme/docs-pt-BR.git
|
|
267
|
+
ref: main
|
|
268
|
+
locale: pt-BR
|
|
269
|
+
|
|
270
|
+
locales:
|
|
271
|
+
- id: en
|
|
272
|
+
label: English
|
|
273
|
+
- id: fr
|
|
274
|
+
label: Français
|
|
275
|
+
- id: pt-BR
|
|
276
|
+
label: Português (Brasil)
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
URLs: `/docs/en/...`, `/docs/fr/...`, `/docs/pt-BR/...`. Plus a
|
|
280
|
+
default-locale redirect from `/docs/...` to `/docs/en/...`.
|
|
281
|
+
|
|
282
|
+
## Common mistakes
|
|
283
|
+
|
|
284
|
+
- ❌ Setting `version:` on one source and not declaring the
|
|
285
|
+
version in `versions:[]` — fails validation.
|
|
286
|
+
- ❌ Mixing `defaultVersion: latest` with no `version:` field on a
|
|
287
|
+
source — the source's pages get `/docs/latest/...` URLs even
|
|
288
|
+
when you wanted them flat. Drop `defaultVersion` for the
|
|
289
|
+
current-baseline pattern.
|
|
290
|
+
- ❌ Hand-editing `multiSource.namespace` in frontmatter — the
|
|
291
|
+
aggregator overwrites it on every build.
|
|
292
|
+
- ❌ Trying to emit nav hrefs with hand-written axis prefixes —
|
|
293
|
+
the aggregator does this; importers should write hrefs
|
|
294
|
+
relative to their content root.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dogsbay:nav-file
|
|
3
|
+
description: Write or edit a Dogsbay nav file (nav.yml, nav.yaml, or nav.json) with the correct single-key-map syntax. Use when the user asks to add pages to the sidebar, reorder the sidebar, create grouped sections, or fix a malformed nav file.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Writing a Dogsbay nav file
|
|
7
|
+
|
|
8
|
+
Dogsbay's sidebar nav lives in the content directory under one of:
|
|
9
|
+
|
|
10
|
+
- `nav.json` (highest precedence)
|
|
11
|
+
- `nav.yml`
|
|
12
|
+
- `nav.yaml`
|
|
13
|
+
|
|
14
|
+
The loader auto-detects in that order. Most users pick `nav.yml` because YAML is friendlier to edit.
|
|
15
|
+
|
|
16
|
+
## Format — single-key maps
|
|
17
|
+
|
|
18
|
+
Each entry is a **single-key map** where the key is the sidebar label and the value is one of:
|
|
19
|
+
|
|
20
|
+
- A file path relative to `content/` — leaf link
|
|
21
|
+
- An absolute URL (`http://`, `https://`, etc.) — external leaf
|
|
22
|
+
- A list of child entries — group
|
|
23
|
+
|
|
24
|
+
```yaml
|
|
25
|
+
- Home: index.md
|
|
26
|
+
- Getting started: getting-started.md
|
|
27
|
+
- Guides:
|
|
28
|
+
- Configuration: guides/configuration.md
|
|
29
|
+
- Deployment: guides/deployment.md
|
|
30
|
+
- Source: https://github.com/your-org/your-repo
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## What NOT to write
|
|
34
|
+
|
|
35
|
+
This is the most common mistake. The loader will print a "malformed" warning and fall back to directory-scan order:
|
|
36
|
+
|
|
37
|
+
```yaml
|
|
38
|
+
# ❌ WRONG — multi-key map
|
|
39
|
+
- label: Home
|
|
40
|
+
href: /docs/
|
|
41
|
+
|
|
42
|
+
# ❌ WRONG — using href for internal pages
|
|
43
|
+
- Home: /docs/
|
|
44
|
+
- Getting started: /docs/getting-started
|
|
45
|
+
|
|
46
|
+
# ❌ WRONG — missing .md extension on file paths
|
|
47
|
+
- Home: index
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The validator throws `Nav entry must have exactly one key at [N]. Got 2: ["label","href"]` for the first form.
|
|
51
|
+
|
|
52
|
+
## URL derivation — never write absolute paths for internal pages
|
|
53
|
+
|
|
54
|
+
URLs are composed at build time from the configured `basePath`, the active multi-source axes (locale / version / namespace), and the file path. Always use the **file path relative to the content directory**, never a hand-written URL.
|
|
55
|
+
|
|
56
|
+
If the user has `basePath: /docs` and a markdown source named `api`:
|
|
57
|
+
|
|
58
|
+
- `index.md` → `/docs/api/`
|
|
59
|
+
- `getting-started.md` → `/docs/api/getting-started`
|
|
60
|
+
- `guides/configuration.md` → `/docs/api/guides/configuration`
|
|
61
|
+
|
|
62
|
+
Hand-writing `/docs/getting-started` works today but breaks when the user changes `basePath`, adds a version axis, or activates locales. Always use the file path.
|
|
63
|
+
|
|
64
|
+
## Groups vs leaf-with-children
|
|
65
|
+
|
|
66
|
+
A group has no associated page — clicking the label expands the children. To make the GROUP itself link to a page (a section landing page), use this combined shape:
|
|
67
|
+
|
|
68
|
+
```yaml
|
|
69
|
+
- Guides:
|
|
70
|
+
- guides/index.md # bare string entry — sets the group's href to this page
|
|
71
|
+
- Configuration: guides/configuration.md
|
|
72
|
+
- Deployment: guides/deployment.md
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The leading bare-string entry is parsed as the group's own `href`/`file`. Without it, the group is an expand-only label.
|
|
76
|
+
|
|
77
|
+
## External URLs
|
|
78
|
+
|
|
79
|
+
Use absolute URLs for external destinations. The loader treats anything starting with `http://`, `https://`, or `mailto:` as an external link (no axis prefixing applied):
|
|
80
|
+
|
|
81
|
+
```yaml
|
|
82
|
+
- API reference: api/index.md
|
|
83
|
+
- GitHub: https://github.com/your-org/your-repo
|
|
84
|
+
- Status: https://status.your-org.com
|
|
85
|
+
- Contact: mailto:hello@your-org.com
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## When there's no nav file
|
|
89
|
+
|
|
90
|
+
If `content/nav.{json,yml,yaml}` doesn't exist, the loader does a directory scan and produces nav from filenames. The order is alphabetical with `index.md` first per directory. This works for prototyping but quickly stops being what the user wants — encourage authoring `nav.yml` early.
|
|
91
|
+
|
|
92
|
+
## When the user moves or renames a page
|
|
93
|
+
|
|
94
|
+
Update three places:
|
|
95
|
+
|
|
96
|
+
1. The file itself (move/rename in `content/`)
|
|
97
|
+
2. The `nav.yml` entry (update the file path)
|
|
98
|
+
3. Add a redirect in `dogsbay.config.yml` if the old URL was published
|
|
99
|
+
|
|
100
|
+
```yaml
|
|
101
|
+
# In dogsbay.config.yml
|
|
102
|
+
site:
|
|
103
|
+
redirects:
|
|
104
|
+
/docs/old-page: /docs/new-page
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Skipping (3) breaks bookmarks and external links.
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dogsbay:openapi-source
|
|
3
|
+
description: Add an OpenAPI 3.x spec as a content source in a Dogsbay site. Renders endpoint pages inline alongside markdown prose. Use when configuring API reference, multi-version OpenAPI, or x-codeSamples.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# OpenAPI as a content source
|
|
7
|
+
|
|
8
|
+
Dogsbay treats OpenAPI 3.x as a first-class content source. The
|
|
9
|
+
`@dogsbay/format-openapi` importer reads the spec, parses it
|
|
10
|
+
with `@scalar/openapi-parser` (handles dereferencing, includes
|
|
11
|
+
Swagger 2 conversion), and emits one `.astro` page per
|
|
12
|
+
operation plus tag-overview pages and a root info page.
|
|
13
|
+
|
|
14
|
+
The rendering is **inline** — endpoints render through real
|
|
15
|
+
Dogsbay components (`EndpointCard`, `ApiLayout`,
|
|
16
|
+
`ParameterTable`, `SchemaViewer`, `ResponseTabs`,
|
|
17
|
+
`CodeSamples`), not via an iframe.
|
|
18
|
+
|
|
19
|
+
## Basic config
|
|
20
|
+
|
|
21
|
+
```yaml
|
|
22
|
+
content:
|
|
23
|
+
sources:
|
|
24
|
+
- path: ./content # markdown prose
|
|
25
|
+
from: dogsbay-md
|
|
26
|
+
|
|
27
|
+
- name: api
|
|
28
|
+
path: ./openapi/petstore.yaml # path to spec file (or URL)
|
|
29
|
+
from: openapi
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Required: `from: openapi`. Auto-detection (`from: auto`) doesn't
|
|
33
|
+
fire for OpenAPI — extension-based detection is too ambiguous.
|
|
34
|
+
|
|
35
|
+
## Path forms
|
|
36
|
+
|
|
37
|
+
The `path:` value can be:
|
|
38
|
+
|
|
39
|
+
- A direct file path (`./openapi/petstore.yaml`, `./spec.json`)
|
|
40
|
+
- A directory containing `openapi.{yaml,yml,json}` or
|
|
41
|
+
`spec.{yaml,yml,json}` — auto-detected
|
|
42
|
+
- An HTTP(S) URL — fetched at build time
|
|
43
|
+
|
|
44
|
+
YAML and JSON specs both work; the parser handles both.
|
|
45
|
+
|
|
46
|
+
## URLs produced
|
|
47
|
+
|
|
48
|
+
With `name: api` and `basePath: /docs`:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
/docs/api/ ← root info page (info.title + description)
|
|
52
|
+
/docs/api/<tag-slug>/ ← per-tag overview
|
|
53
|
+
/docs/api/<tag-slug>/<operation-slug> ← one per operation
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Operation slug derivation:
|
|
57
|
+
|
|
58
|
+
- `operationId` if set (kebab-cased) — most public specs set it
|
|
59
|
+
- Fallback: `{method}-{path-slug}` from the wire path
|
|
60
|
+
|
|
61
|
+
Stripe-style URLs (`/docs/api/pets/list-pets`) come from
|
|
62
|
+
operationId. Method-path URLs (`/docs/api/get-pets-petid`) come
|
|
63
|
+
from the fallback. Either way, the path is stable.
|
|
64
|
+
|
|
65
|
+
## Multi-version OpenAPI
|
|
66
|
+
|
|
67
|
+
The version axis works for OpenAPI sources just like markdown
|
|
68
|
+
sources. Per-source independent versioning:
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
content:
|
|
72
|
+
sources:
|
|
73
|
+
- path: ./content # markdown evergreen
|
|
74
|
+
from: dogsbay-md
|
|
75
|
+
|
|
76
|
+
- name: api
|
|
77
|
+
path: ./openapi/2024-04-10.yaml
|
|
78
|
+
from: openapi
|
|
79
|
+
version: "2024-04-10"
|
|
80
|
+
|
|
81
|
+
- name: api
|
|
82
|
+
path: ./openapi/2023-12-01.yaml
|
|
83
|
+
from: openapi
|
|
84
|
+
version: "2023-12-01"
|
|
85
|
+
|
|
86
|
+
versions:
|
|
87
|
+
- id: "2024-04-10"
|
|
88
|
+
label: "2024-04-10 (latest)"
|
|
89
|
+
default: true
|
|
90
|
+
- id: "2023-12-01"
|
|
91
|
+
label: "2023-12-01"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Resulting URLs:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
/docs/ ← prose, versionless
|
|
98
|
+
/docs/api/2024-04-10/pets/list-pets
|
|
99
|
+
/docs/api/2023-12-01/pets/list-pets
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The version-switcher UI scopes to whichever pages have axis
|
|
103
|
+
activity — only `/docs/api/...` pages show the switcher; prose
|
|
104
|
+
stays flat.
|
|
105
|
+
|
|
106
|
+
This is the **Mintlify-style independent-axis model** (Stripe,
|
|
107
|
+
Twilio, GitHub all do this). API moves on its own cadence;
|
|
108
|
+
prose stays evergreen.
|
|
109
|
+
|
|
110
|
+
## Hand-curated code samples — `x-codeSamples`
|
|
111
|
+
|
|
112
|
+
Auto-generated samples (curl + Python + TypeScript) are
|
|
113
|
+
emitted by default. To override with hand-written examples,
|
|
114
|
+
use the Redoc convention `x-codeSamples` on the operation:
|
|
115
|
+
|
|
116
|
+
```yaml
|
|
117
|
+
paths:
|
|
118
|
+
/pets:
|
|
119
|
+
post:
|
|
120
|
+
summary: Create a pet
|
|
121
|
+
x-codeSamples:
|
|
122
|
+
- lang: shell
|
|
123
|
+
label: cURL
|
|
124
|
+
source: |
|
|
125
|
+
curl -X POST "https://api.example.com/v1/pets" \
|
|
126
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
127
|
+
-d '{"name":"Rex"}'
|
|
128
|
+
- lang: typescript
|
|
129
|
+
source: |
|
|
130
|
+
await client.pets.create({ name: "Rex" });
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
When `x-codeSamples` is present, it **replaces** the
|
|
134
|
+
auto-generated samples entirely (not added alongside). The
|
|
135
|
+
legacy `x-code-samples` (kebab) spelling is also accepted.
|
|
136
|
+
|
|
137
|
+
## Deprecating an operation
|
|
138
|
+
|
|
139
|
+
Set `deprecated: true`:
|
|
140
|
+
|
|
141
|
+
```yaml
|
|
142
|
+
paths:
|
|
143
|
+
/orders:
|
|
144
|
+
post:
|
|
145
|
+
summary: Place an order
|
|
146
|
+
deprecated: true
|
|
147
|
+
…
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
The endpoint page renders a warning banner. The `.md` mirror
|
|
151
|
+
prefixes the operation with a `> [!WARNING]` callout so agents
|
|
152
|
+
see the deprecation status too.
|
|
153
|
+
|
|
154
|
+
## Components on the rendered page
|
|
155
|
+
|
|
156
|
+
Each operation page emits an `<ApiLayout>` with two slots:
|
|
157
|
+
|
|
158
|
+
- **description**: `<EndpointCard>` containing `<EndpointSection>`
|
|
159
|
+
blocks for parameters / request body / responses, using
|
|
160
|
+
`<PropertyList>` (Stripe-style location-grouped) /
|
|
161
|
+
`<SchemaViewer>` / `<ResponseTabs>`
|
|
162
|
+
- **code**: `<ApiCodePanel>` with `<CodeSamples>` plus per-status
|
|
163
|
+
`<ExampleBlock>` panels with content-type-aware syntax
|
|
164
|
+
highlighting
|
|
165
|
+
|
|
166
|
+
The full URL bar at the top of the description column tints
|
|
167
|
+
its background to the HTTP method colour (Stripe / Redoc /
|
|
168
|
+
Mintlify convention) — GET = green, POST = blue, etc.
|
|
169
|
+
|
|
170
|
+
## What's NOT yet supported
|
|
171
|
+
|
|
172
|
+
- **Multi-server picker** (`servers[]` with sandbox / production)
|
|
173
|
+
— currently uses `servers[0].url` only.
|
|
174
|
+
- **`x-internal` honour** — known limitation; see
|
|
175
|
+
`plans/openapi-builtin-followups.md`.
|
|
176
|
+
- **Live "Try it" execution** — out of scope; ships as a future
|
|
177
|
+
plugin.
|
|
178
|
+
- **AsyncAPI / WebSocket / gRPC** — different specs; separate
|
|
179
|
+
importer.
|
|
180
|
+
|
|
181
|
+
## Common patterns
|
|
182
|
+
|
|
183
|
+
### Single-source API ref
|
|
184
|
+
|
|
185
|
+
```yaml
|
|
186
|
+
content:
|
|
187
|
+
sources:
|
|
188
|
+
- path: ./openapi/petstore.yaml
|
|
189
|
+
from: openapi
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
URLs: `/docs/`, `/docs/<tag>/<operation>` (no namespace prefix
|
|
193
|
+
because there's only one source).
|
|
194
|
+
|
|
195
|
+
### Multi-source: prose + API ref under /docs/api/
|
|
196
|
+
|
|
197
|
+
```yaml
|
|
198
|
+
content:
|
|
199
|
+
sources:
|
|
200
|
+
- path: ./content
|
|
201
|
+
from: dogsbay-md
|
|
202
|
+
- name: api
|
|
203
|
+
path: ./openapi/spec.yaml
|
|
204
|
+
from: openapi
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
The seminal Dogsbay-OpenAPI pattern. Prose stays flat at
|
|
208
|
+
`/docs/`; API reference under `/docs/api/`.
|
|
209
|
+
|
|
210
|
+
### Remote OpenAPI URL
|
|
211
|
+
|
|
212
|
+
```yaml
|
|
213
|
+
content:
|
|
214
|
+
sources:
|
|
215
|
+
- name: api
|
|
216
|
+
path: https://api.example.com/openapi.json
|
|
217
|
+
from: openapi
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Fetched at build time. Useful when the spec is generated
|
|
221
|
+
upstream (e.g. by a backend codebase) and the docs site
|
|
222
|
+
shouldn't have a vendored copy.
|
|
223
|
+
|
|
224
|
+
## Common mistakes
|
|
225
|
+
|
|
226
|
+
- ❌ Forgetting `from: openapi` — auto-detection fails on `.yaml`
|
|
227
|
+
/ `.json` (too ambiguous), the source falls through importers
|
|
228
|
+
and errors.
|
|
229
|
+
- ❌ Setting `name: api` and expecting to write `/api/foo`
|
|
230
|
+
manually in a markdown link — the namespace prefix is
|
|
231
|
+
build-time-resolved, write `./api/foo` (relative) or use the
|
|
232
|
+
full `${basePath}/api/...`.
|
|
233
|
+
- ❌ Per-version OpenAPI with the same `version:` value on both
|
|
234
|
+
sources — version axis doesn't activate; pages collide. Each
|
|
235
|
+
spec needs a distinct version label.
|
|
236
|
+
- ❌ Using `x-codeSamples` AND expecting auto-generated samples
|
|
237
|
+
alongside — vendor samples replace, not augment.
|