Skip to content
Back to skills

Setup

BSecurity

Verify the markdown-format hook's runtime prerequisites and configuration for this repository. Use when: 'set up markdown-format', 'configure markdown-format', 'is markdown-format working', formatting silently isn't happening, or the hook reported a missing prerequisite. Actions: check (read-only verification, default) | apply (resolve what check found). Re-runnable and safe.

  • 13 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 2, 2026
ai-agentsrustgoshellbashnodegit

Works with

  • claude code
  • cli

Security analysis

B76/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies
  • mediumInstalls packages at runtime which could introduce malicious dependencies
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 2 files and shows the line behind each finding

Scanned October 4, 2026

npx -y skills add melodic-software/claude-code-plugins --skill setup --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Setup?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Setup
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/melodic-software-setup-07cd92a9/badge)](https://www.skillsdirectory.com/skills/melodic-software-setup-07cd92a9)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
description: "Verify the markdown-format hook's runtime prerequisites and configuration for this repository. Use when: 'set up markdown-format', 'configure markdown-format', 'is markdown-format working', formatting silently isn't happening, or the hook reported a missing prerequisite. Actions: check (read-only verification, default) | apply (resolve what check found). Re-runnable and safe."
argument-hint: "[check|apply] [install-lint]"
user-invocable: true
disable-model-invocation: true
shell: bash
---

## Pre-computed context

`check`'s `jq` probe ran at load time. Read this row instead of re-issuing it; it shows
the tool's path when present, or `absent` when missing:

- `jq`: !`{ command -v jq 2>/dev/null || echo "absent"; }`

A row missing, reading as literal command text (the skill was reached through
`/markdown-format:check`, where this line never runs), or reading `[shell command execution
disabled by policy]` carries no result: run that tool's `command -v` probe via Bash instead.

## Purpose

Thin check-centric setup per the uniform setup contract (`docs/plugin-philosophy.md`
"Setup is explicit and repeatable" in the marketplace repository): `check` inspects and
reports, `apply` resolves. This plugin owns no consumer-project configuration. Rules
come from the repository's own markdownlint config, and the only tunable is the native
`userConfig` toggle, so `apply` is guidance-and-verify, with exactly one write path:
the explicitly invoked `apply install-lint` dependency install described below.

Action routing: no argument or `check` runs the check; `apply` runs the check first, then
remediation; `apply install-lint` additionally authorizes the consumer-repo dependency
install described below. All are non-interactive. Never prompt when the action is given.

## `check` (read-only)

The hook script (`${CLAUDE_PLUGIN_ROOT}/hooks/markdown-format.sh`) is the single source of
truth for what it requires and how it resolves things.

**Read it first.** Probe what it actually does, don't recite this file. Then read the
pre-computed `jq` row, run the remaining probes via Bash, and report a PASS/FAIL/INFO
table with one remediation line per FAIL. Do not modify anything.

When the plugin's toggle is disabled, every prerequisite absence except Node.js (item 1)
downgrades from FAIL to INFO. The hook and the `SessionStart` probe both exit through the
enabled gate before probing anything, so a deliberately disabled plugin is not broken.
Node.js stays FAIL: Claude Code must spawn `node` for the hook row before that gate can run. Report the probes informationally and note that re-enabling
restores the FAIL semantics.

1. **Node.js.** Every hook row starts through `node hooks/exec-bash.mjs`, so without
   `node` on `PATH` no hook launches and nothing is enforced. Probe it via Bash with
   `node --version` (a hook cannot report its own missing launcher; a stale version-manager
   shim resolves on `PATH` yet cannot run, so resolution alone is not a PASS). FAIL if it is
   absent or exits non-zero, in every toggle state; the remediation is to install or repair
   Node.js (README Requirements).
2. **Bash version.** Check against the hook's documented floor (README Requirements),
   noting any features the hook degrades without (for example telemetry's Bash builtin).
3. **`jq`.** The pre-computed `jq` row, or the Bash probe when that row carries no result. FAIL if absent *and* the repository opted in per item 5: the
   hook then skips with a visible notice, once per session and agent and renewed every
   eighth skip, instead of formatting. Without
   that opt-in the hook decides the opt-in first and emits nothing at all, so report jq's
   absence as INFO there. The missing config, not jq, is why nothing happens.
4. **`markdownlint-cli2`.** Resolve it exactly the way the hook's resolution code does
   (its sanctioned lookup paths, including its symlink/escape validation of a repo-local
   shim). A binary or shim the hook would reject must not PASS here. Then confirm the
   resolved tool actually executes. Run it with `--version` (a repo shim can resolve yet
   still be broken: missing Node interpreter, dangling target); resolution without
   successful execution is FAIL, with the execution error in the remediation line. FAIL
   when nothing the hook would accept resolves.
5. **Consumer markdownlint config, the opt-in.** This is what activates the hook, not a
   style detail. Mirror its walk: from an edited file's directory up to the repo root, so
   nested configs apply to nested files and the opt-in is per-path (a root config covers
   the tree; a `docs/` config covers only `docs/`). Where that walk finds nothing the hook
   exits silently: no `--fix`, no findings, and no per-edit notice, not even a missing
   prerequisite. The `SessionStart` probe does not check for a config, so it can still report
   a missing `markdownlint-cli2` in a repository that never opted in. Search the whole tree (skip `node_modules`), report the root config the
   cascade discovers, list nested configs with their directory scope, and surface the
   README's configuration trust boundary for every config the hook's own risk collection
   (`collect_risky_configs`) would flag. For a path no config governs, report the hook as
   **INFO, inactive, not PASS**: nothing is broken, the repository simply never opted in,
   and that is the whole reason formatting is not happening. Name the remediation in the
   same line rather than leaving the reader to infer it. Never report markdownlint's own
   default rules as the fallback. An unconfigured repo gets no rules, not the defaults.
6. **Path scope, the repository's `.gitignore`.** INFO: the hook leaves a gitignored
   file alone, neither rewriting nor reporting on it, because a path the repository
   excludes is not part of the reviewable artifact. List the ignored Markdown the
   repository carries as out of scope with
   `git ls-files --others --ignored --exclude-standard -- '*.md' '*.mdc'`,
   and note that a tracked file is never treated
   as ignored even when a pattern matches it. Report the effective
   `${user_config.markdown_format_lint_gitignored}` value (unexpanded or empty means
   default `false`, i.e. gitignored files are skipped); `true` restores linting there.
7. **Hook toggle.** Report the effective `markdown_format_enabled` value:
   `${user_config.markdown_format_enabled}` (unexpanded or empty means default `true`).
8. **Hook registration.** INFO: confirm the plugin is enabled for this project
   (`/plugin` → Installed) rather than parsing settings files.

## `apply` (idempotent)

Run `check`, then for each FAIL offer the resolution. Never install anything without the
consumer's explicit go-ahead in the invocation. `apply install-lint` adds
`markdownlint-cli2` as a dev dependency in the consumer repository **using the
repository's own package manager**, resolved in order: lockfile (`pnpm-lock.yaml` →
`pnpm add -D`, `yarn.lock` → `yarn add -D`, `bun.lock`/`bun.lockb` → `bun add -d`,
`package-lock.json` or `npm-shrinkwrap.json` → `npm install --save-dev`), then the
`package.json` `"packageManager"` field when no lockfile exists, then npm only when
neither signal is present. With no `package.json`, an ambiguous multi-lockfile state, or a lockfile that
contradicts `packageManager`, stop with manager-specific guidance instead of guessing.
Never introduce a competing lockfile. The change is stated before running. For a Yarn repository, don't infer the linker. Ask
the repo's own Yarn: run `yarn config get nodeLinker` in the repo. `pnp` (Berry's default
when unset) → skip the install and give guidance, because Plug'n'Play generates a loader file,
not the `node_modules/.bin` shim the hook resolves; install `markdownlint-cli2` on
`PATH` or switch the linker. `node-modules`/`pnpm`, or Yarn Classic (which has no such
setting and always materializes `node_modules`) → install. The
verify-after-remediation rule below is the backstop when an install still yields no
usable shim. After ANY remediation, re-run the
relevant `check` probe live via Bash (a pre-computed row predates the remediation) and report
its actual result. Never claim resolved on the
install command's exit code alone. For everything else `apply` only points:

- missing `jq` / Bash / Node.js: platform install instructions from the README Requirements section;
  this skill never installs system packages.
- toggle off: reconfigure through Claude Code's native flow, per the marketplace's
  plugin-reconfiguration convention
  (<https://github.com/melodic-software/claude-code-plugins/blob/main/docs/conventions/plugin-reconfiguration/README.md>,
  which owns the verified-version record): interactive `/plugin configure markdown-format@<marketplace>`
  any time, or headless
  `claude plugin install markdown-format@<marketplace> -s <scope> --config markdown_format_enabled=true`
  (repeatable per key). Against an already-installed plugin it prints `already installed` and
  still writes the value. Do **not** uninstall to reconfigure: that drops the plugin's entire
  stored `pluginConfigs` entry, resetting every option in the README's Options reference to its
  manifest default. Pass the scope `claude plugin list` reports for this plugin, and for a
  `project` or `local` scope run from that project's directory, so the rerun matches the existing
  install record; from the home directory pass `user`. A rejected value prints a warning yet
  exits 0, so read the output. This skill never writes user settings or `pluginConfigs`. Afterwards rerun
  `check` in a **fresh session**. The rendered `${user_config.*}` and the hook's
  `CLAUDE_PLUGIN_OPTION_*` are fixed at session start, so a same-session `check` still reports
  the OLD value; report the observed effective value, never an unobserved change.
- no markdownlint config: this is why the hook does nothing here, so lead with it rather
  than leaving it as a footnote under the passing prerequisites. Then offer to create a
  minimal `.markdownlint-cli2.jsonc` in the repository root only when explicitly asked.
  The plugin imposes no rules of its own, and which rules a repository adopts is its own
  decision, never this skill's.

Re-running `apply` after everything passes changes nothing and reports "already configured".

## What this skill does NOT do

- Run the formatter. Editing any `.md` file exercises the hook end-to-end. The only
  execution `check` performs is the harmless `--version` liveness probe of the resolved
  linter; it never lints, fixes, or touches repository content.
- Write the plugin cache, Claude Code user settings, or `pluginConfigs`.
- Download anything during `check`; network use happens only in an explicitly
  requested `apply install-lint` inside the consumer repository.

Files in this skill

  • SKILL.md9.4 KB
  • evals/evals.json7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.