Markdown Article Formatter
JimLiu/baoyu-skills
Reformats plain text or Markdown articles with frontmatter, a title, a summary, headings, bold, lists and code blocks, and saves a separate formatted copy.
A skill your agent uses when authoring or editing markdown that will be rendered by md2hd as a graph or mind map — writing node frontmatter, linking nodes with rel: or [[wikilinks]], setting up the…
$ npx skills add evan-steinhilb/md2hd --skill writing-md2hd-maps -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install evan-steinhilb/md2hd writing-md2hd-maps --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/evan-steinhilb/md2hd.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/writing-md2hd-maps .claude/skills/writing-md2hd-maps && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "writing-md2hd-maps" agent skill from https://github.com/evan-steinhilb/md2hd/tree/main/skills/writing-md2hd-maps into .claude/skills/writing-md2hd-maps/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "writing-md2hd-maps", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/evan-steinhilb/md2hd/tree/main/skills/writing-md2hd-mapsType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add evan-steinhilb/md2hd --skill writing-md2hd-maps -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install evan-steinhilb/md2hd writing-md2hd-maps --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/evan-steinhilb/md2hd.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/writing-md2hd-maps .agents/skills/writing-md2hd-maps && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "writing-md2hd-maps" agent skill from https://github.com/evan-steinhilb/md2hd/tree/main/skills/writing-md2hd-maps into .agents/skills/writing-md2hd-maps/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "writing-md2hd-maps", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add evan-steinhilb/md2hd --skill writing-md2hd-maps -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install evan-steinhilb/md2hd writing-md2hd-maps --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/evan-steinhilb/md2hd.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/writing-md2hd-maps .cursor/skills/writing-md2hd-maps && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "writing-md2hd-maps" agent skill from https://github.com/evan-steinhilb/md2hd/tree/main/skills/writing-md2hd-maps into .cursor/skills/writing-md2hd-maps/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "writing-md2hd-maps", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/evan-steinhilb/md2hd.git --path skills/writing-md2hd-maps--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add evan-steinhilb/md2hd --skill writing-md2hd-maps -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install evan-steinhilb/md2hd writing-md2hd-maps --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/evan-steinhilb/md2hd.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/writing-md2hd-maps .gemini/skills/writing-md2hd-maps && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "writing-md2hd-maps" agent skill from https://github.com/evan-steinhilb/md2hd/tree/main/skills/writing-md2hd-maps into .gemini/skills/writing-md2hd-maps/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "writing-md2hd-maps", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install evan-steinhilb/md2hd writing-md2hd-mapsInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add evan-steinhilb/md2hd --skill writing-md2hd-maps -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/evan-steinhilb/md2hd.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/writing-md2hd-maps .github/skills/writing-md2hd-maps && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "writing-md2hd-maps" agent skill from https://github.com/evan-steinhilb/md2hd/tree/main/skills/writing-md2hd-maps into .github/skills/writing-md2hd-maps/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "writing-md2hd-maps", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add evan-steinhilb/md2hd --skill writing-md2hd-maps -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install evan-steinhilb/md2hd writing-md2hd-maps --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/evan-steinhilb/md2hd.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/writing-md2hd-maps .opencode/skills/writing-md2hd-maps && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "writing-md2hd-maps" agent skill from https://github.com/evan-steinhilb/md2hd/tree/main/skills/writing-md2hd-maps into .opencode/skills/writing-md2hd-maps/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "writing-md2hd-maps", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
writing-md2hd-mapsA skill your agent uses when authoring or editing markdown that will be rendered by md2hd as a graph or mind map — writing node frontmatter, linking nodes with rel: or [[wikilinks]], setting up the…
Writing Md2hd Maps is an agent skill from evan-steinhilb/md2hd. Use when authoring or editing markdown that will be rendered by md2hd as a graph or mind map — writing node frontmatter, linking nodes with rel: or [[wikilinks]], setting up the type:map configuration block, converting a folder of existing notes into a map, or diagnosing a map that parses cleanly but draws the wrong thing (nodes missing, arrows reversed, dashed placeholder nodes, unlabelled grey lines).
Its SKILL.md is about 3.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Documents & Office, covering Markdown. The repository describes itself as: Markdown, mapped - the MD2HD CLI. Pull the repo, tell your agent to create an MD2HD map, visually comprehend complex topics and relationships. The licence is MIT.
5 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 2c0921c. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
npxFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use npx, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Writing Md2hd Maps loads about 3.8k tokens when it runs. Until then it costs about 106 tokens; SKILL.md has 1,829 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from evan-steinhilb/md2hd at commit 2c0921c, republished under its MIT licence (© evan-steinhilb). 1,829 words, ~3,816 tokens.
.claude/skills/writing-md2hd-maps/SKILL.md (or your agent's skills folder).md2hd turns a folder of markdown into a graph. Every YAML frontmatter block is a
node, rel: entries and [[wikilinks]] are edges, the prose under a
block is that node's notes, and one block with type: map configures the
whole map.
The governing fact: the parser never rejects anything. Malformed YAML, a misspelled setting, a block that never opened — all of it parses to something and draws something. There is no error state. Every mistake below is silent, so the job is not "does it parse" but "does it draw what I meant".
Everything in this document was verified against the parser (src/lib/parse.ts
in the md2hd repo). Where a friendlier user guide disagrees, this wins.
One file may hold the whole map. A --- line opens a new block, and the body
runs until the next line that opens one.
---
type: map
title: Partnerships
---
---
id: riverside-council
type: org
title: Riverside City Council
---
Prose here is this node's notes.
---
id: dana-whitfield
type: person
title: Dana Whitfield
---
And this is Dana's.--- runs parse identically.--- followed by prose stays a horizontal rule and remains inside the
current node's body. Only a --- whose next non-blank line looks like a YAML
key opens a block, which is why existing notes full of rules still work.*** and ___ never open a block.The line after --- must match /^[A-Za-z_][\w .-]*\s*:(\s|$)/.
Line after --- | Opens a block? | Why |
|---|---|---|
id: acme | yes | letter, colon, space |
id:acme | no | needs whitespace or end-of-line after the colon |
rel: | yes | colon at end of line is fine |
_id: acme | yes | leading underscore allowed |
2026: thing | no | must start [A-Za-z_] |
my key.v: x | yes | spaces, dots, hyphens legal inside a key |
A block that fails to open is not an error — the --- becomes a rule and the
entire node silently disappears from the map. id:acme with no space is the
single easiest way to lose a node.
1. The map block. Exactly one, and it is configuration — it never draws as a node and never links to anything.
---
type: map
title: Partnerships
layout: LR
types:
org: { label: Organization, color: "#4A9BFF" }
person: "#3FC8D4"
inverse:
works_at: employs
symmetric: [knows]
---2. Nodes with an explicit id and title. Both have fallbacks and both
fallbacks surprise people (see below). Two extra lines removes the whole class.
3. Name every relationship. Use rel: for structure. A bare [[wikilink]]
draws an unlabelled grey mentions line — use it only when you mean "this came
up here". A map full of them says nothing.
4. Declare inverse: and symmetric: deliberately. Both are global per
label, not per node pair. See the normalisation section — this is the most
common way to get a graph that is subtly wrong.
5. Read back every link as drawn, not just "it parsed". The normalisation pass rewrites directions and merges edges before anything appears.
Every key is optional; a block with empty frontmatter still becomes a node.
| Field | Behaviour |
|---|---|
type | Category, freely invented. Defaults to note. type: map is reserved for config. |
id | Slugged. Falls back to slug(title), then slug("<file>-<n>"). |
title / name | Card name. Falls back to the first heading anywhere in the body, then Untitled. |
subtitle | One line under the title. |
description | Opening paragraph of the detail view. |
weight | How loudly the card draws. Word or 1–5. |
tags | Chips. Nested arrays are flattened. |
rel / rels / links | Edges. Map or list. |
| any other key | A wikilink value becomes an edge; anything else becomes a metadata row. |
title falling back to any heading — not just a leading one — means a node
whose body starts with prose and has ## Open questions halfway down will be
named "Open questions". Set title: on anything containing headings.
Two nodes with neither title: nor a heading both become Untitled and both
slug to the same id.
Absent or empty → 3. A number (or numeric string) is rounded and clamped to
1–5. Otherwise a case-insensitive word lookup, and any unrecognised word
silently becomes 3.
| Value | Weight |
|---|---|
lead critical primary key | 5 |
major high | 4 |
normal medium default | 3 |
minor low | 2 |
faint background trivial | 1 |
7→5, 0→1, 2.6→3, "4"→4 | clamped and rounded |
urgent, blocker, anything else | 3 |
Weight affects drawing only, never the graph.
slug() runs on id, on the title fallback, and on both ends of every link
— which is why [[Acme Corp]] finds id: acme-corp.
trim → lowercase → delete everything except [A-Za-z0-9_ -] → collapse [\s_]+ to "-" → trim "-"| Input | Slug | Note |
|---|---|---|
my_node | my-node | underscores become hyphens |
Acme Corp. | acme-corp | punctuation dropped |
Foo—Bar | foobar | em-dash dropped with no separator |
Ünïcode Name | ncode-name | non-ASCII letters are deleted, not transliterated |
2026-07-14 | 2026-07-14 | digits and hyphens survive |
So id: my_node, [[my-node]] and [[my_node]] are all the same node. Give
accented or non-Latin titles an explicit ASCII id:.
Duplicate ids do not merge, despite a warning that says "later copy merged". Both nodes draw; only the second is reachable by link. Treat it as an error.
| Key | Behaviour |
|---|---|
title | The map's name. |
layout | Exactly LR for left-to-right. Every other value — lr, RL, horizontal — silently gives TB. |
types | Per type { label, color }, or a bare colour string as shorthand (label defaults to the key). |
inverse | works_at: employs — key is the passive wording, value the active one. |
symmetric | Relations with no direction: [knows, met]. |
Those five keys are the only ones read. Anything else is never looked at.
direction:, colors:, rankdir: and palette: are all valid YAML that does
absolutely nothing — this is the most common authoring mistake, because the
names are so plausible.
Types you omit get a palette colour in encounter order, so a map needs no colours at all to read clearly.
Two map blocks do not merge. The last one replaces the config wholesale, so
a layout: LR in the first is lost if the second omits it. Keep exactly one.
1. rel: / rels: / links:
rel:
employs: [dana, marcus] # relation -> id, or list of ids
runs: records-portal
rel:
- employs: dana # list of single-key maps also works
rel: [dana, marcus] # list of bare scalars -> label is "links"2. Any non-reserved frontmatter key whose value is a wikilink
works_at: "[[acme]]" # edge labelled "works_at"
attendees: ["[[dana]]", "[[marcus]]"]Reserved keys are skipped: id type title name subtitle description weight tags rel rels links layout types inverse symmetric. A wikilink inside description:
makes no edge.
3. Inline fields in the body — /(?:^|\s)([A-Za-z][\w-]*)::\s*(.+)$/gm
owns:: [[depot]] label "owns"
mid sentence owns:: [[depot]] also matches — preceded by a space
nope-owns:: [[d]] matches; label is "nope-owns" (hyphens legal)
1bad:: [[d]] no match — must start with a letter4. Bare wikilinks in the body → an untyped mentions edge, unless an inline
field on the same node already claimed that target.
[[target|alias]] links to target; the alias only changes displayed text.
Self-links are dropped — a node with rel: { knows: <its own id> } produces
no edge at all.
This pass rewrites what you wrote. It is where authored text stops matching the canvas, and where most "the graph is wrong but it parsed" bugs live.
Up to 3 rounds per edge. Each round:
inverse[label] exists → relabel to that value and swap the ends;/^(.+?)[\s_-]by$/ → strip the suffix and swap;So owned_by, owned-by and owned by all become owned pointing the other
way. standby and nearby do not match — a separator is required.
inverse: is checked first each round, and the rules chain: with
inverse: { x: owned_by }, a label x relabels to owned_by and swaps, then
the _by rule fires on the result and swaps back — ending as owned in the
original direction. Two flips cancel. Avoid declaring an inverse: value that
itself ends in _by.
The identity is source > target > stem(label), where stem lowercases,
turns any run of spaces/underscores/hyphens into a single space, and strips a
trailing ed, s or d.
Consequences:
owns, owned and own between the same pair are one edge. The first
spelling encountered is kept.paired_with, paired-with and Paired With are the same relation.knew and knows stay distinct.An edge carries label (as drawn) and reverse (the same fact from the far
end), so one link reads employs from the organisation and works at from the
person. reverse comes from whatever the far end actually wrote, or failing
that from the declared inverse: counterpart.
inverse:is global per label, not per pair. Declaringinverse: { assigned_to: owns }gives everyownsedge in the map the reverse voice "assigned to" — includingrosa owns session-store, which then reads as a service assigned to a person. If a label means different things in different places, give those relations different names.
symmetric: matches the same way, so [paired_with], [paired with] and
[paired-with] are interchangeable, and [knows] also matches a know label.
If a→b and b→a share a stem they become one edge marked symmetric, drawn
with no arrowhead and a chevron at each end. Anything in symmetric: is marked
the same way.
A mentions edge is discarded when any named relation already connects that
unordered pair.
Link targets that were never defined become ghost nodes — dashed,
type: unresolved. Nothing you reference vanishes, but a typo'd id becomes a
ghost rather than an error.
Every one of these parses cleanly.
| Symptom | Cause |
|---|---|
| A node is missing entirely | key:value with no space — the block never opened |
| Layout ignored | layout: anything but exactly LR |
| Type colours ignored | a key the map block does not read (colors:, direction:) |
| Config half-applied | a second type: map block replaced the first wholesale |
| Arrow points backwards | a _by/-by/ by suffix, or an inverse: pair, flipped it — by design |
| A relation reads oddly on unrelated nodes | inverse: is global per label |
| Two relations became one | same stem between the same pair |
| A dashed node you never wrote | typo in a link target → ghost |
| Two identical cards | duplicate id: — they do not merge |
| Node named after a subheading | no title:; the fallback found a heading in the body |
| Several nodes named "Untitled" | no title: and no heading; their ids collide |
| Unlabelled grey lines everywhere | bare [[wikilinks]] where a named relation was meant |
| Everything equally loud | an unrecognised weight: word fell back to 3 |
| A relationship you wrote is absent | it pointed at itself |
Inside the md2hd repo, run the real parser and read every link as drawn:
npx vite-node .claude/skills/writing-md2hd-maps/check-map.ts -- path/to/map.mdAnywhere else, there is no validator — check by eye, in this order:
--- you intended as a node is followed by a
key with a space after its colon. This grep flags the killer:grep -nE '^[A-Za-z_][A-Za-z0-9 ._-]*:[^[:space:]]' map.mdtitle layout types inverse symmetric.layout: is exactly LR if you wanted left-to-right.type: map block.id: is unique, and every link target matches an id after
slugging.weight: is a listed word or 1–5.inverse: and symmetric: entry and confirm the label means
the same thing everywhere it is used.[[wikilinks]] — each is an unlabelled line. Convert the ones
that deserve a name.---
type: map
title: Checkout Outage — 14 July
layout: LR
types:
service: { label: Service, color: "#4A9BFF" }
person: { label: Responder, color: "#3FC8D4" }
event: { label: Timeline, color: "#EA8A62" }
action: { label: Action Item, color: "#4FBE8B" }
inverse:
assigned_to: owns_action
symmetric: [paired_with]
---
---
id: payments-api
type: service
title: Payments API
weight: lead
rel:
depends_on: session-store
---
The blast radius. Every checkout path routes through it.
---
id: session-store
type: service
title: Session Store
subtitle: Redis · 3 replicas
---
---
id: rosa-imani
type: person
title: Rosa Imani
subtitle: On-call, platform
weight: major
rel:
operates: session-store
paired_with: theo-nakamura
---
Took the page at 14:06.
verified:: [[rollback-1447]]
---
id: theo-nakamura
type: person
title: Theo Nakamura
---
---
id: config-push-1402
type: event
title: Config push 14:02
rel:
degraded: payments-api
---
---
id: rollback-1447
type: event
title: Rollback 14:47
rel:
reverted: config-push-1402
restored: payments-api
---
---
id: action-canary
type: action
title: Canary config pushes
rel:
assigned_to: rosa-imani
addresses: config-push-1402
---
---
id: action-alerts
type: action
title: Alert on session pool saturation
rel:
assigned_to: theo-nakamura
covers: session-store
---Note what this does not do: it uses operates rather than owns for the
service, because owns_action is declared as an inverse and would otherwise
attach "assigned to" to a service. That is step 3 above, and it is the mistake
worth watching for.
© evan-steinhilb, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in skills/writing-md2hd-maps of evan-steinhilb/md2hd.
Open the folder on GitHubat commit 2c0921c
Writing Md2hd Maps next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Writing Md2hd Maps this skillevan-steinhilb/md2hd | 137 | — | ~3.8k | Automated safety check: Pass | MIT | |
| Markdown Article FormatterJimLiu/baoyu-skills | 27k | 6 repos | ~3.5k | Automated safety check: Pass | MIT | |
| MarkitdownImCa0/just-laws | 781 | 14 repos | ~3.2k | Automated safety check: Notes | MIT | |
| Obsidian MarkdownAtmosphere/atmosphere | 3.8k | 20 repos | ~1.3k | Automated safety check: Pass | Apache-2.0 | |
| Crosspostingwasp-lang/wasp | 19k | — | ~1.1k | Automated safety check: Pass | MIT | |
| Gzh Designisjiamu/gzh-design-skill | 4k | — | ~2.2k | Automated safety check: Pass | AGPL-3.0 |
JimLiu/baoyu-skills
Reformats plain text or Markdown articles with frontmatter, a title, a summary, headings, bold, lists and code blocks, and saves a separate formatted copy.
ImCa0/just-laws
Convert files and office documents to Markdown. An agent skill from ImCa0/just-laws.
Atmosphere/atmosphere
Create and edit Obsidian Flavored Markdown with wikilinks, embeds, callouts, properties, and other Obsidian-specific syntax.
wasp-lang/wasp
Crosspost Wasp blog articles (MDX) to DEV.to and Medium. An agent skill from wasp-lang/wasp.
isjiamu/gzh-design-skill
微信公众号文章排版引擎,将 Markdown 转换为可直接粘贴到公众号编辑器的 HTML。主题风格从 references/theme-index.md 注册的自定义主题库中选取,自动章节编号、关键词下划线标记、引言卡片、目录导航、代码块、图片/GIF、作者签名。支持 Markdown / Word(.docx) / PDF / 纯文本输入(非 Markdown…
supabase/supabase
Review Supabase docs changes locally in your supabase/supabase checkout — either an open PR (triage, classify, verify) or your own branch before opening a PR (local self-review).
Categories
A skill your agent uses when authoring or editing markdown that will be rendered by md2hd as a graph or mind map — writing node frontmatter, linking nodes with rel: or [[wikilinks]], setting up the…. Writing Md2hd Maps is an agent skill from evan-steinhilb/md2hd. Use when authoring or editing markdown that will be rendered by md2hd as a graph or mind map — writing node frontmatter, linking nodes with rel: or [[wikilinks]], setting up the type:map configuration block, converting a folder of existing notes into a map, or diagnosing a map that parses cleanly but draws the wrong thing (nodes missing, arrows reversed, dashed placeholder nodes, unlabelled grey lines).
Writing Md2hd Maps fits situations like: editing markdown that will be rendered by md2hd as a graph; mind map — writing node frontmatter; linking nodes with rel:; setting up the type:map configuration block.
Run `npx skills add evan-steinhilb/md2hd --skill writing-md2hd-maps -a claude-code`. Or copy the skill folder (skills/writing-md2hd-maps in evan-steinhilb/md2hd) into .claude/skills/writing-md2hd-maps in your project. Claude Code loads it when a task matches its description.
Run `npx skills add evan-steinhilb/md2hd --skill writing-md2hd-maps -a codex`. Or copy the skill folder (skills/writing-md2hd-maps in evan-steinhilb/md2hd) into .agents/skills/writing-md2hd-maps in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add evan-steinhilb/md2hd --skill writing-md2hd-maps -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/writing-md2hd-maps, .gemini/skills/writing-md2hd-maps, .github/skills/writing-md2hd-maps and .opencode/skills/writing-md2hd-maps in your project.
Going by SKILL.md and its folder, Writing Md2hd Maps needs the command-line tools its instructions call (npx).
SKILL.md contains no URLs. Its commands use npx, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Writing Md2hd Maps is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3.8k tokens (SKILL.md is roughly 15k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Writing Md2hd Maps: Markdown Article Formatter (JimLiu/baoyu-skills, 27k stars), Markitdown (ImCa0/just-laws, 781 stars), Obsidian Markdown (Atmosphere/atmosphere, 3.8k stars) and Crossposting (wasp-lang/wasp, 19k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
evan-steinhilb (a GitHub user) maintains it in evan-steinhilb/md2hd, which has 137 GitHub stars. The repository was last updated on August 26, 2026.
Source: evan-steinhilb/md2hd on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.