Skip to content

feat(biome-format): add Biome format/lint-on-edit plugin#19

Merged
kyle-sexton merged 4 commits into
mainfrom
feat/biome-format-plugin
Jun 29, 2026
Merged

feat(biome-format): add Biome format/lint-on-edit plugin#19
kyle-sexton merged 4 commits into
mainfrom
feat/biome-format-plugin

Conversation

@kyle-sexton

Copy link
Copy Markdown
Contributor

What

Adds biome-format, the third plugin in this marketplace — a PostToolUse hook that runs Biome's check --write on edits to JS/TS/JSX/JSON files, auto-applying safe fixes + formatting + import sorting and surfacing residual findings to Claude as advisory context. It uses the consuming repo's own biome.json and ships no rules.

Built to the bash-lint structural template: .claude-plugin/plugin.json, hooks/hooks.json, hooks/biome-format.sh, byte-identical hooks/hook-utils.sh, self-contained *.test.sh, and a README.md.

Key design decisions

  • Opt-in gate. Biome runs only when a biome.json (or .jsonc/dotted) governs the edited file — the conservative opt-in mirroring bash-lint's .editorconfig gate. A repo without Biome config is left untouched rather than rewritten to Biome's built-in defaults.
  • CWD-anchored discovery. Verified against current Biome docs that config discovery walks up from the CWD (not the target file) with a nested-config scanner — so the hook cds to the topmost governing config dir (the root config's directory).
  • No npx. The Biome binary is resolved from the repo's node_modules/.bin/biome or PATH; never downloaded on a per-edit hook.
  • Compact findings. --reporter=github yields one-line-per-diagnostic output (the gcc-format analog) with a clean repo-relative path. Residual findings surface via additionalContext; the hook always exits 0.
  • Respects ignores. Biome 2.x honors the config's files.includes ignores even for an explicitly-edited path — verified empirically; the hook treats that as a silent skip (no nagging).

Verification

All local CI lanes pass: shellcheck, typos, editorconfig-checker, markdownlint, comment-hygiene, exec-bit (3 scripts 100755, hook-utils.sh 100644), LF + final newline, hook-utils.sh byte-identical to the existing copies. claude plugin validate --strict passes for both the plugin and the catalog. Both test suites green (hook-utils 37, black-box 36) against real Biome 2.5.1, plus a runtime wiring smoke invoking the exact hooks.json command with ${CLAUDE_PLUGIN_ROOT} set and a real envelope on stdin.

Registered in .claude-plugin/marketplace.json and the root README catalog.

🤖 Generated with Claude Code

Third plugin in the marketplace, mirroring the bash-lint structural
template. A PostToolUse hook runs `biome check --write` on edits to
JS/TS/JSX/JSON files, surfacing residual findings as advisory context
(always exits 0) and using the consuming repo's own biome.json.

- Opt-in on a biome.json governing the edited file (conservative gate,
  mirroring bash-lint's .editorconfig opt-in); absent config leaves the
  file untouched rather than imposing Biome's built-in defaults.
- Biome is CWD-anchored for config discovery (verified against current
  Biome docs), so the hook cd's to the topmost governing config dir.
- Binary resolved from the repo's node_modules/.bin or PATH; never npx
  (no surprise downloads on a per-edit hook).
- --reporter=github yields compact one-line findings (the gcc-format
  analog) with a clean repo-relative path; respects the config's own
  ignore rules for explicitly-edited files; tool breaks are skipped.
- hook-utils.sh is byte-identical to the existing copies.

Registered in marketplace.json and the README catalog. Both test
suites green and validated with `claude plugin validate --strict`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WWt8nQzh8BAoZXRZRt2ARU
@claude

claude Bot commented Jun 29, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 2m 39s —— View job


Code Review — feat(biome-format): Biome format/lint-on-edit plugin

  • Gather context and read changed files
  • Review plugin manifest (plugin.json, hooks.json, marketplace.json)
  • Review hook script (biome-format.sh)
  • Review hook utilities (hook-utils.sh)
  • Review test suites (*.test.sh)
  • Review README

Overall this is a solid, well-structured plugin. The logic, test coverage, and cross-platform defensive coding are all excellent. I found a few issues — one functional correctness concern and a handful of minor ones.


Findings

1. build_data_json printf fallback — potential JSON injection (minor)

hooks/biome-format.sh L84

|| printf '{"tool":"%s","file":"%s","findings":[]}' "$TOOL" "$FILE_REL"

If $FILE_REL contains a double-quote or backslash (e.g. a path like src/"weird"/file.ts), this produces malformed JSON. This fallback is only reached when jq itself is absent, so it's a best-effort telemetry path — but a file path with a quote would silently corrupt the telemetry envelope. Since jq is already required for hook::emit_additional_context, the envelope will simply be dropped if jq is absent anyway; making the fallback printf '{}' (or just omitting it and letting hook::emit_telemetry guard on command -v jq) would be safer.

Fix this →


2. hook-utils.sh header still says "markdown-formatter" (cosmetic)

hooks/hook-utils.sh L4

# Minimal hook utility library for the markdown-formatter plugin.

Since hook-utils.sh is byte-identical across all three plugins (confirmed), this is an inherited comment artifact from its markdown-formatter origin. Fixing it in one copy requires fixing all three simultaneously (to maintain the byte-identical invariant), or accepting it as a permanent cross-plugin quirk. If the intent is to keep them identical, this is fine to leave — just documenting for awareness.


3. hook-utils.sh guard variable has a stale "MDFMT" prefix (cosmetic)

hooks/hook-utils.sh L8–9

[[ -n "${_MDFMT_HOOK_UTILS_LOADED:-}" ]] && return 0
readonly _MDFMT_HOOK_UTILS_LOADED=1

"MDFMT" reads as markdown-formatter-specific. Functionally correct (guard prevents double-sourcing in any scenario where two plugins share a process), but a _HOOK_UTILS_LOADED name would be clearer. Same byte-identical constraint applies as finding #2.


4. No minimum Biome version documented (minor gap)

plugins/biome-format/README.md L35–39

The hook uses --error-on-warnings and --reporter=github — flags that may not be present in Biome 1.x. The README documents "Biome available to the repo" without a version floor. Tested against 2.5.1; a >= 2.x or >= 1.8 minimum note would prevent silent misbehavior on older installs.

Fix this →


5. matcher does not cover MultiEdit (consistency note)

hooks/hooks.json L5

"matcher": "Write|Edit"

This matches bash-lint's pattern exactly. If Claude Code ever sends a MultiEdit tool event, edits via that tool won't be formatted. This is a cross-plugin consistency choice rather than a bug, but worth documenting in the README's Behavior section so consumers know the scope. No action required if it mirrors the marketplace's established baseline.


What's done well

  • Opt-in gate is correct. Walking up from the file to the repo root and finding the topmost config dir ensures monorepo-safe CWD for Biome's discovery, not just any config.
  • Binary resolution is safe. Walking up from FILE_DIR_POSIX to the repo root for node_modules/.bin/biome, then falling back to PATH, and never npx — correct.
  • Three-way exit triage (findings / ignored / tool-break) cleanly maps Biome's exit-non-zero cases to the right advisory outcomes without false positives.
  • EPOCHREALTIME fallback is properly guarded — older Bash doesn't abort the hook, it just skips telemetry.
  • Fire-and-forget telemetry ("$sink" >/dev/null 2>&1 &) with both stdout and stderr redirected prevents the C1 fd1-inheritance blocker. Well handled.
  • Windows path normalization via cygpath and hook::normalize_path with the OSTYPE gate is thorough.
  • Test coverage is excellent. 36 black-box + 37 unit tests covering gate-off, gate-on, format, lint, syntax errors, JSON, kill switch, config ignores, telemetry envelope shape, timestamp UTC alignment, relative vs. absolute sink, and the POSIX/Windows normalize_path distinction.
  • hook-utils.sh confirmed byte-identical to bash-lint's copy ✓
  • File permissions confirmed correct: biome-format.sh 755, biome-format.test.sh 755, hook-utils.sh 644.
  • Marketplace and plugin manifests are clean, correctly tagged, and use the $schema pointer.

Summary

The one item I'd flag for a follow-up before merging (or as a quick commit on this branch) is the printf fallback in build_data_json (#1) — a path with a quote would produce invalid JSON in the telemetry envelope's tool-break and clean-ok paths. Everything else is cosmetic or doc-gap level. The core hook logic, test suite, and CLAUDE.md compliance look solid.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 04cb3eb5e5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/biome-format/hooks/biome-format.sh Outdated
…floor

Address review on PR #19:
- build_data_json fallback no longer interpolates TOOL/FILE_REL (a path
  with a quote/backslash could corrupt the envelope); emit a fixed
  empty-shape object instead. The path is near-unreachable — it fires
  only if `jq -n` itself fails, and hook::emit_telemetry already drops
  the envelope when jq is absent — so dropping the values is harmless
  and strictly safer than emitting malformed JSON.
- README documents Biome 2.x as recommended (tested against 2.5.1),
  since --reporter=github / --error-on-warnings may be absent on much
  older releases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WWt8nQzh8BAoZXRZRt2ARU
@claude

claude Bot commented Jun 29, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 55s —— View job


Code Review — feat(biome-format) (follow-up pass)

  • Read new commit diff (d6fcf9f)
  • Review updated biome-format.sh
  • Review updated README.md
  • Check Codex finding (dotted config / Biome version gating)
  • Final assessment

The follow-up commit (d6fcf9f) addresses two of the findings from the first review pass. Here's the verdict on each open item.


Addressed in d6fcf9f

Finding #1 — printf fallback JSON injection ✅ Fixed

hooks/biome-format.sh L87

The fallback now emits a fixed empty-shape object instead of interpolating $TOOL/$FILE_REL:

|| printf '{"tool":"","file":"","findings":[]}'

The inline comment explaining WHY (path values can inject quotes/backslashes, the fallback is essentially unreachable anyway) is thorough. Fix is correct.

Finding #4 — Missing Biome version floor ✅ Fixed

README.md L40–43

The Requirements section now says "Biome 2.x is recommended (tested against 2.5.1)" and explains the flags used. Good.


Still open — Codex finding: dotted config detection with Biome < 2.4

hooks/biome-format.sh L112

for name in biome.json biome.jsonc .biome.json .biome.jsonc; do

The Codex reviewer correctly notes that dotted config loading (.biome.json / .biome.jsonc) was added in Biome 2.4. On Biome ≥ 1.8 (where --reporter=github and --error-on-warnings already exist, so the hook doesn't fail at the flag level) but < 2.4, the following can happen:

  1. The hook detects .biome.json → sets CONFIG_DIR → opt-in triggers
  2. biome check --write runs from CONFIG_DIR with no --config-path
  3. Biome < 2.4 doesn't recognize .biome.json → falls back to built-in defaults
  4. The edited file gets reformatted with Biome's defaults, not the consumer's config

This is a functional correctness issue, not a cosmetic one. The scenario is narrow (a repo that adopted dotted config naming while pinned to a pre-2.4 Biome version), but the consequence — silent reformatting under wrong settings — is the exact thing the opt-in gate is designed to prevent.

The README now says "Biome 2.x is recommended" which partially mitigates this, but it doesn't specifically connect that floor to dotted config support. The most surgical fix is a one-sentence addition to the existing version note in the README:

Support for dotted config names (.biome.json / .biome.jsonc) requires Biome ≥ 2.4; on earlier versions only biome.json / biome.jsonc act as the opt-in.

Fix this →

An alternative is to pass --config-path when the winning config name is a dotted file — but since Biome < 2.4 wouldn't know the flag either, documentation is likely the right layer.


Remaining cosmetic / acknowledged items


Summary

Two of the original five findings are resolved in this commit. The Codex finding about dotted config support is the one remaining item worth a quick doc fix before merge — the README's "Biome 2.x is recommended" note should be extended to explicitly link that floor to dotted config name support (.biome.json / .biome.jsonc ≥ 2.4). Everything else — hook logic, test coverage, cross-platform handling, telemetry, and manifest compliance — looks solid.

@kyle-sexton

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review. Dispositions:

#1build_data_json printf fallback (fixed in d6fcf9f). Agreed. The fallback no longer interpolates TOOL/FILE_REL; it emits a fixed {"tool":"","file":"","findings":[]}. As you noted, the path is near-unreachable (it fires only if jq -n fails, and hook::emit_telemetry already drops the envelope when jq is absent), so dropping the values is harmless and strictly safer than risking malformed JSON. Note: bash-lint and markdown-formatter carry the identical fallback pattern — I'll propagate this same hardening to them in a follow-up rather than diverge silently.

#2 & #3hook-utils.sh header + _MDFMT_ guard (intentional, leaving). These are deliberate: hook-utils.sh is a byte-identical copy across all three plugins (verified via cmp), and that invariant is a hard requirement for this migration — including not renaming the load guard. Renaming here would break the byte-identical guarantee for a cosmetic gain. If the shared lib graduates to a single source (Rule of Three), the rename + header fix lands there for all copies at once. Documenting as a known cross-plugin quirk, as you suggested.

#4 — Minimum Biome version (fixed in d6fcf9f). Added to the README Requirements: Biome 2.x recommended (tested against 2.5.1), noting that --reporter=github / --error-on-warnings may be absent on much older releases (in which case the run is reported as a tool break, not a finding). I documented what I empirically tested rather than asserting an unverified exact floor.

#5Write|Edit matcher / MultiEdit (intentional parity, flagging as baseline item). This mirrors bash-lint and markdown-formatter exactly. If MultiEdit coverage is wanted, it's a cross-plugin baseline change (all three matchers move together), not a one-off divergence here — so I'm keeping parity and flagging it as a marketplace-wide follow-up rather than splitting the three plugins' triggers.

All lanes green and both test suites pass after the fixes.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d6fcf9f6a2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/biome-format/hooks/biome-format.sh Outdated
Address Codex P2 finding on PR #19: the opt-in walk treated the hidden
.biome.json / .biome.jsonc names as configs, but Biome only loads those
from 2.4 onward (verified against the 2.4.0 changelog). On an older
Biome the gate would fire while Biome's own discovery ignored the dotted
file and reformatted the edit with built-in defaults — the exact silent
wrong-config reformat the opt-in exists to prevent.

Gate only on biome.json / biome.jsonc, the names every flag-supporting
Biome discovers, keeping the gate in lockstep with discovery across
versions. Dotted-config support is deferred behind a future Biome>=2.4
probe. Adds a regression test (hidden .biome.json alone must not opt in)
and updates the README/header to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WWt8nQzh8BAoZXRZRt2ARU
@claude

claude Bot commented Jun 29, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 2m 18s —— View job


Code Review — feat(biome-format) (third pass, commit 557fbb8)

  • Gather context and read PR history
  • Read new commit diff (557fbb8)
  • Verify Codex P2 finding: BIOME_CONFIG_PATH env override
  • Verify dotted config documentation note
  • Final assessment

Addressed in 557fbb8

Codex P2 (first) — dotted config gate ✅ Fixed

hooks/biome-format.sh L120

The walk now considers only biome.json and biome.jsonc:

for name in biome.json biome.jsonc; do

.biome.json / .biome.jsonc are no longer treated as the opt-in trigger. The inline comment at L110–116 explains the version-gate rationale clearly. The README Behavior section is updated to match and explains to consumers why dotted names are excluded.

Test coverage ✅ Added

The new Case 1b regression test in biome-format.test.sh creates a repo where only .biome.json exists (no canonical biome.json) and asserts exit 0 + file untouched. That's exactly the right regression target.


Still open — Codex P2 (second): BIOME_CONFIG_PATH override

hooks/biome-format.sh L172

if OUTPUT=$(cd "$CONFIG_DIR" && "$BIOME_BIN" check --write --error-on-warnings --reporter=github "$BIOME_ARG" 2>&1); then

The BIOME_CONFIG_PATH concern from the second Codex pass (on d6fcf9f) was not addressed here. As raised: if BIOME_CONFIG_PATH is present in the environment (a user-level export, a CI-injected variable, another tool), Biome uses that path instead of CWD-anchored discovery, bypassing the CONFIG_DIR the hook carefully selected. The opt-in gate fires correctly, but the wrong config runs — the exact silent-wrong-config reformat the gate exists to prevent.

The minimal fix is to unset the variable for this invocation. The cleanest option is env -u:

if OUTPUT=$(cd "$CONFIG_DIR" && env -u BIOME_CONFIG_PATH "$BIOME_BIN" check --write --error-on-warnings --reporter=github "$BIOME_ARG" 2>&1); then

env -u is available on Linux, macOS, and Windows Git Bash. Alternatively, track the winning config name in the walk loop and pass --config-path "$CONFIG_DIR/$CONFIG_NAME" explicitly — that's more explicit about the config source and doesn't depend on CWD-anchored discovery, though it does require verifying that --config-path still allows Biome to discover nested "root": false sub-configs.

Fix this →


Summary

557fbb8 is a clean, correct fix for the dotted-config gate: the walk is tightened to canonical names only, the rationale is documented inline and in the README, and a regression test locks the behavior. The second Codex finding — BIOME_CONFIG_PATH env override — is the one remaining item before merge. It's a one-line fix (env -u BIOME_CONFIG_PATH) on the biome check invocation.

Address Codex P2 finding on PR #19: Biome reads BIOME_CONFIG_PATH as a
config-path override, so a stray user- or project-level export would make
the hook format the edit with an unrelated config even though the opt-in
gated on the repo's own biome.json (verified empirically against Biome
2.5.1 — the external config won in both directory and file form).

Run the biome command with `env -u BIOME_CONFIG_PATH` so the discovered
CONFIG_DIR config stays authoritative. This is consistent with the
in-tree opt-in the plugin is built on: an out-of-tree config has no
in-tree biome.json, so the gate skips anyway. Adds a regression test
(repo single-quote config beats an external double-quote config pointed
at by BIOME_CONFIG_PATH).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WWt8nQzh8BAoZXRZRt2ARU
@claude

claude Bot commented Jun 29, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 41s —— View job


Code Review — feat(biome-format) (fourth pass, commit 25e5a0c)

  • Gather context and read PR history
  • Read latest commit diff (25e5a0c)
  • Verify BIOME_CONFIG_PATH fix
  • Check for any remaining open items
  • Final assessment

Addressed in 25e5a0c

Codex P2 (second) — BIOME_CONFIG_PATH env override ✅ Fixed

hooks/biome-format.sh L179

The biome check invocation now strips the variable before calling Biome:

if OUTPUT=$(cd "$CONFIG_DIR" && env -u BIOME_CONFIG_PATH "$BIOME_BIN" check --write --error-on-warnings --reporter=github "$BIOME_ARG" 2>&1); then

The fix is correct and idiomatic. env -u is POSIX-standard and available on Linux, macOS, and Windows Git Bash. The inline comment at L172–178 explains the rationale clearly, including the empirical verification note. This is a minimal, surgical change to the exact call site that needed it.

Regression test ✅ Added

hooks/biome-format.test.sh L258–273

Case 9 creates:

  • A repo biome.json with quoteStyle: single
  • An external config with quoteStyle: double
  • BIOME_CONFIG_PATH pointing at the external config (injected via run_hook_env)

Then asserts the edited file ends up single-quoted — proving the discovered CONFIG_DIR config won, not the env-injected external one. This is exactly the right regression target.


Summary of all findings across all passes

# Finding Status
1 build_data_json printf fallback JSON injection ✅ Fixed in d6fcf9f
2 hook-utils.sh stale "markdown-formatter" header ✅ Intentional — byte-identical invariant
3 _MDFMT_ load guard variable ✅ Intentional — byte-identical invariant
4 No minimum Biome version documented ✅ Fixed in d6fcf9f
5 MultiEdit not in matcher ✅ Intentional — baseline parity with bash-lint
Codex P2a Dotted config names gated without version check ✅ Fixed in 557fbb8 (canonical names only)
Codex P2b BIOME_CONFIG_PATH could override discovered config ✅ Fixed in 25e5a0c

All five original findings and both Codex findings are resolved or intentionally left as documented quirks. The hook logic, test coverage, cross-platform handling, telemetry, and manifest compliance remain solid throughout.

This PR is ready to merge.

@kyle-sexton
kyle-sexton merged commit 100977e into main Jun 29, 2026
16 checks passed
@kyle-sexton
kyle-sexton deleted the feat/biome-format-plugin branch June 29, 2026 19:08

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 25e5a0ce97

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


# Resolve repo root early — used to bound the biome-config opt-in walk and to
# compute the schema-required repo-relative path in data.file.
REPO_ROOT="$(hook::repo_root "$(dirname "$FILE")")"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use CLAUDE_PROJECT_DIR when Git root is unavailable

When the edited project is not a Git worktree, hook::repo_root falls back to dirname "$FILE", so root becomes the edited file's own directory. In that setup (for example /proj/biome.json, /proj/node_modules/.bin/biome, and editing /proj/src/a.ts under CLAUDE_PROJECT_DIR=/proj), both upward walks stop at src and the hook silently reports skipped instead of using the parent Biome config/install. Falling back to CLAUDE_PROJECT_DIR or continuing the walk when git rev-parse fails would keep non-Git Claude projects working.

Useful? React with 👍 / 👎.

kyle-sexton added a commit that referenced this pull request Jun 29, 2026
…er (#20)

## What

Follow-up to #19. Propagates two cross-plugin items I flagged when
shipping `biome-format`:

**1. Telemetry fallback hardening (the real change).** `bash-lint` and
`markdown-formatter` carried the same `build_data_json` jq-failure
fallback that `biome-format` had before review hardened it: `printf
'{"tool":"%s","file":"%s","findings":[]}' "$TOOL" "$FILE_REL"`. A path
containing a quote or backslash could corrupt the telemetry envelope.
Both now emit a fixed empty-shape object instead. The path is
near-unreachable (fires only if `jq -n` fails, and
`hook::emit_telemetry` already drops the envelope when `jq` is absent),
so dropping the values is harmless and strictly safer than risking
malformed JSON. All three plugins' `build_data_json` are now consistent.

Patch-bumped so consumers pull the change via `claude plugin update`:
`bash-lint` 0.1.0 → 0.1.1, `markdown-formatter` 0.1.1 → 0.1.2.

**2. `MultiEdit` matcher — investigated, no change (moot).** Codex
flagged that `Write|Edit` omits `MultiEdit`. Verified against the
current [tools
reference](https://code.claude.com/docs/en/tools-reference): the only
file-modification tools are **`Edit`, `Write`, `NotebookEdit`** —
`MultiEdit` is gone (merged into `Edit`), and the permission-format
table confirms `Edit(...)` applies to "Edit, Write, NotebookEdit". So
`Write|Edit` is already complete; `NotebookEdit` only touches `.ipynb`,
which none of these plugins' extensions match. No matcher change
warranted.

## Verification

`shellcheck`, `typos`, `editorconfig-checker`, `comment-hygiene` all
pass on the changed files. Both test suites green against real tools
(`bash-lint` 31, `markdown-formatter` 41). `claude plugin validate
--strict` passes for both plugins and the catalog.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant