Image of lefthookを使ってClaude Codeに確実にlintを通させる

lefthookを使ってClaude Codeに確実にlintを通させる

Text by 宮城 広隆

Published

AIエージェントが開発チームの一員として定着する中で発生する新しい課題と、lefthookとClaude Code設定による二段構えの解決アプローチを紹介します。
Table of Contents

こんにちは、Liam のプロダクトマネージャーをしている宮城です。
Claude Code に実装をさせていると、lint が失敗しているにもかかわらずタスクを完了したと見なしてしまうことがあります。この挙動に悩まされた結果、根気よく lint を解決してからタスクを完了してくれる設定を見つけたので、今回はその手法を紹介します。

Liam はオープンソースのDB設計ツールであり、今回の設定内容も直接コードを読むことができます。こちらも合わせてご覧ください。

GitHub - liam-hq/liam: Automatically generates beautiful and easy-to-read ER diagrams from your database.

github.com

Claude Code は自身の変更ファイル以外を「無関係」と判断しがち

Claude Code に実装やテストを指示した際、AI は変更したファイルに限定して lint や test を実行しようとすることがよくあります。
素早いフィードバックを得る上では合理的な判断ですが、この挙動が原因で、プロジェクト全体の lint が失敗していても「今回の変更とは関係ない」と判断し、タスクを完了させてしまう問題がありました。
状況を確認すると、そのエラーの大半はそのセッション内での変更によるもので、結局「そのエラーは今回の変更が原因なので、合わせて修正してください」と追加で指示する手間が発生していました。
私はコーディングエージェントに大して、人間の介入を可能な限り減らし自律的に理想の状態へ到達することを求めています。そのため、「プロジェクト全体の lint を常にパスしなければならず、lint が通らない限りタスクは完了と見なさない」というルールを徹底させる必要がありました。
CLAUDE.md のようなプロンプトによる指示だけでは挙動が安定しないため、より確実な仕組みが求められました。

解決アプローチ:二段構えの制御

これらの課題を解決するために、私たちは二段構えのアプローチを採用しました。

  1. Lefthook による pre-commit hook の実装
  2. Claude Code の設定による --no-verify の禁止

1. Lefthook の導入

まず、Lefthook を導入しました。

Add lefthook pre-commit hooks for automatic linting by devin-ai-integration[bot] · Pull Request #2311 · liam-hq/liam

github.com

これは git の pre-commit hook を利用してコミット前に lint を自動的に実行させるアプローチです。
正直、私は pre-commit hook をあまり好んでいませんでした。コミットに時間がかかるのがどうしても受け入れられず、デバッグ時など、必ずしも lint を通さずにコミットしたい場面もあるからです。
しかし、AI に大半のコミットを任せるようになった現代では、この考えを改めるべきだと判断しました。

Lefthook を選んだ理由

その上で Lefthook の良い点は、通常の設定ファイルである lefthook.yml とは別に lefthook-local.yml で設定を上書きできることです。
これによりチーム共通の設定に影響を与えることなく、開発者が必要に応じて hook を無効化したりカスタマイズしたりできます。もちろん、従来通り git commit --no-verify でスキップすることも可能です。
また Go 製で高速な点や、prepare スクリプトによって pnpm install 時に git hook が自動でセットアップされるため開発者の既存のワークフローにほとんど影響を与えない点も魅力的でした。

他のツールと厳密に比較して選んだわけではなく、Devin に調査と実装をさせてみたところ、要件を満たしていたためそのまま採用した、という背景もあります。

実装の詳細

# lefthook.yml
pre-commit:
  parallel: true
  commands:
    lint:
      glob: "*.{js,ts,json,md,yml,yaml}"
      run: pnpm lint
      fail_text: "Lint failed. For AI Agents: Please fix all linting errors before committing."

fail_text は lint 失敗時に表示されるメッセージです。このメッセージもエージェントに与えるコンテキストの一部と考え、すべてのエラーを修正するよう明確に指示しています。

プロジェクト全体 lint 実行

ステージングされたファイルだけでなく、プロジェクト全体の lint を実行する方針を採用しました。これも人間向けというより、AI エージェント向けの判断です。


2. Claude Code 設定による追加制御

しかし、Lefthook の設定だけでは不十分でした。Claude Code は git commit --no-verify の回避策を知っていたからです。ぐぬぬ...
そのためプロジェクト内設定で明示的に禁止することにしました。

chore: add Claude Code settings with git commit permissions by MH4GF · Pull Request #2397 · liam-hq/liam

github.com
# .claude/settings.json
{
  "permissions": {
    "allow": [],
    "deny": [
      "Bash(git commit --no-verify:*)"
    ]
  }
}

人間が作業する上ではこのコマンドで一時的に hook をスキップしたい場面もあります。その場合は、開発者が別のターミナルセッションから手動でコミットすることで対応しています。
この設定により、Claude Code が Bash ツール経由で git commit --no-verify を実行することを完全に禁止できました。

やったぜ!

今後の展望と課題

Claude Code Action での制約

実はこの仕組みには一つ制約があります。現在、Claude Code Action ではこの pre-commit hook が機能しません。

これは、Claude Code Action 内部で利用されている mcp__github_file_ops__commit_files ツールが、ローカルの Git フックを介さず、GitHub API を直接呼び出してコミットを作成するためです。

参考:https://github.com/anthropics/claude-code-action/blob/3c739a8cf3a36907c339cf2574cb56bd2ee923d6/src/mcp/github-file-ops-server.ts#L59

しかしこの問題は、Claude Code の Prehook 機能を活用して解決できる可能性があります。MCP 操作の前に lint 処理を挟むことで同様の制約を課せるはずです。この件については、今後の記事で調査・報告したいと思います。

まとめ

本記事では、AI エージェントである Claude Code に、lint を確実にパスさせてからタスクを完了させるための手法を紹介しました。

  1. Lefthook による技術的な制御: pre-commit hook で lint 実行を強制する
  2. Claude Code 設定による行動制御: 回避手段となるコマンドの実行を禁止する

この二段構えのアプローチにより、開発者には柔軟性を、AI エージェントには厳格なルールを、それぞれ提供できるようになりました。

Liam の開発チームでは、AI 開発ツールを積極的に活用するだけでなく、AI を組み込んだ新しい機能の開発にも取り組んでいます。今後もそういった取り組みを紹介していきたいと思います。

Text by宮城 広隆

ROUTE06のテックリード。Web開発を専門とするフルスタックエンジニアで、複数のスタートアップで豊富な経験を積んだ後、ROUTE06に参画し、技術的な取り組みをリードしている。

Last edited on

Categories
Glossary

現在、このブログ記事に関する用語集はありません。