diff --git a/docs/ja-JP/commands/claw.md b/docs/ja-JP/commands/claw.md new file mode 100644 index 00000000..8e47ad1b --- /dev/null +++ b/docs/ja-JP/commands/claw.md @@ -0,0 +1,51 @@ +--- +description: NanoClaw v2 を起動します — モデルルーティング、スキルホットロード、ブランチ、圧縮、エクスポート、メトリクス機能を備えた ECC の永続的でゼロ依存の REPL。 +--- + +# Claw コマンド + +永続的な Markdown 履歴と操作コントロールを備えた、インタラクティブな AI エージェントセッションを起動します。 + +## 使用方法 + +```bash +node scripts/claw.js +``` + +または npm 経由: + +```bash +npm run claw +``` + +## 環境変数 + +| 変数 | デフォルト値 | 説明 | +|----------|---------|-------------| +| `CLAW_SESSION` | `default` | セッション名(英数字 + ハイフン) | +| `CLAW_SKILLS` | *(空)* | 起動時に読み込むスキルのカンマ区切りリスト | +| `CLAW_MODEL` | `sonnet` | セッションのデフォルトモデル | + +## REPL コマンド + +```text +/help ヘルプを表示 +/clear 現在のセッション履歴をクリア +/history 会話履歴全体を表示 +/sessions 保存済みセッションを一覧表示 +/model [name] モデルを表示/設定 +/load スキルをコンテキストにホットロード +/branch 現在のセッションをブランチ +/search セッションをまたいでクエリを検索 +/compact 古いラウンドを圧縮し、最近のコンテキストを保持 +/export [path] セッションをエクスポート +/metrics セッションメトリクスを表示 +exit 終了 +``` + +## 説明 + +* NanoClaw はゼロ依存を維持します。 +* セッションは `~/.claude/claw/.md` に保存されます。 +* 圧縮は最近のラウンドを保持し、圧縮ヘッダーを書き込みます。 +* エクスポートは Markdown、JSON ラウンド、プレーンテキストに対応しています。 diff --git a/docs/ja-JP/commands/context-budget.md b/docs/ja-JP/commands/context-budget.md new file mode 100644 index 00000000..763e24c2 --- /dev/null +++ b/docs/ja-JP/commands/context-budget.md @@ -0,0 +1,29 @@ +--- +description: エージェント、スキル、MCP サーバー、ルールにわたるコンテキストウィンドウの使用状況を分析し、最適化の機会を探ります。トークンオーバーヘッドの削減とパフォーマンス警告の回避に役立ちます。 +--- + +# コンテキストバジェット最適化ツール + +Claude Code の設定におけるコンテキストウィンドウの消費量を分析し、トークンオーバーヘッドを削減するための実用的な推奨事項を提供します。 + +## 使用方法 + +``` +/context-budget [--verbose] +``` + +* デフォルト:サマリーと主要な推奨事項を提供 +* `--verbose`:コンポーネントごとの完全な内訳を提供 + +$ARGUMENTS + +## 操作手順 + +**context-budget** スキル(`skills/context-budget/SKILL.md`)を実行し、以下を入力します: + +1. `$ARGUMENTS` に `--verbose` フラグが存在する場合、そのフラグを渡す +2. ユーザーが別途指定しない限り、200K コンテキストウィンドウ(Claude Sonnet のデフォルト)を仮定する +3. スキルの4フェーズに従う:インベントリ → 分類 → 問題検出 → レポート +4. フォーマット済みのコンテキストバジェットレポートをユーザーに出力する + +すべてのスキャンロジック、トークン推定、問題検出、レポートフォーマットはスキルが担当します。 diff --git a/docs/ja-JP/commands/devfleet.md b/docs/ja-JP/commands/devfleet.md new file mode 100644 index 00000000..1eb1d966 --- /dev/null +++ b/docs/ja-JP/commands/devfleet.md @@ -0,0 +1,93 @@ +--- +description: Claude DevFleet を使って並列 Claude Code エージェントをオーケストレーションします — 自然言語でプロジェクトを計画し、隔離されたワークツリーにエージェントをディスパッチし、進捗を監視し、構造化レポートを読み取ります。 +--- + +# DevFleet — マルチエージェントオーケストレーション + +Claude DevFleet を使って並列の Claude Code エージェントをオーケストレーションします。各エージェントは隔離された git worktree 内で動作し、完全なツールチェーンを備えています。 + +DevFleet MCP サーバーが必要です:`claude mcp add devfleet --transport http http://localhost:18801/mcp` + +## フロー + +``` +ユーザーがプロジェクトを説明 + → plan_project(prompt) → タスク DAG と依存関係 + → 計画を表示し、承認を取得 + → dispatch_mission(M1) → エージェントがワークスペースで生成 + → M1 完了 → 自動マージ → M2 が自動ディスパッチ(M1 に依存) + → M2 完了 → 自動マージ + → get_report(M2) → ファイル変更、完了内容、エラー、次のステップ + → ユーザーにサマリーをレポート +``` + +## ワークフロー + +1. **ユーザーの説明に基づいてプロジェクトを計画する**: + +``` +mcp__devfleet__plan_project(prompt="<ユーザーの説明>") +``` + +これはチェーン状のタスクを含むプロジェクトを返します。ユーザーに以下を表示します: + +* プロジェクト名と ID +* 各タスク:タイトル、タイプ、依存関係 +* 依存関係 DAG(どのタスクがどのタスクをブロックしているか) + +2. **ディスパッチ前にユーザーの承認を待つ**。計画を明確に表示します。 + +3. **最初のタスクをディスパッチする**(`depends_on` が空のタスク): + +``` +mcp__devfleet__dispatch_mission(mission_id="") +``` + +残りのタスクは依存関係が完了すると自動的にディスパッチされます(`plan_project` が `auto_dispatch=true` でタスクを作成するため)。`create_mission` を使ってタスクを手動作成する場合は、この動作を有効にするために `auto_dispatch=true` を明示的に設定する必要があります。 + +4. **進捗を監視する** — 実行中の内容を確認: + +``` +mcp__devfleet__get_dashboard() +``` + +または特定のタスクを確認: + +``` +mcp__devfleet__get_mission_status(mission_id="") +``` + +長時間実行するタスクには、`wait_for_mission` ではなく `get_mission_status` によるポーリングを優先し、ユーザーが進捗の更新を確認できるようにします。 + +5. **完了した各タスクのレポートを読む**: + +``` +mcp__devfleet__get_report(mission_id="") +``` + +終了状態に達した各タスクに対してこのツールを呼び出します。レポートには files\_changed、what\_done、what\_open、what\_tested、what\_untested、next\_steps、errors\_encountered が含まれます。 + +## 利用可能なすべてのツール + +| ツール | 用途 | +|------|---------| +| `plan_project(prompt)` | AI が説明を `auto_dispatch=true` のチェーン状タスクに分解する | +| `create_project(name, path?, description?)` | プロジェクトを手動作成し、`project_id` を返す | +| `create_mission(project_id, title, prompt, depends_on?, auto_dispatch?)` | タスクを追加する。`depends_on` はタスク ID 文字列のリスト | +| `dispatch_mission(mission_id, model?, max_turns?)` | エージェントを起動する | +| `cancel_mission(mission_id)` | 実行中のエージェントを停止する | +| `wait_for_mission(mission_id, timeout_seconds?)` | 完了までブロックする(長いタスクにはポーリングを優先) | +| `get_mission_status(mission_id)` | ノンブロッキングで進捗を確認する | +| `get_report(mission_id)` | 構造化レポートを読む | +| `get_dashboard()` | システム概要 | +| `list_projects()` | プロジェクトを参照する | +| `list_missions(project_id, status?)` | タスクを一覧表示する | + +## ガイドライン + +* ユーザーが明示的に「始めてください」と言わない限り、ディスパッチ前に必ず計画を確認する +* ステータスをレポートする際はタスクのタイトルと ID を含める +* タスクが失敗した場合、再試行前にそのレポートを読んでエラーを把握する +* エージェントの同時実行数は設定可能(デフォルト:3)。超過したタスクはキューに入れられ、スロットが空くと自動的にディスパッチされる。スロットの可用性は `get_dashboard()` で確認する +* 依存関係は DAG を形成する — 循環依存は絶対に作成しない +* 各エージェントは完了時に自動的に worktree をマージする。マージ競合が発生した場合、変更は手動解決のために worktree ブランチに保持される diff --git a/docs/ja-JP/commands/docs.md b/docs/ja-JP/commands/docs.md new file mode 100644 index 00000000..eff49502 --- /dev/null +++ b/docs/ja-JP/commands/docs.md @@ -0,0 +1,32 @@ +--- +description: Context7 を使ってライブラリやトピックの最新ドキュメントを検索します。 +--- + +# /docs + +## 目的 + +ライブラリ、フレームワーク、または API の最新ドキュメントを検索し、関連するコードスニペットを含む要約された回答を返します。Context7 MCP(resolve-library-id と query-docs)を使用するため、回答はトレーニングデータではなく最新のドキュメントを反映しています。 + +## 使い方 + +``` +/docs [library name] [question] +``` + +複数の単語からなる引数には、単一のトークンとして解析されるよう引用符を使用してください。例:`/docs "Next.js" "How do I configure middleware?"` + +ライブラリまたは質問が省略された場合、ユーザーに入力を求めます: + +1. ライブラリまたは製品名(例:Next.js、Prisma、Supabase)。 +2. 具体的な質問またはタスク(例:「ミドルウェアの設定方法は?」、「認証方法」)。 + +## ワークフロー + +1. **ライブラリ ID を解決する** — Context7 ツール `resolve-library-id` をライブラリ名とユーザーの質問とともに呼び出し、Context7 互換のライブラリ ID(例:`/vercel/next.js`)を取得する。 +2. **ドキュメントをクエリする** — そのライブラリ ID とユーザーの質問を使って `query-docs` を呼び出す。 +3. **要約する** — 簡潔な回答を返し、取得したドキュメントから抽出した関連コード例を含める。ライブラリ(関連する場合はバージョンも含めて)に言及する。 + +## 出力 + +ユーザーは、最新のドキュメントに基づいた簡潔で正確な回答と、役立つコードスニペットを受け取ります。Context7 が利用できない場合は、その旨を説明し、トレーニングデータに基づいて回答しますが、ドキュメントが古い可能性があることを注記します。 diff --git a/docs/ja-JP/commands/projects.md b/docs/ja-JP/commands/projects.md new file mode 100644 index 00000000..21f4766c --- /dev/null +++ b/docs/ja-JP/commands/projects.md @@ -0,0 +1,39 @@ +--- +name: projects +description: 既知のプロジェクトとその本能統計を一覧表示する +command: true +--- + +# プロジェクト コマンド + +continuous-learning-v2 のプロジェクト登録エントリと各プロジェクトの本能/観察カウントを一覧表示します。 + +## 実装 + +プラグインルートパスを使って本能 CLI を実行します: + +```bash +python3 "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" projects +``` + +または `CLAUDE_PLUGIN_ROOT` が設定されていない場合(手動インストール): + +```bash +python3 ~/.claude/skills/continuous-learning-v2/scripts/instinct-cli.py projects +``` + +## 使い方 + +```bash +/projects +``` + +## 操作手順 + +1. `~/.claude/homunculus/projects.json` を読み取る +2. 各プロジェクトについて以下を表示する: + * プロジェクト名、ID、ルートディレクトリ、リモートアドレス + * 個人および継承された本能カウント + * 観察イベントカウント + * 最終確認タイムスタンプ +3. グローバル本能の合計も表示する diff --git a/docs/ja-JP/commands/prompt-optimize.md b/docs/ja-JP/commands/prompt-optimize.md new file mode 100644 index 00000000..88ee704c --- /dev/null +++ b/docs/ja-JP/commands/prompt-optimize.md @@ -0,0 +1,37 @@ +--- +description: ドラフトプロンプトを分析し、ECC が強化された最適化済みバージョンを出力します。貼り付けてすぐに実行できる状態で出力されます。タスクは実行しません — コンサルティング分析のみを出力します。 +--- + +# /prompt-optimize + +以下のプロンプトを分析し、ECC レバレッジを最大化するよう最適化します。 + +## あなたのタスク + +ユーザーの入力に **prompt-optimizer** スキルを適用します。6フェーズの分析プロセスに従ってください: + +0. **プロジェクト検出** — CLAUDE.md を読み取り、プロジェクトファイル(package.json、go.mod、pyproject.toml など)から技術スタックを検出する +1. **意図検出** — タスクタイプを分類する(新機能、バグ修正、リファクタリング、調査、テスト、レビュー、ドキュメント、インフラ、設計) +2. **スコープ評価** — 複雑さを評価する(シンプル / 低 / 中 / 高 / エピック)、コードベースが検出された場合はそのサイズをシグナルとして使用する +3. **ECC コンポーネントマッチング** — 特定のスキル、コマンド、エージェント、モデル階層にマッピングする +4. **不足コンテキスト検出** — 情報のギャップを特定する。3つ以上の重要な項目が不足している場合は、生成前にユーザーに確認を求める +5. **ワークフローとモデル** — ライフサイクルフェーズを決定し、モデル階層を推奨し、複雑さが高/エピックの場合は複数のプロンプトに分割する + +## 出力要件 + +* 診断結果、推奨 ECC コンポーネント、prompt-optimizer スキルの出力フォーマットを使用した最適化済みプロンプトを提示する +* **完全版**(詳細)と**クイック版**(コンパクト、意図タイプによって変化)を提供する +* ユーザーの入力と同じ言語で回答する +* 最適化済みプロンプトは完全で、新しいセッションにコピー&ペーストしてそのまま使用できる状態でなければならない +* 調整オプションまたは明確な次のアクション(別途実行リクエストを開始するため)を提供するフッターで締めくくる + +## 重要 + +ユーザーのタスクを実行しないでください。分析結果と最適化済みプロンプトのみを出力してください。 +ユーザーが直接実行を求めた場合は、`/prompt-optimize` はコンサルティング的な出力のみを生成することを説明し、通常のタスクリクエストを開始するよう伝えてください。 + +注意:`blueprint` は**スキル**であり、スラッシュコマンドではありません。「ブループリントスキルを使用する」と書き、`/...` コマンドとして表現しないでください。 + +## ユーザー入力 + +$ARGUMENTS diff --git a/docs/ja-JP/commands/rules-distill.md b/docs/ja-JP/commands/rules-distill.md new file mode 100644 index 00000000..f09d092d --- /dev/null +++ b/docs/ja-JP/commands/rules-distill.md @@ -0,0 +1,11 @@ +--- +description: "スキルをスキャンして横断的な原則を抽出し、ルールとして提炼する" +--- + +# /rules-distill — スキルから原則をルールとして提炼する + +インストール済みのスキルをスキャンし、横断的な原則を抽出して、ルールとして提炼します。 + +## フロー + +`rules-distill` スキルで定義された完全なワークフローに従います。 diff --git a/docs/ja-JP/skills/frontend-slides/STYLE_PRESETS.md b/docs/ja-JP/skills/frontend-slides/STYLE_PRESETS.md new file mode 100644 index 00000000..0dd86b61 --- /dev/null +++ b/docs/ja-JP/skills/frontend-slides/STYLE_PRESETS.md @@ -0,0 +1,333 @@ +# スタイルプリセットリファレンス + +`frontend-slides` 用にまとめられたビジュアルスタイル。 + +このファイルの用途: + +* 強制的なビューポート適合CSSの基礎 +* プリセットの選択とムードマッピング +* CSSの落とし穴とバリデーションルール + +抽象的な形状のみを使用する。ユーザーが明示的に要求しない限り、イラストを避ける。 + +## ビューポート適合は妥協しない + +各スライドは1つのビューポートに完全に収まる必要がある。 + +### 黄金ルール + +```text +各スライド = ちょうど1つのビューポートの高さ。 +コンテンツが多すぎる = 複数のスライドに分割する。 +スライド内でスクロールさせない。 +``` + +### コンテンツ密度の制限 + +| スライドタイプ | 最大コンテンツ量 | +|---|---| +| タイトルスライド | 1つのタイトル + 1つのサブタイトル + オプションのキャッチフレーズ | +| コンテンツスライド | 1つのタイトル + 4〜6つの箇条書きまたは2段落 | +| 機能グリッド | 最大6枚のカード | +| コードスライド | 最大8〜10行 | +| 引用スライド | 1つの引用 + 出典 | +| 画像スライド | 1枚の画像、理想的には60vh未満 | + +## 強制基礎CSS + +このコードブロックを生成されるすべてのプレゼンテーションにコピーし、その上にテーマを適用する。 + +```css +/* =========================================== + VIEWPORT FITTING: MANDATORY BASE STYLES + =========================================== */ + +html, body { + height: 100%; + overflow-x: hidden; +} + +html { + scroll-snap-type: y mandatory; + scroll-behavior: smooth; +} + +.slide { + width: 100vw; + height: 100vh; + height: 100dvh; + overflow: hidden; + scroll-snap-align: start; + display: flex; + flex-direction: column; + position: relative; +} + +.slide-content { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + max-height: 100%; + overflow: hidden; + padding: var(--slide-padding); +} + +:root { + --title-size: clamp(1.5rem, 5vw, 4rem); + --h2-size: clamp(1.25rem, 3.5vw, 2.5rem); + --h3-size: clamp(1rem, 2.5vw, 1.75rem); + --body-size: clamp(0.75rem, 1.5vw, 1.125rem); + --small-size: clamp(0.65rem, 1vw, 0.875rem); + + --slide-padding: clamp(1rem, 4vw, 4rem); + --content-gap: clamp(0.5rem, 2vw, 2rem); + --element-gap: clamp(0.25rem, 1vw, 1rem); +} + +.card, .container, .content-box { + max-width: min(90vw, 1000px); + max-height: min(80vh, 700px); +} + +.feature-list, .bullet-list { + gap: clamp(0.4rem, 1vh, 1rem); +} + +.feature-list li, .bullet-list li { + font-size: var(--body-size); + line-height: 1.4; +} + +.grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr)); + gap: clamp(0.5rem, 1.5vw, 1rem); +} + +img, .image-container { + max-width: 100%; + max-height: min(50vh, 400px); + object-fit: contain; +} + +@media (max-height: 700px) { + :root { + --slide-padding: clamp(0.75rem, 3vw, 2rem); + --content-gap: clamp(0.4rem, 1.5vw, 1rem); + --title-size: clamp(1.25rem, 4.5vw, 2.5rem); + --h2-size: clamp(1rem, 3vw, 1.75rem); + } +} + +@media (max-height: 600px) { + :root { + --slide-padding: clamp(0.5rem, 2.5vw, 1.5rem); + --content-gap: clamp(0.3rem, 1vw, 0.75rem); + --title-size: clamp(1.1rem, 4vw, 2rem); + --body-size: clamp(0.7rem, 1.2vw, 0.95rem); + } + + .nav-dots, .keyboard-hint, .decorative { + display: none; + } +} + +@media (max-height: 500px) { + :root { + --slide-padding: clamp(0.4rem, 2vw, 1rem); + --title-size: clamp(1rem, 3.5vw, 1.5rem); + --h2-size: clamp(0.9rem, 2.5vw, 1.25rem); + --body-size: clamp(0.65rem, 1vw, 0.85rem); + } +} + +@media (max-width: 600px) { + :root { + --title-size: clamp(1.25rem, 7vw, 2.5rem); + } + + .grid { + grid-template-columns: 1fr; + } +} + +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + transition-duration: 0.2s !important; + } + + html { + scroll-behavior: auto; + } +} +``` + +## ビューポートチェックリスト + +* すべての `.slide` に `height: 100vh`、`height: 100dvh`、`overflow: hidden` がある +* すべてのタイポグラフィが `clamp()` を使用している +* すべての間隔が `clamp()` またはビューポート単位を使用している +* 画像に `max-height` 制約がある +* グリッドが適合のために `auto-fit` + `minmax()` を使用している +* 短い高さのブレークポイントが `700px`、`600px`、`500px` に存在する +* コンテンツが窮屈に感じられる場合は、スライドを分割する + +## ムードからプリセットへのマッピング + +| ムード | 推奨プリセット | +|---|---| +| 印象的 / 自信あり | Bold Signal, Electric Studio, Dark Botanical | +| 興奮 / 活力 | Creative Voltage, Neon Cyber, Split Pastel | +| 落ち着き / 集中 | Notebook Tabs, Paper & Ink, Swiss Modern | +| インスピレーション / 感動 | Dark Botanical, Vintage Editorial, Pastel Geometry | + +## プリセットカタログ + +### 1. Bold Signal + +* 雰囲気:自信あり、高インパクト、基調講演に適している +* 最適用途:ピッチデッキ、製品ローンチ、アナウンス +* フォント:Archivo Black + Space Grotesk +* カラーパレット:チャコールの基調色、明るいオレンジのフォーカスカード、純白のテキスト +* 特徴:超大きなセクション番号、ダーク背景上の高コントラストカード + +### 2. Electric Studio + +* 雰囲気:クリーン、大胆、機関誌レベルの洗練さ +* 最適用途:クライアントデッキ、戦略レビュー +* フォント:Manropeのみ +* カラーパレット:ブラック、ホワイト、彩度の高いコバルトブルーのアクセント +* 特徴:デュアルパネル分割とシャープな編集スタイルのアライメント + +### 3. Creative Voltage + +* 雰囲気:活力、レトロモダン、遊び心と自信 +* 最適用途:クリエイティブスタジオ、ブランドワーク、プロダクトストーリーテリング +* フォント:Syne + Space Mono +* カラーパレット:エレクトリックブルー、ネオンイエロー、ディープネイビー +* 特徴:ハーフトーンテクスチャ、バッジ、強いコントラスト + +### 4. Dark Botanical + +* 雰囲気:エレガント、ハイエンド、雰囲気がある +* 最適用途:ラグジュアリーブランド、思慮深いナラティブ、プレミアム製品デモ +* フォント:Cormorant + IBM Plex Sans +* カラーパレット:ほぼブラック、温かみのあるアイボリー、ブラッシュ、ゴールド、テラコッタ +* 特徴:ぼかされた抽象的な円、細いライン、抑制されたモーション + +### 5. Notebook Tabs + +* 雰囲気:編集的、整理された、触覚的 +* 最適用途:レポート、レビュー、構造化されたストーリーテリング +* フォント:Bodoni Moda + DM Sans +* カラーパレット:チャコール上のクリーム色の用紙とソフトカラーのタブ +* 特徴:紙の効果、カラーサイドタブ、バインダーの詳細 + +### 6. Pastel Geometry + +* 雰囲気:親しみやすい、モダン、フレンドリー +* 最適用途:製品概要、入門、軽めのブランドプレゼン +* フォント:Plus Jakarta Sansのみ +* カラーパレット:薄いブルーの背景、クリーム色のカード、ソフトなピンク/ミント/ラベンダーのアクセント +* 特徴:縦長のピル形状、角丸カード、ソフトシャドウ + +### 7. Split Pastel + +* 雰囲気:楽しい、モダン、クリエイティブ +* 最適用途:エージェンシー紹介、ワークショップ、ポートフォリオ +* フォント:Outfitのみ +* カラーパレット:ミントバッジとのピーチ + ラベンダーの分割背景 +* 特徴:分割背景、角丸タグ、軽いグリッドオーバーレイ + +### 8. Vintage Editorial + +* 雰囲気:機知に富む、個性的、雑誌にインスパイアされた +* 最適用途:パーソナルブランド、オピニオントーク、ストーリーテリング +* フォント:Fraunces + Work Sans +* カラーパレット:クリーム、チャコール、くすんだ温かみのあるアクセント +* 特徴:幾何学的なアクセント、ボーダー付きのコールアウト、印象的なセリフの見出し + +### 9. Neon Cyber + +* 雰囲気:未来的、テック感、ダイナミック +* 最適用途:AI、インフラ、デベロッパーツール、未来トレンドについての講演 +* フォント:Clash Display + Satoshi +* カラーパレット:ミッドナイトネイビー、シアン、マゼンタ +* 特徴:グロー効果、パーティクル、グリッド、データレーダーエナジー感 + +### 10. Terminal Green + +* 雰囲気:デベロッパー向け、ハッカーな簡潔さ +* 最適用途:API、CLIツール、エンジニアリングデモ +* フォント:JetBrains Monoのみ +* カラーパレット:GitHubダーク + ターミナルグリーン +* 特徴:スキャンライン、コマンドラインフレーミング、精確なモノスペースのリズム + +### 11. Swiss Modern + +* 雰囲気:ミニマリスト、精密、データ指向 +* 最適用途:エンタープライズ、製品戦略、アナリティクス +* フォント:Archivo + Nunito +* カラーパレット:ホワイト、ブラック、シグナルレッド +* 特徴:可視グリッド、非対称、幾何学的な秩序感 + +### 12. Paper & Ink + +* 雰囲気:文学的、思慮深い、ストーリー駆動 +* 最適用途:散文、基調講演のナラティブ、マニフェスト的なプレゼン +* フォント:Cormorant Garamond + Source Serif 4 +* カラーパレット:温かみのあるクリーム、チャコール、ディープレッドのアクセント +* 特徴:引用のハイライト、ドロップキャップ、エレガントなライン + +## 直接選択プロンプト + +ユーザーがすでに望むスタイルを知っている場合、プレビューを強制的に生成するのではなく、上記のプリセット名から直接選んでもらう。 + +## アニメーションの感覚マッピング + +| 感覚 | モーションの方向 | +|---|---| +| ドラマチック / シネマティック | ゆっくりとしたフェード、視差スクロール、大スケールのズームイン | +| テック感 / 未来的 | グロー、パーティクル、グリッドモーション、テキストのスクランブル表示 | +| 楽しい / フレンドリー | バウンスのイージング、丸い形状、フローティングモーション | +| プロフェッショナル / エンタープライズ | 微妙な200〜300msのトランジション、クリーンなスライド切り替え | +| 落ち着き / ミニマリスト | 非常に控えめなモーション、空白を優先 | +| 編集的 / 雑誌的 | 強い階層性、テキストと画像のずらしたインタラクション | + +## CSSの落とし穴:否定関数 + +以下は絶対に書かない: + +```css +right: -clamp(28px, 3.5vw, 44px); +margin-left: -min(10vw, 100px); +``` + +ブラウザはそれらを静かに無視する。 + +代わりに常にこのように書く: + +```css +right: calc(-1 * clamp(28px, 3.5vw, 44px)); +margin-left: calc(-1 * min(10vw, 100px)); +``` + +## バリデーションサイズ + +少なくとも以下のサイズでテストする: + +* デスクトップ:`1920x1080`、`1440x900`、`1280x720` +* タブレット:`1024x768`、`768x1024` +* モバイル:`375x667`、`414x896` +* 横向きモバイル:`667x375`、`896x414` + +## アンチパターン + +使用しない: + +* 紫背景に白テキストのスタートアップテンプレート +* Inter / Roboto / Arial をビジュアルボイスとして使用する(ユーザーが実用主義的なニュートラルスタイルを明示的に望む場合を除く) +* 箇条書きの詰め込み、過小なフォント、スクロールが必要なコードブロック +* 抽象的な幾何学形状がより良い働きをする場合に装飾的なイラストを使用する diff --git a/docs/ja-JP/skills/regex-vs-llm-structured-text/SKILL.md b/docs/ja-JP/skills/regex-vs-llm-structured-text/SKILL.md new file mode 100644 index 00000000..cfd4fa36 --- /dev/null +++ b/docs/ja-JP/skills/regex-vs-llm-structured-text/SKILL.md @@ -0,0 +1,217 @@ +--- +name: regex-vs-llm-structured-text +description: 構造化テキストの解析に正規表現と大規模言語モデルのどちらを使うかを選択するための意思決定フレームワーク——まず正規表達式から始め、信頼度の低いエッジケースにのみ大規模言語モデルを追加する。 +origin: ECC +--- + +# 構造化テキスト解析における正規表現 vs LLM + +構造化テキスト(クイズ、フォーム、請求書、ドキュメント)を解析するための実用的な意思決定フレームワーク。核心的な洞察:正規表現は低コストかつ決定論的に95〜98%のケースを処理できる。コストのかかるLLM呼び出しは残りのエッジケースに留める。 + +## 使用場面 + +* 繰り返しパターンを持つ構造化テキスト(設問、フォーム、表)の解析 +* テキスト抽出に正規表現とLLMのどちらを使うかの判断 +* 両方のアプローチを組み合わせたハイブリッドパイプラインの構築 +* テキスト処理におけるコスト/精度のトレードオフの最適化 + +## 意思決定フレームワーク + +``` +テキスト形式は一貫していて繰り返しがあるか? +├── はい (>90% が何らかのパターンに従う) → 正規表現から始める +│ ├── 正規表現が 95%+ を処理 → 完了、LLM は不要 +│ └── 正規表現が <95% を処理 → エッジケースのみ LLM を追加 +└── いいえ (自由形式、高度に可変) → LLM を直接使用 +``` + +## アーキテクチャパターン + +``` +[正規表現パーサー] ─── 構造を抽出(95〜98% の精度) + │ + ▼ +[テキストクリーナー] ─── ノイズを除去(マーカー、ページ番号、アーティファクト) + │ + ▼ +[信頼度スコアラー] ─── 信頼度の低い抽出結果にフラグを立てる + │ + ├── 高信頼度(≥0.95)→ 直接出力 + │ + └── 低信頼度(<0.95)→ [LLM バリデーター] → 出力 +``` + +## 実装 + +### 1. 正規表現パーサー(大半のケースを処理) + +```python +import re +from dataclasses import dataclass + +@dataclass(frozen=True) +class ParsedItem: + id: str + text: str + choices: tuple[str, ...] + answer: str + confidence: float = 1.0 + +def parse_structured_text(content: str) -> list[ParsedItem]: + """Parse structured text using regex patterns.""" + pattern = re.compile( + r"(?P\d+)\.\s*(?P.+?)\n" + r"(?P(?:[A-D]\..+?\n)+)" + r"Answer:\s*(?P[A-D])", + re.MULTILINE | re.DOTALL, + ) + items = [] + for match in pattern.finditer(content): + choices = tuple( + c.strip() for c in re.findall(r"[A-D]\.\s*(.+)", match.group("choices")) + ) + items.append(ParsedItem( + id=match.group("id"), + text=match.group("text").strip(), + choices=choices, + answer=match.group("answer"), + )) + return items +``` + +### 2. 信頼度スコアリング + +LLMによるレビューが必要かもしれない項目にフラグを立てる: + +```python +@dataclass(frozen=True) +class ConfidenceFlag: + item_id: str + score: float + reasons: tuple[str, ...] + +def score_confidence(item: ParsedItem) -> ConfidenceFlag: + """Score extraction confidence and flag issues.""" + reasons = [] + score = 1.0 + + if len(item.choices) < 3: + reasons.append("few_choices") + score -= 0.3 + + if not item.answer: + reasons.append("missing_answer") + score -= 0.5 + + if len(item.text) < 10: + reasons.append("short_text") + score -= 0.2 + + return ConfidenceFlag( + item_id=item.id, + score=max(0.0, score), + reasons=tuple(reasons), + ) + +def identify_low_confidence( + items: list[ParsedItem], + threshold: float = 0.95, +) -> list[ConfidenceFlag]: + """Return items below confidence threshold.""" + flags = [score_confidence(item) for item in items] + return [f for f in flags if f.score < threshold] +``` + +### 3. LLM バリデーター(エッジケースのみ) + +```python +def validate_with_llm( + item: ParsedItem, + original_text: str, + client, +) -> ParsedItem: + """Use LLM to fix low-confidence extractions.""" + response = client.messages.create( + model="claude-haiku-4-5-20251001", # Cheapest model for validation + max_tokens=500, + messages=[{ + "role": "user", + "content": ( + f"Extract the question, choices, and answer from this text.\n\n" + f"Text: {original_text}\n\n" + f"Current extraction: {item}\n\n" + f"Return corrected JSON if needed, or 'CORRECT' if accurate." + ), + }], + ) + # Parse LLM response and return corrected item... + return corrected_item +``` + +### 4. ハイブリッドパイプライン + +```python +def process_document( + content: str, + *, + llm_client=None, + confidence_threshold: float = 0.95, +) -> list[ParsedItem]: + """Full pipeline: regex -> confidence check -> LLM for edge cases.""" + # Step 1: Regex extraction (handles 95-98%) + items = parse_structured_text(content) + + # Step 2: Confidence scoring + low_confidence = identify_low_confidence(items, confidence_threshold) + + if not low_confidence or llm_client is None: + return items + + # Step 3: LLM validation (only for flagged items) + low_conf_ids = {f.item_id for f in low_confidence} + result = [] + for item in items: + if item.id in low_conf_ids: + result.append(validate_with_llm(item, content, llm_client)) + else: + result.append(item) + + return result +``` + +## 実際のメトリクス + +本番のクイズ解析パイプライン(410項目)より: + +| メトリクス | 値 | +|--------|-------| +| 正規表現の成功率 | 98.0% | +| 低信頼度項目 | 8 (2.0%) | +| 必要なLLM呼び出し回数 | ~5 | +| 全件LLM比のコスト節約 | ~95% | +| テストカバレッジ | 93% | + +## ベストプラクティス + +* **正規表現から始める** — 不完全な正規表現でも改善のベースラインになる +* **信頼度スコアリングを使用**して、LLMの助けが必要なものをプログラムで特定する +* **最も安価なLLMを使用**して検証する(Haikuクラスのモデルで十分) +* **解析済み項目を変更しない** — クリーニング/検証ステップから新しいインスタンスを返す +* **TDDは解析器に効果的** — まず既知のパターンのテストを書き、次にエッジケースを書く +* **メトリクスを記録**(正規表現の成功率、LLM呼び出し回数)してパイプラインの健全性を追跡する + +## 避けるべきアンチパターン + +* 正規表現が95%以上を処理できる場合に全テキストをLLMに送る(コスト高・低速) +* 自由形式で高度に可変なテキストに正規表現を使用する(LLMの方が適切) +* 信頼度スコアリングをスキップして正規表現が「うまくいく」ことを期待する +* クリーニング/検証ステップで解析済みオブジェクトを変更する +* エッジケースをテストしない(不正な入力、欠損フィールド、エンコーディング問題) + +## 適用場面 + +* クイズ/試験問題の解析 +* フォームデータの抽出 +* 請求書/レシートの処理 +* ドキュメント構造の解析(見出し、セクション、表) +* 繰り返しパターンがあり、コストが重要なあらゆる構造化テキスト diff --git a/docs/ja-JP/skills/remotion-video-creation/SKILL.md b/docs/ja-JP/skills/remotion-video-creation/SKILL.md new file mode 100644 index 00000000..01dcbb3d --- /dev/null +++ b/docs/ja-JP/skills/remotion-video-creation/SKILL.md @@ -0,0 +1,43 @@ +--- +name: remotion-video-creation +description: Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。 +metadata: + tags: remotion, video, react, animation, composition, three.js, lottie +--- + +## 使用場面 + +Remotion のコードを扱い、ドメイン固有の知識が必要な場合にこのスキルを使用してください。 + +## 使い方 + +詳細な説明とコード例については、各ルールファイルをお読みください: + +* [rules/3d.md](rules/3d.md) - Three.js と React Three Fiber を使用して Remotion で 3D コンテンツを作成する +* [rules/animations.md](rules/animations.md) - Remotion の基本的なアニメーションスキル +* [rules/assets.md](rules/assets.md) - Remotion で画像、動画、音声、フォントをインポートする +* [rules/audio.md](rules/audio.md) - Remotion での音声とサウンドの使用——インポート、トリミング、音量、速度、ピッチ +* [rules/calculate-metadata.md](rules/calculate-metadata.md) - コンポジションの長さ、サイズ、プロパティを動的に設定する +* [rules/can-decode.md](rules/can-decode.md) - Mediabunny を使用してブラウザが動画をデコードできるか確認する +* [rules/charts.md](rules/charts.md) - Remotion のチャートとデータビジュアライゼーションパターン +* [rules/compositions.md](rules/compositions.md) - コンポジション、静止画、フォルダー、デフォルトプロパティ、動的メタデータの定義 +* [rules/display-captions.md](rules/display-captions.md) - TikTok スタイルのページと単語ハイライトに対応した Remotion での字幕表示 +* [rules/extract-frames.md](rules/extract-frames.md) - Mediabunny を使用して指定タイムスタンプの動画フレームを抽出する +* [rules/fonts.md](rules/fonts.md) - Remotion で Google フォントとローカルフォントを読み込む +* [rules/get-audio-duration.md](rules/get-audio-duration.md) - Mediabunny を使用して音声ファイルの長さ(秒)を取得する +* [rules/get-video-dimensions.md](rules/get-video-dimensions.md) - Mediabunny を使用して動画ファイルの幅と高さを取得する +* [rules/get-video-duration.md](rules/get-video-duration.md) - Mediabunny を使用して動画ファイルの長さ(秒)を取得する +* [rules/gifs.md](rules/gifs.md) - Remotion のタイムラインと同期した GIF を表示する +* [rules/images.md](rules/images.md) - Img コンポーネントを使用して Remotion に画像を埋め込む +* [rules/import-srt-captions.md](rules/import-srt-captions.md) - @remotion/captions を使用して .srt 字幕ファイルを Remotion にインポートする +* [rules/lottie.md](rules/lottie.md) - Remotion に Lottie アニメーションを埋め込む +* [rules/measuring-dom-nodes.md](rules/measuring-dom-nodes.md) - Remotion で DOM 要素のサイズを測定する +* [rules/measuring-text.md](rules/measuring-text.md) - テキストサイズの測定、コンテナへのテキスト適合、オーバーフローの確認 +* [rules/sequencing.md](rules/sequencing.md) - Remotion のシーケンスパターン——遅延、トリミング、項目の長さ制限 +* [rules/tailwind.md](rules/tailwind.md) - Remotion で TailwindCSS を使用する +* [rules/text-animations.md](rules/text-animations.md) - Remotion のタイポグラフィとテキストアニメーションパターン +* [rules/timing.md](rules/timing.md) - Remotion の補間曲線——線形、イージング、スプリングアニメーション +* [rules/transcribe-captions.md](rules/transcribe-captions.md) - Remotion で字幕を生成するための音声文字起こし +* [rules/transitions.md](rules/transitions.md) - Remotion のシーントランジションパターン +* [rules/trimming.md](rules/trimming.md) - Remotion のトリミングパターン——アニメーションの最初または最後をトリミングする +* [rules/videos.md](rules/videos.md) - Remotion への動画埋め込み——トリミング、音量、速度、ループ、ピッチ diff --git a/docs/ja-JP/skills/repo-scan/SKILL.md b/docs/ja-JP/skills/repo-scan/SKILL.md new file mode 100644 index 00000000..35aad3ee --- /dev/null +++ b/docs/ja-JP/skills/repo-scan/SKILL.md @@ -0,0 +1,79 @@ +--- +name: repo-scan +description: クロススタックのソースコード資産監査——各ファイルを分類し、埋め込まれたサードパーティライブラリを検出し、各モジュールに対してインタラクティブなHTMLレポートとともに実用的な4段階の判定を提供する。 +origin: community +--- + +# repo-scan + +> どのエコシステムにも独自の依存関係マネージャーがあるが、C++、Android、iOS、Web をまたいで「どのコードが本当に自分のもので、どれがサードパーティで、どれが余分な負担か」を教えてくれるツールはない。 + +## 適用場面 + +* 大規模なレガシーコードベースを引き継ぎ、全体的な構造を把握する必要がある場合 +* 大規模なリファクタリング前——コアコード、重複コード、廃止コードを特定する +* パッケージマネージャーで宣言せずにソースに直接埋め込まれたサードパーティの依存関係を監査する +* モノレポの再編成に向けたアーキテクチャ決定記録を準備する + +## インストール + +```bash +# Fetch only the pinned commit for reproducibility +mkdir -p ~/.claude/skills/repo-scan +git init repo-scan +cd repo-scan +git remote add origin https://github.com/haibindev/repo-scan.git +git fetch --depth 1 origin 2742664 +git checkout --detach FETCH_HEAD +cp -r . ~/.claude/skills/repo-scan +``` + +> エージェントスキルをインストールする前に、ソースコードをレビューしてください。 + +## コア機能 + +| 機能 | 説明 | +|---|---| +| **クロススタックスキャン** | C/C++、Java/Android、iOS(OC/Swift)、Web(TS/JS/Vue)を一度にスキャン | +| **ファイル分類** | 各ファイルをプロジェクトコード、サードパーティコード、またはビルドアーティファクトとしてマーク | +| **ライブラリ検出** | 50以上の既知ライブラリ(FFmpeg、Boost、OpenSSL…)を識別しバージョン番号を抽出 | +| **4段階の判定** | コア資産 / 抽出・統合 / 再構築 / 廃止 | +| **HTMLレポート** | 階層的なドリルダウンナビゲーションに対応したインタラクティブなダークテーマページ | +| **モノレポサポート** | 階層的スキャンによるサマリー + サブプロジェクトレポート | + +## 分析の深さレベル + +| レベル | 読み取りファイル数 | 適用場面 | +|---|---|---| +| `fast` | モジュールあたり1〜2個 | 大規模ディレクトリの素早い棚卸し | +| `standard` | モジュールあたり2〜5個 | デフォルト監査、完全な依存関係 + アーキテクチャチェック | +| `deep` | モジュールあたり5〜10個 | スレッド安全性、メモリ管理、API一貫性チェックを追加 | +| `full` | 全ファイル | 統合前の包括的レビュー | + +## 動作原理 + +1. **リポジトリの表面を分類**:ファイルを列挙し、各ファイルをプロジェクトコード、埋め込みサードパーティコード、ビルドアーティファクトとしてマークする。 +2. **埋め込みライブラリを検出**:ディレクトリ名、ヘッダーファイル、ライセンスファイル、バージョンマーカーを検査して、バンドルされた依存関係とその可能性のあるバージョンを識別する。 +3. **各モジュールをスコアリング**:ファイルをモジュールまたはサブシステムにグループ化し、所有権、重複度、保守コストに基づいて4つの判定のいずれかを割り当てる。 +4. **構造的リスクを強調**:冗長なアーティファクト、重複したラッパー、古いベンダーコード、および抽出・再構築・廃止すべきモジュールを指摘する。 +5. **レポートを生成**:簡潔なサマリーとインタラクティブなHTML出力を返し、モジュールごとのドリルダウンにより監査結果を非同期でレビューできる。 + +## 例 + +50,000ファイルのC++モノレポで: + +* FFmpeg 2.x(2015年版)がまだ使用されていることを発見 +* 同じSDKラッパーが3回重複していることを発見 +* 636 MBのコミット済みDebug/ipch/objビルドアーティファクトを識別 +* 分類結果:3 MBのプロジェクトコード vs 596 MBのサードパーティコード + +## ベストプラクティス + +* 初回監査は `standard` の深さから始める +* 100以上のモジュールを含むモノレポには `fast` で素早く棚卸しする +* リファクタリングが必要とフラグ立てされたモジュールに対して段階的に `deep` を実行する +* クロスモジュール分析の結果をレビューして、サブプロジェクト間の重複コードを検出する + +## リンク + +* [GitHub リポジトリ](https://github.com/haibindev/repo-scan) diff --git a/docs/ja-JP/skills/research-ops/SKILL.md b/docs/ja-JP/skills/research-ops/SKILL.md new file mode 100644 index 00000000..31278894 --- /dev/null +++ b/docs/ja-JP/skills/research-ops/SKILL.md @@ -0,0 +1,112 @@ +--- +name: research-ops +description: 証拠優先のECC現状調査ワークフロー。ユーザーが現在の公開証拠と提供されたローカルコンテキストに基づいて最新の事実、比較、情報の充実、または推奨事項を求める場合に使用する。 +origin: ECC +--- + +# リサーチオペレーション + +ユーザーが現在の情報の調査、オプションの比較、人物や企業情報の充実、または繰り返しのクエリをモニタリング可能なワークフローに変換することを求める場合に使用する。 + +これはリポジトリのリサーチスタックの操作ラッパーである。`deep-research`、`exa-search`、`market-research` の代替品ではなく、それらをいつどのように組み合わせて使うかを指示するものである。 + +## スキルスタック + +関連する場面では、これらのECCネイティブスキルをワークフローに組み込む: + +* `exa-search`:現在のウェブ情報の素早い発見に使用 +* `deep-research`:引用付きの複数ソース統合に使用 +* `market-research`:最終結果が推奨または優先順位付け決定である場合に使用 +* `lead-intelligence`:タスクが一般的な調査ではなく人物/企業を対象とする場合に使用 +* `knowledge-ops`:結果を後続のコンテキスト用に永続的に保存する必要がある場合に使用 + +## 使用場面 + +* ユーザーが「調査」「調べる」「比較」「誰に連絡すべきか」「最新情報」に言及する場合 +* 答えが現在の公開情報に依存する場合 +* ユーザーが証拠を提供し、それを新しい推奨事項に組み込んでほしい場合 +* タスクが繰り返し発生する可能性があり、一回限りのクエリではなくモニタリングに転換すべき場合 + +## 安全策 + +* 新鮮な検索が安価な場合、古い記憶に頼って現在の問いに答えない +* 以下を区別する: + * 出典付きの事実 + * ユーザーが提供した証拠 + * 推論 + * 推奨事項 +* 答えがローカルコードまたはドキュメントにすでに存在する場合、重い調査プロセスを起動しない + +## ワークフロー + +### 1. ユーザーがすでに提供した情報から始める + +提供された素材を以下に正規化する: + +* すでに証拠がある事実 +* 検証が必要な内容 +* 未解決の問い + +ユーザーがすでに部分的なモデルを構築している場合、ゼロから再分析しない。 + +### 2. リクエストを分類する + +検索前に正しいパスを選択する: + +* 素早い事実的回答 +* 比較または意思決定メモ +* リード/情報充実処理 +* 繰り返しモニタリング候補 + +### 3. 最も軽量な有効な証拠パスを優先する + +* `exa-search` を使って素早い発見を行う +* 統合または複数ソース情報が必要な場合、`deep-research` にアップグレードする +* 結果を推奨形式で提示する必要がある場合、`market-research` を使用する +* 実際のニーズがターゲット優先順位付けやウォームパス発見の場合、`lead-intelligence` に転送する + +### 4. 証拠の境界を明示してレポートする + +重要な主張については、それが以下のどれであるかを述べる: + +* 出典付きの事実 +* ユーザーが提供したコンテキスト +* 推論 +* 推奨事項 + +時効性の高い回答には具体的な日付を含める。 + +### 5. タスクを手動のままにすべきか決定する + +ユーザーが同じ調査の問いを繰り返す可能性がある場合、それを明示し、永遠に同じ手動検索を繰り返すのではなく、モニタリングまたはワークフローレイヤーの採用を提案する。 + +## 出力フォーマット + +```text +問いのタイプ +- 事実的 / 比較的 / 補完的 / モニタリング的 + +証拠 +- 出典付きの事実 +- ユーザーが提供したコンテキスト + +推論 +- 証拠から導かれた結論 + +推奨事項 +- 答えまたは次のアクション +- モニタリング項目にすべきか否か +``` + +## よくある落とし穴 + +* 出典付きの事実と推論を、ラベルなしで混在させない +* ユーザーが提供した証拠を無視しない +* ローカルリポジトリのコンテキストで答えられる問いに重い調査パスを使わない +* 日付のない時効性の高い答えを返さない + +## 検証 + +* 重要な主張には証拠タイプのラベルを付ける +* 時効性の高い出力には日付を含める +* 最終的な推奨事項は実際に使用した調査モードと一致させる diff --git a/docs/ja-JP/skills/returns-reverse-logistics/SKILL.md b/docs/ja-JP/skills/returns-reverse-logistics/SKILL.md new file mode 100644 index 00000000..2582fb9b --- /dev/null +++ b/docs/ja-JP/skills/returns-reverse-logistics/SKILL.md @@ -0,0 +1,225 @@ +--- +name: returns-reverse-logistics +description: 返品承認、受取・検品、処分決定、返金処理、不正検出、保証クレーム管理のための標準化された専門知識。15年以上の経験を持つ返品オペレーションマネージャーの知見に基づく。段階的フレームワーク、処分経済性、不正パターン認識、ベンダー回収プロセスを含む。製品返品、逆物流、返金決定、返品不正検出、保証クレームを扱う場合に使用。license: Apache-2.0 +version: 1.0.0 +homepage: https://github.com/affaan-m/everything-claude-code +origin: ECC +metadata: + author: evos + clawdbot: + emoji: "" +--- + +# 返品と逆物流 + +## 役割と背景 + +あなたは15年以上の経験を持つシニア返品オペレーションマネージャーであり、小売・eコマース・オムニチャネル環境における完全な返品ライフサイクルを担当する。業務範囲は返品承認(RMA)、受取・検品、状態グレーディング、処分経路計画、返金・クレジット処理、不正検出、ベンダー回収(RTV)、保証クレーム管理に及ぶ。使用システムはOMS(注文管理システム)、WMS(倉庫管理システム)、RMS(返品管理システム)、CRM、不正検出プラットフォーム、ベンダーポータルである。顧客満足と利益保護、処理速度と検品精度、不正防止と正当な顧客へのフリクションのバランスを追求する。 + +## 使用場面 + +* 返品リクエストを処理し、RMAの適格性を判断する +* 返品品を検品し、処分のための状態グレードを割り当てる +* 処分決定経路(再販、リファービッシュ、クリアランス、廃棄、ベンダー返品)を計画する +* 返品不正パターンや返品ポリシーの悪用を調査する +* 保証クレームとベンダー回収の控除を管理する + +## 運用方法 + +1. 返品リクエストを受け取り、返品ポリシー(時間ウィンドウ、状態、カテゴリー制限)に基づいて適格性を確認する +2. 商品価値と返品理由に基づいて、プリペイドラベルまたはドロップポイント配送指示を含むRMAを発行する +3. 返品センターで商品を受取・検品し、状態グレード(AからD)を割り当てる +4. 回収経済性(再販利益 vs クリアランス vs 廃棄コスト)に基づいて最適な処分チャネルへ経路を設定する +5. ポリシーに従って返金または交換を処理し、不正レビューのために異常をフラグ立てする +6. ベンダーに請求可能な返品を集計し、契約上の規定ウィンドウ内にRTVクレームを提出する + +## 例 + +* **高額電子機器返品**:顧客が「不具合あり」として1,200ドルのノートパソコンを返品。検品で外観の損傷が不具合の主張と矛盾していることが判明。グレーディング、リファービッシュコスト評価、処分経路計画(70%回収率でリファービッシュして再販 vs 85%回収率でベンダー返品)、不正フラグ評価を演習する。 +* **シリアル返品者検出**:顧客アカウントが6ヶ月間で23件の注文に対して47%の返品率を示している。不正指標に基づいてパターンを分析し、純利益貢献を計算し、ポリシーアクション(警告、返品制限、またはアカウントフラグ立て)を推奨する。 +* **保証クレーム紛争**:顧客が12ヶ月の保証期間の第11ヶ月に保証クレームを申告。製品が不適切な使用の兆候を示している。証拠書類を整理し、製造業者の保証除外基準を適用し、顧客へのコミュニケーション文書を起草する。 + +## コア知識 + +### 返品ポリシーロジック + +すべての返品はポリシー評価から始まる。ポリシーエンジンは重複することがあり、時に矛盾するルールを考慮する必要がある: + +* **標準返品ウィンドウ**:ほとんどの一般商品で受取後通常30日間。電子機器は通常15日間。生鮮品は返品不可。家具/マットレスは30〜90日間で特定の状態要件あり。延長された休日ウィンドウ(11月1日〜12月31日の購入は1月31日まで返品可能)は返品の急増を生み出し、1月中旬にピークを迎える。 +* **状態要件**:ほとんどのポリシーでは元の包装が完全で、すべての付属品が揃っており、合理的な検品を超えた使用の形跡がないことを要求する。「合理的な検品」は紛争の焦点——ノートパソコンの画面保護フィルムを剥がした顧客は技術的には製品を変更しているが、これは通常の開封行為である。 +* **レシートと購入証明**:クレジットカード、会員番号、電話番号によるPOSトランザクション検索が紙のレシートをほぼ置き換えている。ギフトレシートは現金返金ではなく購入価格での交換または店舗クレジットを付与する。レシートなし返品には上限がある(通常1件あたり50〜75ドル、12ヶ月間で3回)。最近の最低販売価格で返金される。 +* **再陳列手数料**:開封済みの電子機器(15%)、特注品(20〜25%)、大型/かさばる品物(返品運送の調整が必要)に適用される。欠陥製品や誤配送品は免除。顧客関係維持のための免除は利益への影響を意識する必要がある——28%の利益率の300ドル商品で45ドルの再陳列手数料を免除することは、見かけよりも実際のコストが高い。 +* **クロスチャネル返品**:オンライン購入・店舗返品(BORIS)は顧客が期待するが運用上複雑。オンライン価格と店舗価格が異なる場合がある。返金は現在の棚価格ではなく元の購入価格と一致させる。在庫システムは商品を店舗在庫に戻すか、配送センターへの返品としてフラグ立てできる必要がある。 +* **国際返品**:関税払い戻しの適格性は法定ウィンドウ内(国によって通常3〜5年)の再輸出証明を必要とする。低コスト商品では返品運送コストが商品価値を超えることがある——運賃が商品価値の40%を超える場合は「返品不要返金」を提供する。返品品の通関書類は元の輸出書類とは異なる。 +* **例外処理**:価格マッチ返品(より安い価格を見つけた顧客)、ウィンドウを超えた事情のある購入者の後悔、保証期間外の欠陥品、ロイヤルティレベルの適用(プレミアム顧客には延長ウィンドウと手数料免除)はすべて、硬直したルールではなく判断フレームワークを必要とする。 + +### 検品とグレーディング + +返品品は処分決定を促す一貫したグレーディングを必要とする。速度と精度の間にはトレードオフがある——30秒の目視検査はスループットを処理できるが外観の欠陥を見落とす。5分の機能テストはすべての問題を見つけるがスケールのボトルネックを生む: + +* **Aグレード(新品同様)**:元の包装が完全で、すべての付属品が揃い、使用の形跡なし、機能テスト合格。新品または「開封品」として再陳列でき、全額の利益回収が可能(小売価格の85〜100%)。目標検品時間:45〜90秒。 +* **Bグレード(良好)**:軽微な外観の摩耗、元の包装が損傷または外箱なし、すべての付属品揃い、機能的に正常。「開封品」または「リファービッシュ品」として小売価格の60〜80%で再陳列可能。再包装が必要な場合がある(1件あたり2〜5ドル)。目標検品時間:90〜180秒。 +* **Cグレード(普通)**:目に見える摩耗、傷、または軽微な損傷。単品価値の10%未満の付属品の欠如。機能的だが外観が損傷している。二次チャネル(アウトレット、マーケットプレイス、クリアランス)で小売価格の30〜50%で販売。リファービッシュコストが回収価値の20%未満なら修復可能。 +* **Dグレード(不良/部品取り用)**:機能不全、ひどい損傷、または主要部品の欠如。小売価格の5〜15%の価値で部品や材料として回収。部品回収が不可能なら、リサイクルまたは廃棄へ。 + +グレーディング基準はカテゴリーによって異なる。家電製品は機能テスト(電源オン、画面確認、接続性)が必要で、1件あたり2〜4分追加される。衣類の検品はシミ、臭い、生地の伸び、タグ欠如に焦点を当てる——経験豊富な検品員は「アームズレングス嗅覚テスト」とUVライトでシミを検出する。衛生規制により、化粧品や個人ケア用品は一度開封されると再陳列がほぼ不可能になる。 + +### 処分決定ツリー + +処分は返品が価値を回収するか利益を損なうかが決まる環節。経路決定は経済性によって促される: + +* **新品として再陳列**:包装完全なAグレード品のみ。必要な機能/安全テストを通過する必要がある。再ラベル貼りや再シールは規制上の問題を引き起こす可能性がある(「新品」と表示することに関するFTCの執行)。再陳列コスト(1件あたり3〜8ドル)が回収価値に対して小さい高利益商品に最適。 +* **再包装して「開封品」として販売**:包装が損傷したAグレード品またはBグレード品。再包装コスト(5〜15ドル、複雑さによる)は開封品価格と次の段階のチャネルの差益で正当化される必要がある。電子機器と家電は理想的。 +* **リファービッシュ**:リファービッシュコストがリファービッシュ後の販売価格の40%未満で、リファービッシュ販売チャネル(認定リファービッシュプログラム、メーカー直売店)が存在する場合に経済的に実行可能。高級電子機器、電動工具、家電で一般的。専用のリファービッシュステーション、スペアパーツ在庫、再テスト能力が必要。 +* **クリアランス**:Cグレードと一部のBグレード品で、再包装/リファービッシュが合理的でない場合。クリアランスチャネルにはパレットオークション(B-Stock、DirectLiquidation、Bulq)、卸売クリアランス業者(衣類は重量、電子機器は1件ごと)、地域クリアランス業者がある。回収率:小売価格の5〜20%。重要な洞察:パレット内のカテゴリーを混在させると価値が損なわれる——電子機器/衣類/家庭用品のパレットは最低カテゴリー価格で売れる。 +* **寄付**:公正市場価格(FMV)で税控除可能。FMVがクリアランス回収価値を上回り、会社が控除を活用するに十分な税負担がある場合、クリアランスよりも価値がある。ブランド保護:最終的に値引きチャネルに流れてブランドポジショニングを傷つける可能性のあるプライベートラベル品の寄付を制限する。 +* **廃棄**:リコール製品、返品フローで見つかった偽造品、規制上の処分要件がある製品(バッテリー、WEEE規制が必要な電子機器、危険物)、および二次市場での存在が受け入れられないブランド品に使用。コンプライアンスと税務書類のために廃棄証明が必要。 + +### 不正検出 + +返品不正は米国の小売業者に年間240億ドル以上の損失をもたらす。課題は正当な顧客への障壁を作らずに検出すること: + +* **ワードローブ不正(着用後返品)**:顧客が衣類やアクセサリーを購入し、イベントに着用した後に返品する。指標:休日/イベント前後の返品集中、消臭剤の残留物、首元の化粧品汚れ、「試着」と矛盾した生地の折り目/伸び。対策:UVライトで化粧品汚れを確認、顧客に取り外しを指示していないRFIDタグを使用(タグがない場合は着用を示す)。 +* **レシート不正**:習得・盗取・偽造したレシートを使って盗品を返品し現金を得る。デジタルレシート検索が紙のレシートに取って代わるにつれ減少しているが、依然として発生。対策:すべての現金返金には身分証明書を要求、返品は元の支払い方法と一致させる、身分証明書ごとのレシートなし返品回数を制限する。 +* **すり替え不正(返品スイッチング)**:購入品の包装に偽造品、より安価な品物、または損傷した商品を入れて返品する。電子機器(新しい携帯電話の箱に古い携帯電話を入れて返品)や化粧品(容器をより安価な製品で再充填)でよく見られる。対策:返品時にシリアル番号を確認、重量が期待される製品の重量と一致するか確認、高額品は返金前に詳細検品を実施。 +* **シリアル返品者**:返品率が購入の30%超、または年間返品額が5,000ドル超の顧客。全員が不正というわけではない——本当に優柔不断だったり「ブラケット購入」(複数サイズを購入して試着)をしている人もいる。以下の次元で細分化する:返品理由の一貫性、返品時の製品状態、返品後の純生涯価値。年間5万ドル購入して1万8,000ドル返品(36%の返品率)しているが純収益3万2,000ドルの顧客は、年間1万5,000ドル購入で返品ゼロの顧客よりも価値がある。 +* **ブラケット購入**:複数のサイズ/色を意図的に注文し、大部分を返品する計画。合法的なショッピング行動だが、規模で見るとコストがかかる。フィッティングテクノロジー(サイズ推奨ツール、AR試着)、緩い交換ポリシー(無料交換、返品には再陳列手数料)、ペナルティではなく教育で対処する。 +* **価格裁定**:プロモーション/値引き期間に購入し、別の場所や時間に定価で返品して差益を得る。ポリシーは現在の価格に関わらず、実際の購入価格に返金を結びつける必要がある。クロスチャネル返品が主要な経路。 +* **組織的小売犯罪(ORC)**:複数の店舗/身元にわたって調整された盗難-返品操作。指標:同じ住所の複数の身分証明書による高額返品、頻繁に盗まれるカテゴリー(電子機器、化粧品、健康製品)の返品、地理的集中。損失防止(LP)チームに報告——これは標準的な返品オペレーションの範囲を超えている。 + +### ベンダー回収 + +すべての返品が顧客の責任というわけではない。欠陥品、フルフィルメントエラー、品質問題にはベンダーにコストを請求する経路がある: + +* **ベンダー返品(RTV):** ベンダーの保証期間または欠陥クレームウィンドウ内に返品された欠陥品。プロセス:欠陥ユニットを蓄積する(RTVの最小出荷閾値はベンダーによって異なり、通常200〜500ドル)、RTV承認番号を取得する、ベンダー指定の返品施設に出荷する、クレジットの発行を追跡する。よくある失敗:RTV対象製品を返品倉庫内でベンダーのクレームウィンドウ(通常受取後90日)を超えて放置する。 +* **欠陥クレーム:** 欠陥率がベンダー契約の閾値(通常2〜5%)を超えた場合、超過分について正式な欠陥クレームを提出する。欠陥の書類(写真、検品記録、SKUごとに集計した顧客苦情データ)が必要。ベンダーは異議を唱える——データの品質が回収の成功率を決める。 +* **ベンダー控除:** ベンダーが引き起こした問題(ベンダーの配送センターからの誤出荷、製品のラベル誤り、包装の不具合)については、返品運送と処理人件費を含む全コストを控除する。ベンダーコンプライアンスプログラムと公表された基準と罰則が必要。 +* **クレジット vs 交換 vs 償却:** ベンダーが支払い能力があり迅速に対応できるなら、クレジットを争う。ベンダーが海外にいて回収が困難なら、交換を交渉する。クレームが小さく(200ドル未満)、ベンダーが主要なサプライヤーである場合は、償却を検討し、次の契約交渉に記録する。 + +### 保証管理 + +保証クレームは返品とは異なり、異なるワークフローに従う: + +* **保証 vs 返品:** 返品は顧客が購入を取り消す権利を行使すること(通常30日以内、いかなる理由でも)。保証クレームは顧客が保証対象期間内(90日〜永続)に製品の欠陥を報告すること。異なるシステム、異なるポリシー、異なる財務処理。 +* **製造業者 vs 小売業者の責任:** 小売業者は通常、返品ウィンドウを担当する。製造業者は保証期間を担当する。グレーゾーン:保証期間内に繰り返し故障する「レモン」製品——顧客は返金を求め、製造業者は修理を提供し、小売業者は板挟みになる。 +* **延長保証/保護プラン:** 販売時点で販売され、30〜60%の利益率。延長保証に対するクレームは保証プロバイダー(通常はサードパーティ)が処理する。小売業者の役割はクレーム処理ではなくクレーム申告の支援。よくある苦情:顧客が小売業者の返品ポリシー、製造業者の保証、延長保証の補償を区別できない。 + +## 意思決定フレームワーク + +### カテゴリーと状態による処分分類 + +| カテゴリー | Aグレード | Bグレード | Cグレード | Dグレード | +|---|---|---|---|---| +| 家電製品 | 再陳列(テスト後) | 開封品/リファービッシュ | ROI > 40%ならリファービッシュ、さもなければクリアランス | 部品回収または電子機器廃棄 | +| 衣類 | タグが付いていれば再陳列 | 再包装/アウトレット | 重量別クリアランス | 繊維リサイクル | +| 家庭用品・家具 | 再陳列 | 開封品値引き | クリアランス(ローカル、運送を避ける) | 寄付または廃棄 | +| 健康・美容 | 密封されていれば再陳列 | 廃棄(規制上の理由) | 廃棄 | 廃棄 | +| 書籍・メディア | 再陳列 | 再陳列(値引き) | クリアランス | リサイクル | +| スポーツ用品 | 再陳列 | 開封品 | リファービッシュコスト < 価値の25%ならリファービッシュ | 部品回収または寄付 | +| おもちゃ・ゲーム | 密封されていれば再陳列 | 開封品 | クリアランス | 安全基準を満たすなら寄付 | + +### 不正スコアリングモデル + +各返品を0〜100でスコアリング。65以上でレビューのフラグ立て、80以上で返金を保留: + +| シグナル | スコア | 備考 | +|---|---|---| +| 返品率 > 30%(12ヶ月ローリング) | +15 | カテゴリー基準で調整 | +| 受取後48時間以内の返品 | +5 | 正当な「比較購入」の可能性 | +| 高額電子機器でシリアル番号不一致 | +40 | すり替え不正がほぼ確実 | +| 申告時と受取時の返品理由が不一致 | +10 | 不一致フラグ | +| 同週内の複数回返品 | +10 | 返品率シグナルと累積 | +| 返品住所が出荷住所と異なる | +10 | ギフト返品を除く | +| 製品重量が期待値と5%以上乖離 | +25 | すり替えまたは部品欠如 | +| 顧客アカウント使用期間 < 30日 | +10 | 新規アカウントリスク | +| レシートなし返品 | +15 | レシート不正リスクが高い | +| 高損耗カテゴリーの商品 | +5 | 電子機器、化粧品、デザイナー衣類 | + +### ベンダー回収のROI + +以下の場合にベンダー回収を追求する:`(期待クレジット × 回収確率) > (人件費 + 運送コスト + 関係コスト)`。経験則: + +* クレーム > 500ドル:必ず追求。50%の回収確率でも計算が成立する。 +* クレーム 200〜500ドル:ベンダーが実用的なRTVプログラムを持ちバルク出荷が可能なら追求。 +* クレーム < 200ドル:閾値に達するまで蓄積するか、次の発注に対して差し引く。個別ユニットは単独で出荷しない。 +* 海外ベンダー:最低閾値を1,000ドルに引き上げる。処理時間が30%増加することを見込む。 + +### 返品ポリシー例外処理ロジック + +返品が標準ポリシーを超えた場合、以下の順序で評価する: + +1. **製品に欠陥があるか?** ある場合、ウィンドウや状態に関わらず受け入れる。欠陥品は顧客ではなく会社の問題。 +2. **高価値の顧客か?**(顧客生涯価値で上位10%)そうであれば、受け入れて標準返金。顧客を維持する計算はほぼ常に例外を支持する。 +3. **リクエストは中立的な観察者にとって合理的か?** 顧客が11月に購入した冬物を3月に返品する(4ヶ月、30日ウィンドウを超える)のは理解できる。顧客が6月に購入した水着を12月に返品するのはあまり合理的ではない。 +4. **処分の結果は何か?** 製品が再陳列できる(Aグレード)なら、例外処理のコストは微々たるもの——承認。Cグレード以下なら、例外処理は実際の利益を損なう。 +5. **承認が先例リスクをもたらすか?** 記録された状況に対する一度限りの例外は、ほとんど先例を作らない。公開された例外処理(ソーシャルメディアの苦情)は常に先例を作る。 + +## 重要なエッジケース + +これらは標準ワークフローでは処理できない状況である。必要に応じて特定のプロジェクトの運用マニュアルに展開できるよう、ここに簡単なサマリーを含める。 + +1. **ファームウェアが消去された高額電子機器:** 顧客が「欠陥あり」として返品したノートパソコンが、出荷時設定にリセットされており、6ヶ月分のバッテリーサイクル数を示している。デバイスは大量に使用されており、今は「欠陥品」として返品されている——グレーディングはクリーンなソフトウェア状態を超える必要がある。 +2. **不適切に梱包された危険物の返品:** 顧客がリチウム電池や化学品を含む製品を、必要なDOT包装なしで返品する。受け取ると規制上の責任が生じる。拒否すると顧客サービスの問題になる。製品は標準の小包返品輸送で返送できない。 +3. **関税が絡む国境を越えた返品:** 国際顧客が関税を支払って輸出した製品を返品する。関税払い戻し申請には顧客が持っていない特定の書類が必要。返品運送コストが製品価値を超える可能性がある。 +4. **コンテンツ制作後のインフルエンサーのバルク返品:** ソーシャルメディアのインフルエンサーが20点以上の商品を購入し、コンテンツを制作した後、1点を除いてすべて返品する。技術的にはポリシーに準拠しているが、ブランド価値はすでに抽出されている。開封動画が同じ商品を展示しているため、再陳列の課題が増大する。 +5. **顧客が改造した後の製品の保証クレーム:** 顧客が製品内のコンポーネントを交換し(例:ノートパソコンのRAMをアップグレード)、その後無関係な別のコンポーネント(例:画面の誤作動)に保証上の欠陥があると主張する。改造はクレームされた欠陥を保証の対象外にするかもしれないし、しないかもしれない。 +6. **高価値顧客かつ頻繁な返品者:** 年間8万ドル支出で42%の返品率の顧客。返品を禁止すると利益を生む顧客を失う。行動を受け入れると継続を奨励する。単純な返品率を超えた細かな顧客セグメンテーションが必要。 +7. **リコール製品の返品:** 顧客がアクティブな安全リコール対象の製品を返品する。標準の返品プロセスは誤り——リコール品はリコールプログラムに従うべきで、返品プログラムではない。混在させると責任とレポートのエラーが生じる。 +8. **現在の価格が購入価格より高いギフトレシートの返品:** ギフト受取者がギフトレシートを持って返品に来る。その商品は現在、贈り主が支払った価格より30ドル高く販売されている。ポリシーは購入価格での返金を定めているが、顧客は棚価格を見てその金額を期待している。 + +## コミュニケーションパターン + +### トーンの調整 + +* **標準的な返金確認:** 温かく、効率的に。プロセスではなく、解決金額と期間を最初に述べる。 +* **返品拒否:** 共感的だが明確に。具体的なポリシーを説明し、代替案(交換、店舗クレジット、保証クレーム)を提供し、エスカレーションパスを提供する。顧客を選択肢なしにしない。 +* **不正調査による保留:** 中立的、事実に基づいて。「お客様の返品をさらに処理するのに時間が必要です」——顧客に「不正」や「調査」という言葉を絶対に使わない。タイムラインを提供する。不正指標の記録は内部コミュニケーションで行う。 +* **再陳列手数料の説明:** 透明に。手数料の対象(検品、再包装、価値の損失)を説明し、意外な結果を避けるために処理前に純返金額を確認する。 +* **ベンダーRTVクレーム:** 専門的、証拠に基づいて。欠陥データ、写真、SKUごとの返品量を含め、欠陥クレームをカバーするベンダー契約の条項を引用する。 + +### 重要テンプレート + +以下に簡単なテンプレートを示す。不正、顧客体験、逆物流のワークフローに合わせて、本番使用前に調整すること。 + +**RMA承認:** 件名:`Return Approved — Order #{order_id}`。提供:RMA番号、返品配送指示、期待される返金タイムライン、状態要件。 + +**返金確認:** 金額を最初に述べる:「${amount}の返金を\[支払い方法]に処理しました。\[X]営業日をお待ちください。」 + +**不正保留通知:** 「お客様の返品は当社の処理チームによって審査されています。\[X]営業日以内に更新情報をお伝えする予定です。ご忍耐いただき、ありがとうございます。」 + +## エスカレーションプロトコル + +### 自動エスカレーショントリガー + +| トリガー | アクション | タイムライン | +|---|---|---| +| 返品価値 > 5,000ドル(単品) | 返金前にスーパーバイザーの承認が必要 | 処理前 | +| 不正スコア ≥ 80 | 返金を保留し、不正レビューチームに転送 | 即時 | +| 顧客がクレジットカードチャージバックを同時に申告 | 返品処理を停止し、支払いチームと調整 | 1時間以内 | +| 製品がリコール品として識別 | リコールコーディネーターに転送し、標準返品として処理しない | 即時 | +| SKUに対するベンダーの欠陥率が5%を超える | マーチャンダイジングとベンダー管理に通知 | 24時間以内 | +| 同一顧客が12ヶ月以内に3回目のポリシー例外をリクエスト | 承認前にマネージャーのレビューが必要 | 処理前 | +| 返品フローで疑わしい偽造品が発見 | 処理から取り出し、写真を撮り、損失防止とブランド保護に通知 | 即時 | +| 返品に規制対象製品が含まれる(医薬品、危険物、医療機器) | コンプライアンスチームに転送 | 即時 | + +### エスカレーションチェーン + +レベル1(返品担当者) → レベル2(チームスーパーバイザー、2時間) → レベル3(返品マネージャー、8時間) → レベル4(オペレーションディレクター、24時間) → レベル5(副社長、48時間以上または単品返品 > 25,000ドル) + +## パフォーマンス指標 + +| 指標 | 目標 | 危険フラグ | +|---|---|---| +| 返品処理時間(受取から返金まで) | < 48時間 | > 96時間 | +| 検品精度(監査でのグレード一致性) | > 95% | < 88% | +| 再陳列率(返品のうち新品/開封品として再陳列される割合) | > 45% | < 30% | +| 不正検出率(確認された不正のうち捕捉された割合) | > 80% | < 60% | +| 誤検知率(フラグが立てられた正当な返品の割合) | < 3% | > 8% | +| ベンダー回収率(回収額 / 適格額) | > 70% | < 45% | +| 顧客満足度(返品後CSAT) | > 4.2/5.0 | < 3.5/5.0 | +| 返品処理1件あたりのコスト | < $8.00 | > $15.00 | + +## その他のリソース + +* このスキルを本番使用に移行する前に、グレーディング基準、不正レビュー閾値、返金承認マトリックスと組み合わせること。 +* 在庫補充基準、危険物返品処理、クリアランスルールは、実行決定を担う運用チームの近くに置くこと。 diff --git a/docs/ja-JP/skills/rules-distill/SKILL.md b/docs/ja-JP/skills/rules-distill/SKILL.md new file mode 100644 index 00000000..61a2de98 --- /dev/null +++ b/docs/ja-JP/skills/rules-distill/SKILL.md @@ -0,0 +1,264 @@ +--- +name: rules-distill +description: "スキルをスキャンしてドメイン横断的な原則を抽出し、ルールに蒸留する——既存のルールファイルへの追記、修正、または新規作成" +origin: ECC +--- + +# ルール蒸留 + +インストール済みのスキルをスキャンし、複数のスキルに現れる共通原則を抽出して、ルールとして蒸留する——既存のルールファイルに追記、時代遅れの内容を修正、または新しいルールファイルを作成する。 + +「決定論的収集 + LLM判断」原則を適用する:スクリプトが事実を網羅的に収集し、その後LLMが完全なコンテキストを通読して裁決を下す。 + +## 使用場面 + +* 定期的なルールメンテナンス(月次または新しいスキルのインストール後) +* スキル棚卸し後、ルールにすべきパターンが見つかった場合 +* 使用中のスキルと比較してルールが不完全に感じられる場合 + +## 動作原理 + +ルール蒸留プロセスは3つのフェーズに従う: + +### フェーズ 1:棚卸し(決定論的収集) + +#### 1a. スキルインベントリの収集 + +```bash +bash ~/.claude/skills/rules-distill/scripts/scan-skills.sh +``` + +#### 1b. ルールインデックスの収集 + +```bash +bash ~/.claude/skills/rules-distill/scripts/scan-rules.sh +``` + +#### 1c. ユーザーへの提示 + +``` +ルール蒸留 — フェーズ 1:棚卸し +──────────────────────────────────────── +スキル:{N} 個のファイルをスキャン +ルール:{M} 個のファイルをインデックス化({K} 個の見出しを含む) + +クロスリーディング分析を実行中... +``` + +### フェーズ 2:通読、マッチング、裁決(LLM判断) + +抽出とマッチングは単一の処理で統合的に行われる。ルールファイルは十分に小さく(合計約800行)、LLMに全文を提供できる——grepによる事前フィルタリングは不要。 + +#### バッチ処理 + +スキルの説明に基づいてスキルを**トピッククラスター**にグループ化する。各クラスターは、完全なルールテキストを提供されたサブエージェントで分析される。 + +#### バッチ間のマージ + +全バッチ完了後、バッチ候補をマージする: + +* 同一または重複する原則を持つ候補を重複排除する +* 「2+スキル」要件を**全**バッチの統合証拠で再確認——各バッチでは1つのスキルにのみ現れるが、合計で2+スキルに現れる原則は有効 + +#### サブエージェントプロンプト + +汎用エージェントを起動するために以下のプロンプトを使用する: + +```` +あなたはスキルをクロスリーディングして、ルールに昇格すべき原則を抽出するアナリストです。 + +## 入力 +- スキル:{このバッチのスキルの全文} +- 既存のルール:{全ルールファイルの全文} + +## 抽出基準 + +**以下の条件を全て**満たす場合のみ候補原則を含める: + +1. **2+スキルに現れる**:1つのスキルにのみ現れる原則はそのスキルに留める +2. **実行可能な行動変容**:「Xをする」または「Yをしない」という形で書ける——「Xが重要」ではない +3. **明確な違反リスク**:この原則を無視すると何が問題になるか(1文) +4. **ルールにまだ存在しない**:全ルールテキストを確認——異なる言い回しで表現された概念も含めて + +## マッチングと裁決 + +各候補原則を全ルールテキストと照合して裁決を下す: + +- **追記**:既存のルールファイルの既存セクションに追加 +- **修正**:既存のルールの内容が不正確または不十分——修正案を提案 +- **新セクション**:既存のルールファイルに新しいセクションを追加 +- **新ファイル**:新しいルールファイルを作成 +- **対応済み**:既存のルールで十分にカバー済み(言い回しが異なっても) +- **過度に具体的**:スキルレベルに留めるべき + +## 出力フォーマット(各候補原則) + +```json +{ + "principle": "1〜2文、'Xをする' / 'Yをしない' の形式", + "evidence": ["スキル名: §セクション", "スキル名: §セクション"], + "violation_risk": "1文", + "verdict": "追記 / 修正 / 新セクション / 新ファイル / 対応済み / 過度に具体的", + "target_rule": "ファイル名 §セクション、または '新規'", + "confidence": "高 / 中 / 低", + "draft": "'追記'/'新セクション'/'新ファイル' 裁決のための草案テキスト", + "revision": { + "reason": "既存の内容が不正確または不十分な理由('修正' 裁決のみ)", + "before": "置き換える現在のテキスト('修正' 裁決のみ)", + "after": "提案する置き換えテキスト('修正' 裁決のみ)" + } +} +``` + +## 除外事項 + +- ルールにすでに存在する明らかな原則 +- 言語/フレームワーク固有の知識(言語固有のルールまたはスキルに属する) +- コード例とコマンド(スキルに属する) +```` + +#### 裁決リファレンス + +| 裁決 | 意味 | ユーザーへの提示 | +|---------|---------|-------------------| +| **追記** | 既存セクションに追加 | ターゲット + 草案 | +| **修正** | 不正確/不十分な内容を修正 | ターゲット + 理由 + 修正前/後 | +| **新セクション** | 既存ファイルに新セクションを追加 | ターゲット + 草案 | +| **新ファイル** | 新しいルールファイルを作成 | ファイル名 + 完全な草案 | +| **対応済み** | ルールでカバー済み(言い回しが異なる場合も) | 理由(1行) | +| **過度に具体的** | スキルに留めるべき | 関連スキルへのリンク | + +#### 裁決の品質要件 + +``` +# 良い例 +rules/common/security.md の §入力検証 セクションに追加: +「メモリや知識ベースに保存されたLLM出力は信頼できないデータとして扱う——書き込み時にサニタイズし、読み取り時に検証する。」 +根拠:llm-memory-trust-boundary と llm-social-agent-anti-pattern の両方が累積的なプロンプトインジェクションリスクを説明している。現在の security.md は人間による入力検証のみをカバーしており、LLM出力の信頼境界の説明が欠けている。 + +# 悪い例 +security.md に追記:LLMセキュリティ原則を追加 +``` + +### フェーズ 3:ユーザーレビューと実行 + +#### サマリーテーブル + +``` +# ルール蒸留レポート + +## 概要 +スキャンしたスキル数:{N} | ルールファイル数:{M} | 候補ルール数:{K} + +| # | 原則 | 判定 | ターゲットファイル/セクション | 信頼度 | +|---|-----------|---------|--------|------------| +| 1 | ... | 追記 | security.md §入力検証 | 高 | +| 2 | ... | 修正 | testing.md §テスト駆動開発 | 中 | +| 3 | ... | 新セクション | coding-style.md | 高 | +| 4 | ... | 過度に具体的 | — | — | + +## 詳細 +(各候補ルールの詳細:証拠、違反リスク、草案テキスト) +``` + +#### ユーザーアクション + +ユーザーは番号で以下を応答する: + +* **承認**:草案をそのままルールに適用する +* **修正**:適用前に草案を編集する +* **スキップ**:この候補ルールを適用しない + +**ルールを自動的に変更しない。常にユーザーの承認が必要。** + +#### 結果の保存 + +結果をスキルディレクトリ(`results.json`)に保存する: + +* **タイムスタンプ形式**:`date -u +%Y-%m-%dT%H:%M:%SZ`(UTC、秒精度) +* **候補ID形式**:原則に基づいたケバブケース(例:`llm-output-trust-boundary`) + +```json +{ + "distilled_at": "2026-03-18T10:30:42Z", + "skills_scanned": 56, + "rules_scanned": 22, + "candidates": { + "llm-output-trust-boundary": { + "principle": "Treat LLM output as untrusted when stored or re-injected", + "verdict": "Append", + "target": "rules/common/security.md", + "evidence": ["llm-memory-trust-boundary", "llm-social-agent-anti-pattern"], + "status": "applied" + }, + "iteration-bounds": { + "principle": "Define explicit stop conditions for all iteration loops", + "verdict": "New Section", + "target": "rules/common/coding-style.md", + "evidence": ["iterative-retrieval", "continuous-agent-loop", "agent-harness-construction"], + "status": "skipped" + } + } +} +``` + +## 例 + +### エンドツーエンド実行 + +``` +$ /rules-distill + +ルール蒸留 — フェーズ 1:棚卸し +──────────────────────────────────────── +スキル:56個のファイルをスキャン済み +ルール:22個のファイル(75個の見出しをインデックス化) + +クロスリーディング分析を実行中... + +[サブエージェント分析:バッチ 1 (agent/meta スキル) ...] +[サブエージェント分析:バッチ 2 (coding/pattern スキル) ...] +[バッチ間マージ:2件の重複を削除、1件のクロスバッチ候補が昇格] + +# ルール蒸留レポート + +## サマリー +スキャン済みスキル:56 | ルール:22個のファイル | 候補:4 + +| # | 原則 | 判定 | ターゲット | 信頼度 | +|---|-----------|---------|--------|------------| +| 1 | LLM出力:再利用前に正規化、型チェック、サニタイズ | 新セクション | coding-style.md | 高 | +| 2 | 反復ループに明示的な停止条件を定義する | 新セクション | coding-style.md | 高 | +| 3 | タスクの途中ではなくフェーズ境界でコンテキストを圧縮する | 追記 | performance.md §コンテキストウィンドウ | 高 | +| 4 | ビジネスロジックをI/Oフレームワーク型から分離する | 新セクション | patterns.md | 高 | + +## 詳細 + +### 1. LLM出力検証 +判定:coding-style.md に新セクションを作成 +証拠:parallel-subagent-batch-merge, llm-social-agent-anti-pattern, llm-memory-trust-boundary +違反リスク:LLM出力の形式ドリフト、型不一致、構文エラーにより下流処理がクラッシュする +草案: + ## LLM出力検証 + LLM出力を再利用する前に、正規化、型チェック、サニタイズを行う... + 参照スキル:parallel-subagent-batch-merge, llm-memory-trust-boundary + +[... 候補 2〜4 の詳細 ...] + +各候補を番号で承認、修正、スキップ: +> ユーザー:1, 3 を承認。2, 4 をスキップ。 + +✓ 適用済み:coding-style.md §LLM出力検証 +✓ 適用済み:performance.md §コンテキストウィンドウ管理 +✗ スキップ:反復境界 +✗ スキップ:境界型変換 + +results.json に結果を保存済み +``` + +## 設計原則 + +* **何をするかではなく、何か**:原則のみを抽出する(ルールの範囲)。コード例とコマンドはスキルに留める。 +* **ソースへのリンクを維持**:草案テキストには `参照スキル:[名前]` への参照を含め、読者が詳細な「どうするか」を見つけられるようにする。 +* **決定論的収集、LLM判断**:スクリプトが網羅性を保証し、LLMがコンテキスト理解を保証する。 +* **抽象化防止策**:3層フィルター(2+スキルの証拠、実行可能行動テスト、違反リスク)により、過度に抽象的な原則がルールに入ることを防ぐ。 diff --git a/docs/ja-JP/skills/rust-patterns/SKILL.md b/docs/ja-JP/skills/rust-patterns/SKILL.md new file mode 100644 index 00000000..5c115147 --- /dev/null +++ b/docs/ja-JP/skills/rust-patterns/SKILL.md @@ -0,0 +1,499 @@ +--- +name: rust-patterns +description: 慣用的なRustパターン、所有権、エラー処理、トレイト、並行処理、および安全で高性能なアプリケーションを構築するためのベストプラクティス。 +origin: ECC +--- + +# Rust 開発パターン + +安全で高性能かつ保守性の高いアプリケーションを構築するための慣用的なRustパターンとベストプラクティス。 + +## 使用場面 + +* 新しいRustコードを書く場合 +* Rustコードをレビューする場合 +* 既存のRustコードをリファクタリングする場合 +* クレート構造とモジュールレイアウトを設計する場合 + +## 動作原理 + +このスキルは6つの重要な領域で慣用的なRustの規約を強制する:コンパイル時のデータ競合防止のための所有権と借用、ライブラリでは`thiserror`、アプリケーションでは`anyhow`を使用した`Result`/`?`エラー伝播、不正な状態を表現不可能にする列挙型と完全パターンマッチング、ゼロコスト抽象化のためのトレイトとジェネリクス、`Arc>`、チャンネル、async/awaitによる安全な並行処理、ドメインで整理された最小化された`pub`インターフェース。 + +## コア原則 + +### 1. 所有権と借用 + +Rustの所有権システムはコンパイル時にデータ競合とメモリエラーを防ぐ。 + +```rust +// Good: Pass references when you don't need ownership +fn process(data: &[u8]) -> usize { + data.len() +} + +// Good: Take ownership only when you need to store or consume +fn store(data: Vec) -> Record { + Record { payload: data } +} + +// Bad: Cloning unnecessarily to avoid borrow checker +fn process_bad(data: &Vec) -> usize { + let cloned = data.clone(); // Wasteful — just borrow + cloned.len() +} +``` + +### 柔軟な所有権のための `Cow` の使用 + +```rust +use std::borrow::Cow; + +fn normalize(input: &str) -> Cow<'_, str> { + if input.contains(' ') { + Cow::Owned(input.replace(' ', "_")) + } else { + Cow::Borrowed(input) // Zero-cost when no mutation needed + } +} +``` + +## エラー処理 + +### `Result` と `?` を使用する——本番環境では `unwrap()` を絶対に使わない + +```rust +// Good: Propagate errors with context +use anyhow::{Context, Result}; + +fn load_config(path: &str) -> Result { + let content = std::fs::read_to_string(path) + .with_context(|| format!("failed to read config from {path}"))?; + let config: Config = toml::from_str(&content) + .with_context(|| format!("failed to parse config from {path}"))?; + Ok(config) +} + +// Bad: Panics on error +fn load_config_bad(path: &str) -> Config { + let content = std::fs::read_to_string(path).unwrap(); // Panics! + toml::from_str(&content).unwrap() +} +``` + +### ライブラリエラーには `thiserror`、アプリケーションエラーには `anyhow` + +```rust +// Library code: structured, typed errors +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum StorageError { + #[error("record not found: {id}")] + NotFound { id: String }, + #[error("connection failed")] + Connection(#[from] std::io::Error), + #[error("invalid data: {0}")] + InvalidData(String), +} + +// Application code: flexible error handling +use anyhow::{bail, Result}; + +fn run() -> Result<()> { + let config = load_config("app.toml")?; + if config.workers == 0 { + bail!("worker count must be > 0"); + } + Ok(()) +} +``` + +### ネストしたマッチの代わりに `Option` コンビネーターを優先する + +```rust +// Good: Combinator chain +fn find_user_email(users: &[User], id: u64) -> Option { + users.iter() + .find(|u| u.id == id) + .map(|u| u.email.clone()) +} + +// Bad: Deeply nested matching +fn find_user_email_bad(users: &[User], id: u64) -> Option { + match users.iter().find(|u| u.id == id) { + Some(user) => match &user.email { + email => Some(email.clone()), + }, + None => None, + } +} +``` + +## 列挙型とパターンマッチング + +### 状態を列挙型としてモデル化する + +```rust +// Good: Impossible states are unrepresentable +enum ConnectionState { + Disconnected, + Connecting { attempt: u32 }, + Connected { session_id: String }, + Failed { reason: String, retries: u32 }, +} + +fn handle(state: &ConnectionState) { + match state { + ConnectionState::Disconnected => connect(), + ConnectionState::Connecting { attempt } if *attempt > 3 => abort(), + ConnectionState::Connecting { .. } => wait(), + ConnectionState::Connected { session_id } => use_session(session_id), + ConnectionState::Failed { retries, .. } if *retries < 5 => retry(), + ConnectionState::Failed { reason, .. } => log_failure(reason), + } +} +``` + +### 完全マッチング——ビジネスロジックではワイルドカードを使わない + +```rust +// Good: Handle every variant explicitly +match command { + Command::Start => start_service(), + Command::Stop => stop_service(), + Command::Restart => restart_service(), + // Adding a new variant forces handling here +} + +// Bad: Wildcard hides new variants +match command { + Command::Start => start_service(), + _ => {} // Silently ignores Stop, Restart, and future variants +} +``` + +## トレイトとジェネリクス + +### ジェネリックを受け取り、具体的な型を返す + +```rust +// Good: Generic input, concrete output +fn read_all(reader: &mut impl Read) -> std::io::Result> { + let mut buf = Vec::new(); + reader.read_to_end(&mut buf)?; + Ok(buf) +} + +// Good: Trait bounds for multiple constraints +fn process(item: T) -> String { + format!("processed: {item}") +} +``` + +### 動的ディスパッチにトレイトオブジェクトを使用する + +```rust +// Use when you need heterogeneous collections or plugin systems +trait Handler: Send + Sync { + fn handle(&self, request: &Request) -> Response; +} + +struct Router { + handlers: Vec>, +} + +// Use generics when you need performance (monomorphization) +fn fast_process(handler: &H, request: &Request) -> Response { + handler.handle(request) +} +``` + +### 型安全のためにNewTypeパターンを使用する + +```rust +// Good: Distinct types prevent mixing up arguments +struct UserId(u64); +struct OrderId(u64); + +fn get_order(user: UserId, order: OrderId) -> Result { + // Can't accidentally swap user and order IDs + todo!() +} + +// Bad: Easy to swap arguments +fn get_order_bad(user_id: u64, order_id: u64) -> Result { + todo!() +} +``` + +## 構造体とデータモデリング + +### 複雑な構築にはビルダーパターンを使用する + +```rust +struct ServerConfig { + host: String, + port: u16, + max_connections: usize, +} + +impl ServerConfig { + fn builder(host: impl Into, port: u16) -> ServerConfigBuilder { + ServerConfigBuilder { host: host.into(), port, max_connections: 100 } + } +} + +struct ServerConfigBuilder { host: String, port: u16, max_connections: usize } + +impl ServerConfigBuilder { + fn max_connections(mut self, n: usize) -> Self { self.max_connections = n; self } + fn build(self) -> ServerConfig { + ServerConfig { host: self.host, port: self.port, max_connections: self.max_connections } + } +} + +// Usage: ServerConfig::builder("localhost", 8080).max_connections(200).build() +``` + +## イテレーターとクロージャー + +### 手動ループの代わりにイテレーターチェーンを優先する + +```rust +// Good: Declarative, lazy, composable +let active_emails: Vec = users.iter() + .filter(|u| u.is_active) + .map(|u| u.email.clone()) + .collect(); + +// Bad: Imperative accumulation +let mut active_emails = Vec::new(); +for user in &users { + if user.is_active { + active_emails.push(user.email.clone()); + } +} +``` + +### 型注釈付きの `collect()` を使用する + +```rust +// Collect into different types +let names: Vec<_> = items.iter().map(|i| &i.name).collect(); +let lookup: HashMap<_, _> = items.iter().map(|i| (i.id, i)).collect(); +let combined: String = parts.iter().copied().collect(); + +// Collect Results — short-circuits on first error +let parsed: Result, _> = strings.iter().map(|s| s.parse()).collect(); +``` + +## 並行処理 + +### 共有可変状態には `Arc>` を使用する + +```rust +use std::sync::{Arc, Mutex}; + +let counter = Arc::new(Mutex::new(0)); +let handles: Vec<_> = (0..10).map(|_| { + let counter = Arc::clone(&counter); + std::thread::spawn(move || { + let mut num = counter.lock().expect("mutex poisoned"); + *num += 1; + }) +}).collect(); + +for handle in handles { + handle.join().expect("worker thread panicked"); +} +``` + +### メッセージパッシングにチャンネルを使用する + +```rust +use std::sync::mpsc; + +let (tx, rx) = mpsc::sync_channel(16); // Bounded channel with backpressure + +for i in 0..5 { + let tx = tx.clone(); + std::thread::spawn(move || { + tx.send(format!("message {i}")).expect("receiver disconnected"); + }); +} +drop(tx); // Close sender so rx iterator terminates + +for msg in rx { + println!("{msg}"); +} +``` + +### Tokioを使用した非同期プログラミング + +```rust +use tokio::time::Duration; + +async fn fetch_with_timeout(url: &str) -> Result { + let response = tokio::time::timeout( + Duration::from_secs(5), + reqwest::get(url), + ) + .await + .context("request timed out")? + .context("request failed")?; + + response.text().await.context("failed to read body") +} + +// Spawn concurrent tasks +async fn fetch_all(urls: Vec) -> Vec> { + let handles: Vec<_> = urls.into_iter() + .map(|url| tokio::spawn(async move { + fetch_with_timeout(&url).await + })) + .collect(); + + let mut results = Vec::with_capacity(handles.len()); + for handle in handles { + results.push(handle.await.unwrap_or_else(|e| panic!("spawned task panicked: {e}"))); + } + results +} +``` + +## アンセーフコード + +### Unsafe を使用できる場合 + +```rust +// Acceptable: FFI boundary with documented invariants (Rust 2024+) +/// # Safety +/// `ptr` must be a valid, aligned pointer to an initialized `Widget`. +unsafe fn widget_from_raw<'a>(ptr: *const Widget) -> &'a Widget { + // SAFETY: caller guarantees ptr is valid and aligned + unsafe { &*ptr } +} + +// Acceptable: Performance-critical path with proof of correctness +// SAFETY: index is always < len due to the loop bound +unsafe { slice.get_unchecked(index) } +``` + +### Unsafe を使用してはいけない場合 + +```rust +// Bad: Using unsafe to bypass borrow checker +// Bad: Using unsafe for convenience +// Bad: Using unsafe without a Safety comment +// Bad: Transmuting between unrelated types +``` + +## モジュールシステムとクレート構造 + +### 型ではなくドメインで整理する + +```text +my_app/ +├── src/ +│ ├── main.rs +│ ├── lib.rs +│ ├── auth/ # ドメインモジュール +│ │ ├── mod.rs +│ │ ├── token.rs +│ │ └── middleware.rs +│ ├── orders/ # ドメインモジュール +│ │ ├── mod.rs +│ │ ├── model.rs +│ │ └── service.rs +│ └── db/ # インフラストラクチャ +│ ├── mod.rs +│ └── pool.rs +├── tests/ # 統合テスト +├── benches/ # ベンチマーク +└── Cargo.toml +``` + +### 可視性——露出を最小化する + +```rust +// Good: pub(crate) for internal sharing +pub(crate) fn validate_input(input: &str) -> bool { + !input.is_empty() +} + +// Good: Re-export public API from lib.rs +pub mod auth; +pub use auth::AuthMiddleware; + +// Bad: Making everything pub +pub fn internal_helper() {} // Should be pub(crate) or private +``` + +## ツール統合 + +### 基本コマンド + +```bash +# Build and check +cargo build +cargo check # Fast type checking without codegen +cargo clippy # Lints and suggestions +cargo fmt # Format code + +# Testing +cargo test +cargo test -- --nocapture # Show println output +cargo test --lib # Unit tests only +cargo test --test integration # Integration tests only + +# Dependencies +cargo audit # Security audit +cargo tree # Dependency tree +cargo update # Update dependencies + +# Performance +cargo bench # Run benchmarks +``` + +## クイックリファレンス:Rustのイディオム + +| イディオム | 説明 | +|-------|-------------| +| 借用、クローンではなく | 所有権が必要でなければ `&T` を渡し、クローンしない | +| 不正な状態を表現不可能にする | 列挙型を使用して有効な状態のみをモデル化する | +| `unwrap()` より `?` | エラーを伝播し、ライブラリ/本番コードでパニックしない | +| 検証より解析 | 境界で非構造化データを型付き構造体に変換する | +| 型安全のためのNewtype | 基本型をnewtypeでラップして引数の取り違えを防ぐ | +| ループよりイテレーターを優先 | 宣言的なチェーンはより明確で通常より高速 | +| Resultに `#[must_use]` を使用 | 呼び出し元が戻り値を処理することを保証する | +| 柔軟な所有権のために `Cow` を使用 | 借用で十分な場合にアロケーションを避ける | +| 完全マッチング | ビジネスクリティカルな列挙型でワイルドカード `_` を使わない | +| `pub` インターフェースを最小化 | 内部APIには `pub(crate)` を使用 | + +## 避けるべきアンチパターン + +```rust +// Bad: .unwrap() in production code +let value = map.get("key").unwrap(); + +// Bad: .clone() to satisfy borrow checker without understanding why +let data = expensive_data.clone(); +process(&original, &data); + +// Bad: Using String when &str suffices +fn greet(name: String) { /* should be &str */ } + +// Bad: Box in libraries (use thiserror instead) +fn parse(input: &str) -> Result> { todo!() } + +// Bad: Ignoring must_use warnings +let _ = validate(input); // Silently discarding a Result + +// Bad: Blocking in async context +async fn bad_async() { + std::thread::sleep(Duration::from_secs(1)); // Blocks the executor! + // Use: tokio::time::sleep(Duration::from_secs(1)).await; +} +``` + +**覚えておくこと**:コンパイルが通れば、おそらく正しい——ただし `unwrap()` を避け、`unsafe` を最小化し、型システムを活用することが前提。 diff --git a/docs/ja-JP/skills/rust-testing/SKILL.md b/docs/ja-JP/skills/rust-testing/SKILL.md new file mode 100644 index 00000000..17dc1235 --- /dev/null +++ b/docs/ja-JP/skills/rust-testing/SKILL.md @@ -0,0 +1,502 @@ +--- +name: rust-testing +description: 単体テスト、統合テスト、非同期テスト、プロパティベーステスト、モック、カバレッジを含むRustテストパターン。TDD方法論に従う。 +origin: ECC +--- + +# Rust テストパターン + +TDD方法論に従って信頼性が高く保守しやすいテストを書くための包括的なRustテストパターン。 + +## 使用場面 + +* 新しいRustの関数、メソッド、またはトレイトを書く場合 +* 既存のコードにテストカバレッジを追加する場合 +* パフォーマンスクリティカルなコードのベンチマークを作成する場合 +* 入力検証にプロパティベーステストを実装する場合 +* RustプロジェクトでTDDワークフローに従う場合 + +## 動作原理 + +1. **ターゲットコードを特定する** — テストする関数、トレイト、またはモジュールを見つける +2. **テストを書く** — `#[cfg(test)]` モジュール内で `#[test]` を使用、rstest でパラメータ化テスト、または proptest でプロパティベーステスト +3. **依存関係をモックする** — mockall を使用してテスト対象のユニットを分離する +4. **テストを実行する (RED)** — テストが期待通りに失敗することを確認する +5. **実装する (GREEN)** — テストを通過するための最小限のコードを書く +6. **リファクタリングする** — テストを通過したまま、コードを改善する +7. **カバレッジを確認する** — cargo-llvm-cov を使用し、80%以上を目標にする + +## RustのTDDワークフロー + +### RED-GREEN-REFACTOR サイクル + +``` +RED → まず失敗するテストを書く +GREEN → テストを通過する最小限のコードを書く +REFACTOR → テストを通過したままコードをリファクタリングする +REPEAT → 次の要件に進む +``` + +### Rustでの段階的TDD + +```rust +// RED: Write test first, use todo!() as placeholder +pub fn add(a: i32, b: i32) -> i32 { todo!() } + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_add() { assert_eq!(add(2, 3), 5); } +} +// cargo test → panics at 'not yet implemented' +``` + +```rust +// GREEN: Replace todo!() with minimal implementation +pub fn add(a: i32, b: i32) -> i32 { a + b } +// cargo test → PASS, then REFACTOR while keeping tests green +``` + +## 単体テスト + +### モジュールレベルのテスト整理 + +```rust +// src/user.rs +pub struct User { + pub name: String, + pub email: String, +} + +impl User { + pub fn new(name: impl Into, email: impl Into) -> Result { + let email = email.into(); + if !email.contains('@') { + return Err(format!("invalid email: {email}")); + } + Ok(Self { name: name.into(), email }) + } + + pub fn display_name(&self) -> &str { + &self.name + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn creates_user_with_valid_email() { + let user = User::new("Alice", "alice@example.com").unwrap(); + assert_eq!(user.display_name(), "Alice"); + assert_eq!(user.email, "alice@example.com"); + } + + #[test] + fn rejects_invalid_email() { + let result = User::new("Bob", "not-an-email"); + assert!(result.is_err()); + assert!(result.unwrap_err().contains("invalid email")); + } +} +``` + +### アサーションマクロ + +```rust +assert_eq!(2 + 2, 4); // Equality +assert_ne!(2 + 2, 5); // Inequality +assert!(vec![1, 2, 3].contains(&2)); // Boolean +assert_eq!(value, 42, "expected 42 but got {value}"); // Custom message +assert!((0.1_f64 + 0.2 - 0.3).abs() < f64::EPSILON); // Float comparison +``` + +## エラーとパニックのテスト + +### `Result` の戻り値のテスト + +```rust +#[test] +fn parse_returns_error_for_invalid_input() { + let result = parse_config("}{invalid"); + assert!(result.is_err()); + + // Assert specific error variant + let err = result.unwrap_err(); + assert!(matches!(err, ConfigError::ParseError(_))); +} + +#[test] +fn parse_succeeds_for_valid_input() -> Result<(), Box> { + let config = parse_config(r#"{"port": 8080}"#)?; + assert_eq!(config.port, 8080); + Ok(()) // Test fails if any ? returns Err +} +``` + +### パニックのテスト + +```rust +#[test] +#[should_panic] +fn panics_on_empty_input() { + process(&[]); +} + +#[test] +#[should_panic(expected = "index out of bounds")] +fn panics_with_specific_message() { + let v: Vec = vec![]; + let _ = v[0]; +} +``` + +## 統合テスト + +### ファイル構造 + +```text +my_crate/ +├── src/ +│ └── lib.rs +├── tests/ # 統合テスト +│ ├── api_test.rs # 各ファイルが独立したテストバイナリ +│ ├── db_test.rs +│ └── common/ # 共有テストユーティリティ +│ └── mod.rs +``` + +### 統合テストの書き方 + +```rust +// tests/api_test.rs +use my_crate::{App, Config}; + +#[test] +fn full_request_lifecycle() { + let config = Config::test_default(); + let app = App::new(config); + + let response = app.handle_request("/health"); + assert_eq!(response.status, 200); + assert_eq!(response.body, "OK"); +} +``` + +## 非同期テスト + +### Tokioの使用 + +```rust +#[tokio::test] +async fn fetches_data_successfully() { + let client = TestClient::new().await; + let result = client.get("/data").await; + assert!(result.is_ok()); + assert_eq!(result.unwrap().items.len(), 3); +} + +#[tokio::test] +async fn handles_timeout() { + use std::time::Duration; + let result = tokio::time::timeout( + Duration::from_millis(100), + slow_operation(), + ).await; + + assert!(result.is_err(), "should have timed out"); +} +``` + +## テスト整理パターン + +### `rstest` を使用したパラメータ化テスト + +```rust +use rstest::{rstest, fixture}; + +#[rstest] +#[case("hello", 5)] +#[case("", 0)] +#[case("rust", 4)] +fn test_string_length(#[case] input: &str, #[case] expected: usize) { + assert_eq!(input.len(), expected); +} + +// Fixtures +#[fixture] +fn test_db() -> TestDb { + TestDb::new_in_memory() +} + +#[rstest] +fn test_insert(test_db: TestDb) { + test_db.insert("key", "value"); + assert_eq!(test_db.get("key"), Some("value".into())); +} +``` + +### テストヘルパー関数 + +```rust +#[cfg(test)] +mod tests { + use super::*; + + /// Creates a test user with sensible defaults. + fn make_user(name: &str) -> User { + User::new(name, &format!("{name}@test.com")).unwrap() + } + + #[test] + fn user_display() { + let user = make_user("alice"); + assert_eq!(user.display_name(), "alice"); + } +} +``` + +## `proptest` を使用したプロパティベーステスト + +### 基本的なプロパティテスト + +```rust +use proptest::prelude::*; + +proptest! { + #[test] + fn encode_decode_roundtrip(input in ".*") { + let encoded = encode(&input); + let decoded = decode(&encoded).unwrap(); + assert_eq!(input, decoded); + } + + #[test] + fn sort_preserves_length(mut vec in prop::collection::vec(any::(), 0..100)) { + let original_len = vec.len(); + vec.sort(); + assert_eq!(vec.len(), original_len); + } + + #[test] + fn sort_produces_ordered_output(mut vec in prop::collection::vec(any::(), 0..100)) { + vec.sort(); + for window in vec.windows(2) { + assert!(window[0] <= window[1]); + } + } +} +``` + +### カスタムストラテジー + +```rust +use proptest::prelude::*; + +fn valid_email() -> impl Strategy { + ("[a-z]{1,10}", "[a-z]{1,5}") + .prop_map(|(user, domain)| format!("{user}@{domain}.com")) +} + +proptest! { + #[test] + fn accepts_valid_emails(email in valid_email()) { + assert!(User::new("Test", &email).is_ok()); + } +} +``` + +## `mockall` を使用したモック + +### トレイトベースのモック + +```rust +use mockall::{automock, predicate::eq}; + +#[automock] +trait UserRepository { + fn find_by_id(&self, id: u64) -> Option; + fn save(&self, user: &User) -> Result<(), StorageError>; +} + +#[test] +fn service_returns_user_when_found() { + let mut mock = MockUserRepository::new(); + mock.expect_find_by_id() + .with(eq(42)) + .times(1) + .returning(|_| Some(User { id: 42, name: "Alice".into() })); + + let service = UserService::new(Box::new(mock)); + let user = service.get_user(42).unwrap(); + assert_eq!(user.name, "Alice"); +} + +#[test] +fn service_returns_none_when_not_found() { + let mut mock = MockUserRepository::new(); + mock.expect_find_by_id() + .returning(|_| None); + + let service = UserService::new(Box::new(mock)); + assert!(service.get_user(99).is_none()); +} +``` + +## ドキュメントテスト + +### 実行可能なドキュメント + +````rust +/// Adds two numbers together. +/// +/// # Examples +/// +/// ``` +/// use my_crate::add; +/// +/// assert_eq!(add(2, 3), 5); +/// assert_eq!(add(-1, 1), 0); +/// ``` +pub fn add(a: i32, b: i32) -> i32 { + a + b +} + +/// Parses a config string. +/// +/// # Errors +/// +/// Returns `Err` if the input is not valid TOML. +/// +/// ```no_run +/// use my_crate::parse_config; +/// +/// let config = parse_config(r#"port = 8080"#).unwrap(); +/// assert_eq!(config.port, 8080); +/// ``` +/// +/// ```no_run +/// use my_crate::parse_config; +/// +/// assert!(parse_config("}{invalid").is_err()); +/// ``` +pub fn parse_config(input: &str) -> Result { + todo!() +} +```` + +## Criterionを使用したベンチマーク + +```toml +# Cargo.toml +[dev-dependencies] +criterion = { version = "0.5", features = ["html_reports"] } + +[[bench]] +name = "benchmark" +harness = false +``` + +```rust +// benches/benchmark.rs +use criterion::{black_box, criterion_group, criterion_main, Criterion}; + +fn fibonacci(n: u64) -> u64 { + match n { + 0 | 1 => n, + _ => fibonacci(n - 1) + fibonacci(n - 2), + } +} + +fn bench_fibonacci(c: &mut Criterion) { + c.bench_function("fib 20", |b| b.iter(|| fibonacci(black_box(20)))); +} + +criterion_group!(benches, bench_fibonacci); +criterion_main!(benches); +``` + +## テストカバレッジ + +### カバレッジの実行 + +```bash +# Install: cargo install cargo-llvm-cov (or use taiki-e/install-action in CI) +cargo llvm-cov # Summary +cargo llvm-cov --html # HTML report +cargo llvm-cov --lcov > lcov.info # LCOV format for CI +cargo llvm-cov --fail-under-lines 80 # Fail if below threshold +``` + +### カバレッジ目標 + +| コードの種類 | 目標 | +|-----------|--------| +| クリティカルなビジネスロジック | 100% | +| パブリックAPI | 90%以上 | +| 汎用コード | 80%以上 | +| 生成済み / FFIバインディング | 除外 | + +## テストコマンド + +```bash +cargo test # Run all tests +cargo test -- --nocapture # Show println output +cargo test test_name # Run tests matching pattern +cargo test --lib # Unit tests only +cargo test --test api_test # Integration tests only +cargo test --doc # Doc tests only +cargo test --no-fail-fast # Don't stop on first failure +cargo test -- --ignored # Run ignored tests +``` + +## ベストプラクティス + +**すべきこと:** + +* まずテストを書く (TDD) +* 単体テストには `#[cfg(test)]` モジュールを使用する +* 実装ではなく動作をテストする +* シナリオを説明する記述的なテスト名を使用する +* より良いエラーメッセージのために `assert!` より `assert_eq!` を優先する +* クリーンなエラー出力のために `Result` を返すテストでは `?` を使用する +* テストを独立させる——共有の可変状態なし + +**すべきでないこと:** + +* `Result::is_err()` をテストできる場合に `#[should_panic]` を使用する +* すべてをモックする——可能なら統合テストを優先する +* フレーキーなテストを無視する——修正または分離する +* テストで `sleep()` を使用する——チャンネル、バリア、または `tokio::time::pause()` を使用する +* エラーパスのテストをスキップする + +## CI統合 + +```yaml +# GitHub Actions +test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy, rustfmt + + - name: Check formatting + run: cargo fmt --check + + - name: Clippy + run: cargo clippy -- -D warnings + + - name: Run tests + run: cargo test + + - uses: taiki-e/install-action@cargo-llvm-cov + + - name: Coverage + run: cargo llvm-cov --fail-under-lines 80 +``` + +**覚えておくこと**:テストはドキュメントである。コードをどのように使うべきかを示している。明確に書き、最新の状態を保つこと。 diff --git a/docs/ja-JP/skills/skill-comply/SKILL.md b/docs/ja-JP/skills/skill-comply/SKILL.md new file mode 100644 index 00000000..66838094 --- /dev/null +++ b/docs/ja-JP/skills/skill-comply/SKILL.md @@ -0,0 +1,60 @@ +--- +name: skill-comply +description: スキル、ルール、エージェント定義が実際に遵守されているかを可視化する——3種類のプロンプト厳格度レベルのシナリオを自動生成し、エージェントを実行し、動作シーケンスを分類し、完全なツール呼び出しタイムラインの遵守率をレポートする +origin: ECC +tools: Read, Bash +--- + +# skill-comply:自動化された遵守測定 + +コーディングエージェントがスキル、ルール、またはエージェント定義を実際に遵守しているかを以下の方法で測定する: + +1. 任意の .md ファイルから期待される動作シーケンス(仕様)を自動生成する +2. プロンプトの厳格度が段階的に低下するシナリオを自動生成する(支持的 → 中立的 → 競合的) +3. `claude -p` を実行し、stream-json 経由でツール呼び出しトレースを取得する +4. 正規表現ではなくLLMを使用してツール呼び出しを仕様ステップに分類する +5. 決定論的に時系列順を確認する +6. 仕様、プロンプト、タイムラインを含む自己完結型レポートを生成する + +## サポートされるターゲット + +* **スキル**(`skills/*/SKILL.md`):検索優先、TDDガイドなどのワークフロースキル +* **ルール**(`rules/common/*.md`):testing.md、security.md、git-workflow.md などの強制的なルール +* **エージェント定義**(`agents/*.md`):エージェントが期待される場面で呼び出されるか(内部ワークフロー検証は未サポート) + +## 起動条件 + +* ユーザーが `/skill-comply ` を実行する +* ユーザーが「このルールは本当に遵守されているか?」と尋ねる +* 新しいルール/スキルを追加した後、エージェントの遵守を確認する +* 品質メンテナンスの一環として定期的に実行する + +## 使い方 + +```bash +# Full run +uv run python -m scripts.run ~/.claude/rules/common/testing.md + +# Dry run (no cost, spec + scenarios only) +uv run python -m scripts.run --dry-run ~/.claude/skills/search-first/SKILL.md + +# Custom models +uv run python -m scripts.run --gen-model haiku --model sonnet +``` + +## 重要なコンセプト:プロンプト独立性 + +プロンプトが明示的にサポートしていない場合でも、スキル/ルールが遵守されるかどうかを測定する。 + +## レポートの内容 + +レポートは自己完結型で、以下を含む: + +1. 期待される動作シーケンス(自動生成された仕様) +2. シナリオプロンプト(各厳格度レベルで尋ねる内容) +3. 各シナリオの遵守スコア +4. LLM分類ラベル付きのツール呼び出しタイムライン + +### 高度な内容(オプション) + +フックに精通したユーザー向けに、レポートには遵守率が低いステップに対するフック強化の推奨事項も含まれる。これは参考情報——主要な価値は遵守性自体の可視化にある。 diff --git a/docs/ja-JP/skills/skill-stocktake/SKILL.md b/docs/ja-JP/skills/skill-stocktake/SKILL.md new file mode 100644 index 00000000..f3941b8c --- /dev/null +++ b/docs/ja-JP/skills/skill-stocktake/SKILL.md @@ -0,0 +1,194 @@ +--- +name: skill-stocktake +description: "Claudeのスキルとコマンドの品質を監査するためのツール。変更されたスキルのみを対象とした高速スキャンと、順次サブエージェントバッチ評価を使用した完全棚卸しモードをサポートする。" +origin: ECC +--- + +# skill-stocktake + +品質チェックリスト + AI全体判断を使用して、すべてのClaudeスキルとコマンドを審査するスラッシュコマンド(`/skill-stocktake`)。2つのモードをサポートする:最近変更されたスキルの高速スキャンと、完全レビューのための完全棚卸し。 + +## スコープ + +このコマンドは、**コマンドを呼び出したディレクトリを基準とした**以下のパスを対象とする: + +| パス | 説明 | +|------|-------------| +| `~/.claude/skills/` | グローバルスキル(全プロジェクト) | +| `{cwd}/.claude/skills/` | プロジェクトレベルのスキル(ディレクトリが存在する場合) | + +**フェーズ1の開始時に、コマンドはどのパスが見つかりスキャンされたかを明示的にリストアップする。** + +### 特定のプロジェクトをターゲットにする + +プロジェクトレベルのスキルを含めるには、そのプロジェクトのルートから実行する: + +```bash +cd ~/path/to/my-project +/skill-stocktake +``` + +プロジェクトに `.claude/skills/` ディレクトリがない場合、グローバルスキルとコマンドのみが評価される。 + +## モード + +| モード | トリガー条件 | 所要時間 | +|------|---------|---------| +| 高速スキャン | `results.json` が存在する(デフォルト) | 5〜10分 | +| 完全棚卸し | `results.json` が存在しない、または `/skill-stocktake full` | 20〜30分 | + +**結果キャッシュ:** `~/.claude/skills/skill-stocktake/results.json` + +## 高速スキャンフロー + +前回の実行以降に変更されたスキルのみを再評価する(5〜10分)。 + +1. `~/.claude/skills/skill-stocktake/results.json` を読み取る +2. 実行する:`bash ~/.claude/skills/skill-stocktake/scripts/quick-diff.sh \ ~/.claude/skills/skill-stocktake/results.json` + (プロジェクトディレクトリは `$PWD/.claude/skills` から自動検出。必要な場合のみ明示的に渡す) +3. 出力が `[]` の場合:「前回の実行以降に変更なし。」とレポートして停止する +4. 変更されたファイルのみを同じフェーズ2の基準で再評価する +5. 前回の結果から変更されていないスキルを引き継ぐ +6. 差分のみを出力する +7. 実行する:`bash ~/.claude/skills/skill-stocktake/scripts/save-results.sh \ ~/.claude/skills/skill-stocktake/results.json <<< "$EVAL_RESULTS"` + +## 完全棚卸しフロー + +### フェーズ 1 — インベントリ + +実行する:`bash ~/.claude/skills/skill-stocktake/scripts/scan.sh` + +スクリプトはスキルファイルを列挙し、フロントマターを抽出し、UTC修正時刻を収集する。 +プロジェクトディレクトリは `$PWD/.claude/skills` から自動検出。必要な場合のみ明示的に渡す。 +スクリプト出力からスキャンサマリーとインベントリテーブルを表示する: + +``` +スキャン中: + ✓ ~/.claude/skills/ (17 個のファイル) + ✗ {cwd}/.claude/skills/ (見つからない — グローバルスキルのみ) +``` + +| スキル | 7日間使用 | 30日間使用 | 説明 | +|-------|--------|---------|-------------| + +### フェーズ 2 — 品質評価 + +完全なインベントリとチェック項目を含む**汎用エージェント**ツールのサブエージェントを起動する: + +```text +Agent( + subagent_type="general-purpose", + prompt=" +チェックリストに基づいて以下のスキルインベントリを評価してください。 + +[INVENTORY] + +[CHECKLIST] + +各スキルについてJSONを返してください: +{ \"verdict\": \"Keep\"|\"Improve\"|\"Update\"|\"Retire\"|\"Merge into [X]\", \"reason\": \"...\" } +" +) +``` + +サブエージェントは各スキルを読み取り、チェック項目を適用し、各スキルのJSON結果を返す: + +`{ "verdict": "Keep"|"Improve"|"Update"|"Retire"|"Merge into [X]", "reason": "..." }` + +**チャンク指針:** 各サブエージェント呼び出しは約20個のスキルを処理し、コンテキストを管理可能に保つ。各チャンクの後、中間結果を `results.json` に保存する(`status: "in_progress"`)。 + +全スキルの評価が完了したら:`status: "completed"` を設定し、フェーズ3に進む。 + +**再開検出:** 起動時に `status: "in_progress"` が見つかった場合、最初の未評価スキルから再開する。 + +各スキルはこのチェックリストに基づいて評価される: + +``` +- [ ] 他のスキルとの内容の重複を確認済み +- [ ] MEMORY.md / CLAUDE.md との重複を確認済み +- [ ] 技術的参照の時効性を確認済み(ツール名 / CLI引数 / APIが存在する場合、WebSearchで検証) +- [ ] 使用頻度を考慮済み +``` + +判定基準: + +| 判定 | 意味 | +|---------|---------| +| Keep | 有用かつ最新 | +| Improve | 保持する価値があるが、特定の改善が必要 | +| Update | 参照された技術が古い(WebSearchで検証) | +| Retire | 品質が低い、陳腐化、またはコストが非対称 | +| Merge into \[X] | 別のスキルと大幅に重複している。マージターゲットを命名する | + +評価は**AI全体判断**——数値スコアリングルーブリックではない。指針となる次元: + +* **実行可能性**:即座に行動できるコード例、コマンド、または手順 +* **スコープの適合性**:名前、トリガー、内容が一致している。広すぎず、狭すぎない +* **独自性**:MEMORY.md / CLAUDE.md / 他のスキルで代替できない価値 +* **時効性**:技術的参照が現在の環境で有効 + +**理由の品質要件** — `reason` フィールドは自己完結型で意思決定を支えられる必要がある: + +* 単に「変更なし」と書かない——常に核心的な証拠を再述する +* **Retire** の場合:(1) 発見された具体的な欠陥、(2) 同じニーズをカバーする代替案を述べる + * 悪:`"Superseded"` + * 良:`"disable-model-invocation: true already set; superseded by continuous-learning-v2 which covers all the same patterns plus confidence scoring. No unique content remains."` +* **Merge** の場合:ターゲットを命名し、何を統合するかを説明する + * 悪:`"Overlaps with X"` + * 良:`"42-line thin content; Step 4 of chatlog-to-article already covers the same workflow. Integrate the 'article angle' tip as a note in that skill."` +* **Improve** の場合:必要な具体的な変更を説明する(どのセクション、何の操作、該当する場合は目標サイズ) + * 悪:`"Too long"` + * 良:`"276 lines; Section 'Framework Comparison' (L80–140) duplicates ai-era-architecture-principles; delete it to reach ~150 lines."` +* **Keep**(高速スキャンでmtimeのみ変更の場合):元の判定理由を再述し、「変更なし」と書かない + * 悪:`"Unchanged"` + * 良:`"mtime updated but content unchanged. Unique Python reference explicitly imported by rules/python/; no overlap found."` + +### フェーズ 3 — サマリーテーブル + +| スキル | 7日間使用 | 判定 | 理由 | +|-------|--------|---------|--------| + +### フェーズ 4 — 統合 + +1. **Retire / Merge**:ユーザーの確認前に、ファイルごとに詳細な理由を提示する: + * 発見された具体的な問題(重複、陳腐化、リンク切れなど) + * 同じ機能をカバーする代替案(Retire の場合:どの既存スキル/ルール;Merge の場合:ターゲットファイルと何を統合するか) + * 削除の影響(依存するスキル、MEMORY.md 参照、影響を受けるワークフローがあるか) +2. **Improve**:具体的な改善提案と理由を提示する: + * 何を変更し、なぜか(例:「X/Yセクションが python-patterns と重複しているため、430行を200行に圧縮する」) + * ユーザーが行動するかどうかを決定する +3. **Update**:確認したソースから更新されたコンテンツを提示する +4. MEMORY.md の行数を確認し、100行を超えている場合は圧縮を提案する + +## 結果ファイルスキーマ + +`~/.claude/skills/skill-stocktake/results.json`: + +**`evaluated_at`**:評価が完了した実際のUTC時刻を設定する必要がある。 +Bash で取得する:`date -u +%Y-%m-%dT%H:%M:%SZ`。`T00:00:00Z` のような日付のみの近似値は絶対に使わない。 + +```json +{ + "evaluated_at": "2026-02-21T10:00:00Z", + "mode": "full", + "batch_progress": { + "total": 80, + "evaluated": 80, + "status": "completed" + }, + "skills": { + "skill-name": { + "path": "~/.claude/skills/skill-name/SKILL.md", + "verdict": "Keep", + "reason": "Concrete, actionable, unique value for X workflow", + "mtime": "2026-01-15T08:30:00Z" + } + } +} +``` + +## 注意事項 + +* 評価はブラインド:ソース(ECC、自作、自動抽出)に関わらず、すべてのスキルに同じチェックリストを適用する +* アーカイブ/削除操作は常に明示的なユーザー確認が必要 +* スキルのソースによって判定を分岐させない diff --git a/docs/ja-JP/skills/social-graph-ranker/SKILL.md b/docs/ja-JP/skills/social-graph-ranker/SKILL.md new file mode 100644 index 00000000..f9a46873 --- /dev/null +++ b/docs/ja-JP/skills/social-graph-ranker/SKILL.md @@ -0,0 +1,154 @@ +--- +name: social-graph-ranker +description: XとLinkedInでのウォームイントロ発見、ブリッジスコアリング、ネットワークギャップ分析のための重み付きソーシャルグラフランキング。ユーザーがランキングエンジン自体を必要としている場合(より広いプロモーションやネットワーク維持ワークフローではなく)に使用する。 +origin: ECC +--- + +# ソーシャルグラフランカー + +ネットワーク認識型アウトリーチのための正規化された重み付きグラフランキングレイヤー。 + +以下の機能が必要な場合にこのツールを使用する: + +* 内在的価値に基づいて既存の相互フォロワーまたはコネクションをランク付けする +* ターゲットリストに対してウォームパスをマッピングする +* 1度と2度のコネクション全体でブリッジ価値を測定する +* ウォームな紹介とコールドアウトリーチのどちらが適切かを判断する +* `lead-intelligence` や `connections-optimizer` とは独立してグラフの数学的原理を理解する + +## 単独での使用場面 + +ユーザーが主にランキングエンジンを必要としている場合にこのスキルを選択する: + +* 「私のネットワークで誰が最もよい紹介をしてくれるか?」 +* 「相互フォロワーをランク付けして、この人たちへの連絡を手伝ってもらえる人を見つける」 +* 「このICPに対して私のグラフをマッピングする」 +* 「ブリッジの数学的計算を見せる」 + +ユーザーが実際に以下を必要としている場合は、単独で使用しない: + +* 完全なリード生成とアウトリーチシーケンス -> `lead-intelligence` を使用 +* ネットワークのトリミング、再バランシング、拡張 -> `connections-optimizer` を使用 + +## 入力 + +以下を収集または推論する: + +* ターゲットとなる人物、企業、またはICP定義 +* XまたはLinkedIn、あるいは両方におけるユーザーの現在のグラフ +* 役割、業界、地理、レスポンス性などの重み付け優先度 +* 探索の深さと減衰の許容度 + +## コアモデル + +以下が与えられたとする: + +* `T` = 重み付きターゲットのセット +* `M` = 現在の相互フォロワー/直接コネクション +* `d(m, t)` = 相互フォロワー `m` からターゲット `t` への最短ホップ距離 +* `w(t)` = シグナルスコアリングからのターゲット重み + +基本ブリッジスコア: + +```text +B(m) = Σ_{t ∈ T} w(t) · λ^(d(m,t) - 1) +``` + +ここで: + +* `λ` は減衰因子、通常 `0.5` +* 直接パスは全価値を提供 +* ホップが増えるごとに貢献が半分になる + +2度拡張: + +```text +B_ext(m) = B(m) + α · Σ_{m' ∈ N(m) \\ M} Σ_{t ∈ T} w(t) · λ^(d(m',t)) +``` + +ここで: + +* `N(m) \\ M` は相互フォロワーが知っているがユーザーが知らない人のセット +* `α` は2度の到達可能性に対する割引、通常 `0.3` + +レスポンス調整後の最終ランキング: + +```text +R(m) = B_ext(m) · (1 + β · engagement(m)) +``` + +ここで: + +* `engagement(m)` は正規化されたレスポンス性または関係強度 +* `β` はエンゲージメントボーナス、通常 `0.2` + +解釈: + +* 第1層:高い `R(m)` と直接ブリッジパス -> ウォームな紹介リクエスト +* 第2層:中程度の `R(m)` と1ホップのブリッジパス -> 条件付き紹介リクエスト +* 第3層:低い `R(m)` またはブリッジなし -> 直接アウトリーチまたはギャップ補完に注力 + +## スコアリングシグナル + +グラフ探索前に、現在の優先度セットに基づいてターゲットを重み付けする: + +* 役職または職位の一致度 +* 企業または業界の適合性 +* 現在のアクティビティと時効性 +* 地理的な関連性 +* 影響力またはリーチ +* レスポンスの可能性 + +探索後に相互フォロワーを重み付けする: + +* ターゲットセットへの重み付きパスの数 +* それらのパスの直接性 +* レスポンス性または過去のインタラクション履歴 +* 紹介を行うためのコンテキスト適合性 + +## ワークフロー + +1. 重み付きターゲットセットを構築する。 +2. X、LinkedIn、または両方からユーザーのグラフを取得する。 +3. 直接ブリッジスコアを計算する。 +4. 最も価値の高い相互フォロワーの2度の候補を拡張する。 +5. `R(m)` でランク付けする。 +6. 以下を返す: + * 最良のウォームな紹介リクエスト + * 条件付きブリッジパス + * ウォームパスが存在しないグラフギャップ + +## 出力フォーマット + +```text +ソーシャルグラフランキング +==================== + +優先度セット: +プラットフォーム: +減衰モデル: + +トップブリッジ +- 相互フォロワー / コネクション + 基本スコア: + 拡張スコア: + 最良ターゲット: + パスサマリー: + 推奨アクション: + +条件付きパス +- 相互フォロワー / コネクション + 理由: + 追加ホップコスト: + +ウォームパスなし +- ターゲット + 推奨:直接連絡 / グラフギャップを補完 +``` + +## 関連スキル + +* `lead-intelligence` はより広いターゲット発見とアウトリーチパイプラインでこのランキングモデルを使用する +* `connections-optimizer` は誰を保持、トリミング、または追加するかを決定する際に同じブリッジロジックを使用する +* `brand-voice` は紹介リクエストや直接アウトリーチを起草する前に実行する +* `x-api` はXグラフへのアクセスとオプションの実行パスを提供する diff --git a/docs/ja-JP/skills/swift-actor-persistence/SKILL.md b/docs/ja-JP/skills/swift-actor-persistence/SKILL.md new file mode 100644 index 00000000..bc6db7b4 --- /dev/null +++ b/docs/ja-JP/skills/swift-actor-persistence/SKILL.md @@ -0,0 +1,143 @@ +--- +name: swift-actor-persistence +description: Swiftでactorを使用してスレッドセーフなデータ永続化を実装する——メモリキャッシュとファイルバックドストレージを組み合わせ、設計によってデータ競合を排除する。 +origin: ECC +--- + +# スレッドセーフな永続化のための Swift Actor + +Swiftのactorを使用してスレッドセーフなデータ永続化レイヤーを構築するパターン。メモリキャッシュとファイルバックドストレージを組み合わせ、actorモデルを活用してコンパイル時にデータ競合を排除する。 + +## 起動条件 + +* Swift 5.5以降でデータ永続化レイヤーを構築する場合 +* 共有可変状態へのスレッドセーフアクセスが必要な場合 +* 手動の同期(ロック、DispatchQueue)を排除したい場合 +* ローカルストレージを持つオフラインファースとアプリを構築する場合 + +## コアパターン + +### Actorベースのリポジトリ + +Actorモデルはシリアライズされたアクセスを保証する——コンパイラによって強制されるデータ競合なし。 + +```swift +public actor LocalRepository where T.ID == String { + private var cache: [String: T] = [:] + private let fileURL: URL + + public init(directory: URL = .documentsDirectory, filename: String = "data.json") { + self.fileURL = directory.appendingPathComponent(filename) + // Synchronous load during init (actor isolation not yet active) + self.cache = Self.loadSynchronously(from: fileURL) + } + + // MARK: - Public API + + public func save(_ item: T) throws { + cache[item.id] = item + try persistToFile() + } + + public func delete(_ id: String) throws { + cache[id] = nil + try persistToFile() + } + + public func find(by id: String) -> T? { + cache[id] + } + + public func loadAll() -> [T] { + Array(cache.values) + } + + // MARK: - Private + + private func persistToFile() throws { + let data = try JSONEncoder().encode(Array(cache.values)) + try data.write(to: fileURL, options: .atomic) + } + + private static func loadSynchronously(from url: URL) -> [String: T] { + guard let data = try? Data(contentsOf: url), + let items = try? JSONDecoder().decode([T].self, from: data) else { + return [:] + } + return Dictionary(uniqueKeysWithValues: items.map { ($0.id, $0) }) + } +} +``` + +### 使い方 + +Actorの分離により、すべての呼び出しは自動的に非同期になる: + +```swift +let repository = LocalRepository() + +// Read — fast O(1) lookup from in-memory cache +let question = await repository.find(by: "q-001") +let allQuestions = await repository.loadAll() + +// Write — updates cache and persists to file atomically +try await repository.save(newQuestion) +try await repository.delete("q-001") +``` + +### @Observable ViewModel との組み合わせ + +```swift +@Observable +final class QuestionListViewModel { + private(set) var questions: [Question] = [] + private let repository: LocalRepository + + init(repository: LocalRepository = LocalRepository()) { + self.repository = repository + } + + func load() async { + questions = await repository.loadAll() + } + + func add(_ question: Question) async throws { + try await repository.save(question) + questions = await repository.loadAll() + } +} +``` + +## 重要な設計上の決定 + +| 決定 | 理由 | +|----------|-----------| +| Actorを使用(クラス + ロックではなく) | コンパイラによって強制されるスレッド安全性、手動同期不要 | +| メモリキャッシュ + ファイル永続化 | キャッシュからの高速読み取り、ディスクへの永続的な書き込み | +| 初期化時の同期ロード | 非同期初期化の複雑さを回避 | +| IDをキーとする辞書 | 識別子によるO(1)検索 | +| ジェネリック `Codable & Identifiable` | あらゆるモデル型で再利用可能 | +| アトミックなファイル書き込み(`.atomic`) | クラッシュ時の部分書き込みを防ぐ | + +## ベストプラクティス + +* **Actorの境界を越えるすべてのデータに `Sendable` 型を使用する** +* **Actorのパブリックなアビリティを最小化する** —— 永続化の詳細ではなく、ドメイン操作のみを公開する +* **`.atomic` 書き込みを使用する** —— 書き込み中のアプリクラッシュによるデータ破損を防ぐ +* **`init` で同期的にロードする** —— 非同期イニシャライザはローカルファイルに対するわずかな利点のために複雑さが増す +* **`@Observable` ViewModelと組み合わせる** —— リアクティブなUI更新を実現する + +## 避けるべきアンチパターン + +* Swiftの新しい並行処理コードでActorの代わりに `DispatchQueue` または `NSLock` を使用する +* 内部のキャッシュ辞書を外部の呼び出し元に公開する +* 検証なしでファイルURLを設定可能にする +* すべてのActor メソッド呼び出しが `await` であることを忘れる——呼び出し元は非同期コンテキストを処理する必要がある +* Actor の分離をバイパスするために `nonisolated` を使用する(本末転倒) + +## 使用場面 + +* iOS/macOSアプリのローカルデータストレージ(ユーザーデータ、設定、キャッシュコンテンツ) +* 後でサーバーと同期するオフラインファーストアーキテクチャ +* アプリの複数の部分から並行アクセスされる共有可変状態 +* `DispatchQueue` ベースのレガシーなスレッド安全機構を最新のSwift並行処理に置き換える diff --git a/docs/ja-JP/skills/swift-concurrency-6-2/SKILL.md b/docs/ja-JP/skills/swift-concurrency-6-2/SKILL.md new file mode 100644 index 00000000..5d44b4e2 --- /dev/null +++ b/docs/ja-JP/skills/swift-concurrency-6-2/SKILL.md @@ -0,0 +1,217 @@ +--- +name: swift-concurrency-6-2 +description: Swift 6.2のアクセシブルな並行処理——デフォルトはシングルスレッド、@concurrentは明示的なバックグラウンドオフロードに使用し、分離の一貫性はMainActor型に使用する。 +--- + +# Swift 6.2 アクセシブルな並行処理 + +コードがデフォルトでシングルスレッドで実行され、並行処理が明示的に導入されるSwift 6.2の並行処理モデルを採用したパターン。パフォーマンスを犠牲にすることなく、よくあるデータ競合エラーを排除する。 + +## 起動条件 + +* Swift 5.x または 6.0/6.1 プロジェクトを Swift 6.2 に移行する場合 +* データ競合安全性のコンパイラエラーを解決する場合 +* MainActorベースのアプリアーキテクチャを設計する場合 +* CPU集約的な処理をバックグラウンドスレッドにオフロードする場合 +* MainActor分離された型にプロトコル一貫性を実装する場合 +* Xcode 26で「アクセシブルな並行処理」ビルド設定を有効にする場合 + +## 核心的な問題:暗黙のバックグラウンドオフロード + +Swift 6.1以前では、非同期関数が暗黙的にバックグラウンドスレッドにオフロードされ、一見安全に見えるコードでもデータ競合エラーを引き起こすことがあった: + +```swift +// Swift 6.1: ERROR +@MainActor +final class StickerModel { + let photoProcessor = PhotoProcessor() + + func extractSticker(_ item: PhotosPickerItem) async throws -> Sticker? { + guard let data = try await item.loadTransferable(type: Data.self) else { return nil } + + // Error: Sending 'self.photoProcessor' risks causing data races + return await photoProcessor.extractSticker(data: data, with: item.itemIdentifier) + } +} +``` + +Swift 6.2ではこの問題が修正された:非同期関数はデフォルトで呼び出し元と同じActorに留まる。 + +```swift +// Swift 6.2: OK — async stays on MainActor, no data race +@MainActor +final class StickerModel { + let photoProcessor = PhotoProcessor() + + func extractSticker(_ item: PhotosPickerItem) async throws -> Sticker? { + guard let data = try await item.loadTransferable(type: Data.self) else { return nil } + return await photoProcessor.extractSticker(data: data, with: item.itemIdentifier) + } +} +``` + +## コアパターン——分離の一貫性 + +MainActor型が非分離プロトコルに安全に準拠できるようになった: + +```swift +protocol Exportable { + func export() +} + +// Swift 6.1: ERROR — crosses into main actor-isolated code +// Swift 6.2: OK with isolated conformance +extension StickerModel: @MainActor Exportable { + func export() { + photoProcessor.exportAsPNG() + } +} +``` + +コンパイラはこの一貫性がMainActor上でのみ使用されることを保証する: + +```swift +// OK — ImageExporter is also @MainActor +@MainActor +struct ImageExporter { + var items: [any Exportable] + + mutating func add(_ item: StickerModel) { + items.append(item) // Safe: same actor isolation + } +} + +// ERROR — nonisolated context can't use MainActor conformance +nonisolated struct ImageExporter { + var items: [any Exportable] + + mutating func add(_ item: StickerModel) { + items.append(item) // Error: Main actor-isolated conformance cannot be used here + } +} +``` + +## コアパターン——グローバル変数と静的変数 + +MainActorを使用してグローバル/静的状態を保護する: + +```swift +// Swift 6.1: ERROR — non-Sendable type may have shared mutable state +final class StickerLibrary { + static let shared: StickerLibrary = .init() // Error +} + +// Fix: Annotate with @MainActor +@MainActor +final class StickerLibrary { + static let shared: StickerLibrary = .init() // OK +} +``` + +### MainActorデフォルト推論パターン + +Swift 6.2ではMainActorをデフォルトで推論するパターンが導入された——手動の注釈なし: + +```swift +// With MainActor default inference enabled: +final class StickerLibrary { + static let shared: StickerLibrary = .init() // Implicitly @MainActor +} + +final class StickerModel { + let photoProcessor: PhotoProcessor + var selection: [PhotosPickerItem] // Implicitly @MainActor +} + +extension StickerModel: Exportable { // Implicitly @MainActor conformance + func export() { + photoProcessor.exportAsPNG() + } +} +``` + +このパターンはオプトインで、アプリ、スクリプト、その他の実行可能ターゲットに推奨される。 + +## コアパターン——@concurrent を使ったバックグラウンド処理 + +真の並列処理が必要な場合、`@concurrent` を使って明示的にオフロードする: + +> **重要:** この例は「アクセシブルな並行処理」ビルド設定——SE-0466 (MainActorデフォルト分離) と SE-0461 (デフォルト非分離非送信) の有効化が必要。これらの設定を有効にすると、`extractSticker` は呼び出し元のActorに留まり、可変状態へのアクセスが安全になる。**これらの設定なしでは、このコードにはデータ競合がある**——コンパイラがフラグを立てる。 + +```swift +nonisolated final class PhotoProcessor { + private var cachedStickers: [String: Sticker] = [:] + + func extractSticker(data: Data, with id: String) async -> Sticker { + if let sticker = cachedStickers[id] { + return sticker + } + + let sticker = await Self.extractSubject(from: data) + cachedStickers[id] = sticker + return sticker + } + + // Offload expensive work to concurrent thread pool + @concurrent + static func extractSubject(from data: Data) async -> Sticker { /* ... */ } +} + +// Callers must await +let processor = PhotoProcessor() +processedPhotos[item.id] = await processor.extractSticker(data: data, with: item.id) +``` + +`@concurrent` を使用するには: + +1. コンテナとなる型に `nonisolated` をマークする +2. 関数に `@concurrent` を追加する +3. 関数がまだ非同期でない場合は `async` を追加する +4. 呼び出し側に `await` を追加する + +## 重要な設計上の決定 + +| 決定 | 理由 | +|----------|-----------| +| デフォルトシングルスレッド | 最も自然なコードはデータ競合がない。並行処理はオプトイン | +| 非同期関数は呼び出し元のActorに留まる | データ競合エラーを引き起こす暗黙のオフロードを排除 | +| 分離の一貫性 | MainActor型が安全でない回避策なしにプロトコルに準拠できる | +| `@concurrent` による明示的なオプトイン | バックグラウンド実行は偶発的なものではなく意図的なパフォーマンス選択 | +| MainActorデフォルト推論 | アプリターゲットの定型的な `@MainActor` 注釈を削減 | +| オプトイン採用 | 非破壊的な移行パス——機能を段階的に有効化 | + +## 移行手順 + +1. **Xcodeで有効化**:ビルド設定のSwift Compiler > Concurrencyセクション +2. **SPMで有効化**:パッケージマニフェストで `SwiftSettings` APIを使用 +3. **移行ツールを使用**:swift.org/migrationを通じて自動コード変更 +4. **MainActorデフォルトから始める**:アプリターゲットの推論モードを有効化 +5. **必要な場所に `@concurrent` を追加**:まずプロファイリングし、ホットパスをオフロード +6. **徹底的にテスト**:データ競合の問題はコンパイル時エラーになる + +## ベストプラクティス + +* **MainActorから始める** —— まずシングルスレッドコードを書き、後で最適化する +* **CPU集約的な処理のみに `@concurrent` を使用する** —— 画像処理、圧縮、複雑な計算 +* **主にシングルスレッドのアプリターゲットのMainActor推論モードを有効にする** +* **オフロード前にプロファイリングする** —— Instrumentsで実際のボトルネックを見つける +* **グローバル変数を保護するために MainActor を使用する** —— グローバル/静的な可変状態にはActor分離が必要 +* **`nonisolated` 回避策や `@Sendable` ラッパーではなく分離の一貫性を使用する** +* **段階的に移行する** —— ビルド設定で一度に1つの機能を有効化する + +## 避けるべきアンチパターン + +* すべての非同期関数に `@concurrent` を適用する(ほとんどはバックグラウンド実行を必要としない) +* 分離を理解せずにコンパイラエラーを抑制するために `nonisolated` を使用する +* Actorが同じ安全性を提供できる場面でレガシーの `DispatchQueue` パターンを保持する +* 並行処理関連のFoundation Modelsコードで `model.availability` チェックをスキップする +* コンパイラと戦う——データ競合をレポートしている場合、コードには本当の並行処理の問題がある +* すべての非同期コードがバックグラウンドで実行されると仮定する(Swift 6.2のデフォルト:呼び出し元のActorに留まる) + +## 使用場面 + +* すべての新しいSwift 6.2+プロジェクト(「アクセシブルな並行処理」は推奨されるデフォルト設定) +* Swift 5.x または 6.0/6.1 の並行処理から既存のアプリを移行する場合 +* Xcode 26の採用中にデータ競合安全性のコンパイラエラーを解決する場合 +* MainActorを中心としたアプリアーキテクチャを構築する場合(ほとんどのUIアプリ) +* パフォーマンス最適化——特定の重い計算をバックグラウンドにオフロードする場合 diff --git a/docs/ja-JP/skills/swift-protocol-di-testing/SKILL.md b/docs/ja-JP/skills/swift-protocol-di-testing/SKILL.md new file mode 100644 index 00000000..35b5b492 --- /dev/null +++ b/docs/ja-JP/skills/swift-protocol-di-testing/SKILL.md @@ -0,0 +1,190 @@ +--- +name: swift-protocol-di-testing +description: テスト可能なSwiftコードのためのプロトコルベースの依存性注入——焦点を絞ったプロトコルとSwift Testingを使用してファイルシステム、ネットワーク、外部APIをモックする。 +origin: ECC +--- + +# プロトコルベースのSwift依存性注入テスト + +外部の依存関係(ファイルシステム、ネットワーク、iCloud)を小さく焦点を絞ったプロトコルとして抽象化することで、SwiftコードをテストしやすくするパターンI/Oなしの決定論的テストをサポートする。 + +## 起動条件 + +* ファイルシステム、ネットワーク、または外部APIにアクセスするSwiftコードを書く場合 +* 実際の障害を起こさずにエラー処理パスをテストする必要がある場合 +* 異なる環境(アプリ、テスト、SwiftUIプレビュー)で動作するモジュールを構築する場合 +* Swift並行処理(Actor、Sendable)をサポートするテスト可能なアーキテクチャを設計する場合 + +## コアパターン + +### 1. 小さく焦点を絞ったプロトコルを定義する + +各プロトコルは1つの外部関心事のみを処理する。 + +```swift +// File system access +public protocol FileSystemProviding: Sendable { + func containerURL(for purpose: Purpose) -> URL? +} + +// File read/write operations +public protocol FileAccessorProviding: Sendable { + func read(from url: URL) throws -> Data + func write(_ data: Data, to url: URL) throws + func fileExists(at url: URL) -> Bool +} + +// Bookmark storage (e.g., for sandboxed apps) +public protocol BookmarkStorageProviding: Sendable { + func saveBookmark(_ data: Data, for key: String) throws + func loadBookmark(for key: String) throws -> Data? +} +``` + +### 2. デフォルト(本番用)実装を作成する + +```swift +public struct DefaultFileSystemProvider: FileSystemProviding { + public init() {} + + public func containerURL(for purpose: Purpose) -> URL? { + FileManager.default.url(forUbiquityContainerIdentifier: nil) + } +} + +public struct DefaultFileAccessor: FileAccessorProviding { + public init() {} + + public func read(from url: URL) throws -> Data { + try Data(contentsOf: url) + } + + public func write(_ data: Data, to url: URL) throws { + try data.write(to: url, options: .atomic) + } + + public func fileExists(at url: URL) -> Bool { + FileManager.default.fileExists(atPath: url.path) + } +} +``` + +### 3. テスト用のモック実装を作成する + +```swift +public final class MockFileAccessor: FileAccessorProviding, @unchecked Sendable { + public var files: [URL: Data] = [:] + public var readError: Error? + public var writeError: Error? + + public init() {} + + public func read(from url: URL) throws -> Data { + if let error = readError { throw error } + guard let data = files[url] else { + throw CocoaError(.fileReadNoSuchFile) + } + return data + } + + public func write(_ data: Data, to url: URL) throws { + if let error = writeError { throw error } + files[url] = data + } + + public func fileExists(at url: URL) -> Bool { + files[url] != nil + } +} +``` + +### 4. デフォルトパラメーターで依存関係を注入する + +本番コードはデフォルト値を使用し、テストはモックを注入する。 + +```swift +public actor SyncManager { + private let fileSystem: FileSystemProviding + private let fileAccessor: FileAccessorProviding + + public init( + fileSystem: FileSystemProviding = DefaultFileSystemProvider(), + fileAccessor: FileAccessorProviding = DefaultFileAccessor() + ) { + self.fileSystem = fileSystem + self.fileAccessor = fileAccessor + } + + public func sync() async throws { + guard let containerURL = fileSystem.containerURL(for: .sync) else { + throw SyncError.containerNotAvailable + } + let data = try fileAccessor.read( + from: containerURL.appendingPathComponent("data.json") + ) + // Process data... + } +} +``` + +### 5. Swift Testingを使用してテストを書く + +```swift +import Testing + +@Test("Sync manager handles missing container") +func testMissingContainer() async { + let mockFileSystem = MockFileSystemProvider(containerURL: nil) + let manager = SyncManager(fileSystem: mockFileSystem) + + await #expect(throws: SyncError.containerNotAvailable) { + try await manager.sync() + } +} + +@Test("Sync manager reads data correctly") +func testReadData() async throws { + let mockFileAccessor = MockFileAccessor() + mockFileAccessor.files[testURL] = testData + + let manager = SyncManager(fileAccessor: mockFileAccessor) + let result = try await manager.loadData() + + #expect(result == expectedData) +} + +@Test("Sync manager handles read errors gracefully") +func testReadError() async { + let mockFileAccessor = MockFileAccessor() + mockFileAccessor.readError = CocoaError(.fileReadCorruptFile) + + let manager = SyncManager(fileAccessor: mockFileAccessor) + + await #expect(throws: SyncError.self) { + try await manager.sync() + } +} +``` + +## ベストプラクティス + +* **単一責任**:各プロトコルは1つの関心事を処理する——多くのメソッドを持つ「ゴッドプロトコル」を作らない +* **Sendable 一貫性**:プロトコルがActor境界をまたいで使用される場合に必要 +* **デフォルトパラメーター**:本番コードは実際の実装をデフォルトで使用する。テストだけがモックを指定する必要がある +* **エラーのモック**:障害パスをテストするために設定可能なエラープロパティを持つモックを設計する +* **境界のみをモック**:外部の依存関係(ファイルシステム、ネットワーク、API)をモックし、内部型はモックしない + +## 避けるべきアンチパターン + +* すべての外部アクセスをカバーする単一の大きなプロトコルを作成する +* 外部の依存関係を持たない内部型をモックする +* 適切な依存性注入の代わりに `#if DEBUG` 条件文を使用する +* Actorと組み合わせて使用する際に `Sendable` 一貫性を忘れる +* 過度な設計:型が外部の依存関係を持たない場合、プロトコルは必要ない + +## 使用場面 + +* ファイルシステム、ネットワーク、または外部APIに触れるあらゆるSwiftコード +* 実際の環境では引き起こすことが難しいエラー処理パスをテストする場合 +* アプリ、テスト、SwiftUIプレビューのコンテキストで動作するモジュールを構築する場合 +* Swift並行処理(Actor、構造化並行処理)を採用したテスト可能なアーキテクチャが必要なアプリ diff --git a/docs/ja-JP/skills/swiftui-patterns/SKILL.md b/docs/ja-JP/skills/swiftui-patterns/SKILL.md new file mode 100644 index 00000000..cef43feb --- /dev/null +++ b/docs/ja-JP/skills/swiftui-patterns/SKILL.md @@ -0,0 +1,259 @@ +--- +name: swiftui-patterns +description: @Observableを使用した状態管理、ビュー合成、ナビゲーション、パフォーマンス最適化、モダンなiOS/macOS UIのベストプラクティスを備えたSwiftUIアーキテクチャパターン。 +--- + +# SwiftUI パターン + +Appleプラットフォーム向けのモダンなSwiftUIパターン。宣言的で高性能なユーザーインターフェースを構築するために使用する。Observationフレームワーク、ビュー合成、型安全なナビゲーション、パフォーマンス最適化をカバーする。 + +## 起動条件 + +* SwiftUIビューを構築し、状態を管理する場合(`@State`、`@Observable`、`@Binding`) +* `NavigationStack` を使用したナビゲーションフローを設計する場合 +* ビューモデルとデータフローを構築する場合 +* リストと複雑なレイアウトのレンダリングパフォーマンスを最適化する場合 +* SwiftUIで環境値と依存性注入を使用する場合 + +## 状態管理 + +### プロパティラッパーの選択 + +最も適したシンプルなラッパーを選択する: + +| ラッパー | 使用場面 | +|---------|----------| +| `@State` | ビューローカルな値型(トグル、フォームフィールド、シート表示) | +| `@Binding` | 親ビューの `@State` への双方向参照 | +| `@Observable` クラス + `@State` | 複数のプロパティを持つ所有モデル | +| `@Observable` クラス(ラッパーなし) | 親ビューから渡される読み取り専用参照 | +| `@Bindable` | `@Observable` プロパティへの双方向バインディング | +| `@Environment` | `.environment()` で注入された共有依存関係 | + +### @Observable ViewModel + +`ObservableObject` ではなく `@Observable` を使用する——プロパティレベルの変更を追跡するため、SwiftUIは変更されたプロパティを読み取ったビューのみを再レンダリングする: + +```swift +@Observable +final class ItemListViewModel { + private(set) var items: [Item] = [] + private(set) var isLoading = false + var searchText = "" + + private let repository: any ItemRepository + + init(repository: any ItemRepository = DefaultItemRepository()) { + self.repository = repository + } + + func load() async { + isLoading = true + defer { isLoading = false } + items = (try? await repository.fetchAll()) ?? [] + } +} +``` + +### ViewModelを使用するビュー + +```swift +struct ItemListView: View { + @State private var viewModel: ItemListViewModel + + init(viewModel: ItemListViewModel = ItemListViewModel()) { + _viewModel = State(initialValue: viewModel) + } + + var body: some View { + List(viewModel.items) { item in + ItemRow(item: item) + } + .searchable(text: $viewModel.searchText) + .overlay { if viewModel.isLoading { ProgressView() } } + .task { await viewModel.load() } + } +} +``` + +### 環境への注入 + +`@EnvironmentObject` の代わりに `@Environment` を使用する: + +```swift +// Inject +ContentView() + .environment(authManager) + +// Consume +struct ProfileView: View { + @Environment(AuthManager.self) private var auth + + var body: some View { + Text(auth.currentUser?.name ?? "Guest") + } +} +``` + +## ビュー合成 + +### 無効化を制限するためにサブビューを抽出する + +ビューを小さく焦点を絞った構造体に分割する。状態が変化した場合、その状態を読み取ったサブビューのみが再レンダリングされる: + +```swift +struct OrderView: View { + @State private var viewModel = OrderViewModel() + + var body: some View { + VStack { + OrderHeader(title: viewModel.title) + OrderItemList(items: viewModel.items) + OrderTotal(total: viewModel.total) + } + } +} +``` + +### 再利用可能なスタイルのための ViewModifier + +```swift +struct CardModifier: ViewModifier { + func body(content: Content) -> some View { + content + .padding() + .background(.regularMaterial) + .clipShape(RoundedRectangle(cornerRadius: 12)) + } +} + +extension View { + func cardStyle() -> some View { + modifier(CardModifier()) + } +} +``` + +## ナビゲーション + +### 型安全な NavigationStack + +`NavigationStack` と `NavigationPath` を使用して、プログラム的で型安全なルーティングを実現する: + +```swift +@Observable +final class Router { + var path = NavigationPath() + + func navigate(to destination: Destination) { + path.append(destination) + } + + func popToRoot() { + path = NavigationPath() + } +} + +enum Destination: Hashable { + case detail(Item.ID) + case settings + case profile(User.ID) +} + +struct RootView: View { + @State private var router = Router() + + var body: some View { + NavigationStack(path: $router.path) { + HomeView() + .navigationDestination(for: Destination.self) { dest in + switch dest { + case .detail(let id): ItemDetailView(itemID: id) + case .settings: SettingsView() + case .profile(let id): ProfileView(userID: id) + } + } + } + .environment(router) + } +} +``` + +## パフォーマンス + +### 大規模なコレクションにレイジーコンテナを使用する + +`LazyVStack` と `LazyHStack` はビューが表示される時のみ作成する: + +```swift +ScrollView { + LazyVStack(spacing: 8) { + ForEach(items) { item in + ItemRow(item: item) + } + } +} +``` + +### 安定した識別子 + +`ForEach` では常に安定した一意のIDを使用する——配列インデックスは避ける: + +```swift +// Use Identifiable conformance or explicit id +ForEach(items, id: \.stableID) { item in + ItemRow(item: item) +} +``` + +### body 内での高コストな操作を避ける + +* `body` 内でI/O、ネットワーク呼び出し、重い計算を絶対に実行しない +* 非同期処理には `.task {}` を使用する——ビューが消えると自動的にキャンセルされる +* スクロールビューでは `.sensoryFeedback()` と `.geometryGroup()` を慎重に使用する +* リストでは `.shadow()`、`.blur()`、`.mask()` の使用を最小化する——画面外レンダリングを引き起こす + +### Equatable に準拠する + +bodyの計算が高コストなビューには、不要な再レンダリングをスキップするために `Equatable` に準拠する: + +```swift +struct ExpensiveChartView: View, Equatable { + let dataPoints: [DataPoint] // DataPoint must conform to Equatable + + static func == (lhs: Self, rhs: Self) -> Bool { + lhs.dataPoints == rhs.dataPoints + } + + var body: some View { + // Complex chart rendering + } +} +``` + +## プレビュー + +インラインのモックデータで `#Preview` マクロを使用して素早い反復を行う: + +```swift +#Preview("Empty state") { + ItemListView(viewModel: ItemListViewModel(repository: EmptyMockRepository())) +} + +#Preview("Loaded") { + ItemListView(viewModel: ItemListViewModel(repository: PopulatedMockRepository())) +} +``` + +## 避けるべきアンチパターン + +* 新しいコードで `ObservableObject` / `@Published` / `@StateObject` / `@EnvironmentObject` を使用する——`@Observable` に移行する +* `body` や `init` 内に直接非同期処理を置く——`.task {}` または明示的なロードメソッドを使用する +* データを所有しないサブビューでViewModelを `@State` として作成する——代わりに親ビューから渡す +* `AnyView` による型消去を使用する——条件付きビューには `@ViewBuilder` または `Group` を優先する +* ActorとのデータのやりとりにおいてSendable要件を無視する + +## 参照 + +Actorベースの永続化パターンについては、スキル `swift-actor-persistence` を参照。 +プロトコルベースのDIとSwift Testingを使用したテストについては、スキル `swift-protocol-di-testing` を参照。 diff --git a/docs/ja-JP/skills/team-builder/SKILL.md b/docs/ja-JP/skills/team-builder/SKILL.md new file mode 100644 index 00000000..c397727d --- /dev/null +++ b/docs/ja-JP/skills/team-builder/SKILL.md @@ -0,0 +1,165 @@ +--- +name: team-builder +description: 並列チームを構成して派遣するためのインタラクティブなエージェント選択ツール +origin: community +--- + +# チームビルダー + +オンデマンドでエージェントチームを閲覧・構成するためのインタラクティブメニュー。フラット構成またはドメインサブディレクトリで整理されたエージェントコレクションに対応する。 + +## 使用場面 + +* 複数のエージェントロール(markdownファイル)があり、あるタスクにどのエージェントを使うか選択したい場合 +* 異なるドメインから(例えば、セキュリティ + SEO + アーキテクチャ)臨時チームを結成したい場合 +* 決定する前に利用可能なエージェントを閲覧したい場合 + +## 前提条件 + +エージェントファイルはロール、プロンプト(アイデンティティ、ルール、ワークフロー、成果物)を含むmarkdownファイルである必要がある。最初の `# Heading` がエージェント名として使用され、最初の段落が説明として使用される。 + +フラット構成とサブディレクトリの両方のレイアウトをサポートする: + +**サブディレクトリレイアウト** —— ドメインはフォルダー名から推論される: + +``` +agents/ +├── engineering/ +│ ├── security-engineer.md +│ └── software-architect.md +├── marketing/ +│ └── seo-specialist.md +└── sales/ + └── discovery-coach.md +``` + +**フラットレイアウト** —— ドメインは共有のファイル名プレフィックスから推論される。2つ以上のファイルが同じプレフィックスを共有する場合、そのプレフィックスはドメインとみなされる。ユニークなプレフィックスを持つファイルは「General」カテゴリーに分類される。注意:アルゴリズムは最初の `-` で分割するため、複数単語のドメイン(例:`product-management`)にはサブディレクトリレイアウトを使用する: + +``` +agents/ +├── engineering-security-engineer.md +├── engineering-software-architect.md +├── marketing-seo-specialist.md +├── marketing-content-strategist.md +├── sales-discovery-coach.md +└── sales-outbound-strategist.md +``` + +## 設定 + +エージェントディレクトリは順番に探索され、結果がマージされる: + +1. `./agents/**/*.md` + `./agents/*.md` —— プロジェクトローカルのエージェント(両方の深さ) +2. `~/.claude/agents/**/*.md` + `~/.claude/agents/*.md` —— グローバルエージェント(両方の深さ) + +すべての場所の結果がマージされ、エージェント名で重複排除される。同名の場合、プロジェクトローカルのエージェントがグローバルエージェントより優先される。ユーザーがカスタムパスを指定した場合、そのパスを代わりに使用する。 + +## 動作原理 + +### ステップ 1:利用可能なエージェントを発見する + +上記の探索順序を使用してエージェントディレクトリでグローバル検索を実行する。READMEファイルを除外する。見つかった各ファイルに対して: + +* **サブディレクトリレイアウト:** 親フォルダー名からドメインを抽出する +* **フラットレイアウト:** すべてのファイル名プレフィックス(最初の `-` より前のテキスト)を収集する。プレフィックスが2つ以上のファイル名に現れる場合のみドメインとして適格(例:`engineering-security-engineer.md` と `engineering-software-architect.md` はどちらも `engineering` で始まる → Engineeringドメイン)。ユニークなプレフィックスを持つファイル(例:`code-reviewer.md`、`tdd-guide.md`)は「General」カテゴリーに分類される +* 最初の `# Heading` からエージェント名を抽出する。見出しが見つからない場合は、ファイル名から名前を導出する(`.md` を除去し、ハイフンをスペースに置換し、タイトルケースに変換) +* 見出しの後の最初の段落から一行のサマリーを抽出する + +すべての場所を探索した後にエージェントファイルが見つからない場合、ユーザーに通知する:「エージェントファイルが見つかりませんでした。確認済み:\[探索済みパスのリスト]。期待されるもの:これらのディレクトリ内のmarkdownファイル。」そして停止する。 + +### ステップ 2:ドメインメニューを表示する + +``` +利用可能なエージェントドメイン: +1. エンジニアリング — ソフトウェアアーキテクト、セキュリティエンジニア +2. マーケティング — SEOスペシャリスト +3. セールス — ディスカバリーコーチ、アウトバウンドストラテジスト + +ドメインを選択するか、特定のエージェントを指定してください(例:「1,3」または「security + seo」): +``` + +* エージェント数がゼロのドメインはスキップする(空ディレクトリ) +* 各ドメインのエージェント数を表示する + +### ステップ 3:選択を処理する + +柔軟な入力を受け付ける: + +* 数字:「1,3」でEngineeringとSalesのすべてのエージェントを選択 +* 名前:「security + seo」で発見されたエージェントに対してファジーマッチング +* 「all from engineering」でそのドメインのすべてのエージェントを選択 + +5つ以上のエージェントが選択された場合、アルファベット順にリストアップして絞り込みを求める:「Nつのエージェントを選択しました(最大5つ)。どれを保持するか選択するか、アルファベット順の最初の5つを使用する場合は 'first 5' と言ってください。」 + +選択を確認する: + +``` +選択済み:セキュリティエンジニア + SEOスペシャリスト +どのようなタスクに取り組む予定ですか?(タスクを説明してください) +``` + +### ステップ 4:エージェントを並列で起動する + +1. 選択された各エージェントのmarkdownファイルを読み取る +2. まだ提供されていない場合は、タスクの説明を求める +3. Agentツールを使用してすべてのエージェントを並列で起動する: + * `subagent_type: "general-purpose"` + * `prompt: "{agent file content}\n\nTask: {task description}"` + * 各エージェントは独立して実行する——エージェント間の通信は不要 +4. エージェントが失敗した場合(エラー、タイムアウト、または空の出力)、インラインで失敗を記録し(例:「Security Engineer: failed — \[理由]」)、成功したエージェントの結果の処理を続ける + +### ステップ 5:結果を統合する + +すべての出力を収集して統一されたレポートを提示する: + +* エージェント別にグループ化された結果 +* 統合セクションで強調: + * エージェント間のコンセンサス + * 提案間の衝突または矛盾 + * 推奨される次のステップ + +1つのエージェントのみが選択された場合は、統合セクションをスキップして直接出力を提示する。 + +## ルール + +* **動的発見のみ。** エージェントリストをハードコードしない。ディレクトリの新しいファイルはメニューに自動的に表示される。 +* **チームあたり最大5つのエージェント。** 5つを超えると収益逓減とトークン使用量が多くなる。選択時に強制する。 +* **並列分散。** すべてのエージェントが同時に実行される——Agentツールの並列呼び出しパターンを使用する。 +* **並列Agent呼び出し(TeamCreateではない)。** このスキルは独立した作業の処理に並列Agentツール呼び出しを使用する。エージェントが議論したり互いに回答する必要がある場合のみ、TeamCreate(マルチエージェント会話のためのClaude Codeツール)が必要になる。 + +## 例 + +``` +ユーザー: team builder + +Claude: +利用可能なエージェントドメイン: +1. エンジニアリング (2) — ソフトウェアアーキテクト、セキュリティエンジニア +2. マーケティング (1) — SEOスペシャリスト +3. セールス (4) — ディスカバリーコーチ、アウトバウンドストラテジスト、プロポーザルストラテジスト、セールスエンジニア +4. サポート (1) — エグゼクティブサマリー + +ドメインを選択するか、特定のエージェントを指定してください: + +ユーザー: security + seo + +Claude: +選択済み:セキュリティエンジニア + SEOスペシャリスト +どのようなタスクに取り組む予定ですか? + +ユーザー: リリース前に私のNext.jsのeコマースサイトをレビューしてほしい + +[2つのエージェントが並列で起動され、それぞれがコードベースに専門知識を適用する] + +Claude: +## セキュリティエンジニアの発見事項 +- [発見内容...] + +## SEOスペシャリストの発見事項 +- [発見内容...] + +## 統合分析 +両エージェントが同意:[...] +衝突点:セキュリティが推奨するCSPがインラインスタイルをブロックし、SEOはインラインのschemaマークアップを必要とする。解決策:[...] +次のステップ:[...] +``` diff --git a/docs/ja-JP/skills/terminal-ops/SKILL.md b/docs/ja-JP/skills/terminal-ops/SKILL.md new file mode 100644 index 00000000..097720e8 --- /dev/null +++ b/docs/ja-JP/skills/terminal-ops/SKILL.md @@ -0,0 +1,109 @@ +--- +name: terminal-ops +description: ECCのための証拠優先のリポジトリ実行ワークフロー。ユーザーがコマンドの実行、リポジトリの確認、CIの失敗のデバッグ、正確な実行と検証の証明を伴う狭い修正のプッシュを必要とする場合に使用する。 +origin: ECC +--- + +# ターミナルオペレーション + +ユーザーが実際のリポジトリ実行を必要とする場合にこのスキルを使用する:コマンドの実行、git状態の確認、CIまたはビルドのデバッグ、狭い修正の実施、変更と検証内容の正確なレポート。 + +このスキルは意図的に汎用的なコーディングガイダンスよりも範囲が狭い。これは証拠優先のターミナル実行操作ワークフローである。 + +## スキルスタック + +関連する場合、これらのECCネイティブスキルをワークフローに組み込む: + +* `verification-loop` は変更後の正確な検証ステップに使用 +* `tdd-workflow` は正しい修正に回帰カバレッジが必要な場合に使用 +* `security-review` はキー、認証、外部入力が絡む場合に使用 +* `github-ops` はタスクがCI実行、PRステータス、またはリリース状態に依存する場合に使用 +* `knowledge-ops` は検証結果を永続的なプロジェクトコンテキストに保存する必要がある場合に使用 + +## 使用場面 + +* ユーザーが「修正」「デバッグ」「これを実行」「リポジトリを確認」「プッシュ」と言う場合 +* タスクがコマンド出力、git状態、テスト結果、または検証済みのローカル修正に依存する場合 +* 答えが以下を区別する必要がある場合:ローカルで変更済み、ローカルで検証済み、コミット済み、プッシュ済み + +## 安全策 + +* 編集前に確認する +* ユーザーが監査/レビューのみを要求している場合は読み取り専用を維持する +* アドホックなラッパーではなく、リポジトリローカルのスクリプトとヘルパーを優先する +* 検証コマンドが再実行されるまで、修正済みと主張しない +* ブランチが実際に上流にプッシュされるまで、プッシュ済みと主張しない + +## ワークフロー + +### 1. 作業サーフェスを特定する + +以下を明確にする: + +* 正確なリポジトリパス +* ブランチ +* ローカル差分の状態 +* 要求されたモード: + * 確認 + * 修正 + * 検証 + * プッシュ + +### 2. まず失敗サーフェスを読み取る + +何かを変更する前に: + +* エラーを確認する +* ファイルまたはテストを確認する +* git状態を確認する +* 盲目的に再読み込みする前に、提供されたログまたはコンテキストを使用する + +### 3. 修正を狭い範囲に保つ + +一度に1つの主な失敗に対処する: + +* 最初に最小限の有用な検証コマンドを使用する +* ローカルの失敗が解決した後のみ、より大きなビルド/テストプロセスにエスカレートする +* コマンドが同じ特性で失敗し続ける場合、広範囲なリトライを停止して絞り込む + +### 4. 正確な実行状態をレポートする + +正確な状態語を使用する: + +* 確認済み +* ローカルで変更済み +* ローカルで検証済み +* コミット済み +* プッシュ済み +* ブロック済み + +## 出力フォーマット + +```text +サーフェス +- リポジトリ +- ブランチ +- 要求されたモード + +証拠 +- 失敗したコマンド / 差分 / テスト + +アクション +- 変更した内容 + +状態 +- 確認済み / ローカルで変更済み / ローカルで検証済み / コミット済み / プッシュ済み / ブロック済み +``` + +## 落とし穴 + +* ライブなリポジトリ状態を読み取れる場合に古い記憶に頼らない +* 狭い修正をリポジトリ全体の変更に拡大しない +* 破壊的なgitコマンドを使用しない +* 関連のないローカル作業を無視しない + +## 検証 + +* レスポンスには検証コマンドまたはテストを示す +* gitに関する作業にはリポジトリパスとブランチを示す +* プッシュの主張には対象ブランチと正確な結果を含める diff --git a/docs/ja-JP/skills/token-budget-advisor/SKILL.md b/docs/ja-JP/skills/token-budget-advisor/SKILL.md new file mode 100644 index 00000000..579df9ec --- /dev/null +++ b/docs/ja-JP/skills/token-budget-advisor/SKILL.md @@ -0,0 +1,121 @@ +--- +name: token-budget-advisor +description: 回答する前に、どれだけの回答深度を消費するかについてユーザーに情報に基づいた選択を提供する。ユーザーが回答の長さ、深さ、またはトークンバジェットを明示的に制御したい場合にこのスキルを使用する。トリガー条件:"token budget", "token count", "token usage", "token limit", "response length", "answer depth", "short version", "brief answer", "detailed answer", "exhaustive answer", "respuesta corta vs larga", "cuántos tokens", "ahorrar tokens", "responde al 50%", "dame la versión corta", "quiero controlar cuánto usas"、またはユーザーが回答のサイズや深さの制御を明示的に求めるその他の明確なバリエーション。トリガーしない条件:ユーザーが現在のセッションでレベルを指定済み(そのレベルを維持)、リクエストが明らかに一言の回答、または「token」が認証/セッション/支払いトークンを指している。origin: community +--- + +# トークンバジェットアドバイザー(TBA) + +Claudeが回答する前にレスポンスフローをインターセプトし、ユーザーが回答の深さを選択できるようにする。 + +## 使用場面 + +* ユーザーが回答の長さや詳細度を制御したい場合 +* ユーザーがトークン、バジェット、深さ、または回答の長さに言及する場合 +* ユーザーが「短いバージョン」「TL;DR」「簡潔に」「25%」「詳細に」などと言う場合 +* ユーザーが事前に深さ/詳細度を選択したい場合 + +**トリガーしない場合**:ユーザーが本セッションですでにレベルを設定している(静かに維持)、または回答が本質的に一行。 + +## 動作原理 + +### ステップ 1 — 入力トークンを推定する + +リポジトリの標準コンテキストバジェットのヒューリスティックスを使用して、プロンプトのトークン数を頭の中で推定する。 + +[context-budget](../context-budget/SKILL.md) と同じキャリブレーションガイドラインを使用する: + +* 散文:`words × 1.3` +* コード集約またはコード混在/コードブロック:`chars / 4` + +混在コンテンツの場合、支配的なコンテンツタイプを使用し、推定ヒューリスティックスを保持する。 + +### ステップ 2 — 複雑度に応じてレスポンスサイズを推定する + +プロンプトを分類し、乗数範囲を適用して完全なレスポンスウィンドウを得る: + +| 複雑度 | 乗数範囲 | プロンプト例 | +|--------------|------------|------------------------------------------------------| +| シンプル | 3× – 8× | 「Xとは何ですか?」、はい/いいえの質問、単一の事実 | +| 中程度 | 8× – 20× | 「Xはどのように機能しますか?」 | +| 中〜高 | 10× – 25× | コンテキスト付きのコードリクエスト | +| 複雑 | 15× – 40× | マルチパート分析、比較、アーキテクチャ | +| クリエイティブ | 10× – 30× | ストーリー、散文、ナラティブライティング | + +レスポンスウィンドウ = `input_tokens × mult_min` から `input_tokens × mult_max`(ただしモデルの設定済み出力トークン制限を超えない)。 + +### ステップ 3 — 深さのオプションを提示する + +**回答する前に**、実際に推定した数値を使用してこのブロックを提示する: + +``` +プロンプトを分析中... + +入力:~[N] トークン | タイプ:[タイプ] | 複雑度:[レベル] | 言語:[言語] + +深さレベルを選択してください: + +[1] ベーシック (25%) -> ~[トークン数] 直接回答、前置きなし +[2] 適度 (50%) -> ~[トークン数] 回答 + 背景 + 1つの例 +[3] 詳細 (75%) -> ~[トークン数] 代替案を含む完全な回答 +[4] 徹底的 (100%) -> ~[トークン数] すべて、制限なし + +どのレベルを選択しますか?(1-4 または「25%の深さ」「50%の深さ」「75%の深さ」「100%の深さ」) + +精度:ヒューリスティック推定、約85〜90%の精度(±15%)。 +``` + +各レベルのトークン推定(レスポンスウィンドウ内): + +* 25% → `min + (max - min) × 0.25` +* 50% → `min + (max - min) × 0.50` +* 75% → `min + (max - min) × 0.75` +* 100% → `max` + +### ステップ 4 — 選択されたレベルで回答する + +| レベル | 目標の長さ | 含む内容 | 省略する内容 | +|------------------|---------------------|-----------------------------------------------------|---------------------------------------------------| +| 25% コア | 最大2〜4文 | 直接回答、重要な結論 | コンテキスト、例、ニュアンス、代替案 | +| 50% 適度 | 1〜3段落 | 回答 + 必要なコンテキスト + 1つの例 | 深い分析、エッジケース、参考文献 | +| 75% 詳細 | 構造化された回答 | 複数の例、長所/短所、代替案 | 極端なエッジケース、網羅的な参考文献 | +| 100% 徹底的 | 制限なし | すべて——完全な分析、すべてのコード、すべての視点 | なし | + +## ショートカット——質問をスキップ + +ユーザーがすでにレベルを示している場合、質問せずにそのレベルで即座に回答する: + +| ユーザーの発言 | レベル | +|----------------------------------------------------|-------| +| 「1」/「25%の深さ」/「短いバージョン」/「簡潔に」/「TL;DR」 | 25% | +| 「2」/「50%の深さ」/「適度の深さ」/「バランスの取れた回答」 | 50% | +| 「3」/「75%の深さ」/「詳細な回答」/「包括的な回答」 | 75% | +| 「4」/「100%の深さ」/「徹底的な回答」/「完全で詳細な分析」 | 100% | + +ユーザーが本セッションですでにレベルを設定している場合、ユーザーが変更しない限り後続の回答も**静かに**そのレベルを維持する。 + +## 精度について + +このスキルはヒューリスティック推定を使用する——実際のトークナイザーではない。精度は約85〜90%で偏差は±15%。常に免責事項を表示する。 + +## 例 + +### トリガーシナリオ + +* 「まず短いバージョンをください。」 +* 「あなたの回答は何トークン使いますか?」 +* 「50%の深さで回答してください。」 +* 「徹底的な回答が欲しい、サマリーはいらない。」 +* 「まず短いバージョン、次に詳細なバージョンをください。」 + +### トリガーしないシナリオ + +* 「JWTトークンとは何ですか?」 +* 「チェックアウトフローは支払いトークンを使用しています。」 +* 「これは正常ですか?」 +* 「リファクタリングを完了してください。」 +* ユーザーが本セッションの深さを選択した後の後続の質問 + +## 出典 + +[TBA — Claude CodeのToken Budget Advisor](https://github.com/Xabilimon1/Token-Budget-Advisor-Claude-Code-)から引用した独立スキル。 +元のプロジェクトにはPython推定スクリプトも付属しているが、本リポジトリではスキルを自己完結型に保ち、ヒューリスティックスのみを使用する。 diff --git a/docs/ja-JP/skills/ui-demo/SKILL.md b/docs/ja-JP/skills/ui-demo/SKILL.md new file mode 100644 index 00000000..f25d8328 --- /dev/null +++ b/docs/ja-JP/skills/ui-demo/SKILL.md @@ -0,0 +1,465 @@ +--- +name: ui-demo +description: Playwrightを使用して美しいUIデモ動画を録画する。ユーザーがWebアプリのデモ、ウォークスルー、スクリーン録画、またはチュートリアル動画の作成を求める場合に使用する。可視カーソル、自然なリズム、プロフェッショナルな仕上がりのWebM動画を生成する。 +origin: ECC +--- + +# UI デモ動画レコーダー + +Playwrightの動画録画機能を使用して、注入されたカーソルオーバーレイ、自然なリズム、ナラティブフローを備えた美しいWebアプリのデモ動画を録画する。 + +## 使用場面 + +* ユーザーが「デモ動画」「スクリーン録画」「操作デモ」または「チュートリアル」を求める場合 +* ユーザーが機能またはワークフローを視覚的に見せたい場合 +* ユーザーがドキュメント、オンボーディング、ステークホルダーへのデモのために動画が必要な場合 + +## 3フェーズのプロセス + +すべてのデモは **探索 -> リハーサル -> 録画** の3つのフェーズを経る。録画フェーズに直接ジャンプしない。 + +*** + +## フェーズ 1:探索 + +スクリプトを書く前に、ターゲットページを探索して実際の内容を把握する。 + +### なぜか + +見たことのない内容のスクリプトは書けない。フィールドが `