Skip to content
Back to skills

Setup

ASecurity

Verify the eol-normalizer hook's runtime prerequisites and configuration for this repository. Use when: 'set up eol-normalizer', 'configure eol-normalizer', 'is eol-normalizer working', line endings silently aren't normalizing, 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
  • 3 views
  • Added September 2, 2026
ai-agentsgoshellbashnodegit

Works with

  • claude code

Security analysis

A100/100

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: A — Skills Directory](https://www.skillsdirectory.com/api/skills/melodic-software-setup-9a88ef5a/badge)](https://www.skillsdirectory.com/skills/melodic-software-setup-9a88ef5a)

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 eol-normalizer hook's runtime prerequisites and configuration for this repository. Use when: 'set up eol-normalizer', 'configure eol-normalizer', 'is eol-normalizer working', line endings silently aren't normalizing, 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]"
user-invocable: true
disable-model-invocation: true
shell: bash
---

## Pre-computed context

`check`'s `jq` and `node` probes ran at load time. Read these rows instead of re-issuing them; each
shows the tool's path when present, or `absent` when missing:

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

A row reading `[shell command execution disabled by policy]` carries no result: run that tool's
`command -v` probe via Bash instead.

`git` is probed in the body, not here: the harness runs a skill's whole pre-compute block as one
shell invocation, and a worktree-isolated session refuses a compound command that names git.

## 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. The
normalization policy is the repository's own `.gitattributes`, and the only tunable is the
native `userConfig` toggle. Every prerequisite is a system tool (Node.js, Bash, jq, git), so `apply`
is pure guidance and writes nothing.

Action routing: no argument or `check` runs the check; `apply` runs the check first, then
points at each remediation. Both are non-interactive. Never prompt when the action is given.

## `check` (read-only)

The hook is the single source of truth for what it requires and how it resolves things, and it
spans the entry script and the libraries it sources: `${CLAUDE_PLUGIN_ROOT}/hooks/eol-normalizer.sh`
sources `${CLAUDE_PLUGIN_ROOT}/hooks/normalize-eol.sh` (alongside the shared hook utilities), and
that sourced library is where the real resolution lives (the `git check-attr` calls, the repo-root
anchoring, and the NUL-byte binary guard), so the sourced files are in scope and the entry script
alone will not tell you what runs.

**Read it first.** Probe what it actually does, don't recite this file. Then read the
pre-computed `jq` and `node` rows, 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` downgrades from
FAIL to INFO. The hook exits through its enabled-gate before probing anything, so a deliberately
disabled plugin is not broken. Report those probes informationally and note that re-enabling
restores the FAIL semantics. A missing `node` stays FAIL whatever the toggle says: the hook row
launches `node` before `exec-bash.mjs` can evaluate the gate, so every Write/Edit still tries an
unavailable command until `node` is installed or the plugin registration is disabled.

1. **Bash version.** Check against the hook's documented floor (README Requirements),
   noting any features the hook degrades without (for example telemetry's `EPOCHREALTIME`,
   Bash 5.0+).
2. **`node`.** The pre-computed `node` row. FAIL if absent: every hook row runs through
   `node hooks/exec-bash.mjs`, so the hook never launches and emits no notice. This probe is the
   only visibility, and it runs through the Bash tool, so it works without the launcher.
3. **`jq`.** The pre-computed `jq` row. FAIL if absent: the hook then skips with a visible
   once per session and agent notice instead of normalizing.
4. **`git`.** `command -v git`. FAIL if absent: unlike jq, the hook emits NO visible notice
   when git is missing. `git check-attr` and repo-root resolution silently fail and the
   hook no-ops, so this probe is the only visibility. Distinguish the two non-failure cases
   the hook treats differently. Git present but the path is not inside a git repository →
   INFO, not applicable: nothing to normalize against, per the README. Git present
   inside a repo but no `eol=` rule governs any path → INFO, inert by design, the opt-in
   analog: resolution is entirely `.gitattributes`-driven.
5. **Consumer `.gitattributes` `eol=` policy.** Using the hook's own resolver
   (`git check-attr eol` anchored at the repo root), confirm whether any `eol=lf`/`eol=crlf`
   rule governs paths the hook would touch. `check-attr` answers for ANY candidate path,
   tracked or not. The hook normalizes a first write to a brand-new file the same as an
   edit to a tracked one, so probe representative candidate paths (or report the declared
   patterns), never a tracked-files listing that would miss untracked matches. Report what
   governs, or INFO that none does. Absence is the opt-out by design, so the plugin is
   inert (INFO, not FAIL), matching the README's "ships no policy of its own" stance.
6. **Hook toggle.** Report the effective `eol_normalizer_enabled` value:
   `${user_config.eol_normalizer_enabled}` (unexpanded or empty means default `true`).
7. **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 point at the resolution. Every prerequisite here is a system
tool, so `apply` installs nothing and writes nothing. It only points:

- missing `node` / `jq` / Bash / git: 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, which owns the verified-version record
  (<https://github.com/melodic-software/claude-code-plugins/blob/main/docs/conventions/plugin-reconfiguration/README.md>):
  interactive `/plugin configure eol-normalizer@<marketplace>` any time, or headless
  `claude plugin install eol-normalizer@<marketplace> -s <scope> --config eol_normalizer_enabled=true`
  (repeatable per key). Against an already-installed plugin it prints `already installed` **and
  still writes the value**. Do **not** uninstall to reconfigure: uninstalling drops this 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`. `-s` places the install record and
  `enabledPlugins`; the option value lands in user settings either way, and a rerun at another
  scope adds an install record at that scope and enables the plugin there. 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.*}` is injected at skill load and each hook receives its
  `CLAUDE_PLUGIN_OPTION_*` from an environment fixed at session start, so a same-session `check`
  still reports the OLD value; report the observed effective value, never an unobserved change.
- no `eol=` policy: this is the opt-out, not a defect. Point at the repository's own
  `.gitattributes` as the place to declare policy; this skill never writes `.gitattributes`,
  because that would impose a repo-wide line-ending policy the plugin has no mandate to
  choose.

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

## What this skill does NOT do

- Normalize any file. Editing a file exercises the hook end-to-end.
- Write the plugin cache, Claude Code user settings, or `pluginConfigs`. Nor `.gitattributes`.
- Install any tool, during either `check` or `apply`. All prerequisites are system tools
  resolved with guidance only.

Files in this skill

  • SKILL.md6.7 KB
  • evals/evals.json6.4 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.