Claude Code Skills で定型業務を資産化する実践記録——「やり方の記憶」から「再現できる仕組み」へ

約60分で読めます by ぽんたぬき
Claude Code Skills で定型業務を資産化する実践記録——「やり方の記憶」から「再現できる仕組み」へ

Claude Code Skills で定型業務を資産化する実践記録——「やり方の記憶」から「再現できる仕組み」へ

はじめに:なぜ私はSkillを書き始めたのか

正直に言います。最初の3ヶ月間、私はClaude Codeをほぼ「賢いコマンドライン補完」として使っていました。コードを書かせる、バグを直させる、PRの説明文を生成させる。それで十分満足していたし、「AIエージェント」としての使い方はそれで尽きていると思っていました。

転機は、ある月曜の朝でした。週次のリリース作業を始めようとして、「あれ、先週どうやったっけ?」と思いながらNotionのメモを漁り始めたのです。見つかったメモには「git tagを打つ→CHANGELOG更新→GitHubにPRを作る→Slackに通知を流す」と書いてあるだけで、具体的なコマンドや引数は「まあ覚えているだろう」という前提で省略されていました。

40代になると、「まあ覚えているだろう」の精度がガクッと落ちます。笑えない話で、3ヶ月前に自分が書いたシェルスクリプトを読んで「これ誰が書いたんだ?」と思うことが普通になってきました。同じ悩みを持つ方、いますよね?

そこで「定型業務をClaudeに任せる」という発想に至り、さらに「Claudeに任せる手順そのものをコード化できないか」と考えてSkillsに辿り着きました。この記事は、その実験の一部始終です。うまくいったことも、盛大に失敗したことも、全部書きます。

先に結論だけ言ってしまうと:

  • Skill化の判断基準がはっきりしていないと、使われないSkillが増えるだけ
  • description フィールドの書き方が呼び出し精度をほぼ100%決める
  • シェルスクリプトを同梱することで、LLMの確率的な気まぐれを排除できる
  • 認証情報はSkillファイルに書かない。環境変数で渡す設計が鉄則
  • 失敗したパターンは実際に運用してみて初めて分かる——この記事ではその「失敗事例」も全部公開します

では始めましょう。


Claude Code Skills とは:最小限の説明

まず、Skillsについて知らない方のために最小限の説明をします(すでに知っている方は次のセクションへ)。

Claude Codeには、プロジェクトごとにカスタムの「スキル」を定義できる仕組みがあります。プロジェクトの .claude/skills/ ディレクトリにMarkdownファイルを置くだけで、Claudeがそのファイルを「会話中に呼び出せる道具」として認識します。

プロジェクトルート/
├── src/
├── package.json
└── .claude/
    ├── settings.json
    └── skills/
        ├── deploy-staging.md
        ├── weekly-release.md
        └── db-migration-check.md

各Skillファイルの基本構造はシンプルです:

---
name: deploy-staging
description: |
  ステージング環境にデプロイする。
  「ステージングにデプロイして」「stgにあげて」「動作確認用にデプロイ」
  などの指示で呼び出す。
---

# ステージングデプロイ手順

(Claudeへの指示をここに書く)

ポイントは2つだけです。フロントマター---で囲まれた部分)にnamedescriptionを書き、本文にClaudeへの指示を書く。たったこれだけです。

「これだけ?」と思うかもしれませんが、この「これだけ」に奥があって、設計の善し悪しで実用性に天と地ほど差が出ます。それを順番に説明します。


Skill化すべきか否かの判断基準

最初に犯した失敗が、「なんでもSkillにしようとした」ことです。熱心になりすぎて、気がつくとプロジェクトに20個以上のSkillを詰め込んでいました。結果どうなったかというと、Claudeが「どのSkillを使えばいいか分からない」状態になったのです。使われないSkillが増えるだけでなく、関係ないSkillが誤って呼ばれることも増えました。

試行錯誤の結果、私が今使っている判断基準は4つです。

基準1:繰り返し頻度が月2回以上か

週次・月次・リリースのたびに実行する作業がSkillの主な候補です。「一度だけやった特殊対応」をSkillにしても、次に使う頃には状況が変わっていて使えないことがほとんどです。私の場合:

  • 週次レポートの生成(毎週月曜)
  • ステージングへのデプロイ(PRマージのたびに)
  • 月次のDB最適化チェック
  • リリース時のCHANGELOG更新

これらが実際にSkillとして機能しています。

基準2:手順が3ステップ以上で、かつ順序が決まっているか

1〜2ステップの作業をSkillにするのはオーバーエンジニアリングです。「git pullしてnpm installしてnpm run devで起動する」くらいの、複数のコマンドを決まった順序で実行するもの。これがちょうどいい粒度です。

基準3:判断の余地が少ないか

Skillは「決まった手順を確実に実行する」のが得意で、「状況を読んで臨機応変に判断する」のは通常の対話に委ねる方が良いです。「エラーがあったらどうするか」「テストが落ちたら止めるか続けるか」—こういった分岐が多すぎる作業はSkillに向きません。

逆に言えば、「毎回同じことをするのに、毎回考えながらやっている」作業がSkillの金脈です。思い当たる節のある方、多いと思います。

基準4:失敗したときのコストが許容範囲か

デプロイやDB操作は失敗したら大ごとになる可能性があります。こういう高リスクの作業をSkillにするときは、後述する「スクリプト同梱」と「dry-runオプション」を必ず組み合わせます。逆に、ドキュメント生成やSlack通知のような「失敗してもすぐやり直せる」作業は気軽にSkillにできます。

この4つの基準で篩にかけると、最初20個あったSkillが現在は8個になりました。数が減った方が、Claudeの呼び出し精度が明確に上がりました。これは体感として分かる差でした。


description フィールドが呼び出し精度をほぼ決める

ここが記事の核心です。

Claudeがあなたの指示(「ステージングにあげておいて」など)を受け取ったとき、「どのSkillを使うべきか」を判断する主な根拠が description フィールド です。name は人間が管理するためのラベルで、Claudeが判断に使うのはdescriptionの内容です。

なぜdescriptionが重要か

Claude Codeは会話の中で指示を受け取るたびに、利用可能なSkillのdescriptionを読んで「この指示に合うSkillはあるか?」を判断しています。つまりdescriptionは、あなたの指示とSkillをマッチングするためのキーです。

感覚的には検索エンジンのSEOに近いです。適切なキーワードが入っていれば引っかかる、入っていなければ引っかからない。

ダメなdescriptionの例

---
name: deploy-staging
description: ステージングにデプロイする
---

この説明では、「stgにあげて」「動確環境にデプロイ」「テスト用にビルドして反映して」といった言い回しでは呼び出されない可能性が高いです。Claudeは「ステージングにデプロイする」という表現とほぼ完全一致のものしか拾えません。

良いdescriptionの例

---
name: deploy-staging
description: |
  ステージング環境(stg、動作確認環境、テスト環境とも呼ばれる)にアプリケーションをデプロイする。
  
  呼び出しトリガーとなる言い回し(例):
  - 「ステージングにデプロイして」「stgにあげて」
  - 「動作確認用に反映して」「テスト環境にデプロイ」
  - 「PRをstgで確認したい」「動確取って」
  - 「ステージングビルドして」「stgのコードを更新して」
  
  本番環境(production、prod、本番)へのデプロイには使わないこと。
  ロールバックには deploy-rollback Skill を使うこと。
---

実際に私が使っているdescriptionに近い形です。ポイントは3つ:

  1. 別名・略称を列挙する(stg、動確環境、テスト環境)
  2. 実際に使いそうな言い回しを例示する(「PRをstgで確認したい」のような口語的表現も含める)
  3. 使ってはいけないケースを明示する(負の条件がClaudeの誤判断を防ぐ)

descriptionのチューニング方法

私がやっているのは、Claudeとの会話ログを後で読み返して「あのとき意図したSkillが呼ばれなかった」「逆に呼ばれてほしくなかったのに呼ばれた」ケースをメモしておく方法です。

週に1回程度、そのメモを元にdescriptionを修正します。地味な作業ですが、これをやるとやらないとでは使い勝手に大きな差が出ます。

  • 「Skillが呼ばれない」場合 → descriptionに実際に使った言い回しを追加する
  • 「意図せず呼ばれる」場合 → 負の条件(「〜の場合には使わないこと」)を追記する

これだけです。特別なツールは不要です。


スクリプト同梱による「決定論化」

Skillの本文にClaudeへの指示だけを書く方法には、大きな落とし穴があります。

# ステージングデプロイ手順

1. まずテストを全部実行して確認してください
2. git tag でバージョンタグを作成してください  
3. デプロイスクリプトを実行してください
4. Slackの #deploy チャンネルに通知を送ってください

このように「手順をプロンプトで書く」設計では、Claudeが毎回微妙に違う解釈をします。特に問題になるのが:

  • タグのフォーマットが v1.2.3 のときと 1.2.3 のときがある
  • Slack通知のメッセージ内容が毎回違う
  • テストコマンドの実行方法を間違える(npm test ではなく npm run test:ci が正しいのに)

これは「プロンプトベースの指示はLLMの確率的な出力に依存する」という根本的な問題です。定型業務に確率的な揺らぎは困ります。

解決策:シェルスクリプトをSkillに同梱する

この問題を解決するのが、シェルスクリプトをSkillファイルと一緒に管理し、Skillの本文でスクリプトを呼び出す設計です。

ディレクトリ構造:

.claude/
└── skills/
    ├── deploy-staging.md
    └── scripts/
        └── deploy-staging.sh

Skillファイルは「何のスクリプトをどう呼ぶか」だけを書く:

---
name: deploy-staging
description: |
  ステージング環境にデプロイする。
  「ステージングにデプロイして」「stgにあげて」「動作確認用にデプロイ」などで呼び出す。
---

# ステージングデプロイ

以下のスクリプトを実行してください:

```bash
sh .claude/skills/scripts/deploy-staging.sh
```

実行後、スクリプトの出力を確認し、エラーがあれば内容をそのまま報告してください。
スクリプトが正常終了した場合は完了をユーザーに伝えてください。

シェルスクリプトに「やること」を全部移す:

#!/bin/bash
# .claude/skills/scripts/deploy-staging.sh
set -euo pipefail

# カラー出力用
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

echo -e "${YELLOW}=== ステージングデプロイ開始 ===${NC}"

# 1. 未コミットの変更チェック
if [[ -n "$(git status --porcelain)" ]]; then
  echo -e "${RED}エラー: 未コミットの変更があります。コミットまたはスタッシュしてから実行してください。${NC}"
  exit 1
fi

# 2. テスト実行
echo "テストを実行中..."
if ! npm run test:ci --silent; then
  echo -e "${RED}エラー: テストが失敗しました。デプロイを中止します。${NC}"
  exit 1
fi
echo -e "${GREEN}テスト: OK${NC}"

# 3. ビルド
echo "ビルド中..."
npm run build:staging
echo -e "${GREEN}ビルド: OK${NC}"

# 4. デプロイ(環境変数からターゲットを取得)
DEPLOY_TARGET="${STG_SERVER:-staging.example.com}"
echo "デプロイ先: $DEPLOY_TARGET"
rsync -avz --delete dist/ "${DEPLOY_USER}@${DEPLOY_TARGET}:/var/www/staging/"

# 5. ヘルスチェック
echo "ヘルスチェック中..."
sleep 5
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://${DEPLOY_TARGET}/health")
if [[ "$HTTP_STATUS" != "200" ]]; then
  echo -e "${RED}エラー: ヘルスチェックが失敗しました (HTTP $HTTP_STATUS)${NC}"
  exit 1
fi
echo -e "${GREEN}ヘルスチェック: OK (HTTP 200)${NC}"

# 6. Slack通知
COMMIT_HASH=$(git rev-parse --short HEAD)
COMMIT_MSG=$(git log -1 --pretty=format:'%s')
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')

curl -s -X POST "${SLACK_WEBHOOK_URL}" \
  -H 'Content-type: application/json' \
  --data "{
    \"text\": \"✅ ステージングデプロイ完了\",
    \"attachments\": [{
      \"color\": \"good\",
      \"fields\": [
        {\"title\": \"コミット\", \"value\": \"${COMMIT_HASH}: ${COMMIT_MSG}\", \"short\": false},
        {\"title\": \"日時\", \"value\": \"${TIMESTAMP}\", \"short\": true},
        {\"title\": \"デプロイ先\", \"value\": \"${DEPLOY_TARGET}\", \"short\": true}
      ]
    }]
  }"

echo -e "${GREEN}=== デプロイ完了 ===${NC}"

このアプローチのメリットは明確です:

  • 再現性が保証される:スクリプトは毎回同じように動く
  • レビューができる:シェルスクリプトはgitで管理できてコードレビューの対象になる
  • 単体テストができるbash -x deploy-staging.sh と叩けばスクリプト単体で動作確認できる
  • Claudeの役割が明確になる:「スクリプトを実行して結果を報告する」という明快な責務になる

LLMの確率的な判断が入るのは「いつこのSkillを使うか」と「結果の解釈・報告」だけにして、「何をどう実行するか」はスクリプトで決定論的に固定する。この設計が私の中での「答え」になっています。


認証情報・秘密情報の扱い

Skillを書いていると、必ず直面するのが認証情報の問題です。SlackのWebhook URL、デプロイ先サーバーの認証情報、APIキー——これらをどう扱うか。

絶対にやってはいけないのは、Skillファイルに認証情報を直書きすることです。

理由は単純で、.claude/skills/ ディレクトリはリポジトリに含めることが多く、gitにコミットしてしまう危険があるからです。Githubのシークレットスキャンに引っかかる前に、そもそも書かない設計にしておくことが大事です。

環境変数で渡す設計

正解は環境変数です。シェルスクリプト内では環境変数として参照し、値はローカルの .env ファイル(gitignore済み)またはCI/CDシステムの秘密変数管理から注入します。

先ほどのデプロイスクリプトで使っているのがまさにこの設計です:

DEPLOY_TARGET="${STG_SERVER:-staging.example.com}"  # デフォルト値付き
rsync -avz --delete dist/ "${DEPLOY_USER}@${DEPLOY_TARGET}:/var/www/staging/"
curl -s -X POST "${SLACK_WEBHOOK_URL}" ...

DEPLOY_USERSTG_SERVERSLACK_WEBHOOK_URL はすべて環境変数から読みます。

ローカル開発用には .env.claude ファイルを作って:

# .env.claude(.gitignoreに追加必須)
DEPLOY_USER=your-username
STG_SERVER=staging.your-domain.com
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T00000000/B00000000/xxxxxx
DB_BACKUP_BUCKET=my-backup-bucket

Claude Codeのセッション開始時に source .env.claude してから起動するか、direnv を使って自動的に読み込む設定にします。direnv を使う場合は .envrc に以下を書くだけです:

# .envrc
dotenv .env.claude

秘密情報の「在処」をSkillに書くのはOK

「この認証情報は ~/.config/myapp/credentials にある」「AWS CLIのプロファイルは staging を使う」といった「秘密情報の場所の説明」はSkillに書いて構いません。値そのものを書かなければ問題ありません。

# デプロイ前提条件

- AWS認証情報は `~/.aws/credentials``[staging]` プロファイルを使用
- SSHキーは `~/.ssh/deploy_rsa` を使用(権限600であること)
- Slack通知用のWebhook URLは環境変数 `SLACK_WEBHOOK_URL` に設定すること
- 環境変数の設定方法は `.env.claude.example` を参照

これくらいなら安全ですし、むしろ書いておくと引き継ぎに役立ちます。

必須環境変数のチェックをスクリプトに組み込む

スクリプトの先頭で必須環境変数をチェックする習慣をつけると、「なぜかスクリプトが途中で失敗する」という謎のデバッグ時間が激減します:

# 必須環境変数チェック
REQUIRED_VARS=("DATABASE_URL" "SLACK_WEBHOOK_URL" "DEPLOY_USER")
for var in "${REQUIRED_VARS[@]}"; do
  if [[ -z "${!var:-}" ]]; then
    echo -e "${RED}エラー: 環境変数 $var が設定されていません${NC}"
    echo "ヒント: .env.claude を確認してください"
    echo "テンプレート: .env.claude.example"
    exit 1
  fi
done

このチェックが最初に走ることで、「環境変数がセットされていない」というエラーが明示的なメッセージとして出るようになります。Claudeもこのメッセージを見て「環境変数を設定してください」と適切にユーザーに伝えられます。

dry-runオプションを実装する

認証情報が絡む作業——デプロイ・DB操作・課金が発生するAPI呼び出し——では、スクリプトに --dry-run オプションを実装することを強く勧めます:

#!/bin/bash
DRY_RUN=false
while [[ $# -gt 0 ]]; do
  case $1 in
    --dry-run) DRY_RUN=true; shift ;;
    *) echo "不明なオプション: $1"; exit 1 ;;
  esac
done

run_cmd() {
  if [[ "$DRY_RUN" == true ]]; then
    echo "[DRY RUN] $*"
  else
    "$@"
  fi
}

# 使用例
run_cmd rsync -avz --delete dist/ "${DEPLOY_USER}@${DEPLOY_TARGET}:/var/www/staging/"
run_cmd aws s3 cp "/tmp/${BACKUP_FILE}" "s3://${S3_BUCKET}/${S3_PREFIX}/${BACKUP_FILE}"

SkillのdescriptionやPromptに「初めて使う場合や不安な場合は --dry-run で確認してから実行する」と書いておくと、Claudeが適切にdry-runを提案してくれるようになります。


実際に運用しているSKILL.mdとシェルスクリプト全文

ここからが本記事の核心部分です。実際に私が日常業務で使っているSkillを、SKILL.mdとシェルスクリプトの全文を含めて公開します。コピーして自分のプロジェクトに合わせて書き換えれば、すぐに動く形にしています。


Skill 1:週次レポート自動生成

毎週月曜の朝に実行する、開発進捗のレポート生成Skillです。gitのコミット履歴とGitHub CLIからデータを集めて、Claudeが整形してSlackに投稿するまでを自動化しています。

ファイル構成:

.claude/skills/
├── weekly-report.md
└── scripts/
    └── weekly-report.sh

weekly-report.md(全文):

---
name: weekly-report
description: |
  週次の開発進捗レポートを自動生成してSlackに投稿する。
  
  呼び出しトリガーとなる言い回し(例):
  - 「週次レポートを作って」「週報を生成して」「今週のレポート」
  - 「月曜のレポート」「週次まとめ」「週の集計」
  - 「今週のコミットをまとめて」「週の進捗をレポートにして」
  - 「weekly report」「週次を流して」
  
  毎週月曜日の朝に実行することを想定しているが、曜日は問わず実行できる。
  対象期間はデフォルトで直近7日間。
---

# 週次レポート生成

## Step 1: データ収集スクリプトの実行

```bash
bash .claude/skills/scripts/weekly-report.sh
```

## Step 2: レポートの整形

スクリプトの出力を基に、以下の構成でMarkdownレポートを作成してください:

見出し:`# 週次レポート: YYYY年MM月DD日週`

セクション:
- 📊 今週のサマリー(コミット数、マージPR数、クローズIssue数)
- ✅ 今週完了したこと(コミットメッセージとPRタイトルから要約、3〜5行で簡潔に)
- 🔄 進行中のこと(オープン中のPR一覧)
- ⚠️ 注意事項(CI失敗や長期オープンのIssueがあれば記載、なければ省略)
- 📅 来週の予定(Step 3でユーザーに確認)

文体は体言止めで簡潔に。技術用語はそのまま使ってよい。

## Step 3: 来週の予定を確認

レポート本文を作成したあと、「来週の予定を教えてください」とユーザーに確認してください。
入力を受け取ったらレポートに追記します。

## Step 4: 保存とSlack投稿

1. レポートを `reports/weekly/YYYYMMDD.md` に保存する
2. 環境変数 `SLACK_WEEKLY_WEBHOOK_URL` を使ってSlackに投稿する

Slack投稿のフォーマット:
- 先頭に「📋 週次レポートを投稿します」と書く
- 本文をそのまま投稿(Markdownはそのまま貼る)

完了したらユーザーに「週次レポートを投稿しました」と報告してください。

weekly-report.sh(全文):

#!/bin/bash
# .claude/skills/scripts/weekly-report.sh
# 週次レポート用のデータ収集スクリプト
set -euo pipefail

# 期間の設定(デフォルト:直近7日)
DAYS="${REPORT_DAYS:-7}"

# macOS / Linux 両対応の日付計算
if date --version > /dev/null 2>&1; then
  # GNU date (Linux)
  SINCE_DATE=$(date -d "-${DAYS} days" '+%Y-%m-%d')
else
  # BSD date (macOS)
  SINCE_DATE=$(date -v-${DAYS}d '+%Y-%m-%d')
fi
UNTIL_DATE=$(date '+%Y-%m-%d')
REPORT_DATE=$(date '+%Y年%m月%d日')

echo "=== 週次レポート データ収集 ==="
echo "対象期間: ${SINCE_DATE} 〜 ${UNTIL_DATE}"
echo "レポート日: ${REPORT_DATE}"
echo ""

# Gitリポジトリかどうか確認
if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
  echo "エラー: gitリポジトリ内で実行してください"
  exit 1
fi

# ===== コミット情報 =====
echo "## コミット一覧"
COMMITS=$(git log \
  --since="${SINCE_DATE}" \
  --until="${UNTIL_DATE}" \
  --format="%h %ad %s [%an]" \
  --date=short \
  --no-merges)

if [[ -z "$COMMITS" ]]; then
  echo "(この期間のコミットはありません)"
else
  echo "$COMMITS"
fi
echo ""

COMMIT_COUNT=$(git log --since="${SINCE_DATE}" --until="${UNTIL_DATE}" --no-merges --oneline | wc -l | tr -d ' ')
echo "コミット総数: ${COMMIT_COUNT}件"
echo ""

# ===== 変更統計 =====
echo "## ファイル変更統計"
OLDEST_COMMIT=$(git log --since="${SINCE_DATE}" --no-merges --format="%H" | tail -1)
if [[ -n "$OLDEST_COMMIT" ]]; then
  git diff --stat "${OLDEST_COMMIT}^" HEAD 2>/dev/null \
    | tail -5 \
    || echo "(差分統計を取得できませんでした)"
else
  echo "(対象期間内にコミットがありません)"
fi
echo ""

# ===== GitHub CLI 連携 =====
if command -v gh &> /dev/null && gh auth status &> /dev/null 2>&1; then
  echo "## マージ済みPR(直近${DAYS}日)"
  MERGED_PRS=$(gh pr list \
    --state merged \
    --json number,title,mergedAt,author \
    --jq ".[] | select(.mergedAt >= \"${SINCE_DATE}\") | \"#\(.number) \(.title) [@\(.author.login)] \(.mergedAt[:10])\"" \
    2>/dev/null)
  if [[ -z "$MERGED_PRS" ]]; then
    echo "(なし)"
  else
    echo "$MERGED_PRS"
    MERGED_COUNT=$(echo "$MERGED_PRS" | wc -l | tr -d ' ')
    echo "マージPR総数: ${MERGED_COUNT}件"
  fi
  echo ""

  echo "## オープン中のPR"
  OPEN_PRS=$(gh pr list \
    --state open \
    --json number,title,createdAt,author,reviewDecision \
    --jq ".[] | \"#\(.number) \(.title) [@\(.author.login)] 作成: \(.createdAt[:10]) レビュー状態: \(.reviewDecision // \"未レビュー\")\"" \
    2>/dev/null)
  if [[ -z "$OPEN_PRS" ]]; then
    echo "(なし)"
  else
    echo "$OPEN_PRS"
  fi
  echo ""

  echo "## クローズされたIssue(直近${DAYS}日)"
  CLOSED_ISSUES=$(gh issue list \
    --state closed \
    --json number,title,closedAt \
    --jq ".[] | select(.closedAt >= \"${SINCE_DATE}\") | \"#\(.number) \(.title) (\(.closedAt[:10]))\"" \
    2>/dev/null)
  if [[ -z "$CLOSED_ISSUES" ]]; then
    echo "(なし)"
  else
    echo "$CLOSED_ISSUES"
  fi
  echo ""

  echo "## 長期オープンのIssue(30日以上)"
  STALE_DATE=$(date -d "-30 days" '+%Y-%m-%d' 2>/dev/null || date -v-30d '+%Y-%m-%d')
  gh issue list \
    --state open \
    --json number,title,createdAt \
    --jq ".[] | select(.createdAt <= \"${STALE_DATE}\") | \"⚠️  #\(.number) \(.title) (作成: \(.createdAt[:10]))\"" \
    2>/dev/null || true
  echo ""

else
  echo "## 注意"
  echo "GitHub CLI(gh)が使えないため、PR/Issue情報は取得できませんでした。"
  echo "必要であれば 'gh auth login' で認証してください。"
  echo ""
fi

echo "=== データ収集完了 ==="

Skill 2:DBマイグレーション事前チェック

マイグレーション実行前に「本当に安全か」を確認するためのSkillです。実際のDB変更は一切行わず、チェックのみ実施します。

pre-migration-check.md(全文):

---
name: pre-migration-check
description: |
  データベースマイグレーションの事前チェックを行う。実際のDB変更は行わない。
  
  呼び出しトリガーとなる言い回し(例):
  - 「マイグレーション前のチェックをして」「DBマイグレーションを確認して」
  - 「マイグレーション実行前に問題がないか見て」
  - 「スキーマ変更の影響を確認して」「migrationの事前確認」
  - 「マイグレーションして大丈夫か調べて」
  
  実際のマイグレーション実行(apply、run)とは別のSkillであることに注意。
  チェックのみ実施し、DB変更は行わない。
---

# DBマイグレーション事前チェック

**重要**: このSkillはチェックのみ実行します。実際のDB変更は行いません。

## Step 1: チェックスクリプトの実行

```bash
bash .claude/skills/scripts/pre-migration-check.sh
```

## Step 2: 結果の解釈と報告

スクリプトの出力を確認し、以下の観点でユーザーに報告してください:

1. **未適用マイグレーション**: 何件あるか、どのような変更内容か
2. **破壊的変更の有無**: DROP COLUMN、型変更、NOT NULL追加など
3. **推定影響範囲**: 大きなテーブルへの変更でインデックス再構築が必要か
4. **推奨アクション**: 実行前に取るべき対策(バックアップ、メンテナンスウィンドウなど)

問題がなければ「実行可能と判断します」と伝えてください。
懸念点があれば「以下の点を確認してから実行してください」と具体的に示してください。

pre-migration-check.sh(全文):

#!/bin/bash
# .claude/skills/scripts/pre-migration-check.sh
set -euo pipefail

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

echo "=== DBマイグレーション事前チェック ==="
echo ""

# DATABASE_URL の確認
DB_URL="${DATABASE_URL:-}"
if [[ -z "$DB_URL" ]]; then
  echo -e "${RED}エラー: DATABASE_URL が設定されていません${NC}"
  echo "ヒント: .env.claude に DATABASE_URL=postgres://... を設定してください"
  exit 1
fi

# マイグレーションフレームワークの自動検出
if [[ -f "package.json" ]] && grep -q '"prisma"' package.json 2>/dev/null; then
  FRAMEWORK="prisma"
elif [[ -f "package.json" ]] && grep -q '"typeorm"' package.json 2>/dev/null; then
  FRAMEWORK="typeorm"
elif [[ -f "alembic.ini" ]] || [[ -d "alembic" ]]; then
  FRAMEWORK="alembic"
elif [[ -d "db/migrate" ]] && [[ -f "Gemfile" ]]; then
  FRAMEWORK="rails"
elif [[ -d "migrations" ]] && ls migrations/*.sql > /dev/null 2>&1; then
  FRAMEWORK="sql"
else
  FRAMEWORK="unknown"
fi

echo "検出されたフレームワーク: ${FRAMEWORK}"
echo ""

case "$FRAMEWORK" in
  prisma)
    echo "## 未適用マイグレーション確認"
    npx prisma migrate status 2>&1 || true
    echo ""
    echo "## スキーマ変更のプレビュー"
    npx prisma migrate diff \
      --from-schema-datasource prisma/schema.prisma \
      --to-schema-datamodel prisma/schema.prisma \
      --script 2>/dev/null \
      | head -80 \
      || echo "(prisma migrate status を参照してください)"
    ;;

  alembic)
    echo "## マイグレーション履歴"
    python -m alembic history --indicate-current 2>&1 \
      || alembic history --indicate-current 2>&1 \
      || echo "alembic コマンドの実行に失敗しました"
    echo ""
    echo "## 適用予定のSQL(--sql オプション)"
    python -m alembic upgrade head --sql 2>&1 | head -100 \
      || alembic upgrade head --sql 2>&1 | head -100 \
      || echo "SQL出力の取得に失敗しました"
    ;;

  rails)
    echo "## マイグレーション状態"
    bin/rails db:migrate:status 2>&1 \
      || bundle exec rake db:migrate:status 2>&1 \
      || echo "Rails マイグレーション状態の取得に失敗しました"
    ;;

  sql)
    echo "## 未適用のSQLファイル"
    find migrations/ -name "*.sql" | sort | head -20
    ;;

  *)
    echo -e "${YELLOW}警告: マイグレーションフレームワークを自動検出できませんでした${NC}"
    echo "最近変更されたマイグレーション関連ファイル:"
    find . \
      \( -name "*migration*" -o -name "*migrate*" -o -name "schema*" \) \
      -not -path "*/node_modules/*" \
      -not -path "*/.git/*" \
      -newer ".git/index" \
      2>/dev/null | head -20
    ;;
esac

echo ""
echo "## 破壊的変更キーワードチェック"

# 直近で変更されたマイグレーションファイルを検索
MIGRATION_FILES=$(find . \
  \( -name "*.sql" -o -name "*migration*.ts" -o -name "*_migration.py" \
     -o -name "*.rb" -path "*/migrate/*" \) \
  -not -path "*/node_modules/*" \
  -not -path "*/.git/*" \
  -newer ".git/ORIG_HEAD" \
  2>/dev/null || true)

if [[ -n "$MIGRATION_FILES" ]]; then
  echo "変更されたマイグレーションファイル:"
  echo "$MIGRATION_FILES"
  echo ""

  DANGEROUS=$(echo "$MIGRATION_FILES" | xargs grep -iEl \
    "DROP COLUMN|DROP TABLE|ALTER COLUMN|MODIFY COLUMN|NOT NULL|RENAME COLUMN|TRUNCATE" \
    2>/dev/null || true)

  if [[ -n "$DANGEROUS" ]]; then
    echo -e "${RED}⚠️  以下のファイルに破壊的変更の可能性があるキーワードが見つかりました:${NC}"
    echo "$DANGEROUS"
    echo ""
    echo "該当箇所の詳細:"
    echo "$DANGEROUS" | xargs grep -in \
      "DROP COLUMN\|DROP TABLE\|ALTER COLUMN\|MODIFY COLUMN\|NOT NULL\|RENAME COLUMN\|TRUNCATE" \
      2>/dev/null | head -20
  else
    echo -e "${GREEN}✅ 明らかな破壊的変更キーワードは見つかりませんでした${NC}"
  fi
else
  echo "最近変更されたマイグレーションファイルは見つかりませんでした"
fi

echo ""
echo "=== チェック完了 ==="

Skill 3:CHANGELOG自動更新

リリース前に毎回やっていたCHANGELOG更新を自動化したSkillです。gitのコミット履歴から変更をまとめて整形します。

update-changelog.md(全文):

---
name: update-changelog
description: |
  CHANGELOG.md をgitのコミット履歴から自動更新する。
  
  呼び出しトリガーとなる言い回し(例):
  - 「CHANGELOGを更新して」「チェンジログを作って」「変更履歴を更新」
  - 「リリースノートを作って」「バージョンアップのCHANGELOGを書いて」
  - 「今回のリリースの変更をまとめて」「changelog生成して」
  
  新バージョン番号はユーザーが指定するか、既存のCHANGELOGから推測する。
---

# CHANGELOG更新

## Step 1: バージョン番号の確認

ユーザーに新バージョン番号を確認してください。
指定がない場合は package.json または既存の CHANGELOG.md の最新バージョンを読み取り、
セマンティックバージョニングに従って提案してください(例:「v1.2.3 でよいですか?」)。

## Step 2: コミット履歴の取得

```bash
bash .claude/skills/scripts/generate-changelog.sh
```

## Step 3: CHANGELOG.md の更新

スクリプトの出力を基に、以下のフォーマットで CHANGELOG.md の先頭(既存の内容の前)に追記してください:

```
## [バージョン番号] - YYYY-MM-DD

### 追加
- (feat: / add: プレフィックスのコミットから。体言止めで)

### 変更
- (refactor: / improve: / change: プレフィックスのコミットから)

### 修正
- (fix: / bug: プレフィックスのコミットから)

### その他
- (上記以外のコミットから。trivial なもの(typo修正など)は省略可)
```

コミットメッセージをそのまま羅列するのではなく、人間が読みやすいように要約・統合してください。

## Step 4: ユーザー確認と保存

更新内容をユーザーに確認してから、ファイルを保存してください。
確認後は「CHANGELOG.md を更新しました」と報告してください。

generate-changelog.sh(全文):

#!/bin/bash
# .claude/skills/scripts/generate-changelog.sh
set -euo pipefail

echo "=== CHANGELOG生成 データ収集 ==="
echo ""

# 前回のタグを取得
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")

if [[ -n "$LAST_TAG" ]]; then
  echo "前回タグ: ${LAST_TAG}"
  echo "対象: ${LAST_TAG} 〜 HEAD"
  RANGE="${LAST_TAG}..HEAD"
else
  echo "タグが見つかりません。全コミット履歴を対象にします。"
  RANGE="HEAD"
fi
echo ""

echo "## コミット一覧"
git log \
  "$RANGE" \
  --format="%s [%h] %ad" \
  --date=short \
  --no-merges \
  | grep -v "^Merge" \
  | head -100
echo ""

echo "## カテゴリ別集計"

echo "### feat / add(新機能)"
git log "$RANGE" --format="%s" --no-merges \
  | grep -iE "^feat:|^add:|^feature:" \
  | sed 's/^[^:]*: *//' \
  || echo "(なし)"
echo ""

echo "### fix / bug(バグ修正)"
git log "$RANGE" --format="%s" --no-merges \
  | grep -iE "^fix:|^bug:|^hotfix:" \
  | sed 's/^[^:]*: *//' \
  || echo "(なし)"
echo ""

echo "### refactor / improve / chore(改善・整理)"
git log "$RANGE" --format="%s" --no-merges \
  | grep -iE "^refactor:|^improve:|^chore:|^perf:|^docs:|^style:" \
  | sed 's/^[^:]*: *//' \
  || echo "(なし)"
echo ""

echo "### その他"
git log "$RANGE" --format="%s" --no-merges \
  | grep -viE "^feat:|^add:|^feature:|^fix:|^bug:|^hotfix:|^refactor:|^improve:|^chore:|^perf:|^docs:|^style:|^Merge" \
  | head -20 \
  || echo "(なし)"
echo ""

# 変更ファイル数
echo "## 変更統計"
git diff --stat "${LAST_TAG:-$(git rev-list --max-parents=0 HEAD)}..HEAD" 2>/dev/null \
  | tail -3 \
  || echo "(統計取得に失敗)"
echo ""

echo "=== 収集完了 ==="

失敗した設計パターンと運用コスト

うまくいった例ばかり紹介するのは誠実ではありません。実際に失敗して廃棄したSkillの設計パターンを、失敗した理由と一緒に公開します。同じ失敗を繰り返さないために。


失敗パターン1:巨大なSKILL.md(1ファイルに全部入れ)

最初期に作ったSkillがこれです。「何でも一つのファイルに書けば管理が楽」という発想で、200行を超えるSKILL.mdを作りました。

skills/
└── deploy.md   ← ステージング、本番、ロールバック、事後確認が全部入り

deploy.md の中は:

---
name: deploy
description: デプロイ関連の全作業を行う
---

## ステージングデプロイ
(50行の手順)

## 本番デプロイ
```markdown
(70行の手順)

## ロールバック
(40行の手順)

## デプロイ後の確認
(30行の手順)

なぜ失敗したか:

  1. Claudeが混乱した:「ステージングにデプロイして」という指示に対して、Claudeが「ステージングデプロイ」の手順だけを実行すればいいのか、それとも「デプロイ後の確認」まで含めてやるべきかを毎回迷うようになった。実際に「本番デプロイの手順でステージングをデプロイしようとした」という事故も起きました。

  2. descriptionが機能しなかったdescription: デプロイ関連の全作業を行う という曖昧な説明では、どんな指示でも呼ばれる(あるいはどんな指示でも呼ばれない)という極端な挙動になった。

  3. 途中失敗のリカバリーが難しくなった:200行の手順の途中でエラーが発生したとき、Claudeがどこまで実行したかを追えなくなった。「ステップ3まで終わりました」という報告が毎回微妙にずれる。

  4. メンテナンスが苦痛になった:一部の手順を変更するたびに200行のファイル全体を読む必要があった。

解決策:ファイルを機能ごとに分割し、各ファイルを30〜50行以内に収めるルールを設けた。

skills/
├── deploy-staging.md      # ステージングデプロイのみ(35行)
├── deploy-production.md   # 本番デプロイのみ(40行)
├── deploy-rollback.md     # ロールバックのみ(25行)
└── deploy-postcheck.md    # デプロイ後確認のみ(20行)

分割後、「どのSkillをいつ呼ぶか」がClaudeに正確に伝わるようになりました。


失敗パターン2:手順を全部プロンプトに書いたSkill

スクリプト同梱の発想に至る前、「プロンプトを詳しく書けば解決する」と信じていた時期のパターンです。

---
name: db-backup
description: |
  本番DBのバックアップを取る。「DBバックアップして」「バックアップ取って」で呼び出す。
---

# 本番DBバックアップ

以下の手順でバックアップを実行してください:

1. 環境変数 `DATABASE_URL` から接続文字列を読んでください
2. `pg_dump` でダンプを取得してください。ファイル名は `backup_YYYYMMDD_HHMMSS.sql` 形式にしてください
3. ダンプを gzip 圧縮してください
4. 圧縮ファイルを `s3://my-bucket/db-backups/` にアップロードしてください
5. 7日以上前の古いバックアップを削除してください
6. Slackの #ops チャンネルに完了通知を送ってください

失敗の詳細:

ファイル名のブレ:「YYYYMMDD_HHMMSS形式」という指示に対して、backup_20260501_143022.sql.gz になったり、backup_2026-05-01_14:30:22.sql.gz になったり、コロンが入るとLinuxのファイルシステムでエラーになった。

S3パスのブレs3://my-bucket/db-backups/ というパスに対して、s3://my-bucket/db-backups/backup_xxx.sql.gz と直下に置くときと、s3://my-bucket/db-backups/2026/05/01/backup_xxx.sql.gz と日付サブディレクトリを作るときがあった。日付ディレクトリを作ってくれたのは親切なのですが、毎回違うパスにバックアップが散らばって管理不能になった。

削除ロジックが危険だった:「7日以上前の古いバックアップを削除」という指示に対して、Claudeが aws s3 rm s3://my-bucket/db-backups/ --recursive --exclude "*" --include "backup_2026042*" というコマンドを生成したことがあった。ワイルドカードのinclude/excludeの組み合わせが意図通りに動くか毎回怪しくて、バックアップが全消えする寸前まで行ったことがある。これは本当に怖かった。

解決策:このSkillをシェルスクリプトに完全移行しました。ファイル名フォーマットも、S3パスも、削除ロジックも全部スクリプトに落とし込み、プロンプトには「スクリプトを実行して結果を報告する」だけを書く。

特に削除ロジックは、ワイルドカードを使わずにファイル名から日付部分を切り出して比較する方式に変えた:

# ワイルドカードに頼らない安全な削除ロジック
aws s3 ls "s3://${S3_BUCKET}/${S3_PREFIX}/" | \
  awk '{print $4}' | \
  grep -E "^backup_[0-9]{8}_[0-9]{6}\.sql\.gz$" | \  # ← パターンが厳密
  while read -r file; do
    FILE_DATE="${file:7:8}"   # backup_YYYYMMDD_ から日付部分だけ抽出
    if [[ "$FILE_DATE" < "$CUTOFF_DATE" ]]; then
      echo "削除: ${file}"
      aws s3 rm "s3://${S3_BUCKET}/${S3_PREFIX}/${file}"
    fi
  done

失敗パターン3:descriptionを英語で書いた

日本語で会話しているのに、descriptionを英語で書いてしまった時期がありました。

description: Deploy to staging environment

日本語で「ステージングにデプロイして」と指示したとき、このSkillが呼ばれる確率が明らかに下がりました。Claudeは賢いのでどちらの言語でも理解はしますが、呼び出しマッチングの精度はdescriptionの言語と指示の言語が一致している方が体感で3割ほど高い印象です。

解決策:日本語チームでは日本語でdescriptionを書く。英語チームでは英語で書く。多言語チームの場合は両言語を並べる。

description: |
  ステージング環境にデプロイする(Deploy to staging environment)。
  「stgにデプロイ」「staging deploy」「ステージングにあげる」などで呼び出す。

失敗パターン4:Skill間の依存関係を暗黙にした

「ステージングデプロイ成功後に自動でポストチェックを走らせたい」と思い、deploy-staging.md の末尾に「完了後は deploy-postcheck Skill を実行してください」と書きました。

## Step 4: 完了処理

デプロイが成功したら、deploy-postcheck Skill を使って事後確認を実行してください。

なぜ失敗したか:Claudeが「deploy-postcheckを実行する」と書いたまま止まったり、deploy-postcheck の内容を無視して独自の確認をしたりと、挙動が安定しなかった。また、ユーザーが「デプロイだけして、確認は後でする」と言いたいケースで、自動的に事後確認が走ってしまうことへの不満が出た。

解決策:Skill間の依存関係は暗黙にせず、ユーザーに確認を取る設計にした。

## Step 4: 完了処理

デプロイが正常に完了しました。

次のどちらかを選択してください:
1. 事後確認を実行する(推奨)→ 「事後確認してください」と伝えてください
2. 事後確認はスキップする → 「完了でよい」と伝えてください

ユーザーが選択するワンクッションを入れることで、自動連鎖による「意図しない実行」を防げるようになりました。


壊れたときの切り分け手順

「Skillが呼ばれない」「Skillが意図しない動きをする」という問題が起きたときの、私の切り分け手順を共有します。


Step 1:Skillが認識されているか確認する

まずClaudeに直接聞きます:

「現在使えるSkillを一覧表示して」

または、ファイルの存在とフロントマターの文法を確認:

ls -la .claude/skills/

フロントマターのYAML文法が間違っていると、ファイルが存在していても認識されません。特によく起きるのがインデントのずれです:

# NG: description以降のインデントが揃っていない
description: |
  ステージングにデプロイする
「stgにあげて」で呼び出す        ← インデントなし(YAMLエラー)

# OK
description: |
  ステージングにデプロイする
  「stgにあげて」で呼び出す      ← 2スペース以上で揃える

| ブロックスカラーの後は、次の行から同じインデントレベルで書き続ける必要があります。


Step 2:名前を明示して呼び出す

「deploy-staging Skill を使ってステージングにデプロイして」と、Skill名を明示的に指定して呼び出してみます。

  • これで動く → descriptionのマッチングの問題。descriptionに実際に使った言い回しを追加する。
  • これでも動かない → Skill本文か実行するスクリプトの問題。Step 3へ。

Step 3:スクリプト単体で動かす

# 環境変数をセットして直接実行
source .env.claude
bash -x .claude/skills/scripts/deploy-staging.sh

bash -x オプションをつけると各コマンドの実行前に内容がエコーされるので、どのステップで失敗しているかが一目で分かります。

--dry-run がある場合はまずそちらで確認:

source .env.claude
bash -x .claude/skills/scripts/deploy-staging.sh --dry-run

Step 4:環境変数を確認する

「スクリプト単体では動くのにClaudeから実行すると失敗する」という問題の大半は、環境変数が原因です。

# Claude Codeのセッションで使える環境変数を確認
env | grep -E "DEPLOY|SLACK|DATABASE|AWS|S3" | sort

Claude Codeのセッションと通常のターミナルセッションで、読み込まれる環境変数が異なることがあります。.env.claudesource するタイミングと方法を見直してください。

direnv を使っている場合は:

direnv allow
direnv status

Step 5:Claudeに計画を説明させる

「deploy-staging のSkillを使ってデプロイしようとしているが、実行前に何をする予定かステップごとに説明して」と聞きます。

Claudeが誤った解釈をしている場合、ここで分かります。説明が正しければ「では実行して」、誤っていればSkillの本文を修正してから再試行します。

これは「Claudeが理解しているかのデバッグ」です。コードのデバッグと同じで、実行前に意図を確認する習慣が余計なトラブルを防ぎます。


まとめ:Skillは「仕組み」を資産化する手段

最後に、Skillsから私が学んだ本質的なことを書いて終わります。

Skillは「AIにやってもらう手順書」ではなく、定型業務を再現可能な仕組みに変えるための器です。

プロンプトだけで書かれたSkillは、AIの確率的な出力に依存する「不安定な仕組み」です。シェルスクリプトを同梱することで、「AIが判断する部分」(いつ使うか、結果をどう解釈するか)と「決定論的に実行する部分」(何をどう実行するか)が明確に分離されます。

この分離が、業務への適用で一番大事な視点だと思っています。

40代になって実感するのは、知識やノウハウは「覚えている」ではなく「仕組みに落とし込んである」状態にしないと劣化するということです。Skillsはその「仕組みへの落とし込み」を、スクラッチでツールを作るよりずっと低いコストで実現できます。

一緒に少しずつ、定型業務を仕組みに変えていきましょう。


付録:すぐ使えるテンプレートセット

本文で紹介したSkillのテンプレートをまとめました。コピーしてプロジェクトに合わせてカスタマイズしてください。

Skill.md 汎用テンプレート

---
name: YOUR_SKILL_NAME
description: |
  (このSkillが何をするかを1文で)
  
  呼び出しトリガーとなる言い回し(例):
  - 「(よく使う言い回し1)」
  - 「(よく使う言い回し2)」
  - 「(略称や口語表現)」
  
  (使ってはいけないケースがあれば:〜のときには使わないこと)
---

# (Skill名)

## 実行

```bash
bash .claude/skills/scripts/YOUR_SCRIPT.sh
```

## 完了後の対応

- 成功した場合:(Claudeへの指示:何をユーザーに報告するか)
- 失敗した場合:エラーメッセージをそのままユーザーに報告し、対処方法を提案してください。

シェルスクリプト 汎用テンプレート

#!/bin/bash
# .claude/skills/scripts/YOUR_SCRIPT.sh
# 説明: (このスクリプトが何をするか1行で)
set -euo pipefail

# ===== カラー出力 =====
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

# ===== オプション解析 =====
DRY_RUN=false
while [[ $# -gt 0 ]]; do
  case $1 in
    --dry-run) DRY_RUN=true; shift ;;
    *) echo "不明なオプション: $1"; exit 1 ;;
  esac
done

[[ "$DRY_RUN" == true ]] && echo -e "${YELLOW}[DRY RUN] 実際には実行しません${NC}"

# ===== 必須環境変数チェック =====
REQUIRED_VARS=("ENV_VAR_1" "ENV_VAR_2")
for var in "${REQUIRED_VARS[@]}"; do
  if [[ -z "${!var:-}" ]]; then
    echo -e "${RED}エラー: 環境変数 $var が設定されていません${NC}"
    echo "ヒント: .env.claude を確認してください"
    exit 1
  fi
done

# ===== dry-run 対応コマンド実行関数 =====
run_cmd() {
  if [[ "$DRY_RUN" == true ]]; then
    echo "[DRY RUN] $*"
  else
    "$@"
  fi
}

# ===== メイン処理 =====
echo -e "${YELLOW}=== 処理開始 ===${NC}"

# ここに処理を書く
# run_cmd your_command --with-args

echo -e "${GREEN}=== 完了 ===${NC}"

.env.claude テンプレート

# .env.claude
# このファイルは .gitignore に追加してください
# テンプレートは .env.claude.example としてリポジトリに含めること

# デプロイ設定
DEPLOY_USER=your-username
STG_SERVER=staging.your-domain.com
PROD_SERVER=your-domain.com

# Slack通知
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/xxx/yyy/zzz
SLACK_WEEKLY_WEBHOOK_URL=https://hooks.slack.com/services/xxx/yyy/zzz

# DB設定
DATABASE_URL=postgres://user:pass@localhost:5432/dbname

# バックアップ設定
DB_BACKUP_BUCKET=your-backup-bucket
DB_BACKUP_RETENTION=7

.gitignore への追加

# Claude Code Skills 秘密情報
.env.claude
.env.claude.local

# バックアップファイル(誤ってコミットしないように)
*.sql.gz
*.dump

この記事のサンプルコードはすべて、実際に私のプロジェクトで動いているものを元にしています(固有情報を置き換えたもの)。プロジェクトの構成によってパスやコマンドは変わりますが、設計の考え方はそのまま使えるはずです。

試してみて詰まったところがあれば、コメントで教えてください。同じ悩みを持つ仲間として、一緒に改善していきましょう。

関連記事

ultrawork一発で8並列!oh-my-openagentが変えるマルチエージェントオーケストレーションの世界【Claude Code・OpenCode対応】
AI開発ツール

ultrawork一発で8並列!oh-my-openagentが変えるマルチエージェントオーケストレーションの世界【Claude Code・OpenCode対応】

oh-my-openagentのultraworkコマンドで8並列エージェントを一発起動。マルチエージェントオーケストレーションの基礎からClaude Code・OpenCode対応の実践的な活用方法まで徹底解説。

コメント

0/2000