
生成AIを使ってコードを書くとき、こんな経験はありませんか?
「昨日は完璧なコードを書いてくれたのに、今日はなぜかスタイルが違う」 「エラーハンドリングを毎回忘れるので、指摘するのが面倒」 「シニアエンジニアなら絶対にやらないような実装をしてしまった」
Claude CodeやAntigravityのような自律型エージェントは非常に強力ですが、デフォルトの状態では「極めて優秀だが、プロジェクトのルールをまだ知らない新人エンジニア」のようなものです。チーム固有の設計思想や「好み」までは理解していません。
そこで登場するのがSkillsです。
前回の記事ではSkillsの概念について解説しましたが、今回はその続編として、実際の開発現場で使える「Skills」の実装例を具体的に紹介します。Frontend(React)とBackend(FastAPI)を題材に、AIエージェントを「信頼できるテックリード」に育てるための実践ガイドをお届けします。
なぜプロンプトではなくSkillsなのか?
多くの人は「プロンプトエンジニアリング」でこの問題を解決しようとします。「常にエラーハンドリングを書いて」と毎回指示したり、システムプロンプトに長大なルールを書き込んだりします。しかし、これはスケールしません。
Skillsを使うことで、以下の利点が得られます:
- 文脈に応じた発動: Reactのコンポーネントを作るときだけ「Reactのルール」が読み込まれます。
- 強制力: 「知っている」だけでなく「手順書を見ながら作業する」状態になるため、ミスが激減します。
- 資産化: チームのベストプラクティスが、ドキュメントではなく「実行可能なスキル」として蓄積されます。

それでは、具体的な実装を見ていきましょう。
Lv.1 Frontend: React Component Architect
Reactの開発では、コンポーネントの書き方に個人の癖が出がちです。AIも学習データに含まれる様々なパターン(Class Component, Arrow Function, Default Export vs Named Export)を無作為に選んでしまいます。
これを統一するためのSkillを作成します。
1. 定義ファイル: .agent/skills/react-architect/SKILL.md
まず、スキル定義を作成します。
---name: react-architectdescription: Use when creating new React components, refactoring UI code, or fixing styling issues.---
# React Component Architecture
You are the Lead Frontend Architect. Adhere strictly to these rules when touching any `.tsx` file.
## 1. Structure Rules- **Named Exports Only**: Never use default exports. - ✅ `export const Button = ...` - ❌ `export default function Button...`- **Interface Definition**: Define a generic `Props` interface immediately before the component.- **Top-Level Hooks**: All `useState`, `useEffect`, and custom hooks must be at the very top of the component body.
## 2. Logic & View Separation- **No Complex Logic in JSX**: If a conditional or mapping logic takes more than 3 lines, extract it to a variable or helper function inside the component.- **Custom Hooks**: If `useEffect` is complex (>5 lines), extract it to a custom hook immediately.
## 3. Styling Standards- **Tailwind CSS**: Use utility classes.- **Dynamic Classes**: ALWAYS use `clsx` or `tailwind-merge` for conditional classes. - ✅ `className={clsx("p-4", isActive && "bg-blue-500")}` - ❌ `className={"p-4 " + (isActive ? "bg-blue-500" : "")}`
## 4. Accessibility (a11y)- **Interactive Elements**: Buttons and Links MUST have an `aria-label` if they contain only icons.2. Before & After
このSkill導入前と導入後のAIの出力の違いを見てみましょう。
Before (AI Default)
// ❌ 悪い例:型定義が雑、インラインスタイル、クラス名の条件分岐が読みにくいimport React, { useState } from 'react'
export default function UserCard({ user }) { const [open, setOpen] = useState(false)
return ( <div className={'card ' + (open ? 'active' : '')} style={{ padding: '20px' }}> <h3>{user.name}</h3> <button onClick={() => setOpen(!open)}>Toggle</button> {open && <div>{user.bio}</div>} </div> )}After (With react-architect Skill)
// ✅ 良い例:Named Export、明示的な型定義、clsxの使用、a11y配慮import { useState } from 'react'import { clsx } from 'clsx'
interface UserCardProps { user: { name: string bio: string }}
export const UserCard = ({ user }: UserCardProps) => { const [isOpen, setIsOpen] = useState(false)
const toggleOpen = () => setIsOpen((prev) => !prev)
return ( <div className={clsx( 'p-5 rounded-lg border border-gray-200 transition-all', isOpen ? 'bg-blue-50 border-blue-500 shadow-md' : 'bg-white' )} > <h3 className="text-lg font-bold text-gray-900">{user.name}</h3>
<button onClick={toggleOpen} className="mt-2 px-4 py-2 text-sm bg-gray-100 hover:bg-gray-200 rounded" aria-label={isOpen ? 'Hide details' : 'Show details'} > {isOpen ? 'Hide' : 'Show'} Details </button>
{isOpen && <div className="mt-4 text-gray-700 leading-relaxed">{user.bio}</div>} </div> )}Skillがあるだけで、AIは「自分はテックリードである」というロールを認識し、指定されたベストプラクティスを順守します。コードレビューの手間が劇的に減るのがわかるでしょう。

Lv.2 Backend: FastAPI Route Master
バックエンド、特にAPI開発において最も重要なのは「安全性」と「予測可能性」です。Pythonは柔軟な言語なので、辞書型(dict)をそのままAPIレスポンスとして返せてしまいますが、これはメンテナンスの悪夢を生みます。
PydanticとFastAPIの機能を最大限に活用させるためのSkillを定義しましょう。
1. 定義ファイル: .agent/skills/fastapi-master/SKILL.md
---name: fastapi-masterdescription: Use when creating new API endpoints, modifying routes, or working on backend services in FastAPI.---
# FastAPI Route Master Standards
Ensure all backend code complies with strictly typed, secure API patterns.
## 1. Schema First Development- **No Dicts in Routes**: NEVER return a raw `dict` or accept raw arguments.- **Pydantic Models**: - Define all Request/Response models in `src/schemas/`. - Use Pydantic v2 `BaseModel`. - Always set `ConfigDict(from_attributes=True)` for ORM compatibility.
## 2. Route Definition Rules- **Explicit Response Model**: Every `@router` decorator MUST have `response_model` defined.- **Status Codes**: Explicitly define `status_code` for creation (201) and deletion (204).- **Dependency Injection**: - Use `Depends(get_db)` for database sessions. - Use `Depends(get_current_user)` for protected routes.
## 3. Error Handling Protocol- **No Bare Excepts**: Never use `except: pass`.- **HTTPExceptions**: Use `raise HTTPException(status_code=..., detail=...)` for logic errors.- **404 Handling**: Always check if a resource exists before operating on it.
## 4. Service Layer Separation- **Thin Routes**: Route functions should only handle HTTP concerns (params, status).- **Fat Services**: Move business logic and DB queries to `src/crud/` or `src/services/`.2. Before & After
Before (AI Default)
# ❌ IMPLICIT: 辞書を返し、エラー処理もない危険なコード@app.post("/users")def create_user(item: dict, db = Depends(get_db)): user = db.query(User).filter(User.email == item['email']).first() if user: return {"error": "exists"} # ステータスコードが200になってしまう!
new_user = User(email=item['email'], password=item['password']) db.add(new_user) db.commit() return new_user # JSONへのシリアライズが不安定After (With fastapi-master Skill)
# ✅ EXPLICIT: 型安全、適切なステータスコード、明確な責務分離from fastapi import APIRouter, Depends, HTTPException, statusfrom sqlalchemy.orm import Sessionfrom src import schemas, crudfrom src.deps import get_db
router = APIRouter()
@router.post( "/users", response_model=schemas.UserResponse, status_code=status.HTTP_201_CREATED, summary="Create a new user")def create_user( user_in: schemas.UserCreate, db: Session = Depends(get_db)): # 1. Check constraints db_user = crud.get_user_by_email(db, email=user_in.email) if db_user: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Email already registered" )
# 2. Delegate creation to CRUD layer return crud.create_user(db=db, user=user_in)このSkillがあれば、AIは「とりあえず動くコード」ではなく「本番運用に耐えるコード」を最初から提案してくれます。特にresponse_modelの強制は、API仕様書(Swagger UI)の品質を保つ上で非常に重要です。

Skillsをどう管理・運用するか?
Skillsの効果を実感したら、次は運用方法です。
全体か、プロジェクト個別か?
- Global Skills (
~/.gemini/skills/):- どのプロジェクトでも使う汎用的なルール(例:Gitのコミットメッセージ規約、英語の命名規則など)。
- Workspace Skills (
.agent/skills/またはリポジトリルート):- そのプロジェクト固有の技術スタック(React, FastAPI, Next.jsなど)に関するルール。
推奨はWorkspace Skillsです。プロジェクトごとに技術選定やルールは異なるため、リポジトリの中にSkillを含めてGitで管理することで、チーム全員(とAI)が同じルールセットを共有できます。
育て方:AIに作らせる
実は、Skill自体もAIに作らせることができます。
「最近、AIがTailwindのクラス順序を間違えることが多いな」と感じたら、こう頼んでみましょう。
「君がReactコンポーネントを書くときに、Tailwindのクラス順序と命名規則を厳守するための
react-style-guideSkillを作成して。SKILL.mdの形式で出力して」
AIは自分自身への指示書を書くのが得意です。これをベースに人間が微調整すれば、強力なSkillが数分で完成します。
まとめ:AIは「教育」して初めてパートナーになる
生成AIを単なる「時短ツール」として使うのはもったいないことです。Skillsを通じて彼らにプロジェクトの文脈と品質基準を教え込むことで、彼らは:
- 一貫性のあるコードを書き、
- 予期せぬバグを防ぎ、
- チームの一員として振る舞うようになります。
まずは、あなたが普段「コードレビューでよく指摘すること」を一つだけ、Skillにしてみてください。その小さな投資が、日々の開発体験を劇的に変えるはずです。
参考文献 & リンク
参考文献
Footnotes
React - Your First Component - Official React Documentation on component structure. ↩
FastAPI - Bigger Applications - Structuring FastAPI for production. ↩
Anthropic - Building Skills - Guide on creating effective Agent Skills. ↩
