Claude Skillsでプロジェクト固有のコード規約をAIに教える
はじめに
こんにちは。この記事はアドベントカレンダー2025の15日目の記事です。
皆さんはClaude Code使っていますか?私はこのところClaude Codeをメインの開発ツールとして活用しています。コード生成の精度は高いのですが、一つ困っていたことがありました。
「プロジェクト固有のコーディング規約をなかなか覚えてくれない」
たとえば私たちのNuxt4プロジェクトでは、コンポーネントにAtomic Designを採用しており、Ha(Atom)、Hm(Molecule)、Ho(Organism)、Ht(Template)という独自のプレフィックスを使っています。しかしClaude Codeは規約を考慮せずに生成することがあります。
この問題を解決するためにClaude Skillsを導入してみたところ、未導入時に比べて規約に沿った実装を精度が上がりました。
本記事で紹介するSkillsの完成版はGitHubリポジトリで公開しています。
Claude Skillsとは?
Claude Skillsは、Claude Codeにプロジェクト固有のナレッジや規約を教えるための仕組みです。.claude/skills/ディレクトリにマークダウンファイルを配置することで、AIがコード生成時にそれを参照してくれます。
基本構造
.claude/skills/
└── {skill-name}/
├── SKILL.md # 必須:スキルの定義
├── reference.md # 推奨:詳細なリファレンス
├── templates/ # 推奨:コードテンプレート
│ └── template.vue
└── references/ # オプション:追加ドキュメント
└── best-practices.md
SKILL.mdの書き方
SKILL.mdはFrontmatterとMarkdown本文で構成されます。
---
name: my-skill
description: このスキルの説明。Claude Codeがいつこのスキルを使うべきか判断する材料になる。
---
# スキルのタイトル
## 概要
このスキルが何をするか
## 使い方
具体的な使用方法やパターン
Frontmatterのdescriptionは非常に重要です。Claude Codeはこの説明文を読んで、「このタスクにはこのスキルを使うべきか」を判断します。
Skillsを使った開発の流れ
実際にSkillsを使ってコンポーネントを作成する流れを紹介します。
Before: Skillsなしの場合
User: 確認ダイアログコンポーネントを作成して
Claude: はい、確認ダイアログを作成します。
// components/ConfirmDialog.vue ← 命名規則違反
<template>
<div class="dialog"> ← RSCSS命名規則違反
<p>本当によろしいですか?</p> ← i18n未対応
After: Skillsありの場合
User: 確認ダイアログコンポーネントを作成して
Claude: nuxt4-componentsスキルに従って、Hoレベル(ビジネスロジックを含む複合コンポーネント)
の確認ダイアログを作成します。
// app/components/ho/HoConfirmDialog.vue ← 正しい配置と命名
<i18n lang="yaml">
ja:
title: 確認
message: 本当によろしいですか?
en:
title: Confirm
message: Are you sure?
</i18n>
<script setup lang="ts">
type Props = {
isOpen: boolean
message?: string
}
type Emits = {
(emit: 'confirm' | 'close'): void
}
// ... 以下、規約に準拠したコード
Skills作成のコツ
1. descriptionを具体的に書く
# 悪い例
description: コンポーネントを生成する
# 良い例
description: Generates Nuxt4 Vue components following Hikky's Atomic Design pattern
with Ht (Template/Page), Ho (Organism), Hm (Molecule), and Ha (Atom) hierarchy.
Enforces standardized component structure including i18n multilingual support,
TypeScript type definitions, scoped SCSS styling, and proper naming conventions.
2. テンプレートファイルを用意する
実際のコード例をテンプレートとして用意することで、生成されるコードの品質が安定します。
templates/
├── atom.vue # 最小構成のサンプル
├── molecule.vue # 中程度の構成
├── organism.vue # 複雑な構成
└── template.vue # ページ向け構成
3. DO/DON'Tを明確にする
何をすべきか、何をすべきでないかを明確に記載します。
### ✅ DO
- 多言語対応: 必ずi18nでja/enを定義
- 型安全: Props/Emitsの型定義を徹底
- Scoped Style: コンポーネント固有のスタイルはscopedで記述
### ❌ DON'T
- グローバルスタイル: scoped無しのスタイル定義を避ける
- Ht層での直接API呼び出し: emitsでpage層に委譲する
- 型無し実装: anyや型定義無しの実装
4. トラブルシューティングを含める
よくある問題とその解決策を記載しておくと、エラー発生時にもAIが適切に対処できます。
## トラブルシューティング
### Hydration Error
**症状**: アイコンコンポーネントでHydration errorが発生
**解決**: `HaIcon.vue`を使用してClientOnlyでラップ
### i18n未定義エラー
**症状**: `i18n.t()`が未定義
**解決**: `useI18n()`を呼び出す
実際に作成したSkills
私たちのNuxt4プロジェクトで作成した5つのSkillsを紹介します。
1. nuxt4-components - Atomic Designコンポーネント生成
目的: プロジェクト独自のAtomic Design階層に従ったVueコンポーネントを生成する
私たちのプロジェクトでは以下の命名規則を使っています。
| レベル | プレフィックス | 役割 | 例 |
|---|---|---|---|
| Atoms | Ha |
最小単位の再利用可能なUI |
HaIcon.vue, HaButton.vue
|
| Molecules | Hm |
複数のAtomを組み合わせた機能単位 |
HmHeaderIcon.vue, HmFormTitle.vue
|
| Organisms | Ho |
ビジネスロジックを含む複合コンポーネント |
HoConfirmDialog.vue, HoAccountHeader.vue
|
| Templates | Ht |
ページ全体のUI表示を担当 |
HtAccountInfo.vue, HtAccountAsset.vue
|
ディレクトリ構造
.claude/skills/nuxt4-components/
├── SKILL.md # メイン定義
├── references/
│ ├── component-patterns.md # 各レベルの詳細パターン
│ └── styling-guide.md # SCSSスタイリング規約
└── templates/
├── atom.vue # Haテンプレート
├── molecule.vue # Hmテンプレート
├── organism.vue # Hoテンプレート
└── template.vue # Htテンプレート
工夫したポイント
決定フローの明文化: 「どのレベルのコンポーネントを作るべきか」をClaude Codeが判断できるよう、決定フローを記載しました。
ページ全体? YES → Ht (Template)
↓ NO
ビジネスロジック? YES → Ho (Organism)
↓ NO
複数のAtom組み合わせ? YES → Hm (Molecule)
↓ NO
最小単位 → Ha (Atom)
標準構造の明示: 必須要素(i18n、TypeScript型定義、Scoped SCSS)を明記することで、一貫したコンポーネント構造が生成されます。
<i18n lang="yaml">
ja:
title: タイトル
en:
title: Title
</i18n>
<script setup lang="ts">
type Props = {
title: string
}
const props = defineProps<Props>()
</script>
<style lang="scss" scoped>
@use '@/assets/styles/variables' as v;
</style>
2. nuxt4-composables - レイヤー構造に基づくComposables生成
目的: 責務に応じたレイヤー(ui/form/root)でComposableを適切に分離する
レイヤー構造
| レイヤー | 特徴 | 命名規則 |
|---|---|---|
| core/ | 全機能横断の汎用処理、useStateの使用OK | - |
| ui/ | UI状態管理のみ、API呼び出しなし | use{機能名}{UI要素名} |
| form/ | vee-validate + zodでフォーム管理 | use{機能名}Form |
| root | データ保持 + Repository統合 | use{機能名}List/Detail/Editor |
工夫したポイント
InjectionKeyの強制: ui/form/root層ではInjectionKeyを必須とし、provide/injectパターンを徹底させました。
// InjectionKeyの定義例
export const userFormInjectionKey: InjectionKey<ReturnType<typeof useUserForm>> = Symbol('userForm')
切り出し判断の明確化: 「Composableとして切り出すべきか、Vueファイル内で管理すべきか」の判断基準を明文化しました。
Vueファイル内で管理(composable不要):
- 単一コンポーネント専用の状態
- props/emitsで親子通信が完結
- ロジックがシンプル(10行以内)
composableとして切り出す:
- 複数コンポーネントで再利用
- provide/injectで孫に共有
- ロジックが複雑(テストしたい)
3. nuxt4-pages - ページパターン別のテンプレート
目的: ページの種類(静的/一覧/詳細/フォーム)に応じた標準パターンを適用する
ページタイプ
| タイプ | 用途 | データフェッチ |
|---|---|---|
| Simple Page | 静的コンテンツ | なし |
| List Page | データ一覧、検索、ページネーション | useAsyncData |
| Detail Page | 単一データの詳細表示 | useAsyncData + 動的ルート |
| Form Page | データ作成・編集 | vee-validate + zod |
工夫したポイント
データフェッチパターンの標準化: useAsyncDataの使い方、SSR時の401エラー処理など、複雑なパターンをテンプレート化しました。
// データフェッチの標準パターン
const { data, error, refresh } = await useAsyncData(
'data-key',
async () => {
return await composable.getData()
},
{
lazy: import.meta.client, // SSR時: false, クライアント時: true
}
)
// SSR時の認証エラー処理
if (import.meta.client && error.value) {
if (error.value.statusCode === 401) {
await refresh()
}
}
4. nuxt4-models - Zodスキーマベースの型定義
目的: Zodスキーマを使った型安全なModel定義のパターンを統一する
標準パターン
// Enum定義
export const STATUS = {
ACTIVE: 'active',
INACTIVE: 'inactive',
} as const
export const status = z.enum([STATUS.ACTIVE, STATUS.INACTIVE])
export type Status = z.infer<typeof status>
// エンティティ定義
export const userData = z.object({
id: z.number(),
name: z.string(),
status: status,
})
export type UserData = z.infer<typeof userData>
工夫したポイント
OpenAPI型拡張パターン: バックエンドのSwagger定義と一時的に異なる場合の対処法を明記しました。
// TODO: swagger修正後extend削除
export const eventDetail = eventdetailSchema.extend({
positionChannelId: z.string().nullable(),
})
5. repository-creator - API通信層の標準化
目的: Repository層のHTTPメソッド別実装パターンを統一する
標準パターン
export default {
get: {
async getResource(id: string): Promise<GetResourceResponse> {
const baseUrl = requireRuntimeConfig().public?.api
if (typeof baseUrl !== 'string') {
raiseError('not found api url in runtimeConfig')
}
const response = await api('GET', `${baseUrl}/resources/${id}`)
return requireValueOf(getResourceResponseSchema, response)
},
} as const,
}
工夫したポイント
バリデーション必須化: requireValueOfによるレスポンス検証を必須とし、型安全性を担保しました。
最終的なディレクトリ構造
私たちのプロジェクトで作成したSkillsの全体像です。
.claude/skills/
├── nuxt4-components/
│ ├── SKILL.md
│ ├── references/
│ │ ├── component-patterns.md
│ │ └── styling-guide.md
│ └── templates/
│ ├── atom.vue
│ ├── molecule.vue
│ ├── organism.vue
│ └── template.vue
├── nuxt4-composables/
│ ├── SKILL.md
│ ├── reference.md
│ └── templates/
│ ├── ui.ts
│ ├── form.ts
│ └── root.ts
├── nuxt4-pages/
│ ├── SKILL.md
│ ├── references/
│ │ ├── best-practices.md
│ │ └── implementation-guide.md
│ └── templates/
│ ├── simple-page.vue
│ ├── list-page.vue
│ ├── detail-page.vue
│ └── form-page.vue
├── nuxt4-models/
│ ├── SKILL.md
│ ├── reference.md
│ └── template.ts
└── repository-creator/
├── SKILL.md
├── reference.md
└── template.ts
まとめ
Claude Skillsを導入した効果については現在も検証中ですが、体感としてはSkills導入前と比べてコード生成の品質が向上していると感じています。
特に以下の点で改善が見られます:
- 一貫性のあるコード生成: 毎回規約を説明し直す必要がなくなり、プロジェクト規約に準拠したコードを最初から生成できるようになりました
- コンテキストの維持: 長いセッションでも規約を忘れずに適用してくれるようになった印象です
- ナレッジの蓄積: これまで暗黙知だった規約がドキュメント化され、人間にとっても参照しやすい形で残るようになりました
定量的な効果測定はこれからですが、少なくとも「毎回同じ指摘をする」というストレスは大幅に減りました。
Claude Skillsはまだ新しい機能ですが、プロジェクト固有の規約をAIに教える強力な手段です。ぜひ皆さんのプロジェクトでも試してみてください。