A self-contained Hermes Agent skill that automatically lints and fixes Markdown files to enforce GitHub Flavored Markdown (GFM) rules.
Powered by pure Node.js scripts — format-tables.js for single-pass table formatting and markdownlint-cli2 via npx for GFM rule enforcement. No committed node_modules, package install step, or bash runtime required.
This repository follows autonomous agent governance standards — explicit behavioral contracts for LLM agents.
- AGENTS.md defines a formal contract for any Markdown file creation or edit
- Severity levels (BLOCKING/WARNING/INFO) make validation failures actionable
- Imperative section headers (Validate Changes, Resolve Failures) for machine readability
- Safe automation boundaries prevent destructive "helpful AI" behavior
- Consistency checks prevent drift between config, documentation, and formatter behavior
As LLM agents increasingly work autonomously in repositories, explicit governance becomes critical:
- Deterministic validation prevents silent regressions
- Severity levels enable safe autonomous PRs
- Behavioral contracts create reproducible contributor expectations
- Machine-readable sections enable programmatic enforcement
- CI-backed consistency checks turn governance claims into enforceable guarantees
This is part of a broader shift toward AI-native repository standards — where human and agent workflows are equally well-specified.
Learn more: See AGENTS.md for the full behavioral contract.
This skill treats Markdown linting as agent-safe repository governance:
- Formatting must be deterministic and idempotent
- Fenced code blocks are safety boundaries and must not be rewritten as prose
- Table formatting preserves semantic alignment (
:---,---:,:---:) lint.jsis the canonical entry point for manual, CI, and agent-driven execution- Documentation, config, formatter behavior, and governance claims must stay synchronized
Before installing, ensure your environment meets the following requirements:
- Hermes CLI — Required to install the skill. The
post-write.jshook is an optional safety net. - Node.js (v18+) — The linting pipeline relies on native Node.js scripts and
npxto dynamically fetchmarkdownlint-cli2without requiring global installations. - Cross-Platform — The pipeline runs natively on Linux, macOS, and Windows. No WSL or Git Bash required!
hermes skills install CodeSigils/hermes-markdown-lint-skill/markdown-lint --force
The --force flag is required because the security scanner flags post-write hooks as dangerous (expected for a linting skill).
The skill already instructs the AI agent to automatically lint every Markdown file it creates or edits. For guaranteed enforcement even if the agent skips the instruction, you can add a system-level hook:
Edit ~/.hermes/config.yaml:
hooks:
post_tool_call:
- matcher: "write_file"
command: "node ~/.hermes/skills/markdown-lint/scripts/post-write.js"
hooks_auto_accept: trueRestart Hermes for the hook to activate. This is optional — the mandatory lint rule in SKILL.md handles the common case.
# One-liner (recommended — pure Node.js, cross-platform)
node ${HERMES_SKILL_DIR}/lint.js <path>
# Options
node ${HERMES_SKILL_DIR}/lint.js --check <path> # Read-only check
node ${HERMES_SKILL_DIR}/lint.js --all <dir> # Fix all .md in directory
node ${HERMES_SKILL_DIR}/lint.js --validate <path> # Validate table column consistency
node ${HERMES_SKILL_DIR}/lint.js --fences <path> # Check fenced code blocksThe canonical wrapper runs two stages internally:
format-tables.jsformats all tables in a single passmarkdownlint-cli2fixes or checks everything else through the bundled config
Agents should call lint.js; direct npx markdownlint-cli2 commands are only for debugging the skill internals.
The most common table error is column count mismatch between the header, separator, and data rows. This often happens with:
- Extra
|characters in type definitions (e.g.,"tab" | "space") - Copy-paste errors in separator rows
# Add to CI or pre-commit to catch broken tables
node lint.js --validate .This validates:
- Header columns match separator columns
- All data rows have the correct number of columns
- Pipes inside cells are properly escaped with
|
If a table cell contains a pipe character, escape it to prevent column misparsing:
Before (broken) — the raw | breaks the column count:
| Type | Value |
| :------ | :---- |
| Options | "tab" | "space" |After (fixed) — escape with |:
| Type | Value |
| :------ | :------------------------- |
| Options | "tab" | "space" |The pipeline (format-tables.js → markdownlint-cli2) fixes GFM violations automatically:
Table separators — normalizes raw dashes to GFM-compliant aligned separators while preserving semantic alignment:
Before:
| Name | Age | Score |
| --- | ---: | :---: |
| Alice | 25 | A |After:
| Name | Age | Score |
| :---- | --: | :---: |
| Alice | 25 | A |Headings — adds required blank lines around headings:
Before:
Some text
## My Heading
More textAfter:
Some text
## My Heading
More textTabs & blank lines — converts tabs to spaces and collapses multiple blank lines to one.
The skill includes a bundled config at references/.markdownlint.json.
lint.js uses it automatically — no setup required.
Key policy choices:
- MD040 is disabled — blank fences are allowed for output examples
- MD055 is disabled — leading/trailing table pipes are optional
- MD060 is set to
aligned— table column positions are normalized while preserving semantic alignment
Run against the test fixture:
node lint.js --check test/kitchensink.mdThe project uses GitHub Actions to validate every push and PR. You can run the same checks locally:
# 1. Repository governance/config consistency
node scripts/check-consistency.js
# 2. Unit tests for the table formatter
node test/format-tables.test.js
# 3. Check for unclosed code fences or bad closers
node lint.js --fences .
# 4. Validate table column consistency
node lint.js --validate .
# 5. Final lint check
node lint.js --check .Pre-commit:
# .pre-commit-config.yaml
- repo: local
hooks:
- id: hermes-markdown-lint
name: Hermes Markdown lint
entry: node lint.js --check .
language: system
pass_filenames: falseLearn more about creating and managing Hermes skills:
- Creating Skills - Official guide
- Skills User Guide - Using skills
- agentskills.io - Open standard (compatible with Claude, OpenAI, etc.)
.
├── AGENTS.md
├── lint.js # Developer wrapper
├── README.md
├── scripts/
│ └── check-consistency.js # Config/docs anti-drift checker
├── skills/
│ └── markdown-lint/ # <-- The actual skill payload
│ ├── SKILL.md
│ ├── lint.js # Canonical entry point
│ ├── scripts/
│ │ ├── check-fences.js # Fenced code block checker
│ │ └── post-write.js # Auto-lint hook (optional)
│ └── references/
│ ├── format-tables.js # Single-pass table formatter
│ └── .markdownlint.json
└── test/
└── format-tables.test.js
- Strengthened the agent contract: lint after any Markdown file creation or edit, not only a specific write tool.
- Added MUST-level agent requirements to the installed
SKILL.md. - Fixed MD060
alignedtable formatting for right- and center-aligned columns. - Restored README changelog tracking and corrected stale direct-
npxguidance. - Strengthened
check-consistency.jsto compare documented rule tables against.markdownlint.json. - Aligned
SKILL.mdfrontmatter with the official Hermesversionandauthorfields. - Removed redundant GitHub Actions workflow;
ci.ymlis now the canonical validation workflow.
- Replaced shell wrappers with native Node.js entry points.
- Merged table separator fixing and cell padding into
format-tables.js. - Added repository consistency checks to keep config and docs synchronized.
- Added
--fencesmode for fenced code block validation. - Disabled MD055 so leading and trailing table pipes remain optional.
- Disabled MD033 so inline HTML remains valid in Markdown.
- Added
--validatemode for table column consistency checks. - Documented escaped pipe handling for table cells.
- Added optional
post-write.jshook for automatic linting after Markdown writes. - Enabled stricter list and table alignment validation.
MIT License. See LICENSE.