✍️

[進化版] VSCode + Claude Code Hooksでマークダウンの文書作成を爆速化する環境構築方法

に公開

概要

前回の記事「VSCode + Claude Codeでマークダウンによる文章作成を爆速化する環境構築方法」では、VSCodeとClaude Codeを活用した環境構築方法を紹介しました。

しかし、マークダウン作成中に「表記ゆれを統一したい」「日本語の文法チェックを自動化したい」「Claude Codeと文章校正ツールを連携させたい」という課題を感じた方も多いのではないでしょうか。

今回は、その続編として、Claude Code HooksというClaude Codeの新機能を中心に、Node.js系の文章校正ツールと組み合わせることで、これらの課題を解決する方法を解説します。

Claude Code Hooksを使えば、ファイル保存時に自動的に文章チェックが走り、問題があればClaude Codeが修正提案をしてくれる——まるで優秀なレビュアーが隣にいるようなマークダウン作成環境を実現できます。

この記事で実現できること

  • 自動フォーマット: ファイル保存時に自動的にフォーマットとチェックを実行
  • 日本語文章の自動チェック: 「てにをは」の重複や表記ゆれを自動検出・修正
  • 日本語文章の自動校正: 日本語専用ルールセットによる包括的な文章校正
  • マークダウン作成フローの完全自動化: Claude Codeの動作に連動した文章校正

前提条件

最終的なディレクトリ構成

環境構築が完了すると以下のような構成になります

project/
├── .claude/                    # Claude Code設定ディレクトリ
│   └── settings.json          # Claude Code Hooks設定
├── .vscode/                    # VSCode設定ディレクトリ
│   ├── extensions.json        # 推奨拡張機能リスト
│   └── settings.json          # エディタ設定(フォーマット、スペルチェック等)
├── articles/                   # 記事管理ディレクトリ
│   ├── drafts/                # 下書き保存
│   └── published/             # 公開済み記事
├── assets/                     # 静的ファイル管理
│   └── images/                # 画像ファイル(スクリーンショット、図表等)
├── hooks/                      # Claude Code Hooksスクリプト
│   └── auto-format.sh         # 自動フォーマット・校正スクリプト
├── node_modules/              # インストールされたライブラリ
├── templates/                  # テンプレートファイル(記事雛形、コードスニペット等)
├── .gitignore                 # Git除外設定
├── .markdownlint.json         # Markdownlint設定ファイル
├── .prettierrc                # Prettier設定ファイル
├── .textlintrc.json           # textlint設定ファイル
├── package.json               # Node.js依存関係とスクリプト
└── prh-rules.yml              # 技術用語統一ルール

1. Node.jsプロジェクトの初期セットアップ

1-1. フォルダ構造の作成

# プロジェクトディレクトリを作成
mkdir my-markdown-project
cd my-markdown-project

# 必要なディレクトリ構造を作成
mkdir -p articles/{drafts,published} .vscode .claude hooks

1-2. Node.jsプロジェクトの初期化

# package.jsonを生成
npm init -y

# .gitignoreを作成
echo "node_modules/
*.log
.DS_Store
.claude/settings.local.json
.obsidian/" > .gitignore

2. 文章校正ツールのインストールと設定

2-1. ライブラリのインストール

npm install --save-dev \
  prettier \
  textlint \
  textlint-rule-preset-japanese \
  textlint-rule-prh \
  textlint-rule-no-mixed-zenkaku-and-hankaku-alphabet \
  textlint-rule-ja-no-redundant-expression \
  textlint-rule-ja-no-abusage \
  textlint-rule-max-comma \
  textlint-rule-max-kanji-continuous-len \
  textlint-rule-max-ten \
  textlint-rule-no-mix-dearu-desumasu \
  textlint-rule-sentence-length \
  markdownlint-cli2

2-1-1. インストール内容の詳細

ライブラリ名 概要
prettier JSON/YAMLファイルの整形
textlint 文章チェックのコア機能
textlint-rule-preset-japanese 助詞チェック、文体統一等の包括的ルール
textlint-rule-prh カスタム用語辞書による表記ゆれ修正
textlint-rule-no-mixed-zenkaku-and-hankaku-alphabet 全角・半角英数字の混在防止
textlint-rule-ja-no-redundant-expression 「することができる」→「できる」等の簡潔化
textlint-rule-ja-no-abusage よくある日本語の誤用を検出
textlint-rule-max-comma 1文中のカンマ数を制限
textlint-rule-max-kanji-continuous-len 漢字の連続使用を制限
textlint-rule-max-ten 1文中の読点数を制限
textlint-rule-no-mix-dearu-desumasu だ・である調とです・ます調の混在防止
textlint-rule-sentence-length 1文の文字数を制限
markdownlint-cli2 マークダウン記法の品質保持

2-2. npmスクリプトの設定

package.jsonに以下のスクリプトを追加します:

"scripts": {
  "lint": "npm run lint:text && npm run lint:md",
  "lint:text": "textlint \"**/*.md\" --ignore-path .gitignore",
  "lint:md": "markdownlint-cli2 \"**/*.md\" \"!node_modules\" \"!.obsidian\"",
  "lint:fix": "npm run lint:text -- --fix && npm run lint:md -- --fix",
  "format": "prettier --write \"**/*.{json,yml}\" --ignore-path .gitignore",
  "check-all": "npm run format && npm run lint:fix"
},

2-2-1. コマンドの詳細説明

スクリプト名 説明 使用例
lint textlint + Markdownlintの統合チェック npm run lint
lint:text textlintによる日本語文章チェック npm run lint:text
lint:md Markdownlintによる構文チェック npm run lint:md
lint:fix 自動修正付きlint(textlint + Markdownlint) npm run lint:fix
format PrettierによるJSON/YAMLファイル整形 npm run format
check-all format + lint:fixの統合実行 npm run check-all

2-3. 各ツールの設定ファイル作成

2-3-1. Prettier設定ファイル(.prettierrc)

{
  "printWidth": 80,
  "proseWrap": "preserve",
  "tabWidth": 2,
  "useTabs": false,
  "semi": true,
  "singleQuote": true,
  "trailingComma": "all",
  "bracketSpacing": true,
  "arrowParens": "avoid"
}
  1. proseWrap: "preserve"
    • 元の改行位置を保持して改行しない
  2. semi: true
    • JavaScriptコードブロック内でセミコロンを必須に
    • 一貫性のあるコードスタイル
  3. singleQuote: true
    • 文字列にシングルクォートを使用
    • 多くのJavaScriptプロジェクトで採用される標準スタイル
  4. trailingComma: "all"
    • 配列やオブジェクトの最後の要素にもカンマを付ける
    • Git差分が最小限になる
  5. bracketSpacing: true
    • { foo: bar } のようにスペースを入れる
    • 読みやすさの向上
  6. arrowParens: "avoid"
    • x => x + 1 のように単一引数の場合は括弧を省略
    • より簡潔な記述

2-3-2. textlint設定ファイル(.textlintrc.json)

{
  "rules": {
    "no-doubled-joshi": {
      "allow": ["も"]
    },
    "sentence-length": {
      "max": 150
    },
    "max-comma": {
      "max": 3
    },
    "max-ten": {
      "max": 3
    },
    "max-kanji-continuous-len": {
      "max": 6
    },
    "no-mix-dearu-desumasu": {
      "preferInBody": "ですます",
      "preferInList": "である"
    },
    "prh": {
      "rulePaths": ["./prh-rules.yml"]
    },
    "no-mixed-zenkaku-and-hankaku-alphabet": true,
    "ja-no-redundant-expression": true,
    "ja-no-abusage": true
  }
}
2-3-2-1. 主要ルールの詳細
ルール名 設定値 効果
sentence-length max: 150 1文を150文字以内に制限
max-comma max: 3 1文中のカンマ(,)を3個まで
max-ten max: 3 1文中の読点(、)を3個まで
max-kanji-continuous-len max: 6 漢字を6文字まで連続使用可能
no-mix-dearu-desumasu preferInBody: "ですます"
preferInList: "である"
本文:です・ます調
箇条書き:だ・である調
no-doubled-joshi allow: ["も"] 同じ助詞の重複をチェック
(「も」のみ重複を許可)
2-3-2-2. 追加ルールの詳細
ルール名 設定値 効果
prh rulePaths: ["./prh-rules.yml"] 技術用語の表記を統一
no-mixed-zenkaku-and-hankaku-alphabet true 全角・半角アルファベットの混在を検出
ja-no-redundant-expression true 不要に長い表現を簡潔にする提案
ja-no-abusage true よくある日本語の誤用をチェック

2-3-3. マークダウン構文チェック設定(.markdownlint.json)

{
  "MD013": {
    "line_length": 150,
    "code_blocks": false,
    "tables": false
  },
  "MD033": false,
  "MD041": false,
  "MD007": {
    "indent": 2
  },
  "MD003": {
    "style": "atx"
  }
}
2-3-3-1. 重要な設定項目
ルール 設定値 効果
MD013 line_length: 150 行長を150文字に制限(コードブロック・テーブルは除外)
MD033 false HTMLタグの使用を許可
MD041 false ファイル先頭のH1要求を無効化
MD007 indent: 2 リストのインデントを2スペースに統一
MD003 style: "atx" 見出しスタイルを# 見出し形式に統一

2-3-4. 技術用語の表記統一ルール(prh-rules.yml)

version: 1

rules:
  - expected: JavaScript
    pattern: /(?<!\*\.)(?<!\w\.)Javascript(?!\.js)(?!\.mjs)(?!\.ts)/gi
  - expected: TypeScript
    pattern: /(?<!\*\.)(?<!\w\.)Typescript(?!\.ts)(?!\.tsx)(?!\.d\.ts)/gi
  - expected: Node.js
    pattern: /(?<!\*\.)(?<!\w\.)NodeJS|nodejs|node\.js|NODE\.JS(?!\.js)(?!\.mjs)/gi
  - expected: React
    pattern: /(?<!\*\.)(?<!\w\.)react|REACT|ReactJS(?!\.jsx)(?!\.tsx)/gi
  - expected: Vue.js
    pattern: /(?<!\*\.)(?<!\w\.)VueJS|vuejs|vue\.js|Vue(?!\.vue)(?!\.js)/gi
  - expected: VSCode
    pattern: /(?<![\w\/\.])(?:VS Code|Visual Studio Code|VisualStudioCode)(?![\w\/\.])|(?<![\w\/\.])vscode(?![\w\/\.])/gi
  - expected: GitHub
    pattern: /(?<!https?:\/\/)(?<!\*\.)(?<!\w\.)(?<!@)[Gg]ithub(?!\.com)(?!\.io)(?!\/)/
  - expected: GitLab
    pattern: /(?<!https?:\/\/)(?<!\*\.)(?<!\w\.)(?<!@)[Gg]itlab(?!\.com)(?!\.io)(?!\/)/
  - expected: Markdown
    pattern: /(?<!\*\.)(?<!\w\.)(?<!\.)markdown(?!\w)|MarkDown|mark down|MARKDOWN(?!\.md)(?!\.markdown)/gi
  - expected: API
    pattern: /(?<!\*\.)(?<!\w\.)api|Api|A\.P\.I(?!\.json)(?!\.xml)(?!\.yaml)/gi
  - expected: CLI
    pattern: /(?<!\*\.)(?<!\w\.)cli|Cli|C\.L\.I(?!\.exe)(?!\.sh)(?!\.bat)/gi
  - expected: GUI
    pattern: /(?<!\*\.)(?<!\w\.)gui|Gui|G\.U\.I(?!\.exe)(?!\.app)/gi

3. Claude Code Hooksによる自動校正の実装

3-1. 自動校正スクリプトの作成

hooks/auto-format.shを作成:

#!/bin/bash
# ファイル編集後の自動フォーマットとAIフィードバックスクリプト

# 入力JSONを解析
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')

echo "🔍 Hook実行: TOOL_NAME=$TOOL_NAME" >&2

# プロジェクトのルートディレクトリを特定
PROJECT_ROOT=$(pwd)
if [ -f "$PROJECT_ROOT/package.json" ]; then
  echo "📁 プロジェクトルート: $PROJECT_ROOT" >&2
else
  # package.jsonが見つからない場合は親ディレクトリを探索
  while [ "$PROJECT_ROOT" != "/" ] && [ ! -f "$PROJECT_ROOT/package.json" ]; do
    PROJECT_ROOT=$(dirname "$PROJECT_ROOT")
  done
fi

# 最近編集されたマークダウンファイルを検出(1分以内)
RECENT_FILES=$(find "$PROJECT_ROOT" -name "*.md" -type f -mmin -1 2>/dev/null)

if [ -z "$RECENT_FILES" ]; then
  exit 0
fi

# エラーがあったファイルのリスト
FILES_WITH_ERRORS=""
ALL_FEEDBACK=""

# 各ファイルをチェック
while IFS= read -r FILE_PATH; do
  if [ -z "$FILE_PATH" ]; then
    continue
  fi
  
  echo "🔧 チェック中: $FILE_PATH" >&2
  
  # まず自動修正可能なものを修正(.gitignore除外設定を使用)
  npx textlint --fix "$FILE_PATH" --ignore-path "$PROJECT_ROOT/.gitignore" 2>&1 >&2
  npx markdownlint-cli2 --fix "$FILE_PATH" 2>&1 >&2
  
  # 修正後のエラーチェック(.gitignore除外設定を使用)
  TEXTLINT_ERRORS=$(npx textlint "$FILE_PATH" --format json --ignore-path "$PROJECT_ROOT/.gitignore" 2>/dev/null || true)
  MARKDOWNLINT_OUTPUT=$(npx markdownlint-cli2 "$FILE_PATH" 2>&1 || true)
  
  # このファイルのフィードバック
  FILE_FEEDBACK=""
  HAS_ERRORS=false
  
  # textlintのエラーチェック
  if [ -n "$TEXTLINT_ERRORS" ] && [ "$TEXTLINT_ERRORS" != "[]" ]; then
    ERROR_COUNT=$(echo "$TEXTLINT_ERRORS" | jq '[.[] | .messages | length] | add' 2>/dev/null || echo "0")
    if [ "$ERROR_COUNT" -gt 0 ]; then
      HAS_ERRORS=true
      FILE_FEEDBACK+="\\n📝 日本語文章の問題:\\n"
      FILE_FEEDBACK+=$(echo "$TEXTLINT_ERRORS" | jq -r '.[] | .messages[] | "  - \(.line)行目: \(.message)"' | sed 's/$/\\n/')
    fi
  fi
  
  # markdownlintのエラーチェック(特にMD013)
  if echo "$MARKDOWNLINT_OUTPUT" | grep -q "MD013"; then
    HAS_ERRORS=true
    FILE_FEEDBACK+="\\n📏 行が長すぎます(150文字制限):\\n"
    
    # MD013エラーの詳細を抽出
    MD013_LINES=$(echo "$MARKDOWNLINT_OUTPUT" | grep "MD013" | sed -E 's/.*:([0-9]+):[0-9]+ MD013.*/\1/' | sort -u)
    for line in $MD013_LINES; do
      FILE_FEEDBACK+="  - ${line}行目\\n"
    done
  fi
  
  # その他のmarkdownlintエラー
  if echo "$MARKDOWNLINT_OUTPUT" | grep -E "MD[0-9]{3}" | grep -v "MD013" > /dev/null; then
    HAS_ERRORS=true
    FILE_FEEDBACK+="\\n📋 その他のマークダウンエラー:\\n"
    FILE_FEEDBACK+=$(echo "$MARKDOWNLINT_OUTPUT" | grep -E "MD[0-9]{3}" | grep -v "MD013" | sed 's/^/  - /' | sed 's/$/\\n/')
  fi
  
  # エラーがある場合は記録
  if [ "$HAS_ERRORS" = true ]; then
    FILES_WITH_ERRORS+="$FILE_PATH\n"
    ALL_FEEDBACK+="\\n**ファイル: $(basename "$FILE_PATH")**$FILE_FEEDBACK\\n"
  else
    echo "✅ エラーなし: $FILE_PATH" >&2
  fi
  
done <<< "$RECENT_FILES"

# エラーがある場合はClaude向けのJSONレスポンスを返す
if [ -n "$FILES_WITH_ERRORS" ]; then
  FEEDBACK="📝 以下のファイルに修正が必要な箇所があります:\\n$ALL_FEEDBACK"
  FEEDBACK+="\\n💡 **修正方法:**\\n"
  FEEDBACK+="1. 長い行は句読点(。、)で適切に改行\\n"
  FEEDBACK+="2. 日本語の助詞の重複を避ける\\n"
  FEEDBACK+="3. URLなど分割できない場合は前後で改行\\n"
  
  # PostToolUseの場合のみブロック
  if [[ "$TOOL_NAME" =~ ^(Write|Edit|MultiEdit)$ ]]; then
    cat <<EOF
{
  "decision": "block",
  "reason": "$FEEDBACK"
}
EOF
    exit 2
  fi
else
  echo "✅ 最近編集されたすべてのファイルのチェックが完了しました" >&2
fi

exit 0

実行権限を付与:

chmod +x hooks/auto-format.sh

3-2. Claude Code Hooksへのスクリプト登録

Claude Codeで /hooks コマンドを実行し、以下の設定を追加します:

3-2-1. コマンド経由での設定

  1. /hooks コマンドを実行

  2. PostToolUse を選択

  3. + Add new matcher...Write|Edit|MultiEdit を入力

  4. + Add new hook... で以下のコマンドを追加:

    $HOME/my-markdown-project/hooks/auto-format.sh
    

3-2-2. 設定ファイル経由での設定

.claude/settings.json に以下を追加:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "$HOME/my-markdown-project/hooks/auto-format.sh"
          }
        ]
      }
    ]
  }
}

4. VSCode設定と拡張機能のセットアップ

4-1. エディタの基本設定(.vscode/settings.json)

{
  // Prettier & textlint統合設定(日本語文章は150文字)
  "editor.wordWrap": "on",
  "editor.rulers": [80, 150],
  "editor.lineNumbers": "on",
  "editor.minimap.enabled": true,
  "editor.autoClosingBrackets": "always",
  "editor.formatOnSave": true,
  "editor.formatOnPaste": true,
  "editor.codeActionsOnSave": {
    "source.fixAll": "explicit"
  },
  "editor.defaultFormatter": "esbenp.prettier-vscode",

  // Markdown専用設定(markdownlint連携)
  "[markdown]": {
    "editor.quickSuggestions": {
      "comments": "off",
      "strings": "off",
      "other": "off"
    },
    "editor.insertSpaces": true,
    "editor.tabSize": 2,
    "editor.detectIndentation": false,
    "editor.trimAutoWhitespace": true,
    "editor.defaultFormatter": "DavidAnson.vscode-markdownlint"
  },

  // JSON/YAML設定(Prettierと統一)
  "[json]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.tabSize": 2
  },
  "[jsonc]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.tabSize": 2
  },
  "[yaml]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.tabSize": 2
  },

  // Prettier設定(コード用)
  "prettier.configPath": "./.prettierrc",
  "prettier.requireConfig": true,

  // markdownlint設定(DavidAnson.vscode-markdownlint専用)
  "markdownlint.config": {
    "MD013": {
      "line_length": 150,
      "code_blocks": false,
      "tables": false
    },
    "MD033": false,
    "MD041": false,
    "MD024": false,
    "MD007": {
      "indent": 2
    },
    "MD003": {
      "style": "atx"
    }
  },

  // ファイル除外設定
  "files.exclude": {
    "**/.obsidian": true,
    "**/.DS_Store": true,
    "**/node_modules": true
  },

  // 検索除外設定
  "search.exclude": {
    "**/.obsidian": true,
    "**/.DS_Store": true,
    "**/node_modules": true
  },

  // 自動保存設定
  "files.autoSave": "afterDelay",
  "files.autoSaveDelay": 1000,

  // 読みやすさ向上のフォント設定
  "editor.fontSize": 14,
  "editor.lineHeight": 1.5,
  "editor.fontFamily": "Menlo, Monaco, 'Courier New', monospace",

  // 集中モード設定
  "zenMode.hideLineNumbers": false,
  "zenMode.hideStatusBar": false,

  // スペルチェック設定(prh-rulesの用語を追加)
  "cSpell.language": "en,ja",
  "cSpell.enabledFileTypes": {
    "markdown": true,
    "json": true,
    "yaml": true
  },
  "cSpell.words": [
    "Zenn",
    "textlint",
    "textlintrc",
    "yamlint",
    "vuejs",
    "claudecode",
  ],

  // スニペット設定
  "editor.suggest.snippetsPreventQuickSuggestions": false,
  "editor.tabCompletion": "on",
  "editor.snippetSuggestions": "top",

  // ファイル監視設定
  "files.watcherExclude": {
    "**/node_modules/**": true,
    "**/.git/**": true,
    "**/.obsidian/**": true
  },

  // Markdown Preview Enhanced設定
  "markdown-preview-enhanced.previewTheme": "github-light.css",
  "markdown-preview-enhanced.enableScriptExecution": true,
  "markdown-preview-enhanced.mathRenderingOption": "KaTeX",
  "markdown-preview-enhanced.enableTypographer": true,

  // ファイル関連付け設定
  "files.associations": {
    "*.md": "markdown",
    "README": "markdown",
    "CHANGELOG": "markdown",
    "CLAUDE.md": "markdown"
  }
}

4-2. 必要な拡張機能のインストール(.vscode/extensions.json)

{
  "recommendations": [
    "3w36zj6.textlint", // 日本語文章のリアルタイムチェック
    "esbenp.prettier-vscode", // コードフォーマッター(JSON/YAML整形)
    "DavidAnson.vscode-markdownlint", // マークダウン構文チェックと自動修正
    "shd101wyy.markdown-preview-enhanced", // 高機能プレビュー(PDF/HTML出力対応)
    "streetsidesoftware.code-spell-checker", // 英語スペルチェック(日本語対応可)
    "yzhang.markdown-all-in-one", // マークダウン総合機能(目次生成、ショートカット)
    "bierner.markdown-mermaid" // Mermaid図表サポート(フローチャート、シーケンス図)
  ]
}

まとめ

この記事では、前回構築した基本的なマークダウン作成環境を、Claude Code Hooksを軸にして大幅に進化させる方法を解説しました。

実現できたこと

冒頭で提示した課題に対して、以下の解決策を実装しました:

  1. 「表記ゆれを統一したい」
    → prh-rulesとClaude Code Hooksの連携により、JavaScriptGitHubなどの技術用語が自動統一されるように

  2. 「日本語の文法チェックを自動化したい」
    → textlintによる「てにをは」チェックや文長制限が、ファイル保存時に自動実行されるように

  3. 「Claude Codeと文章校正ツールを連携させたい」
    → Hooksによりエラーを検出すると、Claude Codeが自動的に修正提案を提示するように

Claude Code Hooksの活用効果

従来のGit Hooksと異なり、Claude Code Hooksは文章校正ツールの実行結果をClaude Codeに直接フィードバックできます。これにより、エラーメッセージを見ながら手動で修正する手間が減りました。

textlintやMarkdownlintのエラーが検出されると、Claude Codeが具体的な修正方法を提案してくれるため、文章の品質改善がスムーズに行えます。

この環境により、表記統一や文法チェックにかかる時間を削減し、文章の内容により集中できるようになります。

参考文献

Claude Code関連

Claude Code Hooks関連

VSCodeマークダウン関連

textlint関連

Discussion