@developerhub/dh-skills 1.0.2
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/LICENSE +21 -0
- package/README.md +44 -0
- package/package.json +32 -0
- package/skills/write-markdoc/SKILL.md +270 -0
- package/skills/write-markdoc/references/blocks.md +467 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeveloperHub
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# @developerhub/dh-skills
|
|
2
|
+
|
|
3
|
+
Agent Skills that teach AI coding agents how to author
|
|
4
|
+
**[DeveloperHub](https://developerhub.io) Markdoc** — the exact, round-trip-safe
|
|
5
|
+
syntax for every content block.
|
|
6
|
+
|
|
7
|
+
DeveloperHub pages are stored as Markdoc. When an agent edits a page from an IDE,
|
|
8
|
+
a Git-synced repo, or a docs-as-code pipeline, it needs to emit the *canonical*
|
|
9
|
+
dialect DeveloperHub round-trips — not generic Markdown or a look-alike. Emit the
|
|
10
|
+
wrong shape and the edit churns on the first save or silently drops content. This
|
|
11
|
+
skill gives the agent that ground truth.
|
|
12
|
+
|
|
13
|
+
## What's inside
|
|
14
|
+
|
|
15
|
+
| Skill | Teaches |
|
|
16
|
+
|---|---|
|
|
17
|
+
| [`write-markdoc`](skills/write-markdoc/SKILL.md) | Every DeveloperHub Markdoc block and inline mark, with the exact syntax, attributes, and the dialect rules that keep an edit round-trip-safe. |
|
|
18
|
+
|
|
19
|
+
Detailed per-block reference: [`skills/write-markdoc/references/blocks.md`](skills/write-markdoc/references/blocks.md).
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
Install straight from this repo with the [`skills` CLI](https://www.npmjs.com/package/skills):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx skills add developerhub-io/dh-skills
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or copy the `skills/write-markdoc` folder into your agent's skills directory
|
|
30
|
+
(`.claude/skills/`, `.cursor/skills/`, …). `SKILL.md` uses the portable Agent
|
|
31
|
+
Skills format (Markdown with YAML frontmatter), so it works across Claude Code,
|
|
32
|
+
Cursor, Codex, and other compatible agents.
|
|
33
|
+
|
|
34
|
+
It is also published to npm as `@developerhub/dh-skills`, for anyone who prefers to
|
|
35
|
+
vendor the files as a dependency (`npm install @developerhub/dh-skills`).
|
|
36
|
+
|
|
37
|
+
## Contributing
|
|
38
|
+
|
|
39
|
+
This package is published and maintained by DeveloperHub. Spotted an error, or
|
|
40
|
+
want a block documented differently? Please [open an issue](https://github.com/developerhub-io/dh-skills/issues).
|
|
41
|
+
|
|
42
|
+
## License
|
|
43
|
+
|
|
44
|
+
MIT — see [LICENSE](LICENSE).
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@developerhub/dh-skills",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Agent Skills that teach AI coding agents to author DeveloperHub Markdoc — the exact syntax for every content block.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"developerhub",
|
|
7
|
+
"markdoc",
|
|
8
|
+
"documentation",
|
|
9
|
+
"agent-skills",
|
|
10
|
+
"claude",
|
|
11
|
+
"ai",
|
|
12
|
+
"docs-as-code"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://developerhub.io",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/developerhub-io/dh-skills.git"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/developerhub-io/dh-skills/issues"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"author": "DeveloperHub <hello@developerhub.io> (https://developerhub.io)",
|
|
24
|
+
"files": [
|
|
25
|
+
"skills",
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENSE"
|
|
28
|
+
],
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: write-markdoc
|
|
3
|
+
metadata:
|
|
4
|
+
version: "1.0"
|
|
5
|
+
description: >-
|
|
6
|
+
Write, author, edit, and format DeveloperHub documentation pages in the correct
|
|
7
|
+
Markdoc syntax. Use whenever a task involves creating or editing a DeveloperHub
|
|
8
|
+
docs page; writing page frontmatter; inserting or formatting a callout, code
|
|
9
|
+
block, table, image, tabs, accordion, cards, video, badge, icon, or any other
|
|
10
|
+
Markdoc block or inline tag; or when you need the exact syntax, attributes,
|
|
11
|
+
defaults, or allowed values for a DeveloperHub Markdoc tag.
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Writing DeveloperHub Markdoc
|
|
15
|
+
|
|
16
|
+
DeveloperHub pages are authored in **Markdoc** — a superset of Markdown with a set
|
|
17
|
+
of typed custom tags. The same format is used when editing a page through the
|
|
18
|
+
editor, an API/AI edit, or a Git-synced repository: what you write is parsed into
|
|
19
|
+
the editor's document model, and what the editor produces is serialised back to
|
|
20
|
+
this exact syntax. Getting the shape right keeps that round-trip **lossless** —
|
|
21
|
+
emit a non-canonical shape and the edit churns on the first save or silently drops
|
|
22
|
+
content.
|
|
23
|
+
|
|
24
|
+
This skill is the ground truth for the syntax. For the full per-tag reference
|
|
25
|
+
(every attribute, default, and allowed value), read
|
|
26
|
+
[`references/blocks.md`](references/blocks.md).
|
|
27
|
+
|
|
28
|
+
## Core dialect rules
|
|
29
|
+
|
|
30
|
+
These hold for every tag. Break one and the round-trip breaks.
|
|
31
|
+
|
|
32
|
+
1. **Block tags sit on their own lines.** The open tag, the body, and the close
|
|
33
|
+
tag are each on separate lines. Content on the same line as `{% tag %}`
|
|
34
|
+
silently downgrades the tag to a plain paragraph.
|
|
35
|
+
```markdoc
|
|
36
|
+
{% callout title="Note" %}
|
|
37
|
+
Body goes here.
|
|
38
|
+
{% /callout %}
|
|
39
|
+
```
|
|
40
|
+
2. **Inline tags are self-closing:** `{% icon classes="fas fa-star" /%}`.
|
|
41
|
+
3. **Booleans are bare, never quoted.** `open=true`, `showLineNumbers=false`. A
|
|
42
|
+
quoted boolean (`open="false"`) becomes the truthy *string* `"false"` and
|
|
43
|
+
silently inverts the setting.
|
|
44
|
+
4. **Numbers are bare too:** `width=357`, `colspan=2`. Strings are quoted:
|
|
45
|
+
`title="Warning"`.
|
|
46
|
+
5. **Omit any attribute that equals its default.** The serialiser drops them, so
|
|
47
|
+
adding them back only makes diffs noisier. The defaults are listed per tag in
|
|
48
|
+
`references/blocks.md`. It is never *wrong* to include one; just match the
|
|
49
|
+
surrounding page.
|
|
50
|
+
6. **Internal links carry real text:** `[Getting started](/support-center/start)`.
|
|
51
|
+
A text-less link round-trips to nothing.
|
|
52
|
+
7. **Asset references stay verbatim.** An image `url="asset:zvlxyph4f37t"` is kept
|
|
53
|
+
as-is; never resolve it to a URL. (Full `https://uploads.developerhub.io/…`
|
|
54
|
+
URLs are also valid — use whichever the surrounding pages use.)
|
|
55
|
+
8. **Reserve `#` (H1) for the page title.** Body headings start at `##`.
|
|
56
|
+
|
|
57
|
+
## Standard Markdown
|
|
58
|
+
|
|
59
|
+
Plain Markdown works and is preferred wherever a custom tag is not needed:
|
|
60
|
+
|
|
61
|
+
- Headings `##` … `######`
|
|
62
|
+
- `**bold**`, `*italic*`, `~~strikethrough~~`, `` `inline code` ``
|
|
63
|
+
- `[links](/support-center/slug)` — root-relative for internal links
|
|
64
|
+
- Bullet (`-`) and ordered (`1.`) lists, including nested
|
|
65
|
+
- `> blockquote`
|
|
66
|
+
- `---` horizontal rule
|
|
67
|
+
- Fenced code blocks (see the reference)
|
|
68
|
+
|
|
69
|
+
Two things have no Markdown equivalent, so they are tags:
|
|
70
|
+
|
|
71
|
+
- **Underline:** `{% u %}underlined{% /u %}`
|
|
72
|
+
- **A link whose URL contains spaces or parentheses:**
|
|
73
|
+
`{% link href="https://x.com/a (b)" %}text{% /link %}`
|
|
74
|
+
|
|
75
|
+
## The blocks at a glance
|
|
76
|
+
|
|
77
|
+
| Tag | Form | Purpose |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| `callout` | block | Coloured note / warning box |
|
|
80
|
+
| `code` + fences | block | Multi-language code tabs |
|
|
81
|
+
| ` ```lang ` fence | fence | A single code block |
|
|
82
|
+
| `code-steps` | block | Stepped code walkthrough |
|
|
83
|
+
| `table` / `row` / `cell` | block | Rich table (spans, alignment, backgrounds) |
|
|
84
|
+
| `image` | block | Image, with optional caption |
|
|
85
|
+
| `video` | block | Embedded / raw video |
|
|
86
|
+
| `tabs` / `tab` | block | Tabbed content |
|
|
87
|
+
| `accordion-group` / `accordion` | block | Collapsible sections |
|
|
88
|
+
| `cards` / `card` | block | Card grid or list |
|
|
89
|
+
| `conditional` | block | Audience-gated content |
|
|
90
|
+
| `html` | block | Raw custom HTML |
|
|
91
|
+
| `github-code` | block | Code pulled live from a GitHub URL |
|
|
92
|
+
| `index-list` | block | Auto index of child pages |
|
|
93
|
+
| `synced` | block | Reusable synced block, by id |
|
|
94
|
+
| `badge` | inline | Small coloured label |
|
|
95
|
+
| `key` | inline | Keyboard key |
|
|
96
|
+
| `icon` | inline | Font Awesome icon |
|
|
97
|
+
| `glossary` | inline | Glossary term |
|
|
98
|
+
| `inline-image` | inline | Inline image |
|
|
99
|
+
| `%KEY%` | inline | Variable placeholder |
|
|
100
|
+
|
|
101
|
+
## Cheat sheet
|
|
102
|
+
|
|
103
|
+
One of (almost) every block. Full attribute lists in
|
|
104
|
+
[`references/blocks.md`](references/blocks.md).
|
|
105
|
+
|
|
106
|
+
````markdoc
|
|
107
|
+
## A heading
|
|
108
|
+
|
|
109
|
+
A paragraph with **bold**, *italic*, and a [link](/support-center/blocks).
|
|
110
|
+
|
|
111
|
+
{% callout type="warning" title="Heads up" %}
|
|
112
|
+
A coloured note box. `type` is one of info, warning, success, error.
|
|
113
|
+
{% /callout %}
|
|
114
|
+
|
|
115
|
+
{% code %}
|
|
116
|
+
```php {% title="PHP" %}
|
|
117
|
+
echo 'first tab';
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
```javascript {% title="JS" %}
|
|
121
|
+
console.log('second tab');
|
|
122
|
+
```
|
|
123
|
+
{% /code %}
|
|
124
|
+
|
|
125
|
+
```js {% showLineNumbers=true title="Example" %}
|
|
126
|
+
const ready = true;
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
{% table layout="auto" %}
|
|
130
|
+
{% row %}
|
|
131
|
+
{% cell header=true %}
|
|
132
|
+
Header
|
|
133
|
+
{% /cell %}
|
|
134
|
+
{% cell header=true %}
|
|
135
|
+
Header
|
|
136
|
+
{% /cell %}
|
|
137
|
+
{% /row %}
|
|
138
|
+
{% row %}
|
|
139
|
+
{% cell %}
|
|
140
|
+
Cell
|
|
141
|
+
{% /cell %}
|
|
142
|
+
{% cell %}
|
|
143
|
+
Cell
|
|
144
|
+
{% /cell %}
|
|
145
|
+
{% /row %}
|
|
146
|
+
{% /table %}
|
|
147
|
+
|
|
148
|
+
{% image url="asset:zvlxyph4f37t" width=357 %}
|
|
149
|
+
Optional caption.
|
|
150
|
+
{% /image %}
|
|
151
|
+
|
|
152
|
+
{% video provider="raw" videoId="https://uploads.developerhub.io/example.mp4" /%}
|
|
153
|
+
|
|
154
|
+
{% tabs %}
|
|
155
|
+
{% tab title="Android" %}
|
|
156
|
+
Android content.
|
|
157
|
+
{% /tab %}
|
|
158
|
+
{% tab title="iOS" %}
|
|
159
|
+
iOS content.
|
|
160
|
+
{% /tab %}
|
|
161
|
+
{% /tabs %}
|
|
162
|
+
|
|
163
|
+
{% accordion-group %}
|
|
164
|
+
{% accordion title="Getting started" open=true %}
|
|
165
|
+
Collapsible content. Add `open=true` to expand it on load.
|
|
166
|
+
{% /accordion %}
|
|
167
|
+
{% accordion title="Advanced" %}
|
|
168
|
+
Second section.
|
|
169
|
+
{% /accordion %}
|
|
170
|
+
{% /accordion-group %}
|
|
171
|
+
|
|
172
|
+
{% cards %}
|
|
173
|
+
{% card title="Card 1" text="Description" link="/support-center/videos" /%}
|
|
174
|
+
{% card title="Card 2" text="Description" link="/support-center/callouts" /%}
|
|
175
|
+
{% /cards %}
|
|
176
|
+
|
|
177
|
+
{% conditional audience="enterprise" %}
|
|
178
|
+
Shown only to the enterprise audience.
|
|
179
|
+
{% /conditional %}
|
|
180
|
+
|
|
181
|
+
{% github-code url="https://github.com/acme/repo/blob/main/Makefile" /%}
|
|
182
|
+
|
|
183
|
+
{% index-list /%}
|
|
184
|
+
|
|
185
|
+
{% synced id="open-block-menu" /%}
|
|
186
|
+
|
|
187
|
+
{% html %}
|
|
188
|
+
<div style="background:red; height:50px">Custom widget</div>
|
|
189
|
+
{% /html %}
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
Inline: %product% and {% glossary term="coding" /%} and
|
|
194
|
+
{% badge text="Done" type="success" /%} and {% icon classes="fas fa-adjust" /%}
|
|
195
|
+
and {% key key="F1" /%} and {% inline-image url="asset:02grc2jqacve" width=14 /%}.
|
|
196
|
+
````
|
|
197
|
+
|
|
198
|
+
## When to use which block
|
|
199
|
+
|
|
200
|
+
| You want to… | Use | Not |
|
|
201
|
+
|---|---|---|
|
|
202
|
+
| Highlight a note, tip, or warning | `callout` (`type=`) | bold text |
|
|
203
|
+
| Show the same code in several languages | `code` with fenced tabs | one fence with mixed code |
|
|
204
|
+
| Walk through code step by step | `code-steps` | a numbered list of fences |
|
|
205
|
+
| A table with spans, alignment, or cell colours | `table` / `row` / `cell` | a GFM pipe table (it is rewritten) |
|
|
206
|
+
| Group alternative content the reader switches between | `tabs` / `tab` | headings |
|
|
207
|
+
| Collapse optional / long detail | `accordion-group` / `accordion` | `tabs` |
|
|
208
|
+
| A grid of navigation links | `cards` / `card` | a bullet list of links |
|
|
209
|
+
| Content for one audience only | `conditional` (`audience=`) | duplicating the page |
|
|
210
|
+
| A reusable snippet shared across pages | `synced` (`id=`) | copy-paste |
|
|
211
|
+
|
|
212
|
+
## Round-trip gotchas
|
|
213
|
+
|
|
214
|
+
These follow from the two-way sync. Ignoring them drops or mangles content on the
|
|
215
|
+
next save.
|
|
216
|
+
|
|
217
|
+
- **Keep block open/close tags on their own lines** (rule 1). This is the most
|
|
218
|
+
common mistake.
|
|
219
|
+
- **Tables are `row` / `cell` trees**, not Markdown pipes. A pipe table is
|
|
220
|
+
accepted on input but rewritten into the `{% table %}` form on the next save,
|
|
221
|
+
so don't be surprised when your pipe grid comes back expanded.
|
|
222
|
+
- **Multi-language code is `{% code %}` wrapping bare fences**, each annotated with
|
|
223
|
+
`{% title="…" %}`. There is **no** `{% tab %}` inside `{% code %}` — that tag is
|
|
224
|
+
only for generic content tabs.
|
|
225
|
+
- **Line-number / wrap settings ride on the `{% code %}` open tag**, once, shared
|
|
226
|
+
by every tab — not per fence.
|
|
227
|
+
- **Accordions collapse by default.** Add a bare `open=true` to expand one on load.
|
|
228
|
+
- **An intentionally empty paragraph** serialises as `{% p /%}`. You rarely write
|
|
229
|
+
this by hand.
|
|
230
|
+
- **Custom HTML is best kept to a single logical line.** Multi-line *indented* HTML
|
|
231
|
+
in `{% html %}` can lose its indentation on round-trip.
|
|
232
|
+
- **`conditional audience="…"` must name a real project audience.** Omit the
|
|
233
|
+
attribute for public / all-audiences content.
|
|
234
|
+
|
|
235
|
+
## Page frontmatter
|
|
236
|
+
|
|
237
|
+
A page stored as a `.md` file (a Git-synced repo, or an export) opens with a YAML
|
|
238
|
+
`--- … ---` block, then a blank line, then the Markdoc body. The field set is
|
|
239
|
+
**fixed** — the same keys on every page, not project-specific — so keep the block
|
|
240
|
+
intact and edit the values in place; put the Markdoc body after it.
|
|
241
|
+
|
|
242
|
+
```yaml
|
|
243
|
+
---
|
|
244
|
+
type: page
|
|
245
|
+
title: Getting started
|
|
246
|
+
listed: true
|
|
247
|
+
slug: getting-started
|
|
248
|
+
description:
|
|
249
|
+
index_title: Getting started
|
|
250
|
+
hidden:
|
|
251
|
+
keywords:
|
|
252
|
+
tags:
|
|
253
|
+
---
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
| Field | Meaning |
|
|
257
|
+
|---|---|
|
|
258
|
+
| `type` | `page` for a content page. An index entry may instead be `category`, `label`, `separator`, or `link`; those carry fewer fields (`category`/`label` → `type` + `title`; `separator` → `type`; `link` → `type` + `title` + `url`). |
|
|
259
|
+
| `title` | The page title (its `#` H1). |
|
|
260
|
+
| `listed` | `true` / `false` — whether the page appears in navigation. Defaults to `true` when omitted. |
|
|
261
|
+
| `slug` | URL slug. For a Git-synced page the file path *is* the slug, so this field is informational; renaming the file is what changes the URL. |
|
|
262
|
+
| `description` | Meta / SEO description. Left empty when unset. |
|
|
263
|
+
| `index_title` | Overrides the title shown in the sidebar / index; falls back to `title`. |
|
|
264
|
+
| `hidden` | `true` / `false` — hide the page from the auto-generated index. Defaults to `false`. |
|
|
265
|
+
| `keywords` | Comma-separated search keywords. |
|
|
266
|
+
| `tags` | Comma-separated page tags. |
|
|
267
|
+
|
|
268
|
+
**Preserve every key, even when its value is empty** — the format writes them all.
|
|
269
|
+
This skill covers the body; leave the frontmatter block in place and change only the
|
|
270
|
+
values you mean to change.
|
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
# DeveloperHub Markdoc — full block & tag reference
|
|
2
|
+
|
|
3
|
+
Every DeveloperHub Markdoc tag, its form, attributes, defaults, and allowed
|
|
4
|
+
values. Read [`../SKILL.md`](../SKILL.md) first for the core dialect rules.
|
|
5
|
+
|
|
6
|
+
**Conventions used below**
|
|
7
|
+
|
|
8
|
+
- **Form** — `block` (`{% x %}…{% /x %}`), `inline` (`{% x /%}`, self-closing), or
|
|
9
|
+
`fence` (a fenced code block with `{% … %}` annotations).
|
|
10
|
+
- **Default** — omit the attribute when its value equals this; the serialiser does.
|
|
11
|
+
- Booleans are **bare** (`open=true`); numbers are bare (`width=357`); strings are
|
|
12
|
+
quoted (`title="Note"`).
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Text & inline marks
|
|
17
|
+
|
|
18
|
+
Prefer plain Markdown for all of these.
|
|
19
|
+
|
|
20
|
+
| Construct | Syntax |
|
|
21
|
+
|---|---|
|
|
22
|
+
| Bold | `**bold**` |
|
|
23
|
+
| Italic | `*italic*` |
|
|
24
|
+
| Strikethrough | `~~struck~~` |
|
|
25
|
+
| Inline code | `` `code` `` |
|
|
26
|
+
| Underline | `{% u %}underlined{% /u %}` (no Markdown equivalent) |
|
|
27
|
+
| Link | `[text](/support-center/slug)` |
|
|
28
|
+
| Link with spaces/parens in URL | `{% link href="https://x.com/a (b)" %}text{% /link %}` |
|
|
29
|
+
| Heading | `##` … `######` (reserve `#` for the page title) |
|
|
30
|
+
| Bullet list | `- item` (nest by indenting) |
|
|
31
|
+
| Ordered list | `1. item` |
|
|
32
|
+
| Blockquote | `> quoted` |
|
|
33
|
+
| Horizontal rule | `---` |
|
|
34
|
+
| Empty paragraph | `{% p /%}` (rarely authored by hand) |
|
|
35
|
+
|
|
36
|
+
Links must carry real text — a text-less link round-trips to nothing.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Blocks
|
|
41
|
+
|
|
42
|
+
### `callout`
|
|
43
|
+
|
|
44
|
+
Coloured note / warning box. Body holds arbitrary block content.
|
|
45
|
+
|
|
46
|
+
```markdoc
|
|
47
|
+
{% callout type="warning" title="Changing hosting settings" %}
|
|
48
|
+
Redirect any external links if you change hosting after publishing.
|
|
49
|
+
{% /callout %}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
| Attr | Type | Default | Values |
|
|
53
|
+
|---|---|---|---|
|
|
54
|
+
| `type` | enum | `info` | `info`, `warning`, `success`, `error` |
|
|
55
|
+
| `title` | string | `""` | rendered as a header row when set |
|
|
56
|
+
|
|
57
|
+
> The type for a red/error box is **`error`**, not "danger".
|
|
58
|
+
|
|
59
|
+
### `code` (multi-language tabs)
|
|
60
|
+
|
|
61
|
+
Wraps one or more **bare fenced blocks**, each a language tab. There is **no**
|
|
62
|
+
`{% tab %}` inside `{% code %}`. Line-number and wrap settings ride on the open
|
|
63
|
+
tag, once, shared by every tab.
|
|
64
|
+
|
|
65
|
+
````markdoc
|
|
66
|
+
{% code showLineNumbers=true %}
|
|
67
|
+
```javascript {% title="JavaScript" %}
|
|
68
|
+
console.log("hi");
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
```python {% title="Python" %}
|
|
72
|
+
print("hi")
|
|
73
|
+
```
|
|
74
|
+
{% /code %}
|
|
75
|
+
````
|
|
76
|
+
|
|
77
|
+
| Attr | Type | Default | Notes |
|
|
78
|
+
|---|---|---|---|
|
|
79
|
+
| `showLineNumbers` | boolean | `false` | shared by all tabs |
|
|
80
|
+
| `wrapLine` | boolean | `true` | shared by all tabs |
|
|
81
|
+
|
|
82
|
+
Content model: **only** bare code fences.
|
|
83
|
+
|
|
84
|
+
### Fenced code block (single)
|
|
85
|
+
|
|
86
|
+
A single code block. Language on the info string; annotations in `{% … %}` after
|
|
87
|
+
it.
|
|
88
|
+
|
|
89
|
+
````markdoc
|
|
90
|
+
```javascript {% title="fibonacci.js" showLineNumbers=true highlightLines="2,4-6" %}
|
|
91
|
+
function fibonacci(num) {
|
|
92
|
+
return num <= 1 ? 1 : fibonacci(num - 1) + fibonacci(num - 2);
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
````
|
|
96
|
+
|
|
97
|
+
| Annotation | Type | Default | Notes |
|
|
98
|
+
|---|---|---|---|
|
|
99
|
+
| `title` | string | `Code` | shown in the block header |
|
|
100
|
+
| `showLineNumbers` | boolean | `false` | omit inside `{% code %}` (set it there) |
|
|
101
|
+
| `wrapLine` | boolean | `true` | omit inside `{% code %}` |
|
|
102
|
+
| `highlightLines` | string | `""` | e.g. `"1,3-5"` |
|
|
103
|
+
| `id` | string | — | only inside `code-steps` (see below) |
|
|
104
|
+
|
|
105
|
+
The language comes from the fence token itself (` ```js `); default `plaintext`.
|
|
106
|
+
|
|
107
|
+
### `code-steps`
|
|
108
|
+
|
|
109
|
+
A stepped walkthrough: a lead description, then `{% step %}` tags, then one fenced
|
|
110
|
+
language block per step. Each fence carries an `id` that a step's `codeId` points
|
|
111
|
+
at.
|
|
112
|
+
|
|
113
|
+
````markdoc
|
|
114
|
+
{% code-steps title="Set up the client" %}
|
|
115
|
+
Intro prose describing the walkthrough.
|
|
116
|
+
|
|
117
|
+
{% step title="Install" codeId="install" %}
|
|
118
|
+
Install the package.
|
|
119
|
+
{% /step %}
|
|
120
|
+
|
|
121
|
+
```bash {% id="install" title="Terminal" %}
|
|
122
|
+
npm install @acme/sdk
|
|
123
|
+
```
|
|
124
|
+
{% /code-steps %}
|
|
125
|
+
````
|
|
126
|
+
|
|
127
|
+
`code-steps` attrs:
|
|
128
|
+
|
|
129
|
+
| Attr | Type | Default |
|
|
130
|
+
|---|---|---|
|
|
131
|
+
| `title` | string | `Code Steps` |
|
|
132
|
+
|
|
133
|
+
`step` attrs:
|
|
134
|
+
|
|
135
|
+
| Attr | Type | Default | Notes |
|
|
136
|
+
|---|---|---|---|
|
|
137
|
+
| `title` | string | `""` | |
|
|
138
|
+
| `codeId` | string | `""` | matches a fence `id` in this block |
|
|
139
|
+
| `highlightLines` | string | `""` | |
|
|
140
|
+
|
|
141
|
+
Inside `code-steps`, a language fence's `showLineNumbers` defaults to `true`.
|
|
142
|
+
|
|
143
|
+
### `table` / `row` / `cell`
|
|
144
|
+
|
|
145
|
+
An explicit `row` / `cell` tree. Each cell body is itself block content. Use this
|
|
146
|
+
(not a pipe table) whenever you need cell spans, alignment, backgrounds, or the
|
|
147
|
+
fluid `auto` layout.
|
|
148
|
+
|
|
149
|
+
```markdoc
|
|
150
|
+
{% table layout="auto" %}
|
|
151
|
+
{% row %}
|
|
152
|
+
{% cell header=true %}
|
|
153
|
+
Parameter
|
|
154
|
+
{% /cell %}
|
|
155
|
+
{% cell header=true align="right" %}
|
|
156
|
+
Type
|
|
157
|
+
{% /cell %}
|
|
158
|
+
{% /row %}
|
|
159
|
+
{% row %}
|
|
160
|
+
{% cell %}
|
|
161
|
+
user_id
|
|
162
|
+
{% /cell %}
|
|
163
|
+
{% cell %}
|
|
164
|
+
int
|
|
165
|
+
{% /cell %}
|
|
166
|
+
{% /row %}
|
|
167
|
+
{% /table %}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`table` attrs:
|
|
171
|
+
|
|
172
|
+
| Attr | Type | Default | Values |
|
|
173
|
+
|---|---|---|---|
|
|
174
|
+
| `layout` | enum | `fixed` | `fixed`, `auto` (last column fluid) |
|
|
175
|
+
|
|
176
|
+
`row` — no attributes; contains `cell` children only.
|
|
177
|
+
|
|
178
|
+
`cell` attrs:
|
|
179
|
+
|
|
180
|
+
| Attr | Type | Default | Values |
|
|
181
|
+
|---|---|---|---|
|
|
182
|
+
| `header` | boolean | `false` | `true` renders as a header cell |
|
|
183
|
+
| `align` | enum | (none) | `left`, `center`, `right` |
|
|
184
|
+
| `bg` | string | (none) | CSS colour, e.g. `#f6f6f6` |
|
|
185
|
+
| `colspan` | number | `1` | |
|
|
186
|
+
| `rowspan` | number | `1` | |
|
|
187
|
+
| `colwidth` | number | (none) | column width in px |
|
|
188
|
+
|
|
189
|
+
> A plain GFM pipe table is accepted on input but is rewritten into this
|
|
190
|
+
> `{% table %}` form on the next save. Don't be surprised when it comes back
|
|
191
|
+
> expanded.
|
|
192
|
+
|
|
193
|
+
### `image`
|
|
194
|
+
|
|
195
|
+
Block image. Self-closing when there is no caption; body form when there is one
|
|
196
|
+
(the body is the caption, inline content only).
|
|
197
|
+
|
|
198
|
+
```markdoc
|
|
199
|
+
{% image url="asset:zvlxyph4f37t" width=357 /%}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
```markdoc
|
|
203
|
+
{% image url="https://uploads.developerhub.io/prod/02/example.png" %}
|
|
204
|
+
A caption sits in the body.
|
|
205
|
+
{% /image %}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
| Attr | Type | Default | Values |
|
|
209
|
+
|---|---|---|---|
|
|
210
|
+
| `url` | string | `""` | `asset:<id>` (kept verbatim) or a full upload URL |
|
|
211
|
+
| `width` | number | `0` | px; `0` = natural/full width |
|
|
212
|
+
| `align` | enum | `center` | `left`, `center`, `right` |
|
|
213
|
+
|
|
214
|
+
### `video`
|
|
215
|
+
|
|
216
|
+
Embedded or raw video. Self-closing.
|
|
217
|
+
|
|
218
|
+
```markdoc
|
|
219
|
+
{% video provider="loom" videoId="e5b8c04bca094dd8a5507925ab887002" /%}
|
|
220
|
+
{% video provider="raw" videoId="https://uploads.developerhub.io/example.mp4" /%}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
| Attr | Type | Default | Values |
|
|
224
|
+
|---|---|---|---|
|
|
225
|
+
| `provider` | enum | `youtube` | `youtube`, `vimeo`, `loom`, `raw` |
|
|
226
|
+
| `videoId` | string | `""` | the id for embeds; the full URL for `raw` (mp4/webm/ogg) |
|
|
227
|
+
| `params` | string | `""` | e.g. `start=30` |
|
|
228
|
+
|
|
229
|
+
### `tabs` / `tab`
|
|
230
|
+
|
|
231
|
+
Generic tabbed content the reader switches between. Distinct from `{% code %}`.
|
|
232
|
+
|
|
233
|
+
```markdoc
|
|
234
|
+
{% tabs %}
|
|
235
|
+
{% tab title="Android" %}
|
|
236
|
+
Android content.
|
|
237
|
+
{% /tab %}
|
|
238
|
+
{% tab title="iOS" %}
|
|
239
|
+
iOS content.
|
|
240
|
+
{% /tab %}
|
|
241
|
+
{% /tabs %}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
`tabs` — no attributes; contains `tab` children only.
|
|
245
|
+
|
|
246
|
+
`tab` attrs:
|
|
247
|
+
|
|
248
|
+
| Attr | Type | Default |
|
|
249
|
+
|---|---|---|
|
|
250
|
+
| `title` | string | `Tab` |
|
|
251
|
+
|
|
252
|
+
### `accordion-group` / `accordion`
|
|
253
|
+
|
|
254
|
+
Collapsible sections. Each section is **collapsed on load** by default; add a bare
|
|
255
|
+
`open=true` to expand it initially.
|
|
256
|
+
|
|
257
|
+
```markdoc
|
|
258
|
+
{% accordion-group %}
|
|
259
|
+
{% accordion title="Getting started" open=true %}
|
|
260
|
+
Any block content can go inside an accordion.
|
|
261
|
+
{% /accordion %}
|
|
262
|
+
{% accordion title="Advanced features" %}
|
|
263
|
+
Second section.
|
|
264
|
+
{% /accordion %}
|
|
265
|
+
{% /accordion-group %}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
`accordion-group` — no attributes; contains `accordion` children only.
|
|
269
|
+
|
|
270
|
+
`accordion` attrs:
|
|
271
|
+
|
|
272
|
+
| Attr | Type | Default | Notes |
|
|
273
|
+
|---|---|---|---|
|
|
274
|
+
| `title` | string | `Accordion` | |
|
|
275
|
+
| `open` | boolean | `false` | `open=true` = expanded on page load |
|
|
276
|
+
|
|
277
|
+
### `cards` / `card`
|
|
278
|
+
|
|
279
|
+
A grid (default) or list of link cards. Each card is a self-closing `{% card /%}`.
|
|
280
|
+
|
|
281
|
+
```markdoc
|
|
282
|
+
{% cards view="grid" %}
|
|
283
|
+
{% card title="Getting Started" text="Set up your first project." link="/support-center/getting-started" /%}
|
|
284
|
+
{% card title="Hosting" text="Custom domains and SSL." link="/support-center/hosting" /%}
|
|
285
|
+
{% /cards %}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
`cards` attrs:
|
|
289
|
+
|
|
290
|
+
| Attr | Type | Default | Values |
|
|
291
|
+
|---|---|---|---|
|
|
292
|
+
| `view` | enum | `grid` | `grid`, `list` |
|
|
293
|
+
|
|
294
|
+
`card` attrs:
|
|
295
|
+
|
|
296
|
+
| Attr | Type | Default |
|
|
297
|
+
|---|---|---|
|
|
298
|
+
| `title` | string | `""` |
|
|
299
|
+
| `text` | string | `""` |
|
|
300
|
+
| `link` | string | `/` |
|
|
301
|
+
|
|
302
|
+
### `conditional`
|
|
303
|
+
|
|
304
|
+
Wraps content shown only to a given audience (personalised / private docs).
|
|
305
|
+
Resolved server-side.
|
|
306
|
+
|
|
307
|
+
```markdoc
|
|
308
|
+
{% conditional audience="beta-users" %}
|
|
309
|
+
Content only beta users see.
|
|
310
|
+
{% /conditional %}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
| Attr | Type | Default | Notes |
|
|
314
|
+
|---|---|---|---|
|
|
315
|
+
| `audience` | string | `""` | a real project audience id; omit for public content |
|
|
316
|
+
|
|
317
|
+
### `html`
|
|
318
|
+
|
|
319
|
+
Raw custom HTML. The HTML is the body, not an attribute. Keep it to a single
|
|
320
|
+
logical line where practical — multi-line indented HTML can lose indentation on
|
|
321
|
+
round-trip.
|
|
322
|
+
|
|
323
|
+
```markdoc
|
|
324
|
+
{% html %}
|
|
325
|
+
<div class="promo">Custom widget</div>
|
|
326
|
+
{% /html %}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
No attributes.
|
|
330
|
+
|
|
331
|
+
### `github-code`
|
|
332
|
+
|
|
333
|
+
Embeds code straight from a GitHub file URL (optionally a line range in the
|
|
334
|
+
fragment). Self-closing.
|
|
335
|
+
|
|
336
|
+
```markdoc
|
|
337
|
+
{% github-code url="https://github.com/torvalds/linux/blob/master/kernel/signal.c#L152-L170" /%}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
| Attr | Type | Default |
|
|
341
|
+
|---|---|---|
|
|
342
|
+
| `url` | string | `""` |
|
|
343
|
+
|
|
344
|
+
### `index-list`
|
|
345
|
+
|
|
346
|
+
Auto-generates an index of the current page's children. Self-closing, no
|
|
347
|
+
attributes.
|
|
348
|
+
|
|
349
|
+
```markdoc
|
|
350
|
+
{% index-list /%}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### `synced`
|
|
354
|
+
|
|
355
|
+
Inserts a reusable synced block by its id (managed in the project, not in the
|
|
356
|
+
file). Self-closing.
|
|
357
|
+
|
|
358
|
+
```markdoc
|
|
359
|
+
{% synced id="open-block-menu" /%}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
| Attr | Type | Default |
|
|
363
|
+
|---|---|---|
|
|
364
|
+
| `id` | string | `welcome` |
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## Inline tags
|
|
369
|
+
|
|
370
|
+
All self-closing, all sit inside a line of text.
|
|
371
|
+
|
|
372
|
+
### `badge`
|
|
373
|
+
|
|
374
|
+
Small coloured label.
|
|
375
|
+
|
|
376
|
+
```markdoc
|
|
377
|
+
{% badge text="Done" type="success" /%}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
| Attr | Type | Default | Values |
|
|
381
|
+
|---|---|---|---|
|
|
382
|
+
| `text` | string | `OK` | the label |
|
|
383
|
+
| `type` | enum | `info` | `info`, `success`, `warning`, `error`, `primary`, `custom` |
|
|
384
|
+
|
|
385
|
+
### `key`
|
|
386
|
+
|
|
387
|
+
A keyboard key. Multi-key strings like `cmd shift k` are prettified to glyphs
|
|
388
|
+
(`⌘ ⇧ k`) on render.
|
|
389
|
+
|
|
390
|
+
```markdoc
|
|
391
|
+
{% key key="F1" /%} {% key key="⌘" /%}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
| Attr | Type | Default |
|
|
395
|
+
|---|---|---|
|
|
396
|
+
| `key` | string | `Esc` |
|
|
397
|
+
|
|
398
|
+
### `icon`
|
|
399
|
+
|
|
400
|
+
A Font Awesome icon.
|
|
401
|
+
|
|
402
|
+
```markdoc
|
|
403
|
+
{% icon classes="fas fa-adjust" /%}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
| Attr | Type | Default |
|
|
407
|
+
|---|---|---|
|
|
408
|
+
| `classes` | string | `fas fa-star` |
|
|
409
|
+
|
|
410
|
+
### `glossary`
|
|
411
|
+
|
|
412
|
+
Links a word to its glossary entry (the definition is resolved live from the
|
|
413
|
+
project glossary).
|
|
414
|
+
|
|
415
|
+
```markdoc
|
|
416
|
+
{% glossary term="coding" /%}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
| Attr | Type | Default |
|
|
420
|
+
|---|---|---|
|
|
421
|
+
| `term` | string | `term` |
|
|
422
|
+
|
|
423
|
+
### `inline-image`
|
|
424
|
+
|
|
425
|
+
An image sized to sit inline with text.
|
|
426
|
+
|
|
427
|
+
```markdoc
|
|
428
|
+
{% inline-image url="asset:02grc2jqacve" width=14 /%}
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
| Attr | Type | Default | Values |
|
|
432
|
+
|---|---|---|---|
|
|
433
|
+
| `url` | string | `""` | `asset:<id>` (verbatim) or a full URL |
|
|
434
|
+
| `width` | number | `0` | px; applies in `resizable` mode |
|
|
435
|
+
| `mode` | enum | `resizable` | `resizable`, `w100` (fit width), `fit` |
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
## Variables
|
|
440
|
+
|
|
441
|
+
Variables are written in **percent form**, not as a tag:
|
|
442
|
+
|
|
443
|
+
```markdoc
|
|
444
|
+
%product% renders the project product name (e.g. "DeveloperHub")
|
|
445
|
+
%user.name% dotted keys resolve into nested values
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
- Keys are dotted identifiers (`api.base`).
|
|
449
|
+
- Never echo `%product%` back to a user as literal text, and never replace it in
|
|
450
|
+
source.
|
|
451
|
+
- A `%…%` inside inline code or a code fence stays literal.
|
|
452
|
+
- An undefined key renders as `{{key}}`.
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
## Nesting rules
|
|
457
|
+
|
|
458
|
+
- `accordion-group` → `accordion` only; `accordion` → any block.
|
|
459
|
+
- `tabs` → `tab` only; `tab` → any block.
|
|
460
|
+
- `code` → bare code fences only (no `{% tab %}`).
|
|
461
|
+
- `code-steps` → lead blocks, then `step` tags, then language fences.
|
|
462
|
+
- `table` → `row` → `cell`; a `cell` holds any block content.
|
|
463
|
+
- `callout`, `conditional` → any block (they can nest tabs, callouts, etc.).
|
|
464
|
+
- `image` body → caption (inline content only).
|
|
465
|
+
- `video`, `cards`, `github-code`, `index-list`, `synced`, `html` → no children.
|
|
466
|
+
- Inline tags (`badge`, `glossary`, `icon`, `key`, `inline-image`) and `%KEY%`
|
|
467
|
+
variables live inside a line of text.
|