Memoryシステムの整理・Promptカタログチケット

This commit is contained in:
Keisuke Hirata 2026-04-22 13:21:15 +09:00
parent 270d7923ab
commit 0c1276b730
6 changed files with 417 additions and 33 deletions

View File

@ -6,6 +6,7 @@
- [ ] LLM プロバイダ/モデルカタログ → [tickets/llm-provider-catalog.md](tickets/llm-provider-catalog.md)
- [ ] Pod オーケストレーション
- [ ] 動的 Scope 変更 → [tickets/dynamic-scope.md](tickets/dynamic-scope.md)
- [ ] Pod 内部プロンプトのカタログ化 → [tickets/pod-prompt-catalog.md](tickets/pod-prompt-catalog.md)
- [ ] ネイティブ GUI クライアント MVP → [tickets/native-gui-mvp.md](tickets/native-gui-mvp.md)
- [ ] TUI 拡充
- [ ] フルスクリーン化によるオーバーホール → [tickets/tui-fullscreen-overhaul.md](tickets/tui-fullscreen-overhaul.md)

View File

@ -0,0 +1,84 @@
# メモリ機構の prompt 要件
## Context
`docs/plan/memory.md` で決めた memory の挙動を、実装時に prompt 要件へ落とすための補助ページ。ここでは「個別タスクをこなすベーシックな system / developer 指示」の上に追加で必要になる、memory 固有の指示だけをまとめる。
前提は **tool-based + agentic**。専用 schema で挙動を閉じ込めるのではなく、基本は sub-Worker に CRUD tool を渡し、prompt と post-write 検証で振る舞いを制約する。例外は Workflow で、`docs/plan/workflow.md` の通り自動書き込みはしない。
## 決定事項
### 共通原則
memory 関連 prompt は種別を問わず、最低限以下を共有する:
- **source を推論しない**。`session_id` や entry range は wrapper / 呼び出し側が機械付与し、LLM が捏造しない
- **rewrite は許可**するが、情報損失は最小化する。既存の主張・根拠・参照を保ったまま整理・圧縮する
- **単純 append を優先しない**。既存 record に統合できるなら update を優先する
- **session 固有の進行状態を書かない**。長期参照価値のある内容だけを memory に残す
- **既存 docs と重複保存しない**。`AGENTS.md`、`docs/plan/*`、固定運用文書に既にある内容を再保存しない
- **空出力を許容**する。保存価値が無ければ「何も追加しない」を正当な結果として扱う
### Phase 1: 活動抽出 prompt
Phase 1 は「派生物を作る」段階ではなく、「起きたことを抽出する」段階として縛る:
- 対象は `decisions`、`discussions`、`attempts`、`requests` の候補に限る
- Knowledge 化、summary rewrite、slug 命名、`auto_invoke` 判断は行わない
- 一回限りの雑談、浅い質問、長期参照価値の薄い進行ログは返さなくてよい
- 出力は schema 準拠の構造化データのみ。自由文の補足説明で schema 外情報を足さない
- 対象が無ければ空配列を返す
### Phase 2: 統合 prompt
Phase 2 は既存 `memory/*` と staging を見て、追加・更新・統合を agentic に判断する:
- 入力には staging の活動ログ、既存 `memory/*`、Knowledge 化候補レポートを含める
- 新規作成より update を優先し、既存 slug に自然に統合できる場合は新規 file を増やさない
- Decisions / Requests は staging の `source` をそのまま使い、LLM が `sources` を組み立てない
- summary は必要なときだけ rewrite し、常に 1-5k tokens 目安に圧縮する
- 削除は直接行わず、Decision の置き換えは `status: replaced``replaced_by` で表現する
- 人間編集との不整合が見える rewrite は避け、衝突しそうなら保守的に統合する
### Phase 2: Knowledge 書き込み prompt
Knowledge の新規作成 / 更新では、Phase 2 全体の原則に加えて以下を明示する:
- 採択ラインは「このプロジェクト / ユーザーに対して再度参照価値のある事実・ルール・ノウハウ」に限る
- 一回限りの判断や議論は Decisions に留め、繰り返し参照される抽象化だけを Knowledge に上げる
- 新規作成は Knowledge 化候補レポートに載った source から派生する場合に限る
- 既存 Knowledge の slug / description 一覧を見て、適合先があるなら必ず update を優先する
- 新規 slug は「既存に適合先が無い」と説明できるときだけ作る
- `last_sources` は入力で与えられた source を使い、推論で補完しない
- `description` は「何の知識か / いつ使うか」が短く分かる文にする
- `auto_invoke` ON/OFF は頻度・常駐コストの判断材料を踏まえて慎重に扱い、初期値は OFF とする
- `#<slug>` 参照を書く場合は、実在 record への参照だけを使う
- `AGENTS.md``docs/` に既に固定化されたルールの写しは作らない
- 保存価値が無ければ Knowledge を何も追加しない
### 監査 LLM prompt
監査 LLM は「よく書けているか」ではなく、「壊していないか」を見る:
- 入力には write 前後 diff、対象 record の直前内容、今回の source / staging 抜粋、採択基準を渡す
- rewrite / 圧縮で主張、根拠、参照が失われていないかを確認する
- 新規追加が source や活動ログに裏打ちされているかを確認する
- session 固有の進行状態や一時的事情が混入していないかを確認する
- `description` が本文のスコープと一致しているかを確認する
- `auto_invoke` の設定が本文の重要度や再利用性と不整合でないかを確認する
- 問題がある場合は `pass | fail` に加えて違反カテゴリと具体箇所を返し、Hook が差し戻せる形にする
### GC prompt
GC は Phase 2 より攻撃的に整理してよいが、可逆性と説明可能性を保つ:
- 入力には GC 対象 record 群に加えて、Linter Warn、使用頻度メトリクス、`replaced` chain、sources 過多情報を含める
- 明示 invoke 保護閾値を超える record は drop / 大幅圧縮の対象外とする
- `similar-slug`、`sources-overflow`、`replaced` 滞留、stale record を優先的に処理する
- merge / split / trim / drop の理由を diff から読める形で残す
- 直接削除してよいが、git で可逆である前提に甘えすぎず、誤判定しやすいものは merge / trim を優先する
## 関連
- `docs/plan/memory.md`: memory 全体方針
- `docs/plan/workflow.md`: workflow を自動書き込みの例外にしている理由

View File

@ -6,19 +6,20 @@ INSOMNIA がユーザーのプロジェクトに対して提供するメモリ
リサーチは `docs/ref/memory-systems.md`。前提として、**レポジトリがファイルシステム上にある**ケースで設計する(越境・バックエンド抽象は Scope 外)。
prompt 要件の整理は `docs/plan/memory-prompts.md` に切り出した。
Workflow`/<slug>` で呼び出される制約付き作業フロー)は別 plan に切り出した。`docs/plan/workflow.md` 参照。
## 決定事項
### 記録対象の 5
### 記録対象の 4
| 種別 | パス | 備考 |
| ---------------- | ------------------------------ | ----------------------------------------------------------------------------------------------- |
| Always-on サマリ | `memory/summary.md` | 1-5k tokens 目安 |
| Lessons | `memory/lessons/<slug>.md` | |
| Decisions | `memory/decisions/<slug>.md` | `status: open \| resolved \| replaced` で未決議論も保持、置き換え時は `replaced_by: <slug>` |
| Requests | `memory/requests/<slug>.md` | ユーザー submit の構造化要約 |
| Knowledge | `memory/knowledge/<slug>.md` | `#slug` で注入。ノウハウ / 用語 / 運用方針 / ルール / 事実など型を設けず Markdown 自由記述 |
| 種別 | パス | 備考 |
| ---------------- | ---------------------------- | ------------------------------------------------------------------------------------------- |
| Always-on サマリ | `memory/summary.md` | 1-5k tokens 目安 |
| Decisions | `memory/decisions/<slug>.md` | `status: open \| resolved \| replaced` で未決議論も保持、置き換え時は `replaced_by: <slug>` |
| Requests | `memory/requests/<slug>.md` | ユーザー submit の構造化要約 |
| Knowledge | `memory/knowledge/<slug>.md` | `#slug` で注入。ノウハウ / 用語 / 運用方針 / ルール / 事実など型を設けず Markdown 自由記述 |
- `<slug>` は kebab-case内容を要約した短い識別子。**ファイル名そのものが ID**、frontmatter に別途 `id` field は持たない
- **1 件 1 ファイル**。append-only な複数エントリログファイルは作らない
@ -37,18 +38,27 @@ agentskills.io の `SKILL.md` 形式は採用しない。Knowledge は `#<slug>`
| `auto_invoke` | description が LLM context に載り、LLM が自発的に呼べる | **OFF** |
| `user_invocable` | ユーザーが `#<slug>` で明示的に呼べる | **ON** |
`auto_invoke` の ON 化は人間の判断、または consolidation が頻繁に `user_invoke` されているものを検出して offer する。自律的に新規エンティティを生成はしない。Workflow も同じフラグ仕様(`workflow.md` 参照)。
Knowledge は Phase 2 が自律的に新規作成 / 更新 / フラグ切替を行う前提。毎回の人間承認 gate は設けない(実効性が低い)。保護は 3 段で担保:
- **採択 gate**: Knowledge 新規作成は使用頻度メトリクスの Knowledge 化候補レポート(後述)に載った source から派生する場合に限る。閾値未満のうちは decisions / requests に留める
- **Linter + 監査 LLM**: 構造違反と意味破壊を watch詳細は後述
- **OS ファイル権限**: 人間が書き換えさせたくない record は `-r--` にしてロック。Phase 2 / GC の write は OS レベルで弾かれる
Workflow も同じフラグ仕様(`workflow.md` 参照。per-record 保護フラグを提供する拡張は将来検討、初期は OS 権限で足りる。
### 書き込み経路と Linter
人間も consolidation sub-Worker も**同じ CRUD toolfile read / write / edit**で `memory/*` を触る。書き込み時の制約は Linter で検証し、違反時は post-write Hook が turn を戻して sub-Worker に自己修正させるN 回失敗で abort
人間も consolidation sub-Worker も**同じ CRUD toolfile read / write / edit**で `memory/*` を触る。書き込み時の制約は 2 層で検証し、違反時は post-write Hook が turn を戻して sub-Worker に自己修正させるN 回失敗で abort:
1. **Linter静的**: frontmatter / slug / 参照整合などの機械的ルール
2. **監査 LLM意味的**: rewrite が元の情報を壊していないかを別 prompt で check。特に Knowledge の意味損壊を watch する主経路
Linter ルールは 2 系統:
**静的 error**post-write Hook で turn 戻し、sub-Worker が自己修正):
- frontmatter 必須 field
- Lessons / Decisions / Requests: `created_at`, `updated_at`, `sources`
- 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 のみ、人間編集は除外)
@ -75,7 +85,7 @@ Workflow 保護は専用 tool schema のトリックではなく Linter ルー
- **Trigger**: activity tokens の累積閾値。tool call カウントは不採用(ツールカスタマイズ非依存・大小重みづけのため)
- **実行主体**: 既存 compact と同じ Worker spawn 機構を再利用。Pod は立てない
- **入力**: 前回 Phase 1 以降の session log 範囲
- **入力**: 前回 Phase 1 以降の session log 範囲。処理済み境界の pointer は session 側に保持(寿命を session と揃える)
- **出力**: JSON schema で**活動ログ**の候補配列を返す。Knowledge 等の派生物は Phase 2 が活動ログから導出するので、Phase 1 では純粋な「起きたこと」に絞る
- `decisions`: 判断したこと(選択肢 + 選んだ + 根拠)
- `discussions`: 議論したこと(トピック + 論点)
@ -89,17 +99,26 @@ Workflow 保護は専用 tool schema のトリックではなく Linter ルー
#### Phase 2: 永続化への統合
- **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 全件(活動ログ + `source`+ 既存 `memory/*`summary / lessons / decisions / requests / knowledge
- **実行主体**: Phase 1 を終えた pod が consolidation Worker を spawn。並走防止は staging 配下の進行状況ファイル(後述)で担保
- **入力**: 起動時スナップショットで確定した consumed ID list 分の staging エントリ(活動ログ + `source`+ 既存 `memory/*`summary / decisions / requests / knowledge+ **Knowledge 化候補レポート**(後述の使用頻度メトリクスから機械集計、閾値超過の source 一覧)
- **処理**: sub-Worker に**汎用 CRUD toolfile read / write / edit+ post-write Linter Hook** を渡し、agentic に以下を自律判断:
- 新規 lessons / decisions / requests を 1 件 1 ファイルで追加。`sources` は staging の `source` をコピーLLM 推論ではない)
- 活動ログから派生する Knowledge用語定義 / 運用方針 / ルール / 事実 / ノウハウ)を新規作成 or 既存 patch。`last_sources` を更新
- 新規 decisions / requests を 1 件 1 ファイルで追加。`sources` は staging の `source` をコピーLLM 推論ではない)
- 活動ログから派生する Knowledge用語定義 / 運用方針 / ルール / 事実 / ノウハウ)を新規作成 or 既存 patch。**新規作成は候補レポート掲載の source から派生する場合に限る**。`last_sources` を更新
- summary を必要に応じて rewrite
- **書き込み先**: `memory/*` 配下。Workflow 禁止は Linter で担保(`workflow.md` 参照)
- **完了処理**: staging cleanup + lock release。Phase 2 完了時に staging に新着があれば次を発火Coalesce
- **完了処理**: consumed ID list の staging のみ cleanup実行中に Phase 1 が追加した分は残す)。Phase 2 完了時に staging に新着があれば次を発火Coalesce
- **モデル**: `memory.consolidation_model`。reasoning 系
##### 並走防止
- 場所: staging 配下に 1 ファイル(名前・形式は未定)
- 中身: 動作中の Pod 識別子 + **consumed ID list**(この Phase 2 run が起動時スナップショットで確定した staging エントリ ID の列)
- 占有ルール: そのファイルが存在し、示された Pod が動作している間、そのプロセスが排他占有
- 実行中に Phase 1 が staging に追加したエントリは触らず、次回 Phase 2Coalesceに委ねる
- cleanup は consumed ID list のエントリのみ削除、追加分は残す
- クラッシュ時は consumed ID list から処理途中を特定できる。重複作成は同一 slug update に自然収束
- 占有の実現方法pid 存在確認 / flock / 他)は未定
#### Phase 2 agent への原則
`memory/` 配下は人間も git 経由で編集する。Phase 2 prompt で以下を明示:
@ -111,9 +130,8 @@ Workflow 保護は専用 tool schema のトリックではなく Linter ルー
#### Offer 経路
consolidation は自律生成しない。以下は Client に `Event::Notification` で提案し、人間承認で反映:
Memory record の書き込みは Phase 2 が自律判断し、Offer は設けないKnowledge 含む)。人間承認経路が必要なのは以下:
- Knowledge の `auto_invoke` ON 化
- Workflow 関連の offer新規作成 / 改善 / `auto_invoke` ON 化)は `workflow.md` 参照
#### Compact との関係
@ -122,7 +140,7 @@ consolidation は自律生成しない。以下は Client に `Event::Notificati
### GC定期再評価
Phase 2 とは別経路で memory を再評価し、drop / merge / split / `replaced` chain の整理を行う。Shann³ llm-wiki の lint 相当。Phase 2 は rewrite 許可で情報統合寄りの働きをするが、それでも残る以下の課題の出口として機能する:
Phase 2 とは別経路で memory を再評価する定期ジョブ。Phase 2 は rewrite 許可で情報統合寄りの働きをするが、それでも残る以下の課題の出口として機能する:
- 重要度の低い record が累積する
- 類似 slug が乱立するLinter Warn で検出したものをまとめて処理)
@ -130,14 +148,45 @@ Phase 2 とは別経路で memory を再評価し、drop / merge / split / `repl
- sources 累積
- 長期的に陳腐化した記録の drop
**詳細仕様は後で詰める**scope 内、未決定)。方針として LLM 駆動の定期ジョブで、Linter Warn 群 + 人間 offer 承認を併用する前提。
他プロジェクトの GC 設計の横断比較は `docs/ref/memory-systems.md` §8。
#### 権限と操作粒度
GC Agent は **drop / merge / split を自律実行**(削除まで含む)。人間 offer はかけず、結果は git diff で検証する建て付け。operation 粒度は以下の両方:
- **ファイル単位**: 丸ごと drop、複数ファイルの merge、1 ファイルの分割split
- **ファイル内の部分削除**: 本文の一部節・箇条を削除 or 圧縮。frontmatter の `sources` 古いエントリの trim も含む
Phase 2 と同じ CRUD tool + Linter Hook を使うので、operation 粒度は自然にサポートされる(専用 API は用意しない)。
#### 使用頻度メトリクス
時間単位は実時間を使わないLLM スループット向上で陳腐化の意味が変わるため)、累積 input token で正規化する。
**観測経路**: `memory/*` への読み取りは専用の memory 検索ツール(既存 built-in の grep / read とは別に用意経由に揃える。invoke 計測はツール内でフックし、`#<slug>` / `/<slug>` / 明示検索呼び出しを同一経路に集約する。
**カウント対象**:
- **明示 invoke**: 検索ツール経由の読み取り / `#<slug>` / `/<slug>` を n回/Mtoken でスコア化
- **auto_invoke 注入**: 注入は context 常駐コストで、「載っているだけ」か「使われた」かを統計上区別不能。明示 invoke の分子には含めず、**コスト側(注入した record に対する消費 input tokensとして別途記録**する。使われ率 ratio や ON/OFF 判断の材料として後段で使う
- ファイル token 数
**記録先**: staging とは独立。invoke event を UUID + Stats 形式で workspace 側に記録し、session データが失われても統計が残るようにする。具体 schema・フォーマットは未定。
**累積方式**(後集計アプローチ): 上記 invoke 記録に対して最大 10 回前の invoke から現在までの時系列窓でフィルタして集計する。
**Knowledge 化候補レポート**: Phase 2 が入力に受け取る、Knowledge 新規作成 gate 用の機械集計。対象は `memory/*` 配下の recordPhase 1 成果物である decisions / requests / 既存 knowledgeで、明示 invoke 頻度が閾値超過のものを列挙する。spike 除外のため、同一 session 内の連続参照は 1 count に丸め、複数 session での再参照を要件とする。閾値の具体値は運用で調整、設定ファイルで tune。
#### 判断ルール
- 保護閾値: **明示 invoke**`frequency >= 1.0 invokes/Mtoken` の record は drop / 大幅圧縮の対象外(初期値 1.0、workspace 設定でカスタマイズ可。auto_invoke 注入による常駐は計数対象外(別指標として後段で参照)
### ファイル形式
- 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 時は追記累積)
- 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`

View File

@ -33,6 +33,7 @@ Codex CLI に 2026-03 頃から追加された "Memories" 機能と、2026-04-15
- `memory_summary.md` を中心に「summaries / durable entries / recent inputs / supporting evidence」の Markdown を束ねる構成。
- Chronicle 派生メモリは `$CODEX_HOME/memories_extensions/chronicle/` に分離。
- スクリーンキャプチャ中間物は `$TMPDIR/chronicle/screen_recording/` に置かれ、running 中 6h で自動削除。サーバー側には保存しない(法的義務時を除く)。
- **Extension resource retention は決定論的 7 日 hard-coded**`EXTENSION_RESOURCE_RETENTION_DAYS = 7`, `memories/extensions.rs:11`。filename embedded timestamp (`%Y-%m-%dT%H-%M-%S`) が cutoff より古い `.md` リソースを Phase 2 直前に物理削除し、削除リストを `removed_extension_resources` として consolidation prompt に渡すagent はそれを見て派生メモリを抹消)。
### 設定
@ -93,7 +94,7 @@ Shann³ の構成は Karpathy が 2026-04 に公開した `llm-wiki` gist をそ
- **query**: wiki を検索し citation 付きで答える。意義ある合成は `syntheses/` として保存。
- **lint**: 矛盾・stale claim・孤立ページ・参照抜け・データ欠落の定期点検。
`SamurAIGPT/llm-wiki-agent` がこのパターンを具体化しており、ディレクトリ構造が示唆的:
`SamurAIGPT/llm-wiki-agent` がこのパターンを具体化しており、ディレクトリ構造が示唆的(なお `/wiki-lint` のプロダクション実装としては OpenClaw `memory-wiki` extension があり、§4 / §9 で触れる)
```
wiki/
@ -168,6 +169,7 @@ Self-improving agent を名乗るフレーム。メモリ周りは **3 層 + ク
- `skill_manage` tool: OpenAI function-calling schema。frontmatter YAML 検証、security scan、atomic write (temp + `os.replace()`)
- `memory` tool: target = `memory | user`、action = `add | replace | remove`。fcntl/msvcrt で file lock、entry-based rewrite
- **char limit 超過時は `add` を hard reject**`memory_tool.py:248-259`)。エラーメッセージに `Memory at {current}/{limit} chars. Adding this entry would exceed the limit. Replace or remove existing entries first.` と明記し、LLM 側に「自分で削減してから再追加」を強制する。GC は完全に LLM agentic決定論的 eviction は無い)、人間 offer や scoring も無い、非常にシンプルな設計
- FTS5: `messages_fts` virtual table + INSERT/DELETE/UPDATE trigger で auto-sync、CJK は LIKE フォールバック
### 実装観点
@ -197,13 +199,14 @@ Self-improving agent を名乗るフレーム。メモリ周りは **3 層 + ク
- 4 区画: **Message Buffer**(直近)、**Core Memory**in-context の編集可能 block: user prefs / persona、**Recall Memory**(全履歴の検索)、**Archival Memory**(ベクトル or グラフ DB に外部化された宣言的知識)。
- OS メタファ: context window = RAM、外部ストア = Disk。エージェントが function call で階層間を移動させる。
- memory block = `{label, description, value, char_limit}`
- **sleep-time agent** が idle 中に非同期で block を書き換える。
- context 限界近くで要約による eviction → 再帰要約で古いメッセージを累進圧縮。
- **sleep-time agent** が idle 中に非同期で block を書き換える。主要 agent と **別 process で並列**に走り、`core_memory_replace` / `core_memory_append` / archival tool 群を呼んで **直接 memory block を書き換える**。主 agent のターン処理をブロックしないため、「mid-session で memory 品質を上げる」のが特徴。
- context 限界近くで要約による eviction → 再帰要約で古いメッセージを累進圧縮。**eviction 判断は context window fill の決定論的しきい値**で発火するが、要約の内容生成は LLM。evicted message は recursive summary として memory block に残り、古いほど重みが相対的に下がる。
### Cloudflare Agent Memory (2026-04 Agents Week)
- 分類: **Fact / Event / Instruction / Task**Task のみベクトル索引除外)。
- 基盤: Durable Objectsプロファイル毎の SQLite、FTS・supersession chain・tx write を担う、Vectorizeセマンティック、Workers AILlama 4 Scout: 構造化、Nemotron 3: 自然文合成)。
- **Supersession chain は決定論的**(公式 blog 再確認): Fact / Instruction は classification pipeline で **normalized topic key** が振られ、同 key の新 memory が来ると旧 memory を **supersede物理削除せず forward pointer で版チェーン化)**。LLM 判断は入らない。superseded 側の vector は並行して削除され、新 vector が upsert される。SHA-256 content-addressed ID で `INSERT OR IGNORE` による冪等 dedupe も併用。
- API:
```javascript
const profile = await env.MEMORY.getProfile("my-project");
@ -262,6 +265,17 @@ Agent Workspace`~/.openclaw/workspace/`)構成:
**insomnia にとって重要**: consolidation を LLM 依存から切り離せる見本。narrative は subagent が生成するが、promotion の判断は純機械scoring。insomnia の plan では Scope 外Phase 2 は当面 agent 委任)だが、成熟したカテゴリから決定論的 promotion に差し替える upgrade path の参考になる。
**GC 観点の追加詳細**`extensions/memory-core/src/short-term-promotion.ts:1518-1652` 実装より):
- `applyShortTermPromotions()`**append 専用**。gate 通過候補の snippet を `MEMORY.md` 末尾に `<!-- openclaw-memory-promotion:<hash> --> ` marker 付きで追記するだけで、既存 `MEMORY.md` ブロックの書き換えや削除は一切行わない
- **重複回避**: marker set を先読みし、既に書かれた key はスキップ
- **汚染検出**: `isContaminatedDreamingSnippet()` で dreaming narrative prompt が snippet に混入している候補を promotion 前に弾く(再帰汚染防止)
- **日次ノートの decay は物理削除ではなく search score 減衰のみ**`memory/temporal-decay.ts`)。`halfLifeDays = 30` で `exp(-ln2/HL * age)` を score に乗じる。対象は `memory/YYYY-MM-DD.md` 形式のファイル限定で、`MEMORY.md` や topic ファイルは evergreen 扱い(減衰しない)
- **自己参照汚染の退避**: `dreaming-repair.ts` は dreaming narrative が session corpus や `DREAMS.md` に逆流した場合を検出し、該当ファイルを `.openclaw-repair/dreaming/<timestamp>/`**rename で退避**削除ではない。lint と同じく audit-first の GC スタイル
- `MEMORY.md` 側の GC重複 block の統合、stale record の drop 等)は **この extension には存在しない**。書き込みは promotion の append のみで、ユーザーが手で消すか `memory-wiki` lint のレポート経由で扱う
OpenClaw は「**削除は人間、script は append と退避まで**」という強い原則が貫かれている。
設計上の示唆:
- Workspace = git リポジトリ 1 本で完結、配置もフラット。insomnia の pod workspace 概念にそのまま借用できる。
@ -448,9 +462,108 @@ insomnia で意思決定すべきポイントはこの対応表:
---
## 8. 未調査 / 次に掘るべき項目
## 8. GC 機構の横断比較
`docs/plan/memory.md` §GC は「Phase 2 とは別経路で memory を再評価し、drop / merge / split / `replaced` chain 整理を行う」ことを決めた段階で、判断主体と処理種別の仕様をこれから詰める。本節は他プロジェクトの GC 設計を共通の 6 軸で並べて、insomnia で採るべき型の材料とする。
### 8.1 比較表
対象の行は「その system が実装している GC 機構」単位で、同じプロジェクトが複数機構を持つ場合は複数行にした。
| # | プロジェクト / 機構 | 対象 | トリガー | 判断主体 | 処理種別 | 人間介入点 | 履歴保持 |
|---|---------------------|------|----------|----------|----------|-----------|---------|
| 1 | Codex Phase 2 consolidation | `MEMORY.md` block / `memory_summary.md` / `skills/*` | session idle + age | **LLM agentic**sub-agent | drop / merge / split / rewrite、removed thread id に紐づく block を **部分削除**block 丸ごとは消さない、thread-local 記述のみ除去) | 無し(`/memories` で thread 単位 opt-out のみ) | git 任意、memory_root は単なる Markdown |
| 2 | Codex extension resource retention | `memories_extensions/<name>/resources/*.md` | Phase 2 実行直前に cron 相当 | **決定論** | **物理削除** filename timestamp cutoff | 無し | 完全消去、Phase 2 prompt に removed list を通知 |
| 3 | Codex stage1 pruning | `stage1_outputs` SQLite row | Phase 2 後 / 容量超過 | **決定論** | `selected_for_phase2 = 0` の古い row を cutoff + `LIMIT` で DELETE | 無し | SQL 完全削除 |
| 4 | Hermes `memory` tool | `MEMORY.md` / `USER.md` のエントリ | **char limit (2,200 / 1,375) 超過時の add 拒否** | **LLM agentic**(エラー受けて自分で `replace` / `remove` を呼ぶ) | drop / rewrite | 無しall-agent | ディスク消去file lock で tx 化) |
| 5 | Hermes background review | entry / skill | turn / iter カウンタ10 デフォルト) | **LLM agentic**fork agent、max_iterations = 8 | add / update / delete をレビュー判断、`Nothing to save.` で no-op | 無し | same as 4 |
| 6 | OpenClaw `applyShortTermPromotions` | promotion candidate → `MEMORY.md` | Deep dreaming phase | **決定論**6 重み合算 + 3 ゲート、LLM ゼロ) | **append のみ**`<!-- openclaw-memory-promotion:<hash> -->` marker、既存 block は触らない) | 無し | 追記のみ、削除系統は別 |
| 7 | OpenClaw temporal decay | `memory/YYYY-MM-DD.md` | search 呼び出し毎 | **決定論** | **物理削除せず search score 減衰**half-life 30d | 無し | ファイル残置、検索順位だけ沈む |
| 8 | OpenClaw dreaming-repair | `DREAMS.md` / session-corpus / session-ingestion | 手動 + audit CLI | **決定論** | **archive 退避**`.openclaw-repair/dreaming/<timestamp>/` に rename、完全削除しない | 退避後は手動判断 | archive ディレクトリに rename で保持 |
| 9 | memory-wiki `/wiki-lint`OpenClaw extension、SamurAIGPT/llm-wiki-agent と Karpathy llm-wiki の production 実装) | wiki page / claim | `/wiki-lint` 手動 or cron 想定 | **決定論**issue 検出ロジック) + その後の **human/LLM 任意判断** | **削除ゼロ**、`reports/lint.md` に issue を書き出すのみ。修正は別コマンド / 人間が行う | 全出力点が人間承認 | 原ファイル無変更、report は上書き |
| 10 | Cloudflare Agent Memory supersession | Fact / Instruction rowDurable Object SQLite | 新 memory ingest 時 | **決定論**normalized topic key が一致した瞬間) | **supersede**(旧 row を forward pointer で版チェーン化、物理削除せず、vector は非同期 delete + new upsert | 無し(全自動) | SQLite に旧版残置、version chain で参照可能 |
| 11 | Letta sleep-time agent | in-context memory block | 非同期 idle process | **LLM agentic** | `core_memory_replace` / `core_memory_append` / archival 移動で block 書き換え | 無し | 書き換え後の block が保存、旧 block は失われる |
| 12 | Letta recursive summarization | message buffer | **context window fill の決定論閾値** | 発火は決定論 / 要約内容は LLM | evict + 再帰要約(古いほど重み減) | 無し | 要約に畳み込まれる(原メッセージは消失) |
| 13 | LinkedIn CMA公開情報レベル | Episodic / Semantic / Procedural 各層 | 未公開 | 未公開 | **summarization による compaction**(階層別の drop 仕様は非公開、"cache invalidation is one of the hardest problems" と明示) | **高 stake 用途は human validation** を挟む | 非公開 |
### 8.2 軸別の知見
**対象(何が GC されるか)の粒度差**:
- 最小粒度の Hermesentryと Cloudflarerowは、LLM がエントリ単位で `remove` / `replace` する設計に寄る。
- 中粒度の Codex`MEMORY.md` blockは、block 内を thread id で部分削除しながら必要なら split / rewrite する agentic 寄り。
- 最大粒度の OpenClaw / memory-wiki は **ファイル単位でのみ削除 / 退避** し、file 中身は LLM / 人間に委ねる。`docs/plan/memory.md` の「1 件 1 ファイル」方針とは **OpenClaw の粒度が最も近い**
**トリガー(いつ GC するか)の 4 パターン**:
1. **容量超過 hard reject**Hermes: 追加要求を失敗で返して LLM に自律対処を強制。**決定論的 trigger + agentic 処理**で、設計最小コスト。
2. **session idle + age**Codex Phase 2: 人間の活動終了を待って非同期、最もユーザー体感を壊しにくい。
3. **cron / scheduled sweep**OpenClaw dreaming default `0 3 * * *`, Codex extension retention: 定期的・予測可能。人間 review との組み合わせがしやすい。
4. **ingest 時の即時**Cloudflare supersession: 書き込みの tx 内で完結、後続 GC 走査が要らない。topic key 設計が前提。
insomnia の plan は (2) Phase 2 で rewrite 許可を置きつつ、GC は (3) 方向で別経路という構造。これは Codex / OpenClaw の両方と整合する。
**判断主体の 3 系統**:
- **決定論のみ**: Codex retention / stage1 pruning / OpenClaw temporal decay / Cloudflare supersession / lint 検出。条件がはっきりしているものage / key 一致 / 構造的 issueは決定論が強い。
- **決定論 scoring → 閾値 gate → 機械適用**: OpenClaw Deep promotion。LLM の揺れを除き、コストも LLM コールゼロ。ただし対象が append 側のみで、削除には使われていない。
- **LLM agentic**: Codex Phase 2 / Hermes review / Letta sleep-time。判断の柔軟性block 内部分削除、context 依存の mergeを LLM に委ねる。
`docs/plan/memory.md` は Phase 2 が LLM agentic、GC も暫定的に **LLM agentic + Linter Warn 併用**としている。完全に一致する事例は **Codex Phase 2 の consolidation prompt**836 行で、「removed thread id を `MEMORY.md` から部分削除し、blockに他の thread が残っている場合は split / rewrite して保持」という手続きを自然言語で指示している。**insomnia は Linter 側に警告カテゴリ(類似 slug / `replaced` 滞留 / sources 過多 / staleを先に定義し、GC 実行の agent プロンプトはそれを入力にする**構造が素直。
**処理種別の選択肢**:
- `drop / merge / split / rewrite` の組み合わせは Codex Phase 2 が最も自由度高く、Hermes もそれに近いentry 粒度)。
- `replaced` chain の整理は **Cloudflare だけが自動で版チェーン維持**、他は LLM 任せ。insomnia は decision record に `replaced_by` を入れているので、Cloudflare 方式の forward pointer 概念を **人間可読な `replaced_by:` frontmatter** で既に踏襲している。GC 時に chain をどこまで短く畳むか(長大な `a → b → c → d``a → d` に圧縮するかは未決定論点で、Cloudflare は圧縮せず chain を保持する設計。
- **`split` は Codex だけが明示**。block 内に複数 thread id が混ざった場合に thread id 単位で分ける。insomnia の「1 件 1 ファイル」方針では split = ファイル分割となり、主題の粒度判断は GC agent に委ねる必要がある。
**人間介入点の 3 段**:
- 完全無介入: Codex / Cloudflare / Letta / Hermes
- audit-firstissue を surface し、人間が決断): memory-wiki lint / OpenClaw dreaming-repair
- high-stake 限定 gate: LinkedIn CMA
insomnia の plan は「人間 offer 承認を併用」なので **audit-first に寄る**のが自然。lint 相当の Warn を Linter で出し、LLM Phase 2 / GC がそれを消費する前に人間が承認 / 拒否できる UI を提供する構造。memory-wiki lint は `reports/lint.md` というシンプルな Markdown 出力なので、そのまま `memory/reports/gc-lint.md` 相当を tick off する実装が参考になる。
**履歴保持の 3 モデル**:
1. **物理削除**: Codex retention / stage1 / Hermes / Letta要約で畳む分は実質消失
2. **archive 退避rename**: OpenClaw dreaming-repair
3. **forward pointer / tombstone**: Cloudflare supersession
insomnia は **git 管理下に memory を置く**前提なので、物理削除を選んでも git log で復元できるのが強み。`replaced_by:` frontmatter が forward pointer の役割を果たしているので、Cloudflare 型と git を足した「**現物は物理削除、frontmatter pointer で chain を参照、git で history**」が最も設計コストに合う。archive 退避は git を前提にすると冗長。
### 8.3 insomnia の GC 仕様を詰めるときの示唆
1. **GC trigger は 2 系統に割る**。(a) 決定論: Linter Warn 群 + age / count / size 閾値の sweep、(b) LLM 判定: Phase 2 とは別 prompt で Linter の issue リストを入力に渡す。両方が `memory/reports/gc-*.md` 相当を書き、それを次回の GC run が読む、というフィードバックループが OpenClaw lint / Codex Phase 2 input selection の両方と整合する。
2. **Linter に「GC 候補検出」カテゴリを足す**。memory-wiki の lint issue code が参考になる: `stale-page`90d 超)/ `stale-claim` / `low-confidence` / `orphan` / `duplicate-id` / `broken-wikilink` / `contradiction-present` / `open-question`。insomnia 固有の追加候補: `similar-slug`(類似 slug 乱立、既に plan に記載)/ `replaced-chain-long``replaced_by` が 3 段以上)/ `sources-overflow`1 record の sources が閾値超)/ `knowledge-invoke-frequency-low``user_invoke` が一定期間ゼロ)。
3. **処理は rewrite 優先、削除は `status: replaced` 経由**(既に plan 方針と一致。forward pointer は Cloudflare 流、ただし chain 圧縮ルール(例: 「chain が n 段超えたら中間を drop、端のみ残す」を決めるかは別論点。Cloudflare は圧縮しない、insomnia は git があるので圧縮してよい。
4. **char limit は採用しない方が筋が良い**。Hermes の hard limit + LLM self-rewrite は設計最小だが、insomnia は 1 record 1 file なのでファイル内 size 制約は薄く、file 数による grep コストの方が支配的になる。file 数閾値 → GC trigger の方が insomnia の形に合う。
5. **決定論 scoring を後から差し込む余地を残す**。OpenClaw Deep phase のような「頻度 / 関連度 / 多様性 / 時間減衰 / 整合性 / 概念」の 6 重み + 閾値は、agent LLM の出力が運用で評価可能になった段階で部分的に差し替える upgrade path として最適。初期は Phase 2 LLM + Linter Warn で十分。
6. **削除は git commit 単位で可逆**という前提を明示する。プロジェクトメモリは git 管理下なので、GC が誤って drop してもユーザーは revert できる。これは Codex が持っていない利点で、GC agent の判断を多少攻めても安全マージンがある。
一次ソース:
- Codex Phase 2 consolidation: `github.com/openai/codex/codex-rs/core/src/memories/phase2.rs`, `core/templates/memories/consolidation.md`
- Codex retention / stage1 pruning: `github.com/openai/codex/codex-rs/core/src/memories/extensions.rs:11-139`, `codex-rs/state/src/runtime/memories.rs:290-331, 333-464`
- Hermes char limit reject: `github.com/NousResearch/hermes-agent/tools/memory_tool.py:211-266`
- Hermes review spawn: `github.com/NousResearch/hermes-agent/run_agent.py:2727-2830`
- OpenClaw promotion apply: `github.com/openclaw/openclaw/extensions/memory-core/src/short-term-promotion.ts:1518-1652`
- OpenClaw temporal decay: `github.com/openclaw/openclaw/extensions/memory-core/src/memory/temporal-decay.ts`
- OpenClaw dreaming-repair: `github.com/openclaw/openclaw/extensions/memory-core/src/dreaming-repair.ts:70-165`
- memory-wiki lint: `github.com/openclaw/openclaw/extensions/memory-wiki/src/lint.ts`, `claim-health.ts:6-7``WIKI_AGING_DAYS = 30`, `WIKI_STALE_DAYS = 90`
- Cloudflare supersession: https://blog.cloudflare.com/introducing-agent-memory/
- Letta sleep-time: https://docs.letta.com/guides/agents/memory/, https://www.letta.com/blog/sleep-time-compute, arxiv 2504.13171
- Letta recursive summary: https://www.letta.com/blog/agent-memory
- Karpathy llm-wiki lint: https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f
- SamurAIGPT/llm-wiki-agent `/wiki-lint`: https://github.com/SamurAIGPT/llm-wiki-agent
- LinkedIn CMA: https://www.infoq.com/news/2026/04/linkedin-cognitive-memory-agent/
---
## 9. 未調査 / 次に掘るべき項目
- Letta `memory block` の Rust 実装例・永続化形式。
- Cloudflare Agent Memory の supersession chain の具体アルゴリズム(記事は概略のみ)。
- `agentskills.io` の CRDT 的バージョニング方針(標準は version metadata を任意 key にしている。実運用でどう衝突解決するかは未整備)。
- Hermes の Honcho 連携の実体(外部サービス API 越しの dialectic user modeling、repo には prompt と API 呼び出しのみ)。
- LinkedIn CMA の層別 GC 仕様(公開情報では compaction-by-summarization までしか開示されていない)。
- Cloudflare supersession chain の圧縮ポリシーchain 長の上限、vector GC と row GC の tx 境界)。

View File

@ -0,0 +1,140 @@
# Pod 内部プロンプトのカタログ化
## 背景
Pod は Worker を拡張する機構を持つ: コンテキスト圧縮 (Compact)、非同期通知 (Notify)、中断と再開 (Interrupt)、system prompt の trailing section、AGENTS.md 取込時の注記。これらの機構がランタイムで Worker に注入する/Worker 向けに構成するプロンプトは、現状各モジュール内の `const &str` / `format!` に分散している。
| 場所 | 役割 |
|---|---|
| `crates/pod/src/pod.rs:50` `SUMMARY_SYSTEM_PROMPT` | Compact worker の system prompt |
| `crates/pod/src/notification_buffer.rs:73` `format_notification` | `Method::Notify` を Worker history に system_message として注入するラッパー |
| `crates/pod/src/interrupt_and_run.rs:18-20` | 中断時の synthetic tool_result と system_message |
| `crates/pod/src/system_prompt.rs:179-203` `append_trailing_section` | `## Working boundaries` / `## Project instructions (AGENTS.md)` ヘッダとレイアウト |
| `crates/pod/src/agents_md.rs:19` `TRUNCATION_NOTICE` | AGENTS.md が 64KB 超過したときの末尾注記 |
`resources/prompts/default.md` でユーザー向け instruction テンプレートは一元化された一方、Pod が Worker を拡張する側のプロンプトは並行した一元管理を持たない。結果として:
- 全体を俯瞰しづらく、新しい injection 点を足すときに既存との一貫性が取れない
- 多言語化や文体カスタマイズの導線がない
- builtin から差分だけ書き換える軽量な手段がない
tool description は tool 宣言と併置が自然tool 追加 = 1 箇所追加なので本チケット対象外。Pod の Worker 拡張機構は異質なものが「Pod のトーン」として束になって振る舞う性質上、中央で扱う価値がある。
## 要件
### 1. 中央モジュール: `PodPrompt` enum
Pod が Worker に注入する全プロンプトを列挙する enum を 1 つ置く。variant の集合が「存在する injection 点」の master。新しい注入点を増やすときは variant 追加が必要 = コード上で勝手に散らかせない。
Pod 内部の各モジュールは `PodPrompt::CompactSystem.render(&ctx)` のように 1 本の API で引く。直接 `include_str!` / `const &str` / `format!` で prompt 文字列を書かない。
### 2. 翻訳パック形式: `prompts.toml`
全 variant を key-value で持つ TOML。値は minijinja テンプレート文字列builtin/ランタイム問わず一律 minijinja render
```toml
[prompt]
interrupt_system_note = "[The previous turn was interrupted by the user. The user's next request follows.]"
notify_wrapper = """[Notification]
{{ message }}
This is a notification, not a blocking request. ..."""
# 長文は外部ファイルに link
compact_system = "{% include '$insomnia/internal/compact_system.md' %}"
```
変数展開は各 variant ごとに定義された context を render 時に渡す(例: `notify_wrapper``message`、`compact_system` は tool 名リストなど。context の具体形は実装段階で variant ごとに確定する。
### 3. Builtin pack の網羅性をビルドエラーで強制
`resources/prompts/internal.toml``PodPrompt` 全 variant を網羅していないとビルド失敗。enum に variant を足したが builtin pack に key が無い、あるいは逆、はコンパイルが通らない。`build.rs` もしくは proc-macro で検査する(どちらを取るかは実装時判断)。
### 4. 4 段の置換マージ
key 単位で overlay。下層から順に apply、後勝ち:
```
builtin resources/prompts/internal.toml (必須・網羅)
user $XDG_CONFIG_HOME/insomnia/prompts.toml (任意・auto)
workspace <project>/.insomnia/prompts.toml (任意・auto)
manifest pack manifest.pod.prompt_pack で指名 (任意)
```
- 欠落 key: 下層から継承
- ランタイム層 (user/workspace/manifest pack) の unknown key: `tracing::warn!` して無視
- builtin 層の不整合はビルドエラー(前項)
### 5. 値 render は minijinja 統一、include は既存 prefix resolver 流用
全値を minijinja で parse / render。`{% include "$prefix/..." %}` によって外部ファイルを link 可能。resolver は既存 `crates/pod/src/prompt_loader.rs` を流用し、`$insomnia` / `$user` / `$workspace` すべてをどの層の pack からも参照できる。
### 6. manifest 露出
```toml
[pod]
prompt_pack = "$user/packs/japanese.toml"
```
任意フィールド。指定されていれば 4 段目 overlay として適用。auto-discovery (user/workspace) とは独立で共存する。子 Pod を spawn する際、親が子の役割に応じた pack を明示する用途を想定。
## 設計判断
### prompt_pack は prefix 名前空間に載せない
既存 `$insomnia/` / `$user/` / `$workspace/` は**名前空間**で、同じ key で複数の source を指し合うことはない。一方 pack は**レイヤー**で、同じ key を置き換える。この 2 つを同じ軸に混ぜるとユーザーが「どの書き方で上書きされるか」を予測できなくなる。
pack ファイルは**固定パスの auto-discovery** と **manifest による明示指名**の 2 経路のみ。各値内部で `{% include "$prefix/..." %}` を使うのは別軸なので prefix 体系の利点はそのまま享受できる。
### 長文ファイル分離用の独立フィールドを作らない
値が minijinja である以上、長文を別ファイルにしたければ `"{% include '$insomnia/internal/foo.md' %}"` と書けば済む。「TOML 値の文字列」と「ファイル参照」の 2 値型を用意する必要はない。1 種類で統一する。
### ランタイム層の unknown key は warn
pack ファイルを書いた時点と Pod バージョンがずれたとき、hard error にすると古い pack で Pod が起動しなくなる。前方互換のため warn で無視する。builtin 層は build-time に同梱するので不整合はビルドで捕まえられる = error で問題ない。
### tool description は本チケット対象外
tool 追加は tool ごとの 1 箇所の自然な単位で、description は tool の属性として宣言と併置が読みやすい。Pod 内部 injection は「異質なものが一体としてトーンを決める」共通軸なので中央化の価値が別にある。この差を混ぜない。
### auto-discovery と manifest 指定を両立させる
auto-discovery は「ユーザー or プロジェクトの永続設定 (翻訳、文体)」、manifest 指定は「**その Pod の役割**による差し替え」と目的が別。どちらか一方では片方のユースケースが潰れるので両立する。key 単位の merge は共通なので実装コスト差は小さい。
## Scope 外
- tool description の resources 化(併置方針を維持)
- 具体的な翻訳 pack の作成(本チケットは導線のみ)
- pack 編集 GUI / TUI
- user/workspace 以外の auto-discovery パス追加(別 XDG 層、bundle pack 等)
## 依存
- `crates/pod/src/prompt_loader.rs` (`$prefix` resolver を minijinja include から流用)
- `crates/pod/src/system_prompt.rs` (minijinja 使用パターン)
- `crates/manifest`: `pod.prompt_pack: Option<String>` 追加のみで破壊的変更なし
## 影響範囲
- `crates/pod/src/prompts.rs` (新設): `PodPrompt` enum、render API、pack loader、4 段 merge
- `resources/prompts/internal.toml` (新設): builtin pack
- `resources/prompts/internal/*.md` (新設): 長文外出し
- `crates/pod/` 各モジュール: 既存ハードコードを `PodPrompt::...render(&ctx)` 呼び出しに置換
- `crates/pod/build.rs` もしくは proc-macro (新設): enum ⇔ builtin pack 網羅検査
- `crates/manifest/src/config.rs`: `prompt_pack` フィールド追加
## 実装順序
1. `PodPrompt` enum と render API を定義。builtin map (in-memory、`include_str!`) から引くだけの最小実装。variant の render 網羅を単体テストで確認
2. `resources/prompts/internal.toml` に全 key を書き、既存ハードコードをそのまま文字列として移植。各モジュールの呼び出しを `PodPrompt::...render` に置換 (挙動は既存と完全同一)
3. builtin 網羅を build-time 検査に格上げ (enum ⇔ pack の双方向で欠落/余剰を検出)
4. user / workspace の auto-load と 3 段マージ。ランタイム unknown key の warn
5. `manifest.pod.prompt_pack` を追加、4 段目 overlay として load
6. 長文 variant (compact_system など) を `{% include "$insomnia/internal/..." %}` 形式に分離。`$user` / `$workspace` から include で override できることをテスト
各ステップ終了時点でビルド通過・既存テスト合格を維持する。

View File

@ -7,8 +7,5 @@
## 検討事項
- `llm-worker`: LlmClient の mock 実装によるターンループ・ツール実行のテスト
- `llm-worker-persistence`: FsStore / FsBlobStore のファイルシステムテストtempdir
- `pod`: PodController / SocketServer の結合テスト
- `protocol`: シリアライズ/デシリアライズの往復テスト
- `manifest`: パースのバリエーション(既存テストの拡充)
低層部分のテストを信頼し、上層までモックデータを引っ張ってきてテストする必要は無いのか?
実際の認証を使ったE2Eはどの様に結果を出すか/