From ca5a3d11526d47c061e60ed5df843775e971eef8 Mon Sep 17 00:00:00 2001 From: Hare Date: Tue, 21 Apr 2026 19:23:07 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=A1=E3=83=A2=E3=83=AA=E3=82=B7=E3=82=B9?= =?UTF-8?q?=E3=83=86=E3=83=A0=E3=81=AE=E8=A8=AD=E8=A8=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TODO.md | 1 + docs/plan/memory.md | 100 +++++++++++++++++++++++++++++----------- docs/plan/workflow.md | 14 +++--- tickets/agent-skills.md | 98 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 178 insertions(+), 35 deletions(-) create mode 100644 tickets/agent-skills.md diff --git a/TODO.md b/TODO.md index bf0bc77b..214ce9c8 100644 --- a/TODO.md +++ b/TODO.md @@ -1,4 +1,5 @@ - [ ] テスト設計 → [tickets/test-design.md](tickets/test-design.md) +- [ ] Agent Skills サポート → [tickets/agent-skills.md](tickets/agent-skills.md) - [ ] ツール設計 - [ ] Bash ツール (Permission 層と統合) → [tickets/bash-tool.md](tickets/bash-tool.md) - [ ] パーミッション: パターンベースのツール実行制御 → [tickets/permission-extension-point.md](tickets/permission-extension-point.md) diff --git a/docs/plan/memory.md b/docs/plan/memory.md index c83e0669..98f83693 100644 --- a/docs/plan/memory.md +++ b/docs/plan/memory.md @@ -6,39 +6,66 @@ INSOMNIA がユーザーのプロジェクトに対して提供するメモリ リサーチは `docs/ref/memory-systems.md`。前提として、**レポジトリがファイルシステム上にある**ケースで設計する(越境・バックエンド抽象は Scope 外)。 -Workflow(`/workflow-name` で呼び出される制約付き作業フロー)は別 plan に切り出した。`docs/plan/workflow.md` 参照。 +Workflow(`/` で呼び出される制約付き作業フロー)は別 plan に切り出した。`docs/plan/workflow.md` 参照。 ## 決定事項 ### 記録対象の 5 種 -| 種別 | パス | 備考 | -| ---------------- | ---------------------------- | -------------------------------------------------------------------------------------------- | -| Always-on サマリ | `memory/summary.md` | 1-5k tokens 目安 | -| Lessons | `memory/lessons/.md` | | -| Decisions | `memory/decisions/.md` | `status: open \| resolved \| superseded` で未決議論も保持、supersede は `superseded_by` 参照 | -| Requests | `memory/requests/.md` | ユーザー submit の構造化要約 | -| Knowledge | `memory/knowledge/.md` | `#name` で注入。ノウハウ / 用語 / 運用方針 / ルール / 事実など型を設けず Markdown 自由記述 | +| 種別 | パス | 備考 | +| ---------------- | ------------------------------ | ----------------------------------------------------------------------------------------------- | +| Always-on サマリ | `memory/summary.md` | 1-5k tokens 目安 | +| Lessons | `memory/lessons/.md` | | +| Decisions | `memory/decisions/.md` | `status: open \| resolved \| replaced` で未決議論も保持、置き換え時は `replaced_by: ` | +| Requests | `memory/requests/.md` | ユーザー submit の構造化要約 | +| Knowledge | `memory/knowledge/.md` | `#slug` で注入。ノウハウ / 用語 / 運用方針 / ルール / 事実など型を設けず Markdown 自由記述 | -- `` は UUIDv7(時系列順に並ぶ)、`` は slug(小文字英数とハイフン) +- `` は kebab-case(内容を要約した短い識別子)。**ファイル名そのものが ID**、frontmatter に別途 `id` field は持たない - **1 件 1 ファイル**。append-only な複数エントリログファイルは作らない -- Phase 1 の中間ストアとして `memory/_staging/.json` を使う(Phase 2 完了で cleanup、後述) +- **同一 slug の衝突は新規作成禁止**。既存があれば update(Linter で検証、sub-Worker は read→edit に切り替え) + - 同主題の content 進化 = 上書き update + git log で履歴追跡 + - 別主題が古い主題を置き換える場合のみ、別 slug で新規作成し古い方に `status: replaced` + `replaced_by: <新 slug>` を記録 +- Phase 1 の中間ストアとして `memory/_staging/.json` を使う(短命、P2 完了で cleanup。ここは衝突回避と順序のため UUIDv7 可) - Raw session log は既存 `llm-worker-persistence` で保持する。memory 対象外、参照経路のみ ### Knowledge の呼び出し制御 -agentskills.io の `SKILL.md` 形式は採用しない。Knowledge は `#knowledge-name` でユーザー / LLM から注入参照する。名前空間は**フラット**、name は slug。 +agentskills.io の `SKILL.md` 形式は採用しない。Knowledge は `#` でユーザー / LLM から注入参照する。名前空間は**フラット**、slug は kebab-case(小文字英数とハイフン)。 | フラグ | 意味 | デフォルト | | ---------------- | ------------------------------------------------------- | ---------- | | `auto_invoke` | description が LLM context に載り、LLM が自発的に呼べる | **OFF** | -| `user_invocable` | ユーザーが `#` で明示的に呼べる | **ON** | +| `user_invocable` | ユーザーが `#` で明示的に呼べる | **ON** | `auto_invoke` の ON 化は人間の判断、または consolidation が頻繁に `user_invoke` されているものを検出して offer する。自律的に新規エンティティを生成はしない。Workflow も同じフラグ仕様(`workflow.md` 参照)。 -### 書き込み先の制約 +### 書き込み経路と Linter -`memory/workflow/` への自動書き込みは、consolidation Worker の structured output schema に `workflow` カテゴリを含めないことで担保する(後述、および `workflow.md`)。OS ファイル権限や Scope 上の特別な保護機構は設けず、`memory/` 配下を write allow する以上の細工はしない。衝突は git で解決する前提。 +人間も consolidation sub-Worker も**同じ CRUD tool(file read / write / edit)**で `memory/*` を触る。書き込み時の制約は Linter で検証し、違反時は post-write Hook が turn を戻して sub-Worker に自己修正させる(N 回失敗で abort)。 + +Linter ルールは 2 系統: + +**静的 error**(post-write Hook で turn 戻し、sub-Worker が自己修正): + +- frontmatter 必須 field + - Lessons / Decisions / Requests: `created_at`, `updated_at`, `sources` + - Knowledge: `description`, `auto_invoke`, `user_invocable`, `last_sources`, `created_at`, `updated_at` + - Summary: `updated_at`(optional: `last_rewritten_from_range`) +- `memory/workflow/` への書き込み禁止(sub-Worker context のみ、人間編集は除外) +- 同 slug での新規作成禁止(既存があれば update に切り替えるサイン) +- `#` 参照が実在ファイルを指す +- `replaced_by: ` が実在 record を指す +- Decisions の `status` は enum `open | resolved | replaced` +- `auto_invoke: true` の record は description 文字数上限(agentskills 準拠 1024 chars) +- 種別ごとの char 硬上限(具体値は運用で調整、設定ファイルで tune) + +**膨張抑制 Warn**(error ではなく改善ヒント、sub-Worker は task 余力があれば対応): + +- 重要度 × char の天秤: 低重要度で char 使用過多な record に「圧縮余地あり」Warn +- sources 累積: 配列が閾値超過で「直近 N 件に絞り過去は git log に委ねる候補」Warn +- 類似 slug 乱立: 近似 slug の集合に「merge 候補」Warn + +Workflow 保護は専用 tool schema のトリックではなく Linter ルールで担保するため、人間が規則を読んで理解できる。OS ファイル権限や Scope 上の特別な保護機構は設けず、`memory/` 配下を write allow する以上の細工はしない。衝突は git で解決する前提。 ### 自動化(consolidation)メカニズム @@ -56,6 +83,7 @@ agentskills.io の `SKILL.md` 形式は採用しない。Knowledge は `#knowled - `requests`: ユーザー submit の構造化要約(意図 / 対象 / 要約) - **抽出対象がなければ空配列を返してよい**(Hermes の "Nothing to save." と同系。頻繁発火を許容する前提) - **書き込み先**: `memory/_staging/.json` + - LLM 出力(活動ログ JSON)は pod 側ラッパーが `source: { session_id, range: [start_entry, end_entry] }` を**機械付与**して wrap。LLM には source を推論させない - **モデル**: `memory.extract_model`。軽量だが文脈理解できる中堅クラス(Haiku / 4o-mini / Flash 相当)を想定 #### Phase 2: 永続化への統合 @@ -63,13 +91,12 @@ agentskills.io の `SKILL.md` 形式は採用しない。Knowledge は `#knowled - **Trigger**: staging の累積ファイル数 or bytes が閾値超過、または compact 発火時(必ず flush) - **実行主体**: Phase 1 を終えた pod が `memory/_staging/.lock` の advisory file lock を `LOCK_EX | LOCK_NB` で取得試行。取れたら consolidation Worker を spawn。取れなければ skip(他 pod が処理中) - **Lock**: POSIX `flock(2)` / `fcntl` ベース。プロセスが生きている限り保持、落ちれば OS が自動解放。stale 検出・heartbeat 不要。reasoning 処理が数分〜十数分かかる前提 -- **入力**: staging 全件(活動ログ)+ 既存 `memory/*`(summary / lessons / decisions / requests / knowledge) -- **処理**: sub-Worker に memory read/write tool を渡し、agentic に以下を自律判断: - - 新規 lessons / decisions / requests を 1 件 1 ファイルで追加 - - 活動ログから派生する Knowledge(用語定義 / 運用方針 / ルール / 事実 / ノウハウ)を新規作成 or 既存 patch +- **入力**: staging 全件(活動ログ + `source`)+ 既存 `memory/*`(summary / lessons / decisions / requests / knowledge) +- **処理**: sub-Worker に**汎用 CRUD tool(file read / write / edit)+ post-write Linter Hook** を渡し、agentic に以下を自律判断: + - 新規 lessons / decisions / requests を 1 件 1 ファイルで追加。`sources` は staging の `source` をコピー(LLM 推論ではない) + - 活動ログから派生する Knowledge(用語定義 / 運用方針 / ルール / 事実 / ノウハウ)を新規作成 or 既存 patch。`last_sources` を更新 - summary を必要に応じて rewrite -- **書き込み先**: summary / lessons / decisions / requests / knowledge の 5 種 -- **Workflow への書き込み禁止**: Phase 2 の write tool schema に workflow を含めないことで構造的に担保(`workflow.md` 参照) +- **書き込み先**: `memory/*` 配下。Workflow 禁止は Linter で担保(`workflow.md` 参照) - **完了処理**: staging cleanup + lock release。Phase 2 完了時に staging に新着があれば次を発火(Coalesce) - **モデル**: `memory.consolidation_model`。reasoning 系 @@ -77,8 +104,10 @@ agentskills.io の `SKILL.md` 形式は採用しない。Knowledge は `#knowled `memory/` 配下は人間も git 経由で編集する。Phase 2 prompt で以下を明示: -- 既存内容を尊重し、**差分追加を優先**する。全文 rewrite は `summary.md` のみ、かつ人間編集と整合する範囲で -- 削除は supersede 記録(`status: superseded` + `superseded_by: `)で表現、直接削除しない +- **rewrite は許可**。既存内容と新規情報を統合・再構成して情報密度を上げることを優先。単純 append(追記で増やすだけ)は避ける +- rewrite 時は**情報損失を最小化**する: 既存の主張・根拠・sources を保持。表現を整理・短縮しても、含まれている要素は落とさない +- 削除は置き換え記録(`status: replaced` + `replaced_by: `)で表現、直接削除しない +- 人間編集は git diff で顕在化する前提。整合しない rewrite は避け、衝突時は git で解決 #### Offer 経路 @@ -91,13 +120,29 @@ consolidation は自律生成しない。以下は Client に `Event::Notificati 基本分離(memory は独立トリガー、compact は `input_tokens` 既存閾値のまま)。ただし **compact 発火時は Phase 2 を必ず同時 flush**(compact で失われる raw を漏らさないため)。 +### GC(定期再評価) + +Phase 2 とは別経路で memory を再評価し、drop / merge / split / `replaced` chain の整理を行う。Shann³ llm-wiki の lint 相当。Phase 2 は rewrite 許可で情報統合寄りの働きをするが、それでも残る以下の課題の出口として機能する: + +- 重要度の低い record が累積する +- 類似 slug が乱立する(Linter Warn で検出したものをまとめて処理) +- `replaced` が溜まり続けて grep / 注入時のノイズになる +- sources 累積 +- 長期的に陳腐化した記録の drop + +**詳細仕様は後で詰める**(scope 内、未決定)。方針として LLM 駆動の定期ジョブで、Linter Warn 群 + 人間 offer 承認を併用する前提。 + ### ファイル形式 -- frontmatter + Markdown 本文 -- Knowledge の frontmatter: `name`, `description`, `auto_invoke`, `user_invocable` -- Lessons / Decisions / Requests の frontmatter: `id`, `created_at`, および種別固有フィールド -- Decisions は `status: open | resolved | superseded`、supersede 時は `superseded_by: ` を併記 -- Phase 1 staging は `memory/_staging/.json`(JSON、1 件 1 ファイル、Phase 2 完了で削除) +- frontmatter + Markdown 本文。全 record 共通: `created_at`, `updated_at` +- ファイル名(slug)がそのまま識別子、frontmatter に `id` / `name` field は持たない +- source トレーサビリティ(session log への逆引き、粒度は `session_id` + entry range): + - Lessons / Decisions / Requests: `sources: [{session_id, range: [start, end]}, ...]` 永続化(update 時は追記累積) + - Knowledge: `last_sources: [{session_id, range}, ...]`(最新更新時のみ、過去履歴は git log で追う) + - Summary: optional `last_rewritten_from_range`(なしでも可) +- Knowledge 固有: `description`, `auto_invoke`, `user_invocable` +- Decisions 固有: `status: open | resolved | replaced`、置き換え時は `replaced_by: ` +- Phase 1 staging: `memory/_staging/.json`(JSON、1 件 1 ファイル、Phase 2 完了で削除。短命なので UUIDv7 可)。pod 側ラッパーが `source` を機械付与して LLM 出力と wrap - Workflow の frontmatter は `workflow.md` 参照 ## Scope 外 @@ -112,7 +157,6 @@ consolidation は自律生成しない。以下は Client に `Event::Notificati - Phase 2 を担う常駐 daemon 化 — オンデマンド + lock 方式で始める。必要性が出たら upgrade path として daemon 化 - Deterministic promotion(OpenClaw 型 scoring + ゲート)— 初期は Phase 2 agent の LLM 判断に委ねる。運用実績で出力を評価してから、成熟カテゴリから scoring 導入 - Shallow request の自動除外判定 — 初期は Phase 1 prompt で「些細な質問は返さなくてよい」と指示する程度。精緻な filter は後 -- Retention / GC — Phase 2 agent に直接削除禁止(supersede のみ)を課す一方、明示クリーンアップ経路は未定義。別途 LLM 駆動 GC を用意する前提で、初期は無制限蓄積 + summary rewrite で凌ぐ ### 別 plan / ticket で扱う diff --git a/docs/plan/workflow.md b/docs/plan/workflow.md index 2d177266..c7a6c899 100644 --- a/docs/plan/workflow.md +++ b/docs/plan/workflow.md @@ -2,15 +2,15 @@ ## Context -Workflow は制約付きの強制的な作業フロー。`/workflow-name` で明示的に呼び出し、依存 Knowledge を context に inject してから実行する。Knowledge(`#knowledge-name`)は `docs/plan/memory.md` 側で定義。 +Workflow は制約付きの強制的な作業フロー。`/` で明示的に呼び出し、依存 Knowledge を context に inject してから実行する。Knowledge(`#`)は `docs/plan/memory.md` 側で定義。 ## 決定事項 ### 呼び出しと依存 -- 呼び出し: `/workflow-name` -- 名前空間はフラット、name は slug(小文字英数とハイフン) -- frontmatter `requires: [knowledge-name, ...]` で依存 Knowledge を name 参照 +- 呼び出し: `/` +- 名前空間はフラット、slug は kebab-case(小文字英数とハイフン) +- frontmatter `requires: [knowledge-slug, ...]` で依存 Knowledge を slug 参照 - 実行時は依存 Knowledge 本文を context に inject してから Workflow 本文を実行 ### 呼び出し制御フラグ @@ -18,15 +18,15 @@ Workflow は制約付きの強制的な作業フロー。`/workflow-name` で明 | フラグ | 意味 | デフォルト | | ---------------- | ------------------------------------------------------- | ---------- | | `auto_invoke` | description が LLM context に載り、LLM が自発的に呼べる | **OFF** | -| `user_invocable` | ユーザーが `/` で明示的に呼べる | **ON** | +| `user_invocable` | ユーザーが `/` で明示的に呼べる | **ON** | `auto_invoke` の ON 化は人間の判断、または consolidation からの offer 経由のみ。同じ制御は Knowledge 側(`memory.md`)でも採用。 ### 格納先とファイル形式 -- `memory/workflow/.md` +- `memory/workflow/.md`(ファイル名 = slug がそのまま識別子、`name` field は持たない) - frontmatter + Markdown 本文 -- frontmatter フィールド: `name`, `description`, `auto_invoke`, `user_invocable`, `requires` +- frontmatter フィールド: `description`, `auto_invoke`, `user_invocable`, `requires` ### 生成・更新ポリシー diff --git a/tickets/agent-skills.md b/tickets/agent-skills.md new file mode 100644 index 00000000..5477ff68 --- /dev/null +++ b/tickets/agent-skills.md @@ -0,0 +1,98 @@ +# Agent Skills サポート + +## 背景 + +[agentskills.io](https://agentskills.io/) で公開されているオープン標準 "Agent Skills" は、エージェントに手続き的知識・ドメイン能力をフォルダ単位で供給する形式。Anthropic 発で Claude Code / Cursor / OpenCode / Gemini CLI / Goose / OpenHands など主要な coding agent 群が採用しつつあり、ユーザーが既に書いた skill を insomnia に持ち込める/他ツールと共有できる価値が明確になっている。 + +`docs/ref/memory-systems.md` でも Hermes Agent の "Skill Library" が agentskills.io 互換として言及済みで、将来のセルフ生成メモリ経路 (procedural memory) の受け皿としてもこのフォーマットに合わせておく利がある。 + +### Skill の骨格 (仕様要旨) + +``` +skill-name/ +├── SKILL.md # 必須: YAML frontmatter + Markdown 本体 +├── scripts/ # 任意: 実行コード +├── references/ # 任意: 詳細ドキュメント +└── assets/ # 任意: テンプレート等の静的資産 +``` + +SKILL.md frontmatter: + +| フィールド | 必須 | 制約 | +|---|---|---| +| `name` | ○ | 1-64 chars, `[a-z0-9-]+`, 先頭末尾 `-` 不可, `--` 連続不可, **ディレクトリ名と一致** | +| `description` | ○ | 1-1024 chars, 非空 | +| `license` | | 自由文 | +| `compatibility` | | 1-500 chars | +| `metadata` | | 任意の key-value map | +| `allowed-tools` | | experimental (空白区切りのツールリスト) | + +仕様の肝は **progressive disclosure**: + +1. メタデータ (`name` + `description`) — セッション開始時に**全 skill 分**をプロンプトに載せる (~100 tokens/skill) +2. 指示本体 (SKILL.md body) — skill が必要になった時点で agent 側が読みに行く +3. リソース (`scripts/` / `references/` / `assets/`) — さらに on-demand + +## 既存機構との関係 + +insomnia のシステムプロンプトは現状、`instruction` (テンプレ本体) + scope summary + AGENTS.md (trailing section) の 3 要素構成。Skill はこの並びに**任意個のオプショナル能力資産**として追加する位置取り。instruction / AGENTS.md を置き換えない。 + +配置は既存の prefix addressing と同じ軸: + +- `$XDG_CONFIG_HOME/insomnia/skills//SKILL.md` +- `/.insomnia/skills//SKILL.md` +- `$insomnia/skills/` (ビルトイン) は不要になるまで作らない + +## 方針 + +### MVP スコープ + +1. **Skill ディスカバリと検証** + - 上記 2 経路のサブディレクトリを走査して `SKILL.md` を読む + - frontmatter を仕様通り検証。name 不一致・必須欠落・制約違反は hard error (Pod 起動失敗) + - 未知フィールドは `tracing::warn!` して無視 (pod-factory と同方針) + - 重複 name は workspace 層優先で user 層を上書き + ユーザー向け notification 発行 + +2. **システムプロンプトへの注入 (progressive disclosure 準拠)** + - `SystemPromptContext` に `skills: Vec` を追加 (`name`, `description`, 絶対パス) + - ビルトイン `$insomnia/default.md` に skill 列挙ブロックを追加 (空なら一切出力しない) + - ユーザーテンプレートからも `{{ skills }}` で参照可能 + - **本体は注入しない**。description の末尾に絶対パスを併記し、agent が Read ツールで取れるようにする + +3. **本体への agent アクセス** + - skill ディレクトリを `Scope` に `permission = read` で自動 allow + - `scripts/` の実行は将来 Bash ツール + Permission 層で成立するまで Read 経由での閲覧に留める + +### 範囲外 + +- `allowed-tools` フィールドの実効化 — `permission-extension-point.md` が Permission 層を整備するまで受信して無視 +- skill 専用の実行機構 — `scripts/` は Bash / Read で自然に扱う +- skill の自動生成 (Hermes 風 Skill Library) — memory 系チケットで別途。本チケットで作る ingest 経路を再利用する側 +- ビルトイン skill (`$insomnia/skills/`) — 必要になるまで追加しない +- skill 間依存の解決 — 独立単位、相互参照は本体の Markdown リンクで + +## 完了条件 + +- `$user/skills/` と `$workspace/skills/` の両方から skill をロードし、frontmatter 違反は Pod 起動エラーになる +- ビルトインの `$insomnia/default.md` をレンダした結果、存在する skill の name + description + 絶対パスがシステムプロンプトに列挙される +- skill が 0 件のとき、既存の出力 (AGENTS.md / scope summary) が全く変わらない +- skill ディレクトリが scope の readable に含まれ、agent が Read ツールで `SKILL.md` 本体・`scripts/`・`references/` にアクセスできる +- 単体テストで frontmatter 検証の正常 / 異常系、progressive disclosure レンダリング、user/workspace 重複解決が verify される + +## 実装順序 + +1. `manifest` または新設 `skill` クレートに `Skill` 構造体と `SkillDirectoryLoader` を置く。SKILL.md パースと検証のみでテスト完結 +2. `pod::SystemPromptContext` に `skills` を生やし、`ensure_system_prompt_materialized` で loader を呼ぶ +3. `resources/prompts/default.md` に skills ブロックを追加、`Pod::from_manifest` で skill ディレクトリを scope readable に union +4. 重複 name 解決と notification 発行を乗せる + +各ステップ終了時点でビルド通過・既存テスト合格を維持する。skill 0 件時の後方互換は Phase 2 で確認する。 + +## 参照 + +- 仕様本体: https://agentskills.io/specification +- 採用状況: https://agentskills.io/home +- Anthropic 公式サンプル: https://github.com/anthropics/skills +- 検証 CLI: https://github.com/agentskills/agentskills/tree/main/skills-ref (将来 `pod skills validate` 相当を作るなら参考) +- 類似機構: `crates/pod/src/prompt_loader.rs` (prefix addressing), `crates/pod/src/agents_md.rs` (cwd-relative ingest), `crates/pod/src/system_prompt.rs` (render pipeline) +- 後続接続先: `docs/ref/memory-systems.md` の Skill Library (自動生成 skill の保存先)