diff --git a/docs/architecture.md b/docs/architecture.md index 1c7b483d..61cb769c 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -24,11 +24,12 @@ insomnia は環境再現・コンテナ管理・VCS 統合などを自身の責 ## Pod -独立したエージェントの実行単位。llm-worker の Worker をラップし、マニフェストによる宣言的構成とディレクトリスコープを加える。 +独立したエージェントの実行単位。llm-worker の Worker をラップし、マニフェストによる宣言的構成、ディレクトリスコープ、Pod 名に紐づく永続状態を加える。 -- 1 Pod = 1 プロセス = 1 セッション -- マニフェスト(TOML)から完結構築できる -- scope で書き込み可能なパスを制限(読み取りは自由) +- 1 live Pod process は 1 Pod name/current state を所有する +- 会話の永続化は `session-store` の `session_id` / `segment_id` ログ、Pod 名の current state は `pod-store` metadata が担う +- マニフェストまたは profile から完結構築できる +- scope で読み取り・書き込み可能なパスを制限する - 独立した socket サーバーを持ち、Client (TUI / GUI) が接続して操作する ### 実行ループ @@ -50,19 +51,28 @@ Client → Method::Run { input } ### コンテキスト管理 -- **Prune**: 古い tool result の content を除去(summary は残す)。`pre_llm_request` で毎回判定 -- **Compact**: 履歴全体を要約して圧縮。`input_tokens` が閾値を超えたとき、`PreRequestAction::Yield` で Worker を一旦中断し、Pod 側で要約 → 新セッションとして再開 +- **Prune**: 古い tool result の content を除去(summary は残す)。LLM request context だけを加工し、永続 history 本体は変更しない +- **Compact**: 履歴 prefix を要約し、同じ `session_id` 配下の新 `segment_id` へ rotate する。`SegmentStart.compacted_from` が元 segment を参照し、Pod metadata の active pointer は新 segment を指す - サーキットブレーカー: compact が3回連続失敗したら無効化 ## Protocol -Pod の制御・監視に使う JSONL ベースのメッセージプロトコル。トランスポートに依存しない。 +Pod の制御・監視に使う JSONL ベースのメッセージプロトコル。トランスポートに依存しない。正確な wire enum は `crates/protocol/src/lib.rs::{Method, Event}` を正とし、この節はカテゴリの目次として扱う。 -- **Method** (Client → Pod): `Run` / `Notify` / `Resume` / `Cancel` / `Shutdown` / `GetHistory` -- **Event** (Pod → Client, broadcast): `TurnStart` / `TurnEnd` / `TextDelta` / `ToolCallStart` / `ToolCallArgsDelta` / `ToolCallDone` / `ToolResult` / `Usage` / `RunEnd` / `Error` / `History` / `Notification` / `Shutdown` -- リクエストとレスポンスの紐付けはしない。Pod の状態遷移(イベント)を見れば何が起きているか分かる -- イベントは全リスナーに broadcast -- 操作の競合は先勝ち(run 中に別の run → AlreadyRunning エラー) +- **Client → Pod (`Method`)** + - turn 制御: `Run`, `Resume`, `Cancel`, `Pause`, `Shutdown` + - context/session 制御: `Compact`, `ListRewindTargets`, `RewindTo` + - typed injection / child lifecycle: `Notify`, `PodEvent` + - client 補助: `ListCompletions` + - Pod visibility / attach: `ListVisiblePods`, `InspectPod`, `AttachOrRestorePod` +- **Pod → Client (`Event`)** + - accepted input / history seed: `Snapshot`, `UserMessage`, `SystemItem`, `SegmentRotated` + - generation stream: `TurnStart`, `TurnEnd`, `LlmCallStart`, `LlmCallEnd`, retry/continuation events, `Text*`, `Thinking*`, `ToolCall*`, `ToolResult`, `Usage`, `RunEnd` + - control replies: completions, rewind, visible Pod / inspect / attach results + - operational status: `Status`, `Alert`, `MemoryWorker`, `Compact*`, `Error`, `Shutdown` +- リクエストとレスポンスの紐付けを一般化した RPC にはしない。多くの状態は broadcast event と Pod status で観測する +- 一部の reply(例: completions)は要求 socket にだけ返る。broadcast event と request-local reply の違いは enum variant のコメントを正とする +- 操作の競合は先勝ち(run 中に別の run → `AlreadyRunning` エラー) ## マニフェストとファクトリ @@ -116,23 +126,28 @@ Pod が操作できるファイルパスの制御。 - `allow` ルールで読み取り・書き込みを許可、`deny` ルールで制限 - effective permission = allow - deny - `recursive = false` で直下のみに制限可能(summary に `[non-recursive]` マーカー) -- scope 排他: Pod 間の write 衝突は scope lock file (`$XDG_RUNTIME_DIR/insomnia/scope.lock`) で検出。scope 分譲(spawn 時に譲渡、終了時に返却)の記録にも使う +- scope 排他: Pod 間の write 衝突は runtime registry / scope lock で検出する。child Pod へ委譲した write scope は親の effective scope から delegated-out deny として差し引かれ、child 停止・prune 時に reclaim される ## セッション永続化 -- append-only JSONL ログ。1 エントリ = 1 行 -- SHA-256 チェーンでエントリの整合性を保証 -- ログ再生で Worker の状態を完全復元(スナップショット不要) -- Compact 時に新セッションを開始し、旧セッションへのリンクを保持 +- `session-store` は append-only JSONL segment log。1 `LogEntry` = 1 行 +- `SessionId` は論理会話の fork-tree root、`SegmentId` はその中の現在の書き込み先 segment +- fresh conversation だけが新 `SessionId` を作る。compact / fork は同じ `SessionId` 配下に新 `SegmentId` を作り、`SegmentStart.{compacted_from,forked_from}: SegmentOrigin` で出自を持つ +- segment log の先頭は `LogEntry::SegmentStart`。以降に `Invoke`, `UserInput`, `AssistantItem`, `ToolResult`, `SystemItem`, `TurnEnd`, `RunCompleted` / `RunErrored`, `ConfigChanged`, `LlmUsage`, `Extension` などを append する +- replay は segment log から Worker state を再構成する。lineage は entry hash ではなく `SegmentOrigin.at_turn_index` と segment id で参照する +- Pod 名の durable current state(active pointer、resolved manifest snapshot、spawned child delegation/reclaim)は `pod-store` metadata が担う。socket path や runtime mirror は liveness authority ではない ## 組み込みツール -| ツール | 概要 | -| ------ | ------------------------------------------ | -| Read | ファイル内容の読み取り | -| Write | ファイルの新規作成・上書き | -| Edit | 既存ファイルの部分編集(事前 Read が必要) | -| Glob | ファイル名パターンマッチ | -| Grep | ファイル内容の正規表現検索 | +正確な callable set と description は ToolRegistry / manifest permission / scope / profile に依存する。高レベルには以下のカテゴリを持つ。 -すべて scope の permission チェックを経由。`ScopedFs` が書き込み制限を、`Tracker` がセッション内のコンテンツハッシュ追跡を行う。 +| カテゴリ | 例 | 概要 | +|---|---|---| +| File / shell | `Read`, `Write`, `Edit`, `Glob`, `Grep`, `Bash` | workspace ファイル操作と shell 実行。file tools は `ScopedFs` と read-before-edit tracker を通る。`Bash` は permission policy と出力退避で制御する | +| Task | `TaskCreate`, `TaskUpdate`, `TaskList`, `TaskGet` | セッション内の短期 task 状態管理 | +| Memory / Knowledge | `MemoryQuery`, `MemoryRead`, `MemoryWrite`, `MemoryEdit`, `MemoryDelete`, `KnowledgeQuery` | manifest の memory 設定が有効な時に登録される durable memory / knowledge 操作 | +| Pod orchestration | `SpawnPod`, `SendToPod`, `ReadPodOutput`, `StopPod`, `ListPods` | child Pod の起動・通信・停止・一覧 | +| Visible Pod state | `ListVisiblePods`, `InspectPod`, `AttachOrRestorePod` | durable Pod state と visibility に基づく Pod inspection / attach / restore | +| Web | `WebSearch`, `WebFetch` | manifest/env で明示設定された provider 経由の bounded web access | + +すべての tool call は manifest tool permission と scope/policy のチェックを通る。ファイル write scope、Pod delegation、memory layout、web provider 設定はそれぞれ別の authority を持ち、UI 表示だけで権限を広げない。 diff --git a/docs/compaction.md b/docs/compaction.md index e5e08cae..cd1a69ee 100644 --- a/docs/compaction.md +++ b/docs/compaction.md @@ -20,8 +20,8 @@ CompactInterceptor (pre_llm_request) ← safety net → Worker が WorkerResult::Yielded で正常終了 ↓ Pod::handle_worker_result - → persist_turn(旧セッションに記録) - → compact() → resume() + → turn 結果を現在 segment log に記録 + → compact() で同じ session_id 内の新 segment へ rotate → resume() [ターンの合間 — 次の Pod::run 冒頭] Pod::try_pre_run_compact ← proactive @@ -97,21 +97,29 @@ PreRequestAction::Cancel → WorkerError::Aborted → エラー - **サーキットブレーカー**: 3回連続 compact 失敗で無効化 (`CompactState::disabled`) - **Thrash 検出**: compact 直後に再び閾値超過 → `PodError::CompactThrash` -- **Yield 前の永続化**: `persist_turn` を compact の前に実行。失敗しても旧セッションにデータが残る +- **Yield 前後の永続化**: Worker が `Yielded` で抜けた turn は現在 segment log に記録してから compact する。compact が失敗しても元 segment の状態は残る ### セッション管理 -compact は fork と同じ構造。旧セッションを保全し、新 SessionId で圧縮後のセッションを開始。 +compact は「新 SessionId を作る」操作ではなく、同じ `session_id` 配下で active `segment_id` を切り替える操作。 ``` -旧セッション (abc-123): - [...entries...] → Outcome::Yielded (interrupted=true) ← そのまま残る +session_id = abc-123 -新セッション (def-456): - [SessionStart { compacted_from: (abc-123, entryN.hash), history: [要約 + 直近] }] → ... +segment old: + SegmentStart { origin: fresh/fork/... } + [...entries...] + RunCompleted { result: Yielded } + +segment new: + SegmentStart { compacted_from: SegmentOrigin { segment_id: old, at_turn_index: N } } + [system prompt] + [system: 構造化要約] + [system: retained tail / auto-read / references] + ...以後の turn を append ``` -`SessionStart` に `forked_from` / `compacted_from` フィールドで出自を追跡可能。 +`SegmentStart.compacted_from` / `forked_from` が lineage を追跡する。Pod 名からの resume は `pod-store` metadata の active pointer が現在の `(session_id, segment_id)` を指し、conversation/history の replay は `session-store` の segment log から行う。 --- @@ -220,7 +228,7 @@ write_summary(text) — 構造化要約を出力/上書き - `final_reserve_tokens` を割った後は `write_summary` 以外の探索 tool call に synthetic error を返し、最終 summary の余白を守る - `worker_context_max_tokens` 超過は最後の hard stop 5. ターン終了時に write_summary 未呼び出し or read_required 空(かつファイル操作履歴がある場合)→ 追加プロンプトで促す -6. `summary_max_tokens` と `result_context_max_tokens` で compact 結果を検証してから新 session を作る +6. `summary_max_tokens` と `result_context_max_tokens` で compact 結果を検証してから新 segment を作り、Pod metadata の active pointer を更新する ### 構造化要約の要件 diff --git a/docs/plan/ai-maintainer.md b/docs/plan/ai-maintainer.md index cc7f4574..78549fb6 100644 --- a/docs/plan/ai-maintainer.md +++ b/docs/plan/ai-maintainer.md @@ -1,372 +1,210 @@ -# AI maintainer 運用設計 - -## 位置づけ - -この文書は、insomnia を単なる Coding Agent ではなく、開発プロジェクトを継続的に運用する AI maintainer として使うための上位設計である。 - -`/auto-maintain` はこの設計の最初の実行形であり、TODO / tickets から小さな実装作業を選んで実装・レビューを orchestration する Workflow に留まる。本設計はその一段上で、設計相談、ticket 整理、実装委譲、レビュー、運用課題の記録、改善提案までを一つの maintainer loop として扱う。 - -ただし、これは unattended 自動開発ではない。最終判断、危険な権限拡大、push、未合意の要件変更は人間に戻す。 - -また、このフレームワークの対象はプロジェクトの新規立ち上げ・設計ではなく、ある程度タスクの関心対象が分化し、機能追加・課題対応をイテレーションするフェーズにあるプロジェクトである。 +# AI Maintainer Workflow 設計 ## 目的 -AI maintainer の目的は、コードを書くことそのものではなく、開発状態を前に進めることである。 +AI maintainer は、insomnia リポジトリの開発を継続的に進めるための orchestration role である。単発の `/auto-maintain` より広く、設計相談、work item 整理、実装委譲、レビュー、運用課題の記録、改善提案を一つの maintainer loop として扱う。 -具体的には以下を担う。 +`/auto-maintain` はこの設計の限定実行形であり、`tickets.sh` / `work-items/` から小さな実装作業を選んで実装・レビューを orchestration する Workflow に留まる。 -- TODO / tickets / docs / git history から現在の開発状態を把握する -- 要件が十分に固まった作業を実装可能な単位へ落とす -- 設計判断が必要な作業を実装前に人間へ戻す -- 実装 Pod / reviewer Pod / 親 Pod 自身を使い分ける -- 実装結果を ticket の完了条件に照らして review する -- merge / ticket lifecycle / TODO 整理の順序と branch placement を守る -- 作業中に見つかった運用上の障壁を `docs/report/` に残す -- 繰り返し発生する作業を Workflow / Knowledge / ticket 候補として提案する +## 正本と権限境界 -## 役割モデル +現在の作業管理の正本は `tickets.sh` と `work-items/` である。古い `TODO.md` / legacy `tickets/` directory を前提にした運用は superseded。 -### Human maintainer +- work item の作成・コメント・レビュー・状態変更・完了は原則 `./tickets.sh` 経由で行う +- `work-items/{open,pending,closed}//item.md` は要件・受け入れ条件の正本 +- `thread.md` は計画・判断・レビュー・実装報告の時系列 thread +- `resolution.md` は close 時の完了記録 +- 時系列と状態遷移の最終根拠は git history +- `docs/report/` は観測・所感・改善候補の記録であり、最新仕様の authority ではない +- `.insomnia/memory` は個人/生成 state であり、project record の正本ではない -人間は設計上の最終責任者である。 +AI maintainer は project record を勝手に膨らませない。明確な実装単位は work item 化し、小粒な所見は `KNOWN_ISSUES.md`、ドッグフーディング上の障壁やツール問題は `docs/report/` に記録する。 + +## Role model + +### Maintainer Pod + +人間と対話する親 Pod。設計判断、作業選定、scope 委譲、レビュー統括、merge / close の判断を担う。 主な責務: -- プロダクト方針、設計方針、優先順位の決定 -- AI が提示した選択肢の採否 -- scope / permission / history persistence など安全モデルに関わる判断 -- push や外部公開に関わる判断 -- AI maintainer の運用方針そのものの変更承認 +- `work-items/`, `KNOWN_ISSUES.md`, `docs/`, git history, worktree 状態を読んで現在地を把握する +- 作業可能な work item と設計相談が必要な work item を分ける +- child worktree / child Pod に実装を委譲する +- 実装結果を work item の背景・要件・受け入れ条件に照らして review する +- review / close / merge の branch placement を守る +- 人間に判断が必要な境界で止まる -### AI maintainer / orchestrator - -親 Pod が担う役割。コードを書くこともできるが、主な責務は制御面である。 - -主な責務: - -- 状態把握: `TODO.md`, `tickets/`, `docs/`, git history, worktree 状態を読む -- 作業選定: 実装可能な ticket と設計相談が必要な ticket を分ける -// ↑ について、設計相談も含めてOrchestrator-Coder間で行わせて良いのでは -- 計画: 作業範囲、検証方法、child worktree / Pod scope を決める -- 委譲: 実装 Pod / reviewer Pod を spawn し、必要最小 scope を渡す -- 監督: Pod 出力、worktree diff、test 結果を確認する -- レビュー: ticket の背景・要件・完了条件に対して実装を確認する -- lifecycle: review artifact、ticket 完了、TODO 更新、merge の branch placement を守る -- 報告: 完了内容、検証結果、未解決事項、次の人間判断をまとめる +Maintainer Pod は「便利だから」project record を書き換えない。新規 work item 作成、既存 work item の大幅変更、close、merge、commit などは、ユーザー指示または会話上の合意に基づいて行う。 ### Implementation Pod -狭い write scope を持つ作業者である。実装 Pod は ticket と worktree を渡され、その範囲で実装・検証・報告を行う。 - -禁止事項: - -- `/auto-maintain` など上位 Workflow を実行しない -- ticket / TODO / review artifact / docs/report を勝手に編集しない -- git commit / merge / push をしない -- scope / permission / history persistence を勝手に再設計しない - -### Reviewer Pod - -原則 read-only の検証者である。実装 Pod とは分けるのが望ましいが、小さい作業や scope 衝突がある場合は親 Pod が review してよい。 - -主な確認項目: - -- ticket の要件を満たしているか -- 既存設計を歪めていないか -- 不要な抽象化や過剰実装がないか -- test / build の結果が妥当か -- ticket lifecycle 上、どの branch に review / completion commit を置くべきか - -## 状態と成果物 - -AI maintainer は、状態を会話内だけに閉じ込めない。継続的な運用に必要な情報は、用途ごとに既存のファイルへ残す。 - -### `TODO.md` - -未完了 ticket の一覧。1 ticket = 1 行。作業選定の入口であり、完了したら feature branch 側で該当行を削除する。 - -AI maintainer は TODO と ticket の不整合を見つけた場合、勝手に ticket を作成・削除せず、人間に報告する。 - -### `tickets/` - -実装可能な要件単位。作業の完了条件は ticket が基準になる。 - -AI maintainer は ticket を読むだけでなく、git history 上の作成・更新・削除も参照して前提を把握する。 - -ただし、`tickets/` は長い設計相談、実装 Pod の報告、review 指摘、修正依頼、lease、artifact を thread として扱うには弱い。長期的には WorkItem / Thread 抽象を導入し、ticket は WorkItem の linked artifact または backend view として扱う。 - -### WorkItem / Thread - -AI maintainer の上位運用単位。`tickets/` より広く、design / feature / refactor / ops / investigation を含む project coordination record として扱う。 - -WorkItem は Git に依存しない domain model として定義し、初期 backend は repo-managed な `work-items/` または `issues/` directory にできるようにする。正本として残すのは description、acceptance criteria、discussion thread、decision、review、status history、linked branch / worktree / commit、durable artifact metadata である。 - -`.insomnia` に WorkItem 正本は置かない。`.insomnia/maintainer/` は Pod run、lease cache、polling cursor、temporary inbox、local-only trial log など runtime coordination state の置き場とする。 - -将来 network 越し workspace / remote maintainer hub を導入する場合も、AI maintainer は file path ではなく `WorkItemStore` / `LeaseStore` 相当の interface を通す。remote backend は後回しにするが、初期 file backend の時点で Git 前提の API に固定しない。 - -### `tickets/*.review.md` - -review の判断根拠。review artifact は対象 feature branch 側に commit する。`develop` の first-parent に review / completion commit を直接置かない。 - -### `docs/plan/` - -長期設計、概念設計、運用設計を置く。実装 ticket より上位の合意形成に使う。 - -本ファイルは `/auto-maintain` 単体ではなく、AI maintainer 全体の設計を置く場所である。 - -### `docs/report/` - -実際の運用で発生した障壁や改善案を残す。明確な力不足、tool 問題、workflow 問題、ユーザーからの指示があった場合に作る。 - -report は愚痴ではなく、後から改善 ticket / Workflow 改訂 / Knowledge 化へつなげる観測記録である。 - -### `.insomnia/workflow/` - -実行可能な手順。Workflow は人間が書く、または AI が提案して人間が承認する。AI が勝手に自律生成しない。 - -### memory / Knowledge - -作業中の判断や設計を再利用可能な知識として扱う。ただし、turn を跨ぐ根拠を history に残さず context だけへ差し込むことは禁止する。 - -## 権限モード - -AI maintainer の運用は、作業ごとに権限モードを明示する。 - -### Mode 0: Consultation - -設計相談・方針整理のみ。ファイル編集しない。 - -使う場面: - -- 要件が曖昧 -- 複数の設計方針が自然に導ける -- ticket 化する前に合意したい - -### Mode 1: Documentation / ticket maintenance - -`docs/`, `tickets/`, `TODO.md` など制御面だけを編集する。実装コードは触らない。 - -使う場面: - -- 設計文書作成 -- ticket の詳細化 -- report 作成 -- TODO と ticket の整合確認 - -注意点: - -- 新 ticket 作成や既存 ticket の大幅変更は、人間の合意後に行う -- 完了削除は対象 feature branch 側で行う - -### Mode 2: Delegated implementation - -child worktree を作り、実装 Pod に狭い write scope を渡して実装させる。親 Pod は orchestration と review を行う。 - -使う場面: - -- 要件と完了条件が明確 -- 影響範囲が限定されている -- test / build で確認可能 - -### Mode 3: Maintainer execution with explicit git authority - -人間が明示的に許可した場合に、親 Pod が commit / merge / ticket 完了削除まで行う。 - -使う場面: - -- 「レビューして問題なければマージして」など、明示的な実行指示がある -- 実装 branch / review / ticket lifecycle の配置が明確 +狭い write scope を持つ作業者。対象 worktree と work item を渡され、その範囲で実装・検証・報告を行う。 制約: -- push は行わない -- unrelated dirty changes を commit に混ぜない -- review / completion commit は feature branch 側に置く -- `develop` first-parent には merge commit だけが載る形を目標にする +- 指定 scope 外を編集しない +- `.insomnia` や main workspace の control-plane record を勝手に編集しない +- work item / review / close は maintainer の責務として扱う +- 実装報告には変更点、検証、未解決点を含める -## 基本 loop +### Reviewer Pod -AI maintainer の基本 loop は以下である。 +原則 read-only。実装 diff と対象 work item を読み、妥当性を確認する。 -1. 状態把握 - - `git status --short --branch` - - `TODO.md` - - 対象 ticket - - 関連 docs / report - - 既存 review artifact +見るべき点: -2. 分類 - - 実装可能 - - 設計相談が必要 - - ticket 整理が必要 - - 運用上の問題として report すべき +- work item の要件・受け入れ条件を満たしているか +- 設計を歪めていないか +- 不必要な後方互換性や局所最適な変更を作っていないか +- テストが適切か +- ドキュメント / work item / known issue の更新が必要か -3. 方針提示または実行 - - 設計判断が必要なら、人間に質問する - - 実装可能なら、worktree / Pod / scope / test 方針を決める +## Workflow modes -4. 実装 - - 原則 child worktree - - 実装 Pod に任せるか、親 Pod が直接行うかを選ぶ - - `.insomnia` は child worktree から除外する +### Mode 0: Design consultation -5. 検証 - - focused test - - 必要なら broader test - - `git diff --check` - - `cargo fmt --check` は既存 unrelated 差分を区別して扱う +設計や方針を相談するだけの mode。コードや work item は編集しない。 -6. Review - - ticket の背景・要件・完了条件に照らす - - 過剰実装や設計歪みを見る - - 必要なら修正依頼 +使う場面: -7. Lifecycle - - implementation commit - - review commit - - ticket / review / TODO completion commit - - develop への merge - - first-parent 確認 +- 要件がまだ曖昧 +- work item 化する前に合意したい +- 複数案の設計判断が必要 -8. 報告 - - 実装概要 - - 変更ファイル - - test 結果 - - review 判断 - - 未解決事項 - - 残った dirty changes +### Mode 1: Project record maintenance -## エスカレーション基準 +`work-items/`, `KNOWN_ISSUES.md`, `docs/`, `docs/report/` など control-plane record だけを編集する。実装コードは触らない。 -以下では AI maintainer は実装を止め、人間に戻す。 +例: -- ticket の要件から複数の設計方針が自然に導ける -- 長期構造、crate boundary、protocol、permission、scope、history persistence に触れる -- prompt context 加工原則に関わる -- 新 ticket の作成、既存 ticket の大幅変更、ticket 完了削除について合意がない -- git commit / merge / push などの書き込み権限が明示されていない -- test 不能、再現不能、または作業範囲外の不具合に遭遇した -- child worktree に `.insomnia` が出てしまった -- SpawnedPod の完了状態が不明で、worktree 状態からも安全に判断できない +- work item の作成・詳細化 +- review / implementation report / resolution の追記 +- stale docs の修正 +- known issue の追加・削除 -## Orchestration の制約 +新規 work item 作成や大幅変更は、人間の合意後に行う。 -### SpawnedPod の完了は自動検知しない +### Mode 2: Implementation orchestration -現状、親 Pod は SpawnedPod の完了を push 通知として自動検知しない。完了確認は以下で行う。 +Maintainer Pod が child worktree と implementation Pod を作り、実装と review を回す。親は scoped delegation と project record authority を保持する。 -- `ReadPodOutput` による polling -- Pod が出した完了報告 -- `stopped` 状態 -- worktree の `git status` / `git diff` -- build / test 結果 +基本手順: -そのため、AI maintainer は「Pod が何も言わないが実は完了している」ケースと「Pod が止まっているが失敗した」ケースを区別するため、Pod 出力だけでなく worktree 状態を確認する。 +1. 対象 work item を main workspace で作成・詳細化し commit する +2. orchestrator が child worktree を作る +3. implementation Pod に対象 worktree と task を渡す +4. implementation Pod が実装・検証・報告する +5. reviewer Pod が diff と work item を読む +6. 必要なら修正を戻す +7. maintainer が merge-ready dossier を作る -### Scope は所有権として扱う +### Mode 3: Maintainer-managed completion -実装 Pod に write scope を渡している間、親 Pod は同じ path を編集しない。review artifact や ticket lifecycle を書く前に、必要なら `StopPod` して scope を回収する。 +人間が明示的に許可した場合に、親 Pod が commit / merge / close まで行う。 -### main workspace は制御面 +条件: -main workspace は orchestration / docs / ticket lifecycle / merge のための場所である。実装差分は原則 child worktree に隔離する。 +- 対象 work item が明確 +- scope と worktree が分離されている +- review 結果が approve または残件が明示されている +- validation が通っている +- close / merge してよいというユーザー指示または会話上の合意がある -## Git / ticket lifecycle +push はしない。破壊的 git 操作は明示指示なしに行わない。 -feature branch の ticket lifecycle は以下の形を正とする。 +## Work item lifecycle -```text -* merge: # develop -|\ -| * docs(tickets): complete -| * review: -| * feat/fix/refactor: # feature branch -|/ -* previous develop +### 作成 + +``` +./tickets.sh create --title "..." [--slug slug] [--kind task] [--priority P2] [--label a,b] ``` -重要な検査: +作成後、必要なら `item.md` を詳細化し、背景・要件・受け入れ条件を明確にする。worktree を使う場合は、対象 work item を作成・詳細化して commit してから branch/worktree を切る。 -- review / completion commit は feature branch 側にある -- `develop` first-parent に review / completion commit が直接載っていない -- unrelated dirty changes が staged / committed されていない -- ticket / review / TODO cleanup は merge 前に feature branch 側で完了している +### コメント / 計画 / 判断 -## `/auto-maintain` との関係 +``` +./tickets.sh comment --role plan --file path +./tickets.sh comment --role decision --file path +./tickets.sh comment --role implementation_report --file path +``` -`/auto-maintain` は、この設計の Mode 2 を安全側に制限した Workflow である。 +thread は後から読まれる project record なので、実装ログをだらだら貼るより、判断理由・検証結果・残件を簡潔に残す。 -現在の `/auto-maintain` は以下に留める。 +### レビュー -- TODO / tickets を読む -- 将来的には WorkItemStore を入口にして、ticket は linked artifact または backend view として扱う -- 低リスク ticket を選ぶ -- worktree / implementation Pod / reviewer を orchestration する -- 完了候補を報告する -- 原則として commit / merge / ticket 完了削除は人間に戻す +``` +./tickets.sh review --approve --file path +./tickets.sh review --request-changes --file path +``` -一方、この文書が扱う AI maintainer は、ユーザーが明示的に許可した場合に Mode 3 として commit / merge / ticket lifecycle まで実行できる。ただし push はしない。 +レビューは diff の確認だけではない。work item の前提・要件・受け入れ条件が実装で満たされているか、コードベースを歪めていないかを確認する。 -## 今後必要な機能 +### 完了 -この設計を安定運用するには、以下が必要になる。 +``` +./tickets.sh close --resolution "..." +``` -### WorkItemStore / LeaseStore +close は `work-items/closed/` へ移動し、`resolution.md` と thread entry を残す。close commit には resolution と関連 project record 更新を含める。 -`tickets/` file を直接読むだけでなく、AI maintainer が WorkItem / Thread / Event / Artifact を扱うための store interface。初期実装は repo-managed file backend でよいが、network 越し workspace / remote maintainer hub へ差し替えられるよう、Git 操作や path layout を上位 Workflow に漏らさない。 +## Branch / worktree placement -Lease は thread の正本とは分け、`.insomnia/maintainer/` または local DB に置く runtime coordination state として扱う。remote hub を導入する場合は LeaseStore だけを先に集権化できる設計にする。 +main workspace は orchestration / docs / work item lifecycle / merge の control plane。実装差分は原則 child worktree に隔離する。 + +``` +main/develop workspace: + work item 作成・詳細化 commit + child worktree 作成 + +child worktree feature branch: + implementation commit(s) + validation + +main/develop workspace: + reviewer Pod に read-only 依頼 + merge / close / cleanup commit +``` + +child Pod に write scope を渡している間、親 Pod は同じ path を編集しない。必要なら `StopPod` で scope を回収してから project record を更新する。 + +## Human approval boundaries + +AI maintainer は以下で人間に戻す。 + +- 要件から複数の設計方針が自然に導ける +- public API / protocol / manifest / durable data format を変える +- 大規模 rename / directory 移動 / repository-wide format を伴う +- work item の作成・大幅変更・close について合意がない +- reviewer が request-changes しており、修正方針が自明でない +- validation が失敗し、原因が対象変更か既存問題か不明 +- destructive git operation や push が必要 + +## Reports / Knowledge / Memory + +- `docs/report/`: ドッグフーディングで感じた障壁、改善案、ツール問題の記録。明確な作業単位になったら work item 化する +- `.insomnia/knowledge`: curated project knowledge。正本ではなく補助 context +- `.insomnia/memory`: generated/personal state。project record の代替にしない +- `KNOWN_ISSUES.md`: ticket 化するほどではないが、次に近所を触る時に拾いたい小粒所見 + +## Future extension points + +### WorkItemStore API + +現在は `tickets.sh` + repo-managed `work-items/` を正本とする。将来、remote maintainer hub や issue tracker へ差し替えるなら、WorkItem / Thread / Event / Artifact を扱う store interface を追加し、Git/path layout を上位 workflow に漏らさない形にする。 ### Maintainer doctor -merge 前 / ticket 完了前に以下を検査するコマンド。 +merge 前 / close 前に以下を検査する command。 -- current branch -- feature branch と develop の merge base -- review / completion commit の branch placement -- unrelated staged changes -- ticket / TODO の整合 -- child worktree に `.insomnia` が含まれていないこと +- 対象 work item が存在する +- acceptance criteria と implementation report が対応している +- review status が明示されている +- validation log がある +- work item lifecycle と branch placement が矛盾していない -### Pod completion tracking +### Multi-maintainer coordination -SpawnedPod の状態を polling ではなく、親 Pod が扱いやすいイベントとして観測できる仕組み。 - -必要な情報: - -- running / completed / failed / stopped -- 最終 assistant output -- 最終 tool result -- worktree path -- delegated scope - -### Operation inbox / trial log - -maintainer が見つけた改善候補、試走結果、未整理の気づきを一時的に集める場所。恒久的な ticket にする前の buffer として使う。 - -### Profile / role manifest - -Orchestrator / Coder / Reviewer / Researcher で model・prompt・scope 既定値を分けるための manifest profile。人間が用途ごとに起動時設定を切り替えられるようにする。 - -### Workflow quality evaluation - -Workflow 本文が実際に subagent に渡された時、どこで裁量補完が発生し、どこが曖昧だったかを構造化して report する仕組み。 - -## 非目標 - -当面やらないこと: - -- 常駐 scheduler による unattended 開発 -- AI による push -- AI による無承認の ticket 新規作成 / 大幅変更 -- AI による Workflow 自律生成 -- scope owner handoff の暗黙化 -- history に残らない情報を context へ差し込む運用 - -## 現時点の方針 - -AI maintainer は「コードを書く agent」ではなく、「プロジェクト状態を読み、必要な作業単位へ分解し、適切な worker に委譲し、結果を検証し、履歴に残す agent」として扱う。 - -`/auto-maintain` はその最小実行単位であり、今後はこの文書を上位設計として、Workflow 本文・doctor・profile・Pod completion tracking を段階的に足していく。 +複数 maintainer Pod が同じ repository を扱う場合は、work item / branch / scope の lease が必要。現状は人間と git history が最終調停者。 diff --git a/docs/plan/llm_presistence.md b/docs/plan/llm_presistence.md index 331a3a9d..9fa52daa 100644 --- a/docs/plan/llm_presistence.md +++ b/docs/plan/llm_presistence.md @@ -1,235 +1,28 @@ -# 永続化データ構造の設計・実装プラン +# LLM 履歴永続化 plan(superseded) -## Context +> Status: superseded / historical note. +> +> この文書は、`session-store` / segment log / Pod metadata 分離が入る前の検討メモ。現在の実装仕様として読まないこと。現行仕様は `docs/architecture.md` の「セッション永続化」と `crates/session-store` / `crates/pod-store` / `crates/pod` を正とする。 -INSOMNIA の `llm-worker` クレートは現在すべてのセッション状態をインメモリで保持しており、 -プロセス終了時に会話履歴やターン状態が失われる。 -Coding Agent として Pause/Resume・Fork をまたいだセッション継続を実現するため、 -永続化レイヤーを追加する。 +## 現在の要点 -**設計方針**: Codex CLI / Claude Code と同様の **JSONL append-only ログ** 方式を採用。 -セッションログを replay することで Worker 状態を完全に復元する。 -Pause/正常終了で永続化データの構造に差異を設けない。 -理由: Worker の状態は Pause 時も正常終了時も同じ形(`history: Vec` + `turn_count` + `request_config`)であり、 -APIレスポンスのデータ構造上、両者に本質的な違いがない。 -`resume()` は「ユーザー入力を追加せず `run_turn_loop()` に再入する」だけなので、 -復元に必要なのは history の中身であり、前回の終了理由ではない。 -`RunOutcome` の `Finished`/`Paused` 区分は監査・デバッグ用メタデータであり、replay ロジックの分岐には使わない。 +- 会話・worker replay の authority は `session-store` の append-only JSONL segment log。 +- fresh conversation は新しい `SessionId` を作る。 +- compact / fork / rewind は同じ `SessionId` 配下の `SegmentId` を切り替える。 +- segment 出自は `LogEntry::SegmentStart` 内の `SegmentOrigin`(`compacted_from` / `forked_from`)で表す。 +- Pod 名からの current state は `pod-store` metadata が持つ。 + - active `(SessionId, SegmentId)` pointer + - `resolved_manifest_snapshot` + - spawned child delegation / reclaim state +- runtime socket path / registry mirror は live/derived state であり、conversation history や Pod-name current state の durable authority ではない。 -**命名規約**: -- **SessionLog / LogEntry** — 状態復元用の構造化された記録(永続化の本体) -- **EventTrace / TraceEntry** — デバッグ用の生ストリームイベント全録(オプション) +## Superseded な旧前提 -## クレート構成 +この旧 plan は以下の前提を含んでいたため、現在の仕様とは一致しない。 -永続化は `llm-worker` とは別クレートに分離する。 -`llm-worker` は永続化を一切知らず、Session ラッパーが外から Worker を包む。 +- session を単一ファイル・単一系列として扱う前提。 +- compact/fork で新 SessionId を作る前提。 +- entry hash を replay lineage の主参照にする前提。 +- Pod 名 current state と conversation log authority を分離しない前提。 -``` -crates/ - llm-worker/ ← 既存(LLM クライアント + Worker、変更なし以外は最小限) - llm-worker-macros/ ← 既存(変更なし) - llm-worker-persistence/ ← 新規クレート - Cargo.toml - src/ - lib.rs -- モジュールルート・re-exports・SessionId 型エイリアス - session_log.rs -- LogEntry enum(JSONL 1行 = 1エントリ) - event_trace.rs -- TraceEntry(デバッグ用生イベント記録) - store.rs -- Store trait(バックエンド抽象) - fs_store.rs -- JSONL ファイルシステム実装 - session.rs -- Session ラッパー + replay/restore - insomnia/ ← 将来のトップレベルアプリ - -docs/persistence.md -- 設計ドキュメント(このプランの清書版) -``` - -依存グラフ: -``` -llm-worker-persistence → llm-worker → llm-worker-macros -insomnia (将来) → llm-worker-persistence, llm-worker -``` - -### llm-worker-persistence/Cargo.toml 依存 - -```toml -[dependencies] -llm-worker = { path = "../llm-worker" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" -tokio = { version = "1", features = ["fs", "io-util"] } -uuid = { version = "1", features = ["v7", "serde"] } -thiserror = "2" -``` - -## 既存コードへの変更(llm-worker 側) - -### 1. `RequestConfig` に Serialize/Deserialize 追加 -- **ファイル**: `crates/llm-worker/src/llm_client/types.rs:504` -- `#[derive(Debug, Clone, Default)]` → `#[derive(Debug, Clone, Default, Serialize, Deserialize)]` - -### 2. Worker に復元用セッター追加 -- **ファイル**: `crates/llm-worker/src/worker.rs` -- `impl Worker` ブロックに追加: - - `pub fn set_turn_count(&mut self, count: usize)` - - `pub fn set_last_run_interrupted(&mut self, interrupted: bool)` - -### 3. ワークスペース Cargo.toml にメンバー追加 -- **ファイル**: `Cargo.toml`(ワークスペースルート) -- `members` に `"crates/llm-worker-persistence"` を追加 - -## 新規コード: データ型 - -### LogEntry(session_log.rs) - -状態復元に必要な構造化記録。JSONL 1行 = 1エントリ。 - -```rust -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(tag = "kind", rename_all = "snake_case")] -pub enum LogEntry { - // セッション開始(ログ先頭、fork 時は history にシード状態を含む) - SessionStart { - ts: u64, - system_prompt: Option, - config: RequestConfig, - history: Vec, - }, - - // ユーザー入力(worker.rs:229 に対応) - UserInput { ts: u64, item: Item }, - - // アシスタント応答(worker.rs:1040-1041 に対応) - AssistantItem { ts: u64, item: Item }, - - // ツール実行結果(worker.rs:897-900, 1072-1076 に対応) - ToolResult { ts: u64, item: Item }, - - // typed system injection - SystemItem { ts: u64, item: SystemItem }, - - // ターン境界 - TurnEnd { ts: u64, turn_count: usize }, - - // KV キャッシュロック/アンロック - CacheLocked { ts: u64, locked_prefix_len: usize }, - CacheUnlocked { ts: u64 }, - - // run/resume の終了結果 - RunOutcome { ts: u64, outcome: Outcome, interrupted: bool }, - - // RequestConfig 変更 - ConfigChanged { ts: u64, config: RequestConfig }, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -pub enum Outcome { Finished, Paused, Error { message: String } } -``` - -**Replay ロジック**: 全エントリ種別を走査し、`AssistantItem` / `ToolResult` / `SystemItem` / `UserInput` → history に append、 -`TurnEnd` → turn_count 更新、`CacheLocked` → locked_prefix_len 設定。 - -### TraceEntry(event_trace.rs) - -デバッグ用の生ストリームイベント全録。デフォルト OFF。 -セッションログとは別ファイル `{session_id}.trace.jsonl` に記録。 - -```rust -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TraceEntry { - pub ts: u64, - pub turn: usize, - pub event: Event, -} -``` - -replay 対象外。状態復元には使わない。 - -### SessionId - -`uuid` クレートの UUID v7 をそのまま使用。型エイリアスのみ。 - -```rust -pub type SessionId = uuid::Uuid; - -pub fn new_session_id() -> SessionId { - uuid::Uuid::now_v7() -} -``` - -UUID v7 はタイムスタンプ埋め込みで辞書順 = 時系列順。独自フォーマット不要。 - -### Store trait(store.rs) - -```rust -pub trait Store: Send + Sync { - fn append(&self, id: SessionId, entry: &LogEntry) -> impl Future> + Send; - fn read_all(&self, id: SessionId) -> impl Future, StoreError>> + Send; - fn list_sessions(&self) -> impl Future, StoreError>> + Send; - fn create_session(&self, id: SessionId, entries: &[LogEntry]) -> impl Future> + Send; - fn exists(&self, id: SessionId) -> impl Future> + Send; - - // EventTrace 用(デバッグモード時のみ使用) - fn append_trace(&self, id: SessionId, entry: &TraceEntry) -> impl Future> + Send; -} -``` - -RPITIT (Rust 1.75+) 使用。`async_trait` 不要。 - -### FsStore(fs_store.rs) - -ファイル配置: -- セッションログ: `{root}/{session_id}.jsonl` -- イベントトレース: `{root}/{session_id}.trace.jsonl` - -append モードで書き込み。SQLite インデックスなし。 - -### Session ラッパー(session.rs) - -Worker を直接変更せず、**外部ラッパー** として実装: - -```rust -pub struct Session { - pub worker: Worker, // pub で直接アクセス可能 - store: St, - session_id: SessionId, - config: SessionConfig, -} -``` - -- `Session::new()` → SessionStart を append -- `Session::run()` → Worker::run() の前後で history.len() を比較、差分をログ記録 -- `Session::resume()` → 同上 -- `Session::fork()` → 現在の history をシードにした新 SessionStart を書き込み -- `Session::fork_at(store, source_id, entry_idx)` → 任意地点から分岐 - -**復元**: `restore_session(client, store, session_id)` → read_all → replay_entries → Worker 再構築 - -### EventTrace 記録(デバッグモード) - -`SessionConfig::record_event_trace: bool`(デフォルト `false`)が `true` の場合、 -Session が Worker に `OnStreamChunk` Hook を登録。 -Hook 内で `TraceEntry` を `{session_id}.trace.jsonl` に append。 -セッションログとは完全に分離。 - -## 実装順序 - -1. `RequestConfig` に Serialize/Deserialize 追加(llm-worker 側) -2. Worker に `set_turn_count` / `set_last_run_interrupted` 追加(llm-worker 側) -3. `crates/llm-worker-persistence/` クレート作成(Cargo.toml + ワークスペース登録) -4. `session_log.rs` 作成(LogEntry + Outcome + replay_entries) -5. `event_trace.rs` 作成(TraceEntry) -6. `store.rs` 作成(Store trait + StoreError) -7. `fs_store.rs` 作成(JSONL ファイルシステム実装) -8. `session.rs` 作成(Session ラッパー + restore_session) -9. `lib.rs` 作成(re-exports・SessionId 型エイリアス・new_session_id) -10. テスト作成(replay round-trip, FsStore 読み書き, Session::run ログ記録) -11. `docs/persistence.md` 設計ドキュメント作成 - -## 検証方法 - -1. **ユニットテスト**: `replay_entries` に手動構築した LogEntry 列を渡し、復元状態を検証 -2. **統合テスト**: MockLlmClient + FsStore で Session::run → restore_session → history 一致を確認 -3. **Fork テスト**: fork → 新セッションの history が fork 時点と一致することを確認 -4. **cargo test**: 既存テストが壊れていないことを確認 -5. **cargo clippy / cargo check**: 警告なし +履歴としては有用だが、実装時の根拠には使わない。新しい変更を検討する場合は、まず current code と work item を読むこと。 diff --git a/docs/plan/maintainer-work-items.md b/docs/plan/maintainer-work-items.md index 11bd7632..869f7282 100644 --- a/docs/plan/maintainer-work-items.md +++ b/docs/plan/maintainer-work-items.md @@ -1,76 +1,33 @@ # AI maintainer 用 WorkItem / Thread 抽象メモ -## 位置づけ +> Status: mostly implemented / historical design memo. +> +> この文書は `tickets.sh` + `work-items/` MVP の前に書かれた設計メモ。現在の運用上の正本は `AGENTS.md` の Work item / Ticket 運用と、実際の `tickets.sh` / `work-items/{open,pending,closed}`。古い `TODO.md` / `tickets/` 前提は superseded。 -AI maintainer が単なる coding agent ではなく、作業の発見・分解・実装委譲・review・完了判断まで扱うには、現在の `TODO.md` / `tickets/*.md` だけでは足りない。必要なのは、個々の file path ではなく「作業単位」と「その会話・判断・成果物」を扱う抽象である。 +## 現在実現済みの部分 -このメモは実装 ticket ではなく、将来こういうものが必要になるという設計メモとして置く。具体的な最初の実装は `tickets.sh` / `work-items/` の MVP で試す。 +- WorkItem 相当: `work-items/{open,pending,closed}//item.md` +- Thread 相当: `thread.md` +- Event 相当: `tickets.sh comment/review/status/close` が append する thread entry +- Artifact 相当: `artifacts/` directory +- Resolution 相当: close 時の `resolution.md` +- ID: timestamp + slug 形式 +- Doctor: `./tickets.sh doctor` -## 必要になりそうな概念 +`work-items/` は repo-managed な project coordination record であり、`.insomnia/memory` はその代替ではない。 -- WorkItem - - 作業単位。title / status / kind / priority / labels / acceptance criteria / links を持つ。 -- Thread - - WorkItem に紐づく append-only な会話・判断・review・実装報告の流れ。 -- Event - - comment / plan / decision / implementation_report / review / status_change など。 -- Artifact - - review log、test log、設計メモ、branch / commit / worktree への link など。 -- Lease / Run - - どの Pod / agent がどの worktree / scope で作業中かを表す runtime coordination 情報。 +## 現在も残る設計余地 -## 配置の分担 +- Rust crate / Store interface としての WorkItemStore +- LeaseStore / Run tracking / maintainer inbox +- remote maintainer hub / GitHub Issues などへの backend 差し替え +- TUI 統合 -repo-managed な project-visible 領域には、作業の正本として人間が読める coordination data を置く。 +これらは必要になった時点で改めて work item 化する。 -```text -repo/ - work-items/ # WorkItem / Thread / Artifact - tickets/ # 当面の既存 ticket。将来 WorkItem view に寄せる候補 - docs/ # plan / report -``` +## 現在の運用参照 -`.insomnia` は local runtime state として扱い、project coordination の正本にはしない。 - -```text -.insomnia/ - memory/ - workflow/ - maintainer/ - leases/ - runs/ - inbox/ -``` - -## ID と backend の考え方 - -WorkItem ID は中央 `SEQUENCE` にしない。複数 branch / worktree / Pod が同時に作業を作ると conflict しやすいため、timestamp + slug などの衝突しにくい ID にする。 - -```text -YYYYMMDD-HHMMSS- -YYYYMMDD-HHMMSS-- -``` - -backend は最初は repo 内 file backend でよいが、抽象としては Git directory 固定にしない。将来、remote maintainer hub や GitHub Issues などへ移る可能性を潰さない。 - -## 移行イメージ - -1. 既存の `TODO.md` / `tickets/` 運用は維持する。 -2. `tickets.sh` MVP で `work-items/` の file backend と thread 操作を試す。 -3. 既存 `TODO.md` / `tickets/` を手動で `work-items/` に寄せ、`doctor` が通る状態にする。 -4. その運用が安定したら、`TODO.md` を generated view にするか、廃止するかを判断する。 -5. 必要になった段階で Rust crate / Store interface / LeaseStore / remote backend を検討する。 - -## 当面やらないこと - -- remote maintainer hub の実装。 -- SQLite / index / search daemon の導入。 -- Pod lifecycle / completion tracking の完全実装。 -- LeaseStore の本格実装。 -- TUI 統合。 - -## 参照 - -- `tickets/tickets-sh-workitem-thread-mvp.md` -- `docs/plan/ai-maintainer.md` -- `tickets/auto-maintain-workflow.md` +- `AGENTS.md` — Work item / Ticket の運用ルール +- `tickets.sh` — 実際の操作コマンド +- `work-items/` — 現在の project-visible coordination data +- `docs/plan/ai-maintainer.md` — AI maintainer workflow の現行設計 diff --git a/docs/system-prompt-template.md b/docs/system-prompt-template.md index b02e7e6a..d7d201bf 100644 --- a/docs/system-prompt-template.md +++ b/docs/system-prompt-template.md @@ -46,7 +46,7 @@ Available tools: {{ tools | join(", ") }} ### タイミング -1. `Pod::from_manifest` 時点: テンプレート文字列を `SystemPromptTemplate::parse` で **構文検査のみ** 行い、`Pod.system_prompt_template: Option` に保持する。この時点で Worker 側の system_prompt は `None`、session log もまだ書かれない (`head_hash: None`)。 +1. `Pod::from_manifest` 時点: テンプレート文字列を `SystemPromptTemplate::parse` で **構文検査のみ** 行い、`Pod.system_prompt_template: Option` に保持する。この時点で Worker 側の system_prompt は `None`、segment log の head もまだ作られない。 2. `Pod::run` / `Pod::resume` 初回呼び出し冒頭 (`ensure_system_prompt_materialized`): 1. `worker.tool_server_handle().flush_pending()` で pending な tool factory を materialize して tool 名を確定させる @@ -54,12 +54,12 @@ Available tools: {{ tools | join(", ") }} 3. `template.render(ctx)` で文字列化して `worker.set_system_prompt(rendered)` を呼ぶ 4. `Pod.system_prompt_template = None` (`Option::take()` で構造的に1回性を保証) -3. その直後の `ensure_session_head` が `head_hash` を見て初回なら `create_session_with_id` を呼び、materialize 後の system_prompt を **SessionStart ログエントリに焼き付ける**。 +3. その直後の `ensure_segment_head` が現在 segment の entry count を見て初回なら `SegmentStart` を append し、materialize 後の system_prompt を segment log に焼き付ける。 ### 1回性の保証 - `Pod.system_prompt_template` は `Option` で、materialize 時に `take()` する。2 ターン目以降はフィールドが `None` なので `ensure_system_prompt_materialized` は早期 return し、再 render は発生しない。 -- compact は Worker の system_prompt フィールドを触らない (pod.rs の `compact` は `w.get_system_prompt()` を読み取って新セッションに引き継ぐだけ)。そのため compact 前後で同じ文字列が流れ続ける。 +- compact は Worker の system_prompt フィールドを触らない (pod.rs の `compact` は `w.get_system_prompt()` を読み取って新 segment に引き継ぐだけ)。そのため compact 前後で同じ文字列が流れ続ける。 - 統合テスト `compact_preserves_system_prompt` が実装で直接検証している。 ### 責務分離 @@ -79,7 +79,7 @@ Available tools: {{ tools | join(", ") }} ## 関連ファイル - `crates/pod/src/system_prompt.rs` — `SystemPromptTemplate` / `SystemPromptContext` / `SystemPromptError` -- `crates/pod/src/pod.rs` — `Pod.system_prompt_template` フィールド、`ensure_system_prompt_materialized`、`ensure_session_head` の初回 append ロジック +- `crates/pod/src/pod.rs` — `Pod.system_prompt_template` フィールド、`ensure_system_prompt_materialized`、`ensure_segment_head` の初回 append ロジック - `crates/manifest/src/scope.rs` — `Scope::summary` / `readable_paths` / `writable_paths` -- `crates/session-store/src/session.rs` — `create_session_with_id` (事前生成 ID で SessionStart を書くための entry point) +- `crates/session-store/src/segment_log.rs` — `LogEntry::SegmentStart` / segment replay entries - `crates/llm-worker/src/tool_server.rs` — `ToolServerHandle::flush_pending` (pub) diff --git a/docs/tui-keybindings.md b/docs/tui-keybindings.md index 62958829..9987de85 100644 --- a/docs/tui-keybindings.md +++ b/docs/tui-keybindings.md @@ -1,6 +1,6 @@ # TUI キーバインド -`crates/tui` の対話画面で効くキー一覧。`main.rs:handle_key` を単一情報源とし、このドキュメントは人間向けの目次。 +`crates/tui` の対話画面で効くキー一覧。`crates/tui/src/main.rs:handle_key` を単一情報源とし、このドキュメントは人間向けの目次。 ## 入力編集 @@ -11,9 +11,10 @@ | `Backspace` | カーソル直前を削除(ペーストプレースホルダは 1 回で全削除) | | `Delete` | カーソル直後を削除(同上) | | `Left` / `Right` | カーソル移動 | -| `Up` / `Down` | 論理行単位の上下移動(桁位置を保持) | +| `Up` / `Down` | 通常は論理行単位の上下移動。入力欄の先頭/末尾では送信済み composer history を browse | | `Home` / `End` | 現在行の行頭 / 行末へ | | `Alt-Enter` | 改行を挿入(Input を複数行化) | +| `Esc` | completion popup があれば閉じる | ### ペーストプレースホルダ @@ -23,13 +24,34 @@ カーソルはプレースホルダ内部には入れず、`Backspace` / `Delete` 1 回で プレースホルダ全体が消える。`#N` の通し番号は TUI プロセス起動中で連番。 +### Completion + +`@` file ref / `#` knowledge ref / `/` workflow invocation などは completion popup を開く。 + +| キー | 動作 | +|---|---| +| `Up` / `Down` | completion 候補を移動 | +| `Tab` | 選択候補をテキストとして適用 | +| `Enter` | committable な候補は chip 化して空白を追加。directory などはテキスト適用して drill-in | +| `Esc` | popup を閉じる | +| 空白文字 | exact match なら chip 化してから空白を挿入 | + ## 送信(Enter) | 状態 | 入力あり | 入力空 | |---|---|---| | Idle | `Method::Run` で新ターン開始 | no-op | | Paused | `Method::Run`(前ターンは割り込み終了として扱い、新ターンとして開始) | `Method::Resume`(前ターンの続きを再開) | -| Running | 入力は TUI 側でバッファのみ、送信はしない | 同左 | +| Running | 入力は TUI 側 queue に積まれ、現在 turn の終了後に自動送信 | no-op | + +### Running 中の queue + +Running 中に入力ありで Enter すると、現在の provider stream には割り込まず、typed input segments を TUI-local queue に積む。`RunResult::Finished` / `LimitReached` 後に先頭の queued input が次の `Method::Run` として自動送信される。`Paused` / `RolledBack` では自動送信しない。 + +| キー | 動作 | +|---|---| +| `Alt-Q` | queue 先頭を composer に戻す(composer が空の時のみ) | +| `Alt-C` | queued input を全消去 | ### Paused からの挙動 @@ -42,16 +64,32 @@ Paused 中に Enter すると、入力の有無で 2 通り: 3. 入力を新しい user メッセージとして append 4. ターン開始 +## Command mode + +composer が空の通常入力で `:` を押すと command mode に入る。command mode 中は composer が command line として扱われる。 + +| キー | 動作 | +|---|---| +| `Enter` | command を実行 | +| `Esc` | command mode を終了 | +| `Backspace` | 文字を削除。空なら command mode を終了 | +| `Ctrl-U` | command input をクリア | +| `Tab` | command completion を適用 | +| `Up` / `Down` | command completion 候補があれば移動、なければカーソル上下 | + +主な command は `:help`, `:noop`, `:compact`, `:rewind` / `:rollback`。`:compact` は idle 時だけ即時 compaction を要求し、`:rewind` / `:rollback` は rewind target picker を開く。 + ## 履歴ビューのナビゲーション 履歴ビューは全画面 TUI の上段にあり、TUI 内部で全ブロックを state として 保持してスクロール可能。スクロールバック(端末側の履歴)ではなく TUI の 自前バッファを動かす点に注意。 -| キー | 動作 | +| キー / 操作 | 動作 | |---|---| | `Shift-Up` / `Shift-Down` | 1 論理行スクロール | -| `PageUp` / `PageDown` | 1 ページスクロール(`area_height - 1` 行) | +| mouse wheel | 数行単位でスクロール | +| `PageUp` / `PageDown` | 1 ページスクロール(task pane が開いている時は task pane をスクロール) | | `Ctrl-[` / `Ctrl-]` | 前 / 次のターン先頭へジャンプ | | `Ctrl-Home` | 履歴の先頭へ | | `Ctrl-End` | 履歴の末尾へ(末尾追従モードを再開) | @@ -69,7 +107,7 @@ Paused 中に Enter すると、入力の有無で 2 通り: 合わせる。多数のツール呼び出しが挟まった長いターンでも前後ターンの先頭に 1 発で戻れる。末尾ターンから `Ctrl-]` を押すと末尾追従に復帰する。 -## 表示モード +## 表示モード / 補助 pane 履歴各ブロックの密度を 3 段階で切り替える。現在のモードはステータスバー 右端に `[mode]` として表示される。 @@ -77,12 +115,11 @@ Paused 中に Enter すると、入力の有無で 2 通り: | キー | 動作 | |---|---| | `Ctrl-O` | `detail` → `normal` → `overview` → `detail` の順に循環 | +| `Ctrl-T` | task pane を開閉 | - **detail**: 全ブロック完全表示。ツールブロックは結果本体も全量 -- **normal**: 完了ブロックは概ね 5–6 行に圧縮、実行中のツールブロックは - detail と同じ扱い -- **overview**: 各ブロック 1 行に畳む(ツールブロックは - `ToolResult.summary` 1 行、長文 AssistantText は先頭 1 行 + 省略記) +- **normal**: 完了ブロックは概ね 5–6 行に圧縮、実行中のツールブロックは detail と同じ扱い +- **overview**: 各ブロック 1 行に畳む(ツールブロックは `ToolResult.summary` 1 行、長文 AssistantText は先頭 1 行 + 省略記) モード切替は全体に一括適用。個別ブロックの開閉は持たない。 @@ -90,9 +127,10 @@ Paused 中に Enter すると、入力の有無で 2 通り: | キー | Running 中 | Idle / Paused | |---|---|---| -| `Ctrl-X` | `Method::Cancel`(進行中ターンを破棄 → Idle) | `Method::Shutdown`(Pod を終了) | +| `Ctrl-X` | queued input を消去して `Method::Cancel`(進行中ターンを破棄 → Idle) | `Method::Shutdown`(Pod を終了) | | `Ctrl-C` | `Method::Pause`(進行中ターンを中断 → Paused) | 1 回目 warn、3 秒以内の 2 回目で TUI 終了(Pod は残る) | | `Ctrl-D` | TUI 終了(Pod は残る、Pause しない) | TUI 終了(Pod は残る) | +| `Ctrl-R` | rewind picker 要求は拒否される | rewind target picker を開く | ### Cancel と Pause の違い @@ -101,9 +139,21 @@ Paused 中に Enter すると、入力の有無で 2 通り: Running 中に割り込みたい場合、ほとんどのケースで `Ctrl-C`(Pause)が自然。Ctrl-X(Cancel)は明示的に破棄したい時(LLM が暴走した時など)用。Pod を終了したい場合は、先に Running ではない状態(Idle / Paused)にしてから `Ctrl-X` で Shutdown する。 +### Rewind picker + +`Ctrl-R` または `:rewind` / `:rollback` で Pod に `Method::ListRewindTargets` を送り、main area に rewind target picker を開く。picker 中の操作は以下。 + +| キー | 動作 | +|---|---| +| `Up` / `Down` | target を移動 | +| `Enter` | 選択 target へ `Method::RewindTo`。復元された user input は composer に戻る | +| `Esc` | picker を閉じる | + +Running 中の rewind request は拒否される。Paused 中は picker を開けるが、実際の apply は idle で composer が空の時だけ行う。 + ### Ctrl-C と Ctrl-D の終了 UX -- Ctrl-X Running 中: `Method::Cancel`。終了したい場合は、明示的にターンを止めて Idle に戻してからもう一度 `Ctrl-X` +- Ctrl-X Running 中: queued input を消去して `Method::Cancel`。終了したい場合は、明示的にターンを止めて Idle に戻してからもう一度 `Ctrl-X` - Ctrl-X Idle / Paused: `Method::Shutdown` を送って Pod を終了 - Ctrl-C Running 中: 1 回目で即 Pause(破壊的ではない) - Ctrl-C Idle / Paused: 1 回目で warn メッセージ、3 秒以内の 2 回目で TUI 終了(Pod は残る) @@ -115,10 +165,7 @@ TUI のダイアログから Pod を起動する経路では、起動した Pod ## 履歴メモ -- かつて存在した `Ctrl-R`(Resume 専用)は、空 Enter での Resume に統合されたため廃止 -- かつて存在した `Esc`(TUI 終了)は、`Ctrl-C` の 2 連打 UX に統合されたため廃止 +- `Ctrl-R` はかつて Resume 専用だったが、空 Enter での Resume に統合された。現在の `Ctrl-R` は rewind picker の導線 +- かつて存在した `Esc`(TUI 終了)は、`Ctrl-C` の 2 連打 UX に統合されたため廃止。現在の `Esc` は popup / picker / command mode のキャンセル用途 - かつて `Ctrl-D` は Pod に `Method::Shutdown` を送っていたが、TUI だけを抜けるデタッチ操作に変更された -- 旧 inline viewport 時代は履歴スクロールを端末側スクロールバックに - 任せていたため TUI 内のスクロールキーは存在しなかった。全画面 alt screen - への移行(`tickets/tui-fullscreen-overhaul.md`)で `Shift-Up/Down` ほか - のナビゲーションキーが追加された +- 旧 inline viewport 時代は履歴スクロールを端末側スクロールバックに任せていたため TUI 内のスクロールキーは存在しなかった。全画面 alt screen への移行で `Shift-Up/Down` ほかのナビゲーションキーが追加された diff --git a/work-items/open/20260530-062852-refresh-stale-docs/item.md b/work-items/open/20260530-062852-refresh-stale-docs/item.md index 4303757b..c1497124 100644 --- a/work-items/open/20260530-062852-refresh-stale-docs/item.md +++ b/work-items/open/20260530-062852-refresh-stale-docs/item.md @@ -7,7 +7,7 @@ kind: task priority: P2 labels: [docs, maintenance] created_at: 2026-05-30T06:28:52Z -updated_at: 2026-05-30T06:29:24Z +updated_at: 2026-05-30T06:39:11Z assignee: null legacy_ticket: null --- diff --git a/work-items/open/20260530-062852-refresh-stale-docs/thread.md b/work-items/open/20260530-062852-refresh-stale-docs/thread.md index 35c4fc61..eae915fe 100644 --- a/work-items/open/20260530-062852-refresh-stale-docs/thread.md +++ b/work-items/open/20260530-062852-refresh-stale-docs/thread.md @@ -19,4 +19,26 @@ Implementation plan: 5. Review the resulting diff against the audit findings before closing. +--- + + + +## Implementation report + +Implementation report: + +- Refreshed `docs/architecture.md` for current protocol categories, session-store vs pod-store responsibilities, profile/manifest input, scope delegation, and current built-in tool categories. +- Updated `docs/compaction.md` to describe same-session segment rotation and `SegmentStart.compacted_from` instead of the old new-SessionId model. +- Rewrote `docs/tui-keybindings.md` around current command mode, queued input behavior, completion, task pane, and `Ctrl-R` rewind picker behavior. +- Marked `docs/plan/llm_presistence.md` as superseded and replaced old implementation details with current-session persistence pointers. +- Refreshed `docs/plan/ai-maintainer.md` and `docs/plan/maintainer-work-items.md` so current `tickets.sh` + `work-items/` authority replaces old `TODO.md` / legacy `tickets/` assumptions. +- Updated `docs/system-prompt-template.md` for current segment log naming (`ensure_segment_head`, `SegmentStart`) while fixing nearby stale session terminology. + +Validation: + +- `./tickets.sh doctor` +- `git diff --check` +- grep sweep for the high-priority stale phrases from the audit; remaining hits are historical reports/ref docs or explicit superseded notes. + + ---