--- name: hargen description: Claudeの会話ログからフィードバックパターンを分析し、ハーネス改善を提案する trigger: ユーザーが「hargen」「ハーネス改善」「CLAUDE.md改善」「フィードバック分析」と言ったとき --- # hargen — ハーネス改善スキル Claudeの会話ログからユーザーの繰り返しフィードバックを分析し、ハーネス(CLAUDE.md / hooks / skills / memory)の改善提案を行う。 **原則: hargenは「何を改善すべきか」を発見し、具体的な改善案をユーザーに提示する。反映はユーザーの判断を経てから行う。** --- ## Faceted Prompting 設計原則 改善案の生成はこの原則に従う。Phase 4の分類とPhase 6の文言作成で必ず参照すること。 参考: https://nrslib.com/faceted-prompting/ ### 5つのFacetとその役割 | Facet | 役割 | 書くべきもの | 書くべきでないもの | |-------|------|-------------|-------------------| | **Persona** | エージェントの役割・専門性・判断姿勢を定義する | 「あなたは〜である」「〜を重視する」 | 具体的な手順、禁止事項 | | **Policy** | 守るべき規約・禁止事項を定義する | 「〜すること」「〜しないこと」(規範的) | 参照情報、出力形式 | | **Knowledge** | 判断の前提となる参照情報・ドメイン知識を定義する | 事実・原則・前提(記述的) | 行動指示、禁止事項 | | **Output Contract** | 出力の形式・構造・スタイルを定義する | フォーマット、言語、報告構造 | 行動規範、参照情報 | | **Instruction** | ステップ固有の手順・目標を定義する | 今回のタスクの具体手順(命令的) | 恒常的なルール(→ Policyへ) | ### Facet分類の判断基準 指摘を改善案に変換する際、以下で配置先を判定する: - **「常にそうあるべき姿勢」か?** → Persona(例: 「根本原因を探る姿勢」) - **「常に守るべきルール」か?** → Policy(例: 「エラーを握りつぶさない」) - **「判断の前提として知っておくべきこと」か?** → Knowledge(例: 「推測より確認」) - **「出力の形式に関すること」か?** → Output Contract(例: 「日本語・簡潔」) - **「今回だけの手順」か?** → Instruction(CLAUDE.mdには書かない。skill向き) ### 文言の品質基準 - **Personaの文言**: 「あなたは〜です」「〜を最優先とする」。性格・価値観を表す。行動の具体指示は書かない - **Policyの文言**: 「〜すること」「〜しないこと」。条件と行動が明確。曖昧な形容詞(「適切に」「よく」)を避け、検証可能な表現にする - **Knowledgeの文言**: 「〜である」「〜とする」。事実や原則の記述。命令形は使わない - **Output Contractの文言**: 「形式: 〜」「〜を含める」。出力の構造を規定。行動プロセスは書かない ### 既存構造との整合性 改善案は既存CLAUDE.mdの以下と揃える: - **粒度**: 既存ルールが1行なら1行、箇条書きなら箇条書き - **トーン**: 既存が「〜する」体なら「〜する」体で揃える - **抽象度**: 既存ルールが抽象的なセクションに具体的すぎるルールを混ぜない(逆も同様) --- ## Phase 1: ログ抽出とセッション特定 ### Step 1: プロンプト抽出 `npx` でhistory.jsonlからユーザープロンプトを抽出する。 ```bash npx --yes @maito1201/hargen@latest extract-prompts --days 30 --max-chars 200 ``` 出力が多すぎる場合は `--days` を短くするか `--project` で絞り込む。 **判断基準:** - 出力が100件以下: そのまま Step 2 へ - 出力が100〜300件: `--days 14` に短縮して再実行 - 出力が300件超: `--project` で主要プロジェクトに絞る ### Step 2: 深掘り対象セッションの選定 抽出結果を眺め、「行動変更フィードバックを含みそうなセッション」に目星をつける(Phase 4のStep 1にあるYes判定基準をここで軽く適用する。修正要求・ダメ出し・方針表明が1つでもあるセッションが候補)。 候補セッションのトランスクリプトパスを解決する: ```bash npx --yes @maito1201/hargen@latest list-sessions --project {name} --days 30 --ids {id1,id2,...} ``` `--ids` には extract-prompts の `session:xxxxxxxx` の8桁IDをカンマ区切りで渡す。 **上限:** 深掘り分析は**最大10セッション**。超える場合はフィードバック濃度(Yes候補の密度)が高い順に10件を選び、残りはプロンプト抽出結果のみで補完分析する。レポートに「未深掘りセッションN件」と明記すること。 --- ## Phase 2: 既存ハーネスの把握と診断 以下を読み、現在のハーネス構成を把握する: 1. `~/.claude/CLAUDE.md` (グローバル設定) 2. 作業ディレクトリの `CLAUDE.md`(あれば) 3. `~/.claude/settings.json`(hooks設定) 4. `.claude/skills/` 配下のスキル定義(あれば) 5. `~/.claude/projects/{プロジェクトslug}/memory/`(あれば。MEMORY.md=索引と個別メモリファイル) - slugはプロジェクトの絶対パスの非英数字を `-` に置換したもの(例: `/Users/x/project/foo` → `-Users-x-project-foo`) - `list-sessions` の出力パスからslugディレクトリを流用してよい **整理すること:** - 既に書かれているルールを箇条書きにする(Phase 4で重複排除に使う) - memoryに記録済みの教訓(type=feedback)を箇条書きにする(Phase 4の突合とPhase 5の昇格判定に使う) - Faceted Prompting の構造(Persona / Policy / Knowledge / Output Contract)に沿っているか確認する - hooks / skills がどの程度活用されているか確認する --- ## Phase 3: セッション並列分析 Phase 1で選定したセッションを、**1セッション=1サブエージェント**で並列分析する。トランスクリプトの生jsonlは巨大(数MB)なので、メインコンテキストでは絶対に読まないこと。 ### サブエージェントへの指示テンプレート 各サブエージェントには以下を指示する(`{path}` はPhase 1で解決した絶対パス): ``` あなたはClaude Codeのセッションログからユーザーフィードバックを抽出する分析者です。 1. 次のコマンドを実行し、その出力のみを分析対象とする(元の.jsonlファイルは読まないこと): npx --yes @maito1201/hargen@latest extract-session {path} 2. 出力された会話ログから、「Claudeの行動を変えるべきユーザーの指摘」だけを抽出する。 除外(No): 感謝・同意 / 質問・相談 / 思考の独り言 / タスク指示(「〜を実装して」)/ 状況報告(「〜が動かない」) 採用(Yes): 修正要求(「〜しないで」)/ ダメ出し(「まだ治ってない」)/ 方針表明(「〜の方が良い」)/ 期待の明示(「〜を確認してから進めて」) 3. 各指摘について、直前のASSISTANT発言から「Claudeが何をして指摘を受けたか」の文脈を1-2文で要約する。 4. コード断片・シークレット・社内固有名詞を引用に含めない。絶対パスは ~/project/{name} 形式にテンプレート化する。 ``` ### 構造化出力スキーマ サブエージェントの出力は以下のJSONで受け取る: ```json { "type": "object", "properties": { "sessionId": { "type": "string" }, "sessionSummary": { "type": "string", "description": "このセッションで何をしていたか1文" }, "feedbackItems": { "type": "array", "items": { "type": "object", "properties": { "quote": { "type": "string", "description": "ユーザー発言の原文(コード・秘匿情報は除去)" }, "context": { "type": "string", "description": "直前にClaudeが何をしていたか(1-2文)" }, "expectedBehavior": { "type": "string", "description": "ユーザーが期待していた行動" }, "facet": { "enum": ["Persona", "Policy", "Knowledge", "OutputContract", "Instruction"] }, "severity": { "enum": ["high", "med", "low"] }, "isRepeatInSession": { "type": "boolean", "description": "同一セッション内で同種指摘が複数回あったか" } }, "required": ["quote", "context", "expectedBehavior", "facet"] } } }, "required": ["sessionId", "feedbackItems"] } ``` ### 実行方法A: Workflowツール(優先) Workflowツールが使える環境ではこちらを使う: ```javascript export const meta = { name: 'hargen-session-analysis', description: 'セッショントランスクリプトからフィードバックを並列抽出する', phases: [{ title: 'Analyze' }], } // FEEDBACK_SCHEMA は上記スキーマの定数 // セッション一覧はargs経由ではなくスクリプトに直接埋め込む(環境によりargsが渡らないことがある) const sessions = [ { id: 'xxxxxxxx', path: '/absolute/path/to/xxxxxxxx-....jsonl' }, // Phase 1で解決した全対象セッション ] const results = await parallel(sessions.map(s => () => agent(`<上記テンプレートの {path} を ${s.path} に置換したもの>`, { label: `session:${s.id}`, phase: 'Analyze', schema: FEEDBACK_SCHEMA }) )) return results.filter(Boolean) ``` ### 実行方法B: Agentツール(フォールバック) Workflowツールが存在しない環境では、Agentツール(general-purpose等)を**1メッセージで複数並列起動**する。最大5並列とし、6セッション以上はバッチに分割する。プロンプトは同一テンプレートに以下を追記する: ``` 最終応答は上記スキーマに従うJSONのみを ```json コードブロックで返すこと。説明文は不要。 ``` メインエージェントが各応答のJSONをパースして統合する。パースに失敗した応答は破棄せず、テキストから指摘を手動で拾う。 --- ## Phase 4: フィードバック統合分類 Phase 3のサブエージェント出力(feedbackItems)と、Phase 1の未深掘りセッションのプロンプトを統合し、分類する。 ### Step 1: 行動変更フィルタ 未深掘り分のプロンプトに対して「**これはClaudeの行動を変えるべき指摘か?**」をYes/Noで判定する(深掘り分はサブエージェントが判定済み)。 **No(除外):** - 感謝・同意(「ありがとう」「良さそう」「OK」) - 質問・相談(「〜って何?」「どう思う?」) - 思考の独り言(「〜の使い道がわからんね」) - タスク指示(「〜を実装して」「〜を調べて」) - 状況報告(「〜が動かない」「〜のエラーが出た」) **Yes(分析対象):** - 修正要求(「〜しないで」「〜してほしい」) - ダメ出し(「ダメです」「まだ治ってない」「品質が低い」) - 方針表明(「〜の方が良い」「〜は不要」「〜に統一して」) - 期待の明示(「〜を確認してから進めて」「〜を説明して」) ### Step 2: 根本原因の分析 Yesの指摘を個別に並べるのではなく、**なぜその指摘が発生したか**の根本原因でグルーピングする。 例: 以下の3つの指摘は表面的には別だが、根本原因は同じ「行動前に確認しない」 - 「勘でpushする前に読んだか説明して」 - 「落ち着いて、元々なんで動いていたか考えよう」 - 「よく確認してから進めて」 **根本原因の分析手順:** 1. 指摘の背後にある「ユーザーが期待していた行動」を言語化する(深掘り分は expectedBehavior と context を材料にする) 2. 同じ期待を共有する指摘をグルーピングする。**頻度は「出現セッション数」を主指標とする**(同一セッション内の連呼より、複数セッションでの再発を重視する) 3. 各グループがどのFacetに関わるかを「Faceted Prompting 設計原則」の分類基準で判定する 4. 各グループに対して「なぜ既存ルールで防げなかったか」を診断する: - **ルールが存在しない** → 新規追加が必要 - **ルールが抽象的すぎる** → 具体的な条件・行動に書き換える必要がある - **ルールはあるが特定の状況で見落とされる** → トリガー条件を明示するか、hookで強制する - **ルール同士が矛盾している** → 優先順位を明確にする ### Step 3: 既存ハーネスとの突合 各グループをPhase 2の既存ルール・memoryと突合し、状態を判定する: - **未カバー**: 既存ハーネスに該当ルールがない - **カバー済み・遵守**: 以前は指摘されたが最近は出ていない - **カバー済み・違反あり**: ルールがあるのに繰り返し指摘されている(最重要) - **memoryに記録済みだが再発**: memoryに教訓があるのに指摘が再発している(CLAUDE.md昇格の最有力シグナル → Phase 5へ) 「カバー済み・違反あり」の場合、Step 2の診断結果(なぜ防げなかったか)を必ず添える。 ### 分類の判断基準 迷ったら以下で判定する: - 「次回以降も適用すべきか?」→ Yes ならフィードバック、No なら除外 - 「別のプロジェクトでも当てはまるか?」→ Yes ならグローバル、No ならプロジェクト固有 --- ## Phase 5: memory診断 Phase 2で読んだmemoryディレクトリを診断する。memoryが存在しない、またはプロジェクトを特定できない全体分析の場合はこのPhaseをスキップしてよい(レポートにその旨を記載)。 ### 診断基準 | 診断 | 基準 | 提案 | |------|------|------| | **重複** | 期待行動が実質同一=同じ状況で同じ行動を要求している(テーマが隣接するだけなら重複としない) / 内容が包含関係にある | マージ(統合先に一本化し他方を削除、MEMORY.md索引を更新) | | **陳腐化** | 記述の中核となる参照先(ファイル・ブランチ・Issue)が現存しない / 完了済み一過性タスクの進捗記録・申し送り | 削除。付随的な参照のみ欠落・状態記述が古いだけなら削除ではなく内容更新を提案 | | **矛盾** | memory同士、またはmemoryとCLAUDE.mdで指示が食い違う | どちらかへの一本化、または優先順位の明確化 | | **昇格** | type=feedbackで、(a)今回の分析で2セッション以上再発、または(b)プロジェクト非依存の普遍的行動規範 | CLAUDE.mdへ昇格し、memory側は削除(二重管理を残さない) | | **留置** | プロジェクト固有の事実・設計結論・環境知識(type=project/reference) | memoryに留める(変更なし) | **昇格時の追加ルール:** - 昇格前に必ず昇格先CLAUDE.mdの既存ルールと突合する。実質重複するなら新規追加ではなく既存ルールの文言強化に統合する(昇格が新たな重複を生むのを防ぐ) - 汎用規範とプロジェクト固有の具体例が1ファイルに同居する場合は**分割**する: 核の規範のみCLAUDE.mdへ昇格し、固有例はmemoryに残す ### 一行判断基準 - **事実か規範か?** → 事実(設計結論・環境知識)はmemory、規範(行動ルール)はCLAUDE.md候補 - **memory記録後も再発しているか?** → Yes なら昇格 or hook化(memoryでは行動が変わらなかった証拠) --- ## Phase 6: レポート提示 以下の形式でユーザーに提示する。**この段階では一切のファイル変更を行わない。** ### 優先度の判定 各指摘に優先度を付ける: - **HIGH**: カバー済みだが違反が多い(ルールが機能していない)、memoryに記録済みだが再発、または未カバーで3セッション以上出現 - **MED**: 未カバーで2セッション出現、または単発だが影響が大きい - **LOW**: 単発で影響が限定的 ### レポートの構成 レポートは2部構成とする。 **Part 1: 分析結果** — 何が問題か、なぜ起きたか **Part 2: 適用プレビュー** — 改善を適用すると各ファイルがどう変わるか Part 2を先に見せることで、ユーザーが承認判断しやすくする。「適用すると結局何がどうなるのか」と聞かれることがないようにする。 ### Part 1: 分析結果 ``` === hargen フィードバック分析 === ■ サマリー 分析対象: {N}日間 / {M}プロンプト / 深掘り{S}セッション(未深掘り{U}件) 行動変更フィルタ通過: {K}件 根本原因グループ: {G}件 既存ハーネスのカバー率: {高/中/低} ■ 要改善 1: {根本原因を一言で} [HIGH] 出現: {N}セッション なぜ起きたか: {ルールが抽象的 / 特定状況の記載がない / memory記録済みだが再発 / etc.} 文脈: {Claudeが何をして指摘を受けたか(深掘りセッションのcontextから)} 代表的な発言: - 「{元の発言1}」 - 「{元の発言2}」 ■ 要改善 2: ... ■ memory診断 重複: {N}ペア({name1} ⇔ {name2}: 期待行動が同一) 陳腐化: {N}件({name}: 参照先Issueクローズ済み) 昇格候補: {N}件({name}: 記録後も2セッションで再発 → CLAUDE.md Policyへ) 矛盾: {N}件 ■ 変更不要(既存ルールで機能している) - {既存ルール} ← 「{元の発言}」に対応 ``` 分析結果は簡潔に。根本原因と「なぜ防げなかったか」に焦点を絞る。 ### Part 2: 適用プレビュー 分析結果の直後に、**全改善案を適用した場合の各ファイルのdiff**を提示する。 ユーザーに「適用するとどうなる?」と聞かせない。 ``` === 適用プレビュー === ■ ~/.claude/CLAUDE.md に3箇所の変更 1. Knowledge(要改善4に対応) - - 既存コードの尊重: 変更前に関連コードを必ず読む + - 既存成果物の尊重: 変更前に関連コード・テンプレート・ドキュメント・PR説明を + 必ず読む。新規作成時は類似の既存成果物を参照し、一貫性を保つ 2. Policy > 作業前に必ず守ること > 3(要改善1に対応) - 3. **関連ファイルを読む** — 変更対象のファイルと関連コードを先に読んでから提案する + 3. **関連ファイルを読み、現状を説明する** — 変更対象のファイル、その呼び出し元、 + 既存の正常動作している設定を読み、「何が動いていて何を変えるのか」を + 説明してから作業する 3. Policy > 禁止事項(末尾に追加、memory昇格1に対応) + - 会話中にユーザーが設定した制約を無視すること ■ ~/.claude/projects/{slug}/memory/ に3件の変更 4. マージ(memory診断: 重複に対応) check_branch_convention_before_pr.md ← check_origin_develop_before_new_branch.md を統合 - 削除: check_origin_develop_before_new_branch.md MEMORY.md 索引から1行削除 5. 削除(memory診断: 陳腐化に対応) - 削除: issue_cleanup_progress.md(タスク完了済み) MEMORY.md 索引から1行削除 6. 昇格(改善3と同一。CLAUDE.md追記とセットで適用) - 削除: feedback_ignore_user_constraints.md MEMORY.md 索引から1行削除 全部適用 / 番号で選択 / 修正を依頼 のいずれかで回答してください。 ``` **適用プレビューの原則:** - ファイルごとにまとめる(改善案ごとではない) - diff形式(-/+)で示し、どの行がどう変わるか一目でわかるようにする - 各diffに「要改善N / memory診断 に対応」と紐付けを明示する - 新規追加の場合は挿入位置の前後の行を含めて示す - 複数の改善案が同じ既存ルールに影響する場合、マージした結果を1つのdiffで示す - memoryの昇格は「CLAUDE.mdへの追記」と「memoryファイル削除+索引更新」を**同じ番号に紐付け**、片方だけ適用されない形で示す - **文言は「Faceted Prompting 設計原則」の品質基準に従う**: Policyに書くなら規範的表現、Knowledgeなら記述的表現。曖昧な形容詞を避け、既存ルールの粒度・トーンと揃える **推奨反映先の判断基準:** - プロジェクト横断で適用 → グローバルCLAUDE.md - 特定プロジェクトのみの規範 → プロジェクトCLAUDE.md - プロジェクト固有の事実・設計結論 → memory(新規追加・統合先) - 機械的に強制可能(lint, テスト, ブランチ名) → hook - 複数ステップの手順 → skill - ルールの文言強化で解決する → CLAUDE.mdの既存ルール書き換え - 文言を変えても守られない → hookで強制 --- ## Phase 7: 反映(ユーザー承認後) Phase 6の適用プレビューに対するユーザーの回答に従い、承認された変更を反映する。 - **全部適用**: プレビューの全diffを適用する - **番号で選択**: 指定された番号のdiffのみ適用する - **修正を依頼**: ユーザーの指摘に基づきdiffを修正し、再度プレビューを提示する ### 反映時の注意 - CLAUDE.mdの改善: 既存の構造と文脈を尊重し、プレビュー通りに編集する - memoryの変更: プレビュー通りに編集・削除する。**削除・マージ時は必ずMEMORY.md索引も同時に更新し、索引と実ファイルの不整合を残さない**。昇格はCLAUDE.md追記とmemory削除をセットで行う - hookの提案: 設定例を提示し、ユーザーに適用を委ねる(直接settings.jsonは編集しない) - skillの提案: 概要を提示し、実装はユーザーに委ねる --- ## 注意事項 - ログにはコード内容やビジネスロジックが含まれる。分析結果にコードやシークレットを含めない - 絶対パスが含まれる場合はテンプレート化する(例: `~/project/{name}`) - 分析結果はユーザーへの提示のみに使い、外部に送信しない - トランスクリプトの生jsonl(`~/.claude/projects/{slug}/*.jsonl`)をメインコンテキストで直接読まない。必ず `extract-session` 経由でサブエージェントに読ませる - `list-sessions` / `extract-session` が `Unknown command` になる場合はnpxのキャッシュが古い。`npx --yes @maito1201/hargen@0.3.0` とバージョンを明示して再実行する