Instructions for AI coding agents (Codex, Copilot, Claude).
mdsmith — a Markdown linter written in Go.
- How "flavor" (a property of the renderer), "rule" (a single check), "convention" (a project-wide bundle), and "kind" (a per-file role tag) differ in mdsmith, the cases where they overlap, and how the four concepts compose.
- How generated sections work — markers, directives, and fix behavior.
- How the placeholder vocabulary lets rules treat template tokens as opaque rather than flagging them as content violations.
- The mental model behind mdsmith — how flavor, rule, convention, and kind relate, how generated sections work, the placeholder grammar, and how it compares to other Markdown linters.
- How mdsmith compares to other Markdown linters.
- Running log of SOLID and clean-architecture findings on origin/main. The solid-architecture skill (audit mode) appends here; blockers are also filed as plans.
- Checklist for sweeping origin/main for SOLID and boundary violations. Records findings in the audit log; schedules blockers as new plan files.
- External-surface contracts: LSP, CLI, .mdsmith.yml, generated markers, plugin manifest, distribution shims. Public APIs.
- Go-specific SOLID and clean architecture patterns for mdsmith's cmd/ and internal/ packages.
- SOLID and clean-architecture rules for mdsmith's Go core, TypeScript extension, and cross-system surfaces. Canonical home for the solid-architecture skill.
- Four-layer test pyramid (unit, contract, integration, e2e) and the rule that every function ships with a dedicated unit test. Included from the Go and TypeScript architecture pages.
- SOLID and clean architecture patterns for the mdsmith VS Code extension at editors/vscode/.
- Codecov coverage gate and CI status checks.
- Where to place Markdown files and documentation types.
- Process and patterns for keeping mdsmith's Go core fast: the benchmark→profile→fix loop, the patterns to reach for, and the anti-patterns that have already cost the project real CPU and GC time.
- Build commands, project layout, code style, test fixtures, coverage gate, and merge conflicts.
- The pkg/markdown public package: parse, produce, and its compatibility policy.
- Label-driven merge queue workflow using jeduden/merge-queue-action.
- Rebase, CI monitoring, and review comment resolution.
- Per-platform mdsmith binaries plus the .vsix, the checksum file, and a Sigstore signature, attached to a tag-named release.
- Root
@mdsmith/cliplus one platform-specific subpackage per supported host, all published via OIDC Trusted Publishing. - The same
.vsixrepublished to Open VSX so VSCodium, Cursor, Theia, and Gitpod can install it. - One platform-tagged wheel per supported host, published via OIDC Trusted Publishing.
- The mdsmith VS Code extension
.vsix, published via a long-lived Marketplace publisher PAT. - Every GitHub Actions workflow that needs runtime logic invokes the
mdsmith-releaseGo CLI rather than carrying inline shell or per-language scripts. This page captures the rule and the subcommands it applies to. - How a maintainer-dispatched workflow run publishes mdsmith to npm, PyPI, the Visual Studio Marketplace, Open VSX, and GitHub Releases — the workflow structure, the OIDC trusted publishers it relies on, the
releaseenvironment that gates every publishing job, the separate website deploy, and the supply-chain hardening features baked into the pipeline. - Rotation cadence and procedure for the long-lived publisher tokens consumed by the release and merge-queue workflows. Each tracked secret has its own file under
secret-rotations/; the catalog below enumerates them. The scheduled reminder workflow consumes the same files and opens a GitHub issue when any secret is within 30 days of expiry. - GitHub fine-grained PAT for the merge-queue action. Plain repo secret — not gated by an environment.
- Open VSX publisher token. Drives the
ovsx publishstep. - Visual Studio Marketplace publisher PAT issued by Azure DevOps. Drives the
vsce publishstep. mdsmith fixrewrites whitespace, headings, code fences, bare URLs, list indentation, and table alignment in place, looping up to 10 passes and stopping when edits stabilize.mdsmith checkis the read-only CI sibling.- The
<?build?>directive declares an artifact and a recipe.mdsmith fixkeeps the section body in sync with the recipe output;MDS040shell-safety-checks the recipe without running it. - Config layers deep-merge rule by rule: defaults, convention, kinds, then overrides.
--explainandmdsmith kinds resolveshow which layer set each effective value, per leaf. - Built-in rules flag broken links and missing anchors, enforce per-file section schemas, and keep Markdown in the right folders. Schemas can be inline on a file kind or shared via
proto.mdfiles. mdsmith depslists what a file pulls in — includes, catalogs, build sources, and links — or, with--incoming, every file that points at it. The LSP call-hierarchy walks the same graph in your editor.- A bundled VS Code extension and Claude Code plugins drive the same
mdsmith lspserver, so diagnostics, fix-on-save, and navigation reach your editor and your coding agent unchanged. - Tag each file with a
kind, then validate its headings and front matter against a schema declared inline on the kind or shared via aproto.mdtemplate — so a whole directory obeys one contract. - A Git merge driver auto-resolves conflicts inside generated blocks, and a pre-merge-commit hook re-runs
mdsmith fixand re-stages the result, so generated content never blocks a merge. - The mdsmith feature overview shared by the repository README and the website. Each capability links to a fuller page with rules and examples.
- One version-stamped Go binary ships through go install, npm, pip, uvx, mise, asdf, and GitHub Releases — with no postinstall network call, so locked-down CI installs offline.
mdsmith lspemits diagnostics, quick-fixes, and navigation — definition, references, symbol search, and a call-hierarchy over<?include?>,<?catalog?>, and cross-file links — consumed by any LSP-aware editor.- Pin a Markdown convention to get a curated rule preset and a target renderer flavor in one switch.
MDS034flags syntax the flavor will not render; a placeholder vocabulary spares template tokens. - A single static Go binary, no runtime to start. The workspace walk runs in parallel, embeds are linted once, and
checkis built for the hot path — roughly 4x faster than Node markdownlint, with a CI gate against regression. - CI badge, Go Report Card grade, and Codecov coverage badge report live project health. mdsmith lints its own docs with the rules it ships, and a coverage gate blocks any merge that drops below the line.
mdsmith list query 'status: "✅"' plan/selects files by a CUE expression on front matter;mdsmith metrics rankranks files by any shared metric — both ready to pipe into a release script.- Rename a heading and every workspace anchor link that points at it is rewritten in one atomic edit. Link-reference labels rename with their uses. A colliding slug fails loudly instead of silently breaking cross-file links.
- On
mdsmith fix,<?toc?>rebuilds a heading TOC,<?catalog?>generates an index from front matter, and<?include?>splices in another file. A Git merge driver auto-resolves conflicts inside those blocks. - Cap file, section, and token-budget size; enforce reading grade and sentence count; flag verbatim copy-paste across files.
- Prettier owns whitespace and line wrapping; mdsmith owns lint, generated sections, and cross-file checks. Run both in a single pre-commit hook with the order Prettier last.
- Vale owns brand voice and prose style; remark owns Markdown AST transformations; mdsmith owns formatting, cross-file integrity, and generated sections. They sit side by side in CI without overlap.
- How to use the build directive to declare artifact outputs, keep generated bodies in sync, and configure user-declared recipes.
- How to use schemas, require, and allow-empty-section to validate headings, front matter, and filenames.
- How to use catalog and include directives to generate and embed content in Markdown files.
- Key differences between Hugo templates and mdsmith directives for users familiar with Hugo.
- Wire
mdsmith lspinto Neovim's built-in LSP client so diagnostics, code actions, and navigation work inline with no extra plugin. - Install the mdsmith VS Code extension, configure how it spawns
mdsmith lsp, and read diagnostics inline as you edit Markdown files. - How to declare file kinds, assign files to them, and read the merged rule config that results.
- User guides for mdsmith directives, structure enforcement, and migration.
- Every channel that ships the mdsmith binary, the VS Code extension, or the Claude Code plugin — npm, PyPI, asdf, mise, the GitHub release, the Visual Studio Marketplace plus Open VSX, and the in-repository Claude Code marketplace — and which channel to pick for which workflow.
- Trade-offs and threshold guidance for readability, structure, length, and token budgets.
- Move a project from markdownlint-cli or markdownlint-cli2 to mdsmith — the rule mapping, the config rewrite, and the markdownlint rules mdsmith does not implement yet.
- Declare a document-structure schema inline on a kind or in a proto.md file, validate headings and front matter, and tighten rule config per section.
- CLI commands, flags, exit codes, and output format.
- List workspace links that point at a file.
- Lint Markdown files for style issues.
- List a file's dependency-graph edges (includes, links, catalogs, builds).
- Write a portable, directive-free copy of a Markdown file.
- Emit a schema-conformant Markdown file as a JSON/YAML/msgpack data tree.
- Auto-fix lint issues in Markdown files in place.
- Show built-in documentation for rules, metrics, and concept pages.
- Generate a default
.mdsmith.ymlconfig in the current directory. - Inspect declared file kinds and resolve effective rule config per file.
- Selection-style commands that walk the workspace and emit matches.
- Run a Language Server Protocol server on stdio for editor integrations.
- Git merge driver that resolves conflicts inside generated sections.
- List and rank shared Markdown metrics (file length, token estimate, readability, …).
- Install / manage a pre-merge-commit hook that runs
mdsmith fixafter a merge. - Select Markdown files by a CUE expression on front matter.
- Rename a heading or link-reference label and rewrite every dependent edit.
- Print the mdsmith build version and exit.
- Built-in Markdown conventions, the rule presets each one applies, and how user config layers on top via deep-merge.
- Glob pattern syntax across mdsmith config, directives, and CLI argument expansion, with the supported exclusion semantics for each surface.
- Look up exact CLI commands, config glob and schema syntax, the built-in conventions, and the section-schema grammar.
- Each file under
.mdsmith/kinds/declares one kind. The basename is the kind name; the file body carries the fullKindBody— schema, rules,path-pattern:,extends:. Sits alongside inlinekinds.<name>:in.mdsmith.yml. - Named field-type shortcuts for inline schema frontmatter values — the registered names, the canonical CUE each one resolves to, and example usage.
- Section-schema reference for inline
kinds.<name>.schema:blocks. Covers theheading:discriminator, theregex:matcher (a Go RE2 body with\#(digits)and\#(fmvar(...))helpers), therepeat: {min, max}cardinality field, and the matching algorithm.proto.mdfiles are parsed into the same shape by the schema package, but MDS020's file-schema check still uses its legacy parser; see the proto.md section below for what is and is not migrated. - mdsmith collects no telemetry, no usage analytics, no error reports, and no identifiers. The CLI and the LSP server make no outbound network calls at runtime.
- Any change follows Red/Green TDD: failing test, then pass, then commit
- Keep commits small and focused on one change
- Run
mdsmith check .before committing; all markdown must pass - Never modify
.mdsmith.yml(linter configuration) without explicit user consent — this includes rule settings, overrides, ignore patterns, and file-length limits
Use the /pr-fixup, /gh-resolve-threads, and /merge-queue
skills for PR work — they cover rebases, CI monitoring, thread
resolution, and merge enqueuing. After every push, request a
Copilot re-review (the skills do this automatically).
When implementing work tracked by plan/:
- Update the plan file as part of implementation, not a follow-up
- Check off each task and acceptance criterion as it is completed or verified
- Move front-matter
statusfrom🔲to🔳on start, then to✅when all criteria pass - If implementation deviates, update plan text to match what was built
- Run
mdsmith fix PLAN.mdafter editing plan front matter so the catalog table stays current
demo.tape records the demo GIF. Editing notes:
- Backtick-delimited strings for embedded quotes:
Type `cmd 'status: "✅"'`.\"inside double-quoted Type strings crashes VHS - A hidden
set +eruns at start, so don't append; trueto commands demo/sample.mdis in the.mdsmith.ymlignore list; hidden setup copies it to a temp dir for check/fix- Keep Sleep durations short (1–2 s) for fast CI renders
- Use only fixable rules in
demo/sample.md(trailing spaces, long lines, bare URLs) so the fix→check flow works
When writing descriptions, state what specific data must satisfy what condition. Name the inputs (front matter fields, glob pattern, heading level), not just the mechanism. Avoid vague verbs (match, sync, reflect) without saying what is checked against what.
Build and test reference for mdsmith contributors. See also:
- Architecture audit log
- Architecture principles
- Coverage Gate
- File Placement
- High-Performance Go
- Merge Queue
- PR Fixup Workflow
- Public Markdown Library
- Release Pipeline
- Release Tooling Architecture
- Secret Rotations
Requires Go 1.24+.
go build ./...— build all packagesgo test ./...— run all testsgo test -run TestName ./...— run a specific testgo run ./cmd/mdsmith check .— lint markdowngo run ./cmd/mdsmith fix .— auto-fix markdowngo tool golangci-lint run— run lintergo vet ./...— run go vet
Follows the standard Go project layout:
cmd/mdsmith/— main entry point.internal/— private packages.internal/rules/<rule-name>/— rule code (e.g.paragraphstructure/).internal/rules/MDS###-<rule-name>/— rule README and good/bad fixtures (e.g.MDS024-paragraph-structure/).testdata/— shared markdown fixtures.pkg/goldmark/— vendored goldmark fork.
- Follow standard Go conventions (gofmt, goimports).
- Use golangci-lint for linting.
- Keep functions small and focused.
- Error messages: lowercase, no trailing punctuation.
- Prefer returning errors over panicking.
Add a defensive branch only when you can drive it red/green. Write the failing test first. Then add the code that takes the branch.
A rule's Check allocates ≤ 10 times per call on
representative input. Enforced by
internal/integration/alloc_budget_test.go; most
rules allocate 0–6.
- Walk
f.Lines/f.ASTdirectly. - Prefer
bytes.IndexByte/bytes.Containsoverregexpfor fixed searches. - Compile every
regexp.Regexpat package scope. - Pre-size slices with
make([]X, 0, n). - Reuse loop-local buffers via
buf = buf[:0]. - Return
nil, not an empty slice, on no diagnostics.
Rule test fixtures live in
internal/rules/MDS###-<rule-name>/ (e.g.
MDS024-paragraph-structure/). Each rule has good/
and bad/ examples (or good.md / bad.md).
Good fixtures must pass all default-enabled rules
plus the rule under test. Opt-in rules are skipped:
a good MDS001 fixture need not also satisfy MDS043.
When a good fixture uses non-default settings,
override them in .mdsmith.yml so mdsmith check .
also passes. Bad fixtures are excluded via the
ignore: section.
When adding or changing a rule, add both:
- Unit tests in
rule_test.go(inline markdown, fast red/green). Userequirefor preconditions andassertfor checks;Same/NotSamefor pointer identity. - Fixture tests under
internal/rules/MDS###-<rule-name>/with YAML frontmatter specifying expected diagnostics. Discovered automatically byinternal/integration/rules_test.go.
Layered config (defaults → kinds → overrides) is deep-merged rule by rule:
- Maps merge key by key; siblings set in earlier layers survive partial overrides.
- Scalar leaves are replaced wholesale.
- List settings replace by default. Opt into
appendby implementingrule.ListMerger.SettingMergeMode(key). The placeholder vocabulary is the canonical example. - A bool-only layer (
rule-name: false) togglesenabledwithout erasing inherited settings.
New list-typed settings must document the choice
next to their ApplySettings handler.
Content between <?directive ... ?> and
<?/directive?> markers is auto-generated. Edit
directive parameters or the source file, then run
mdsmith fix <file> — never the body by hand. Run
mdsmith merge-driver install [files...] once per
clone so generated-section conflicts resolve
automatically.