ticket: move local storage to .yoi/tickets

This commit is contained in:
2026-06-06 06:44:10 +09:00
parent 749b3f3aee
commit da94b1ec50
529 changed files with 98 additions and 156 deletions
+3
View File
@@ -0,0 +1,3 @@
[backend]
provider = "builtin:yoi_local"
root = ".yoi/tickets"
@@ -0,0 +1,88 @@
---
id: 20260527-000001-auto-maintain-workflow
slug: auto-maintain-workflow
title: 半自動開発運用 Workflow
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:01Z
updated_at: 2026-06-05T15:56:29Z
assignee: null
legacy_ticket: tickets/auto-maintain-workflow.md
---
## Migration reference
- legacy_ticket: tickets/auto-maintain-workflow.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# 半自動開発運用 Workflow
## 背景
insomnia では insomnia 自身の開発を、ユーザーがタスクを投げ、設計相談をし、実装 Pod / reviewer Pod に分担させる形で進めている。既に Workflow / Skills、SpawnPod、Pod 間通信、scope 委譲、ticket / review lifecycle は揃っており、局所的な実装判断は AI に移譲できる余地が大きい。
一方で、完全な unattended 自動開発にするには、永続ジョブキュー、git 書き込み権限、設計判断のエスカレーション基準など未整理の領域がある。初期段階では、常駐 scheduler ではなく、ユーザーが明示的に起動する「maintainer workflow」として、TODO / tickets を俯瞰し、実装・レビュー・修正依頼を orchestration し、設計境界や完了判断だけを人間に戻す運用を整備する。
## 要件
### Workflow の役割
`/auto-maintain` 相当の Workflow を用意し、親 Pod が以下を実行できるようにする。
- `TODO.md``tickets/` から着手候補を把握する
- 既存方針・既存 ticket から実装方針が十分に導ける作業を選ぶ
- 要件が曖昧、または設計判断が必要な場合は実装前に人間へ質問する
- 実装 Pod を spawn し、適切な read / write scope を委譲する
- 実装 Pod の完了報告と diff / build / test 結果を確認する
- 必要に応じて reviewer Pod、または親 Pod 自身でレビューする
- レビュー指摘があれば修正を依頼する
- 最終的に「完了候補」として人間に報告する
### エスカレーション基準
Workflow は、少なくとも以下の場合に作業を止めて人間へ確認する。
- ticket の要件から複数の設計方針が自然に導け、選択が将来の構造に影響する
- scope / permission / history 永続化 / prompt context 加工原則など、システムの安全モデルに触れる
- 新しい ticket の追加、既存 ticket の大幅な要件変更、ticket 完了削除を行う
- git の commit / merge / push など書き込み操作が必要になる
- テスト不能、再現不能、または作業範囲外の不具合に遭遇する
### Pod orchestration 規約
- 実装 Pod と reviewer Pod は原則分ける。ただし scope 衝突や作業粒度により、親 Pod がレビューしてもよい。
- 実装 Pod に worktree write scope を渡す場合、review artifact を親または reviewer が書く前に実装 Pod を停止して scope を回収する。
- spawn 時は、作業対象 worktree の write scope だけでなく、必要な参照元 ticket / project root の read scope も明示する。
- 子 Pod の出力は `ReadPodOutput` で確認し、必要なら `SendToPod` で追加依頼する。
- orphan 化した Pod や不要になった Pod は `StopPod` する。
### 成果物
- Workflow 本文、またはそれに準じる運用手順が workspace から呼び出せる形で追加される
- Workflow が resident workflow として広告可能かどうかを判断し、必要なら `model_invokation` 設定を含める
- 実際の insomnia 開発 ticket を 1 件以上試走し、実装 Pod / review / 人間確認の境界が機能することを確認する
- 試走で見つかった不足(永続ジョブキュー、scope handoff、review artifact の置き場所等)は、本チケット内で解決せず、必要なら別 ticket として切り出す
## 範囲外
- 常駐 scheduler / daemon による unattended 実行
- git commit / merge / push の自動化
- ticket 完了削除の自動化
- Workflow の状態機械化、永続ジョブキュー化、トランザクション管理
- scope owner handoff など、Pod 権限モデル自体の変更
## 完了条件
- `/auto-maintain` 相当の半自動開発運用 Workflow が利用可能になっている
- Workflow は TODO / tickets から作業を選び、実装 Pod / reviewer / 人間確認を使い分ける手順を明示している
- エスカレーション基準により、設計判断・git 書き込み・ticket 完了判断が人間に戻る
- 少なくとも 1 件の小さな実開発作業で試走し、結果と不足点が記録されている
- 既存の Workflow / Skill / memory の設計方針、特に Workflow 自動生成禁止と history に commit されない context input 禁止に反していない
## 参照
- `docs/plan/workflow.md`
- `docs/report/2026-05-05-file-ticket-scope.md`
- `tickets/internal-worker-workflow.md`
@@ -0,0 +1,25 @@
The old Auto Maintain workflow is retired and removed.
Resolution:
- Deleted `.yoi/workflow/auto-maintain.md`.
- Closed this Ticket as superseded by the newer Ticket-based orchestration workflow split:
- `ticket-intake-workflow`
- `ticket-orchestrator-routing`
- `ticket-preflight-workflow`
- `multi-agent-workflow`
- Updated `multi-agent-workflow` to point to Ticket Intake / Orchestrator Routing / Preflight instead of `$user/auto-maintain`.
- Updated `ticket-intake-workflow` to remove the obsolete auto-maintain connection.
- Updated `prompt-eval-metrics` so future prompt/workflow evaluation targets the current Ticket workflows or worktree workflow instead of `/auto-maintain`.
Rationale:
`auto-maintain` had become a broad and unstable WIP workflow with old assumptions around TODO/tickets and maintenance loops. Keeping it resident risks encouraging large implicit automation and bypassing the clearer gates now provided by Ticket Intake, Ticket Orchestrator Routing, Ticket Preflight, and Multi-agent Worktree Workflow.
Future maintainer/scheduler/lease behavior should be designed as explicit follow-up work, not revived through the deleted auto-maintain workflow.
Validation:
- `git diff --check`
- `./tickets.sh doctor`
- open workflow/docs search no longer finds `auto-maintain` references outside this closed historical Ticket context.
@@ -0,0 +1,40 @@
<!-- event: migration author: tickets.sh-migration at: 2026-05-27T00:00:01Z -->
## Migrated
Migrated from tickets/auto-maintain-workflow.md. No legacy review file was present at migration time.
---
<!-- event: close author: hare at: 2026-06-05T15:56:29Z status: closed -->
## Closed
The old Auto Maintain workflow is retired and removed.
Resolution:
- Deleted `.yoi/workflow/auto-maintain.md`.
- Closed this Ticket as superseded by the newer Ticket-based orchestration workflow split:
- `ticket-intake-workflow`
- `ticket-orchestrator-routing`
- `ticket-preflight-workflow`
- `multi-agent-workflow`
- Updated `multi-agent-workflow` to point to Ticket Intake / Orchestrator Routing / Preflight instead of `$user/auto-maintain`.
- Updated `ticket-intake-workflow` to remove the obsolete auto-maintain connection.
- Updated `prompt-eval-metrics` so future prompt/workflow evaluation targets the current Ticket workflows or worktree workflow instead of `/auto-maintain`.
Rationale:
`auto-maintain` had become a broad and unstable WIP workflow with old assumptions around TODO/tickets and maintenance loops. Keeping it resident risks encouraging large implicit automation and bypassing the clearer gates now provided by Ticket Intake, Ticket Orchestrator Routing, Ticket Preflight, and Multi-agent Worktree Workflow.
Future maintainer/scheduler/lease behavior should be designed as explicit follow-up work, not revived through the deleted auto-maintain workflow.
Validation:
- `git diff --check`
- `./tickets.sh doctor`
- open workflow/docs search no longer finds `auto-maintain` references outside this closed historical Ticket context.
---
@@ -0,0 +1,155 @@
---
id: 20260527-000004-manual-turn-rollback
slug: manual-turn-rollback
title: Pod/TUI: 手動 rewind 導線
status: closed
kind: task
priority: P2
labels: [tui, pod, ux]
created_at: 2026-05-27T00:00:04Z
updated_at: 2026-05-29T03:09:22Z
assignee: null
legacy_ticket: tickets/manual-turn-rollback.md
---
## Background
`pod-empty-turn-rollback` / `tui-empty-turn-restore` により、AI 側出力が 0 の interrupted turn については Pod 側で自動 rollback し、TUI 側で入力を復元できるようになった。
次に欲しいのは、直前 turn だけの rollback command ではなく、TUI から過去の user message を選び、その地点まで会話を戻してその入力を composer に復元する **manual rewind** 導線である。
誤送信、モデル選択ミス、途中で方針を変えた場合などに、ユーザーは過去の入力を選び直し、必要なら編集してから Enter で retry できる。選択した瞬間に再実行はしない。
## UX
- `:rewind` command を追加する。
- `:rollback``:rewind` の alias として扱ってよい。
- `Ctrl+R` は rewind/rollback を表す shortcut として、同じ picker を開く。
- `:rewind` / `Ctrl+R` は引数を取らず、TUI 内の picker を開く。
- Rewind picker は popup/overlay ではなく、通常の conversation/history view area を一時的に置き換える dedicated view として表示する。
- composer/input area と actionbar/status area は通常通り残す。
- main view area だけが message history から rewind target list に切り替わる。
- Esc 等で picker を閉じると、通常の conversation/history view に戻る。
- `:rewind` command は `Idle` / `Paused` の時だけ picker を開く。`Running` 中は visible diagnostic を出して何もしない。
- `Ctrl+R` shortcut も Pod が停止中 (`Idle` または `Paused`) の時だけ有効にする。`Running` 中は無視または visible diagnostic にする。
- picker は過去の user message を新しい順に表示する。
- turn number / index
- timestamp または relative time
- message preview
- eligible / disabled reason
- picker で user message を選択すると、Pod はその user message の直前まで history/session log を rewind し、選択された message を TUI composer に復元する。
- 選択後は、composer に該当 message が入っている状態になる。
- Enter を押すとその message で retry できる。
- ユーザーは送信前に編集できる。
- 選択しただけで自動実行しない。
- Esc 等で picker を閉じると何も変更しない。
## Semantics
Manual rewind は destructive operation として扱う。選択地点より後の履歴 suffix は捨てる。fork は優先度低めの別機能であり、この ticket の実装では fork を作らない。
- Rewind は current active segment/session に対して行う。
- Rewind 成功時、選択された `UserInput` entry 自体も履歴から取り除かれ、composer に戻る。
- Rewind 後、選択地点より後の assistant output / later user messages / usage entries / display blocks は現 branch から消える。
- 元 suffix を保持したい場合は将来の `pod-session-fork` で扱う。この ticket では保持しない。
- Tool side effect の undo はしない。
Initial safety policy:
- Pod が `Idle` または `Paused` の時だけ許可する。
- `Running` 中は拒否する。
- picker 表示時から head が変わった場合は apply 時に再検証して拒否する。
- segment rotation / compaction を跨ぐ rewind は初期実装では対象外でよい。
- suffix に tool call / tool result / other side-effect-looking entries が含まれる場合でも、初期方針としては destructive rewind を許可してよい。ただし UI には「以降の履歴は破棄され、tool side effects は undo されない」ことが分かる notice/diagnostic を出す。
- 実装上どうしても安全に整合性を保てない suffix 種別がある場合は、具体的な disabled reason を表示して拒否する。
## Protocol / ownership
TUI がローカルに履歴を削るのではなく、Pod が authoritative に rewind を検証・適用する。
Suggested protocol shape:
```rust
Method::ListRewindTargets { limit: Option<usize> }
Method::RewindTo {
target: RewindTargetId,
expected_head_entries: usize,
}
Event::RewindTargets { targets: Vec<RewindTarget> }
Event::RewindApplied {
entries: Vec<serde_json::Value>,
input: Vec<Segment>,
summary: RewindSummary,
}
```
Exact names may differ, but the behavior should stay:
- listing targets and applying a target are separate operations.
- apply revalidates target identity and current head.
- success returns enough entries for clients to reseed their view.
- success returns the selected user input segments so TUI can restore the composer.
- failure uses visible diagnostics, e.g. `Event::Error { code: InvalidRequest, message }`.
`RunResult::RolledBack` should not be reused for this idle control operation. It remains the run-lifecycle signal for submit-time empty-turn rollback.
## Implementation notes
- Target identity can initially be current segment + entry index:
```rust
RewindTargetId {
segment_id: SegmentId,
user_input_entry_index: usize,
}
```
- Include `expected_head_entries` to reject stale picker selections.
- Each target should include:
- preview
- original `Vec<Segment>`
- turn/index metadata if available
- whether the target is eligible
- disabled/warning reason if relevant
- the entry count to truncate to, which is before the selected user message.
- Rewind apply must keep these in sync:
- worker history
- `user_segments`
- session store segment log
- `SegmentLogSink` mirror
- usage history / trackers
- TUI view reconstructed from returned entries
- If a complete current-state reconstruction from log is simpler and safer than maintaining many historical snapshots, prefer that over fragile partial truncation.
## Acceptance criteria
- `:rewind` opens a picker of past user messages by replacing the normal conversation/history view area, not by drawing a small popup.
- `Ctrl+R` opens the same picker only while Pod status is `Idle` or `Paused`; it is disabled/rejected while `Running`.
- Selecting a message rewinds the Pod state to before that message and restores the message into the TUI composer.
- Rewind does not auto-run; pressing Enter after selection retries the restored message.
- Rewind success updates Pod session log, SegmentLogSink mirror, worker state, and TUI display consistently.
- Esc returns from the rewind picker to the normal conversation/history view without changing Pod state.
- Rewind failure leaves state unchanged and shows a clear reason.
- Picker selections are revalidated at apply time to avoid stale-head corruption.
- Rewound suffix is intentionally discarded; no fork is created.
- Tool side effects are not undone; UI/diagnostics make this clear when relevant.
- Tests cover target listing, apply success, stale-head rejection, composer restore, TUI display reseed, and at least one suffix-with-tool case.
- `cargo fmt --check`
- `cargo check -p protocol -p pod -p tui`
- Relevant focused tests.
## Out of scope
- Creating a fork when rewinding.
- Fork tree visualization.
- Merging branches.
- Undoing tool side effects.
- Rollback history stack / redo.
- Rewind across compacted segments unless it falls out naturally from implementation.
## Related
- `20260527-000009-pod-session-fork` remains a lower-priority future feature for preserving alternate histories.
- Completed: `pod-empty-turn-rollback`
- Completed: `tui-empty-turn-restore`
@@ -0,0 +1,155 @@
---
id: 20260527-000004-manual-turn-rollback
slug: manual-turn-rollback
title: Pod/TUI: 手動 rewind 導線
status: closed
kind: task
priority: P2
labels: [tui, pod, ux]
created_at: 2026-05-27T00:00:04Z
updated_at: 2026-05-29T03:09:22Z
assignee: null
legacy_ticket: tickets/manual-turn-rollback.md
---
## Background
`pod-empty-turn-rollback` / `tui-empty-turn-restore` により、AI 側出力が 0 の interrupted turn については Pod 側で自動 rollback し、TUI 側で入力を復元できるようになった。
次に欲しいのは、直前 turn だけの rollback command ではなく、TUI から過去の user message を選び、その地点まで会話を戻してその入力を composer に復元する **manual rewind** 導線である。
誤送信、モデル選択ミス、途中で方針を変えた場合などに、ユーザーは過去の入力を選び直し、必要なら編集してから Enter で retry できる。選択した瞬間に再実行はしない。
## UX
- `:rewind` command を追加する。
- `:rollback``:rewind` の alias として扱ってよい。
- `Ctrl+R` は rewind/rollback を表す shortcut として、同じ picker を開く。
- `:rewind` / `Ctrl+R` は引数を取らず、TUI 内の picker を開く。
- Rewind picker は popup/overlay ではなく、通常の conversation/history view area を一時的に置き換える dedicated view として表示する。
- composer/input area と actionbar/status area は通常通り残す。
- main view area だけが message history から rewind target list に切り替わる。
- Esc 等で picker を閉じると、通常の conversation/history view に戻る。
- `:rewind` command は `Idle` / `Paused` の時だけ picker を開く。`Running` 中は visible diagnostic を出して何もしない。
- `Ctrl+R` shortcut も Pod が停止中 (`Idle` または `Paused`) の時だけ有効にする。`Running` 中は無視または visible diagnostic にする。
- picker は過去の user message を新しい順に表示する。
- turn number / index
- timestamp または relative time
- message preview
- eligible / disabled reason
- picker で user message を選択すると、Pod はその user message の直前まで history/session log を rewind し、選択された message を TUI composer に復元する。
- 選択後は、composer に該当 message が入っている状態になる。
- Enter を押すとその message で retry できる。
- ユーザーは送信前に編集できる。
- 選択しただけで自動実行しない。
- Esc 等で picker を閉じると何も変更しない。
## Semantics
Manual rewind は destructive operation として扱う。選択地点より後の履歴 suffix は捨てる。fork は優先度低めの別機能であり、この ticket の実装では fork を作らない。
- Rewind は current active segment/session に対して行う。
- Rewind 成功時、選択された `UserInput` entry 自体も履歴から取り除かれ、composer に戻る。
- Rewind 後、選択地点より後の assistant output / later user messages / usage entries / display blocks は現 branch から消える。
- 元 suffix を保持したい場合は将来の `pod-session-fork` で扱う。この ticket では保持しない。
- Tool side effect の undo はしない。
Initial safety policy:
- Pod が `Idle` または `Paused` の時だけ許可する。
- `Running` 中は拒否する。
- picker 表示時から head が変わった場合は apply 時に再検証して拒否する。
- segment rotation / compaction を跨ぐ rewind は初期実装では対象外でよい。
- suffix に tool call / tool result / other side-effect-looking entries が含まれる場合でも、初期方針としては destructive rewind を許可してよい。ただし UI には「以降の履歴は破棄され、tool side effects は undo されない」ことが分かる notice/diagnostic を出す。
- 実装上どうしても安全に整合性を保てない suffix 種別がある場合は、具体的な disabled reason を表示して拒否する。
## Protocol / ownership
TUI がローカルに履歴を削るのではなく、Pod が authoritative に rewind を検証・適用する。
Suggested protocol shape:
```rust
Method::ListRewindTargets { limit: Option<usize> }
Method::RewindTo {
target: RewindTargetId,
expected_head_entries: usize,
}
Event::RewindTargets { targets: Vec<RewindTarget> }
Event::RewindApplied {
entries: Vec<serde_json::Value>,
input: Vec<Segment>,
summary: RewindSummary,
}
```
Exact names may differ, but the behavior should stay:
- listing targets and applying a target are separate operations.
- apply revalidates target identity and current head.
- success returns enough entries for clients to reseed their view.
- success returns the selected user input segments so TUI can restore the composer.
- failure uses visible diagnostics, e.g. `Event::Error { code: InvalidRequest, message }`.
`RunResult::RolledBack` should not be reused for this idle control operation. It remains the run-lifecycle signal for submit-time empty-turn rollback.
## Implementation notes
- Target identity can initially be current segment + entry index:
```rust
RewindTargetId {
segment_id: SegmentId,
user_input_entry_index: usize,
}
```
- Include `expected_head_entries` to reject stale picker selections.
- Each target should include:
- preview
- original `Vec<Segment>`
- turn/index metadata if available
- whether the target is eligible
- disabled/warning reason if relevant
- the entry count to truncate to, which is before the selected user message.
- Rewind apply must keep these in sync:
- worker history
- `user_segments`
- session store segment log
- `SegmentLogSink` mirror
- usage history / trackers
- TUI view reconstructed from returned entries
- If a complete current-state reconstruction from log is simpler and safer than maintaining many historical snapshots, prefer that over fragile partial truncation.
## Acceptance criteria
- `:rewind` opens a picker of past user messages by replacing the normal conversation/history view area, not by drawing a small popup.
- `Ctrl+R` opens the same picker only while Pod status is `Idle` or `Paused`; it is disabled/rejected while `Running`.
- Selecting a message rewinds the Pod state to before that message and restores the message into the TUI composer.
- Rewind does not auto-run; pressing Enter after selection retries the restored message.
- Rewind success updates Pod session log, SegmentLogSink mirror, worker state, and TUI display consistently.
- Esc returns from the rewind picker to the normal conversation/history view without changing Pod state.
- Rewind failure leaves state unchanged and shows a clear reason.
- Picker selections are revalidated at apply time to avoid stale-head corruption.
- Rewound suffix is intentionally discarded; no fork is created.
- Tool side effects are not undone; UI/diagnostics make this clear when relevant.
- Tests cover target listing, apply success, stale-head rejection, composer restore, TUI display reseed, and at least one suffix-with-tool case.
- `cargo fmt --check`
- `cargo check -p protocol -p pod -p tui`
- Relevant focused tests.
## Out of scope
- Creating a fork when rewinding.
- Fork tree visualization.
- Merging branches.
- Undoing tool side effects.
- Rollback history stack / redo.
- Rewind across compacted segments unless it falls out naturally from implementation.
## Related
- `20260527-000009-pod-session-fork` remains a lower-priority future feature for preserving alternate histories.
- Completed: `pod-empty-turn-rollback`
- Completed: `tui-empty-turn-restore`
@@ -0,0 +1,170 @@
<!-- event: migration author: tickets.sh-migration at: 2026-05-27T00:00:04Z -->
## Migrated
Migrated from tickets/manual-turn-rollback.md. No legacy review file was present at migration time.
---
<!-- event: close author: hare at: 2026-05-29T03:09:22Z status: closed -->
## Closed
---
id: 20260527-000004-manual-turn-rollback
slug: manual-turn-rollback
title: Pod/TUI: 手動 rewind 導線
status: closed
kind: task
priority: P2
labels: [tui, pod, ux]
created_at: 2026-05-27T00:00:04Z
updated_at: 2026-05-29T03:09:22Z
assignee: null
legacy_ticket: tickets/manual-turn-rollback.md
---
## Background
`pod-empty-turn-rollback` / `tui-empty-turn-restore` により、AI 側出力が 0 の interrupted turn については Pod 側で自動 rollback し、TUI 側で入力を復元できるようになった。
次に欲しいのは、直前 turn だけの rollback command ではなく、TUI から過去の user message を選び、その地点まで会話を戻してその入力を composer に復元する **manual rewind** 導線である。
誤送信、モデル選択ミス、途中で方針を変えた場合などに、ユーザーは過去の入力を選び直し、必要なら編集してから Enter で retry できる。選択した瞬間に再実行はしない。
## UX
- `:rewind` command を追加する。
- `:rollback``:rewind` の alias として扱ってよい。
- `Ctrl+R` は rewind/rollback を表す shortcut として、同じ picker を開く。
- `:rewind` / `Ctrl+R` は引数を取らず、TUI 内の picker を開く。
- Rewind picker は popup/overlay ではなく、通常の conversation/history view area を一時的に置き換える dedicated view として表示する。
- composer/input area と actionbar/status area は通常通り残す。
- main view area だけが message history から rewind target list に切り替わる。
- Esc 等で picker を閉じると、通常の conversation/history view に戻る。
- `:rewind` command は `Idle` / `Paused` の時だけ picker を開く。`Running` 中は visible diagnostic を出して何もしない。
- `Ctrl+R` shortcut も Pod が停止中 (`Idle` または `Paused`) の時だけ有効にする。`Running` 中は無視または visible diagnostic にする。
- picker は過去の user message を新しい順に表示する。
- turn number / index
- timestamp または relative time
- message preview
- eligible / disabled reason
- picker で user message を選択すると、Pod はその user message の直前まで history/session log を rewind し、選択された message を TUI composer に復元する。
- 選択後は、composer に該当 message が入っている状態になる。
- Enter を押すとその message で retry できる。
- ユーザーは送信前に編集できる。
- 選択しただけで自動実行しない。
- Esc 等で picker を閉じると何も変更しない。
## Semantics
Manual rewind は destructive operation として扱う。選択地点より後の履歴 suffix は捨てる。fork は優先度低めの別機能であり、この ticket の実装では fork を作らない。
- Rewind は current active segment/session に対して行う。
- Rewind 成功時、選択された `UserInput` entry 自体も履歴から取り除かれ、composer に戻る。
- Rewind 後、選択地点より後の assistant output / later user messages / usage entries / display blocks は現 branch から消える。
- 元 suffix を保持したい場合は将来の `pod-session-fork` で扱う。この ticket では保持しない。
- Tool side effect の undo はしない。
Initial safety policy:
- Pod が `Idle` または `Paused` の時だけ許可する。
- `Running` 中は拒否する。
- picker 表示時から head が変わった場合は apply 時に再検証して拒否する。
- segment rotation / compaction を跨ぐ rewind は初期実装では対象外でよい。
- suffix に tool call / tool result / other side-effect-looking entries が含まれる場合でも、初期方針としては destructive rewind を許可してよい。ただし UI には「以降の履歴は破棄され、tool side effects は undo されない」ことが分かる notice/diagnostic を出す。
- 実装上どうしても安全に整合性を保てない suffix 種別がある場合は、具体的な disabled reason を表示して拒否する。
## Protocol / ownership
TUI がローカルに履歴を削るのではなく、Pod が authoritative に rewind を検証・適用する。
Suggested protocol shape:
```rust
Method::ListRewindTargets { limit: Option<usize> }
Method::RewindTo {
target: RewindTargetId,
expected_head_entries: usize,
}
Event::RewindTargets { targets: Vec<RewindTarget> }
Event::RewindApplied {
entries: Vec<serde_json::Value>,
input: Vec<Segment>,
summary: RewindSummary,
}
```
Exact names may differ, but the behavior should stay:
- listing targets and applying a target are separate operations.
- apply revalidates target identity and current head.
- success returns enough entries for clients to reseed their view.
- success returns the selected user input segments so TUI can restore the composer.
- failure uses visible diagnostics, e.g. `Event::Error { code: InvalidRequest, message }`.
`RunResult::RolledBack` should not be reused for this idle control operation. It remains the run-lifecycle signal for submit-time empty-turn rollback.
## Implementation notes
- Target identity can initially be current segment + entry index:
```rust
RewindTargetId {
segment_id: SegmentId,
user_input_entry_index: usize,
}
```
- Include `expected_head_entries` to reject stale picker selections.
- Each target should include:
- preview
- original `Vec<Segment>`
- turn/index metadata if available
- whether the target is eligible
- disabled/warning reason if relevant
- the entry count to truncate to, which is before the selected user message.
- Rewind apply must keep these in sync:
- worker history
- `user_segments`
- session store segment log
- `SegmentLogSink` mirror
- usage history / trackers
- TUI view reconstructed from returned entries
- If a complete current-state reconstruction from log is simpler and safer than maintaining many historical snapshots, prefer that over fragile partial truncation.
## Acceptance criteria
- `:rewind` opens a picker of past user messages by replacing the normal conversation/history view area, not by drawing a small popup.
- `Ctrl+R` opens the same picker only while Pod status is `Idle` or `Paused`; it is disabled/rejected while `Running`.
- Selecting a message rewinds the Pod state to before that message and restores the message into the TUI composer.
- Rewind does not auto-run; pressing Enter after selection retries the restored message.
- Rewind success updates Pod session log, SegmentLogSink mirror, worker state, and TUI display consistently.
- Esc returns from the rewind picker to the normal conversation/history view without changing Pod state.
- Rewind failure leaves state unchanged and shows a clear reason.
- Picker selections are revalidated at apply time to avoid stale-head corruption.
- Rewound suffix is intentionally discarded; no fork is created.
- Tool side effects are not undone; UI/diagnostics make this clear when relevant.
- Tests cover target listing, apply success, stale-head rejection, composer restore, TUI display reseed, and at least one suffix-with-tool case.
- `cargo fmt --check`
- `cargo check -p protocol -p pod -p tui`
- Relevant focused tests.
## Out of scope
- Creating a fork when rewinding.
- Fork tree visualization.
- Merging branches.
- Undoing tool side effects.
- Rollback history stack / redo.
- Rewind across compacted segments unless it falls out naturally from implementation.
## Related
- `20260527-000009-pod-session-fork` remains a lower-priority future feature for preserving alternate histories.
- Completed: `pod-empty-turn-rollback`
- Completed: `tui-empty-turn-restore`
---
@@ -0,0 +1,87 @@
---
id: 20260527-000005-memory-tool-guidance-prompt
slug: memory-tool-guidance-prompt
title: プロンプト: memory / knowledge tool 利用タイミングのガイダンス
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:05Z
updated_at: 2026-05-28T23:59:06Z
assignee: null
legacy_ticket: tickets/memory-tool-guidance-prompt.md
---
## Migration reference
- legacy_ticket: tickets/memory-tool-guidance-prompt.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# プロンプト: memory / knowledge tool 利用タイミングのガイダンス
## 背景
通常 Pod には `MemoryQuery` / `MemoryRead` / `KnowledgeQuery` / `MemoryWrite` 等の memory / knowledge tools が提供されているが、現状の通常 system prompt はそれらを「いつ使うべきか」をほとんど説明していない。
現在の `resources/prompts/common/tool-usage.md` は、既知パスなら Read、検索なら Grep/Glob、並列可能ならまとめる、という汎用 tool 方針に留まる。memory / knowledge tools の description には操作方法はあるが、モデルが自発的に memory lookup すべき状況は明示されていない。
このため、過去の決定・ユーザー嗜好・以前の経緯を問われても、モデルが `MemoryQuery` / `MemoryRead` を自発的に使わない可能性が高い。`summary.md` resident injection により短い durable context は常時見えるようになるが、詳細な過去判断や request を探すには query guidance が必要である。
## 方針
通常 Pod の system prompt に、memory / knowledge tools の利用タイミングを短く追加する。
目的は「必要な時に過去情報を探す」ことであり、毎 turn memory query を強制することではない。memory / knowledge は helpful context だが stale になり得るため、現在の user instruction / files / tickets / git state / session log を上書きする権威として扱わせない。
## 推奨する追加文言
`resources/prompts/common/tool-usage.md` に新しい小節を足すか、`resources/prompts/common/memory.md` を作って `default.md` から include する。
例:
```md
## Memory and knowledge
Use memory and knowledge tools when the user asks about past decisions, prior requests, durable preferences, project history, or why something was done. Do not guess from vague recollection when a targeted memory lookup would answer the question.
- Use `MemoryQuery` for durable memory records: summary, decisions, and requests.
- Use `KnowledgeQuery` for project knowledge records.
- Use `MemoryRead(kind=summary)` when you need the full workspace memory summary.
- Use `MemoryRead` on returned slugs when query excerpts are insufficient.
Resident memory and knowledge are helpful context but may be stale. Current user instructions, repository files, tickets, git history, and session logs are more authoritative for exact current state.
Do not query memory on every turn. Prefer it when past context, user preferences, or prior rationale materially affects the answer or implementation.
```
文言は実装時に自然に調整してよいが、以下の意味は維持する。
- 過去判断 / 過去依頼 / ユーザー嗜好 / project history / why 系では memory lookup を促す。
- `MemoryQuery`, `KnowledgeQuery`, `MemoryRead(kind=summary)`, slug read の役割を明示する。
- resident context は stale になり得ると明示する。
- current user instruction / files / tickets / git / session logs の方が exact current state では強いと明示する。
- 毎 turn query しないと明示する。
## 要件
- 通常 Pod の default prompt に memory / knowledge tool 利用タイミングの guidance が入る。
- internal prompts (`memory_extract_system`, `memory_consolidation_system`, `compact_system`) の挙動を変えない。
- guidance は短く、通常 turn の token overhead を過度に増やさない。
- guidance は memory / knowledge を current authority より上に置かない。
- guidance は毎 turn memory query を促さない。
- `MemoryWrite` / `MemoryEdit` / `MemoryDelete` の自発的利用を安易に促さない。
- 通常作業では read/query を促し、write/edit/delete は明示的な依頼または memory maintenance worker に寄せる。
## 完了条件
- `resources/prompts/default.md` から memory guidance が render される。
- prompt render / catalog 関連 test があれば更新されている。
- internal worker prompt には不要な memory guidance が混ざらない。
- `cargo fmt --check` と関連 test が通る。
## 範囲外
- `summary.md` resident injection の実装。これは `memory-summary-resident-injection.md` で扱う。
- memory tool descriptions の大幅変更。
- memory usage metrics の設計変更。
- global memory / project local memory の store 分離。
@@ -0,0 +1,87 @@
---
id: 20260527-000005-memory-tool-guidance-prompt
slug: memory-tool-guidance-prompt
title: プロンプト: memory / knowledge tool 利用タイミングのガイダンス
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:05Z
updated_at: 2026-05-28T23:59:06Z
assignee: null
legacy_ticket: tickets/memory-tool-guidance-prompt.md
---
## Migration reference
- legacy_ticket: tickets/memory-tool-guidance-prompt.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# プロンプト: memory / knowledge tool 利用タイミングのガイダンス
## 背景
通常 Pod には `MemoryQuery` / `MemoryRead` / `KnowledgeQuery` / `MemoryWrite` 等の memory / knowledge tools が提供されているが、現状の通常 system prompt はそれらを「いつ使うべきか」をほとんど説明していない。
現在の `resources/prompts/common/tool-usage.md` は、既知パスなら Read、検索なら Grep/Glob、並列可能ならまとめる、という汎用 tool 方針に留まる。memory / knowledge tools の description には操作方法はあるが、モデルが自発的に memory lookup すべき状況は明示されていない。
このため、過去の決定・ユーザー嗜好・以前の経緯を問われても、モデルが `MemoryQuery` / `MemoryRead` を自発的に使わない可能性が高い。`summary.md` resident injection により短い durable context は常時見えるようになるが、詳細な過去判断や request を探すには query guidance が必要である。
## 方針
通常 Pod の system prompt に、memory / knowledge tools の利用タイミングを短く追加する。
目的は「必要な時に過去情報を探す」ことであり、毎 turn memory query を強制することではない。memory / knowledge は helpful context だが stale になり得るため、現在の user instruction / files / tickets / git state / session log を上書きする権威として扱わせない。
## 推奨する追加文言
`resources/prompts/common/tool-usage.md` に新しい小節を足すか、`resources/prompts/common/memory.md` を作って `default.md` から include する。
例:
```md
## Memory and knowledge
Use memory and knowledge tools when the user asks about past decisions, prior requests, durable preferences, project history, or why something was done. Do not guess from vague recollection when a targeted memory lookup would answer the question.
- Use `MemoryQuery` for durable memory records: summary, decisions, and requests.
- Use `KnowledgeQuery` for project knowledge records.
- Use `MemoryRead(kind=summary)` when you need the full workspace memory summary.
- Use `MemoryRead` on returned slugs when query excerpts are insufficient.
Resident memory and knowledge are helpful context but may be stale. Current user instructions, repository files, tickets, git history, and session logs are more authoritative for exact current state.
Do not query memory on every turn. Prefer it when past context, user preferences, or prior rationale materially affects the answer or implementation.
```
文言は実装時に自然に調整してよいが、以下の意味は維持する。
- 過去判断 / 過去依頼 / ユーザー嗜好 / project history / why 系では memory lookup を促す。
- `MemoryQuery`, `KnowledgeQuery`, `MemoryRead(kind=summary)`, slug read の役割を明示する。
- resident context は stale になり得ると明示する。
- current user instruction / files / tickets / git / session logs の方が exact current state では強いと明示する。
- 毎 turn query しないと明示する。
## 要件
- 通常 Pod の default prompt に memory / knowledge tool 利用タイミングの guidance が入る。
- internal prompts (`memory_extract_system`, `memory_consolidation_system`, `compact_system`) の挙動を変えない。
- guidance は短く、通常 turn の token overhead を過度に増やさない。
- guidance は memory / knowledge を current authority より上に置かない。
- guidance は毎 turn memory query を促さない。
- `MemoryWrite` / `MemoryEdit` / `MemoryDelete` の自発的利用を安易に促さない。
- 通常作業では read/query を促し、write/edit/delete は明示的な依頼または memory maintenance worker に寄せる。
## 完了条件
- `resources/prompts/default.md` から memory guidance が render される。
- prompt render / catalog 関連 test があれば更新されている。
- internal worker prompt には不要な memory guidance が混ざらない。
- `cargo fmt --check` と関連 test が通る。
## 範囲外
- `summary.md` resident injection の実装。これは `memory-summary-resident-injection.md` で扱う。
- memory tool descriptions の大幅変更。
- memory usage metrics の設計変更。
- global memory / project local memory の store 分離。
@@ -0,0 +1,102 @@
<!-- event: migration author: tickets.sh-migration at: 2026-05-27T00:00:05Z -->
## Migrated
Migrated from tickets/memory-tool-guidance-prompt.md. No legacy review file was present at migration time.
---
<!-- event: close author: hare at: 2026-05-28T23:59:06Z status: closed -->
## Closed
---
id: 20260527-000005-memory-tool-guidance-prompt
slug: memory-tool-guidance-prompt
title: プロンプト: memory / knowledge tool 利用タイミングのガイダンス
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:05Z
updated_at: 2026-05-28T23:59:06Z
assignee: null
legacy_ticket: tickets/memory-tool-guidance-prompt.md
---
## Migration reference
- legacy_ticket: tickets/memory-tool-guidance-prompt.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# プロンプト: memory / knowledge tool 利用タイミングのガイダンス
## 背景
通常 Pod には `MemoryQuery` / `MemoryRead` / `KnowledgeQuery` / `MemoryWrite` 等の memory / knowledge tools が提供されているが、現状の通常 system prompt はそれらを「いつ使うべきか」をほとんど説明していない。
現在の `resources/prompts/common/tool-usage.md` は、既知パスなら Read、検索なら Grep/Glob、並列可能ならまとめる、という汎用 tool 方針に留まる。memory / knowledge tools の description には操作方法はあるが、モデルが自発的に memory lookup すべき状況は明示されていない。
このため、過去の決定・ユーザー嗜好・以前の経緯を問われても、モデルが `MemoryQuery` / `MemoryRead` を自発的に使わない可能性が高い。`summary.md` resident injection により短い durable context は常時見えるようになるが、詳細な過去判断や request を探すには query guidance が必要である。
## 方針
通常 Pod の system prompt に、memory / knowledge tools の利用タイミングを短く追加する。
目的は「必要な時に過去情報を探す」ことであり、毎 turn memory query を強制することではない。memory / knowledge は helpful context だが stale になり得るため、現在の user instruction / files / tickets / git state / session log を上書きする権威として扱わせない。
## 推奨する追加文言
`resources/prompts/common/tool-usage.md` に新しい小節を足すか、`resources/prompts/common/memory.md` を作って `default.md` から include する。
例:
```md
## Memory and knowledge
Use memory and knowledge tools when the user asks about past decisions, prior requests, durable preferences, project history, or why something was done. Do not guess from vague recollection when a targeted memory lookup would answer the question.
- Use `MemoryQuery` for durable memory records: summary, decisions, and requests.
- Use `KnowledgeQuery` for project knowledge records.
- Use `MemoryRead(kind=summary)` when you need the full workspace memory summary.
- Use `MemoryRead` on returned slugs when query excerpts are insufficient.
Resident memory and knowledge are helpful context but may be stale. Current user instructions, repository files, tickets, git history, and session logs are more authoritative for exact current state.
Do not query memory on every turn. Prefer it when past context, user preferences, or prior rationale materially affects the answer or implementation.
```
文言は実装時に自然に調整してよいが、以下の意味は維持する。
- 過去判断 / 過去依頼 / ユーザー嗜好 / project history / why 系では memory lookup を促す。
- `MemoryQuery`, `KnowledgeQuery`, `MemoryRead(kind=summary)`, slug read の役割を明示する。
- resident context は stale になり得ると明示する。
- current user instruction / files / tickets / git / session logs の方が exact current state では強いと明示する。
- 毎 turn query しないと明示する。
## 要件
- 通常 Pod の default prompt に memory / knowledge tool 利用タイミングの guidance が入る。
- internal prompts (`memory_extract_system`, `memory_consolidation_system`, `compact_system`) の挙動を変えない。
- guidance は短く、通常 turn の token overhead を過度に増やさない。
- guidance は memory / knowledge を current authority より上に置かない。
- guidance は毎 turn memory query を促さない。
- `MemoryWrite` / `MemoryEdit` / `MemoryDelete` の自発的利用を安易に促さない。
- 通常作業では read/query を促し、write/edit/delete は明示的な依頼または memory maintenance worker に寄せる。
## 完了条件
- `resources/prompts/default.md` から memory guidance が render される。
- prompt render / catalog 関連 test があれば更新されている。
- internal worker prompt には不要な memory guidance が混ざらない。
- `cargo fmt --check` と関連 test が通る。
## 範囲外
- `summary.md` resident injection の実装。これは `memory-summary-resident-injection.md` で扱う。
- memory tool descriptions の大幅変更。
- memory usage metrics の設計変更。
- global memory / project local memory の store 分離。
---
@@ -0,0 +1,76 @@
---
id: 20260527-000007-pod-inbound-pod-event-dedup
slug: pod-inbound-pod-event-dedup
title: Inbound PodEvent ハンドリングの重複を統合する
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:07Z
updated_at: 2026-05-30T05:37:00Z
assignee: null
legacy_ticket: tickets/pod-inbound-pod-event-dedup.md
---
## Migration reference
- legacy_ticket: tickets/pod-inbound-pod-event-dedup.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# Inbound PodEvent ハンドリングの重複を統合する
## 背景
子 Pod から `Method::PodEvent(event)` を受けたときの処理が `controller_loop``drive_turn` の 2 箇所にコピーされている。
`controller.rs:693-720`idle / paused 中):
```rust
Method::PodEvent(event) => {
crate::ipc::event::apply_event_side_effects(
&event, &spawned_registry, &spawner_name, &self_parent_socket,
).await;
pod.push_pod_event_notify(event);
if shared_state.get_status() == PodStatus::Idle {
pending = Some(PendingRun::RunForNotification);
}
}
```
`controller.rs:861-879`in-flight turn 中):
```rust
Some(Method::PodEvent(event)) => {
let self_parent_socket = parent_socket.cloned();
crate::ipc::event::apply_event_side_effects(
&event, spawned_registry, self_name, &self_parent_socket,
).await;
notify_buffer.push_pod_event(event);
}
```
差分は 2 点:
1. **buffer への push 経路**: `pod.push_pod_event_notify(event)` vs `notify_buffer.push_pod_event(event)`。両者は同じ `NotifyBuffer` を叩く(`pod.rs:845-846``self.pending_notifies.push_pod_event(event)` を呼ぶだけで、`notify_buffer_handle()` はその `pending_notifies.clone()` を返す)。**完全に等価**。
2. **auto-kick**: idle 経路だけ `PendingRun::RunForNotification` を stage する。in-flight 経路は in-flight 自体が消化するので不要。
つまり「event の処理本体」(side-effects + notify buffer への push)は同一で、後段の auto-kick だけが state-dependent な分岐。にもかかわらず関数化されておらず、片方をいじってもう片方を忘れると挙動が割れる。
## 要件
- side-effects 適用 + NotifyBuffer への typed push の流れを単一関数 `handle_inbound_pod_event` に切り出す。
- `controller_loop` / `drive_turn` の両方からこのヘルパーを呼ぶ形に置き換える。
- auto-kick (`PendingRun::RunForNotification` の stage) は呼び出し側の責務として残す。これは Pod のライフサイクル状態に依存した判断で、ヘルパー内には押し込めない。
- 関数シグネチャは引数を最小化する。`event``spawned_registry``self_name: &str``self_parent_socket: &Option<PathBuf>` または `Option<&PathBuf>``notify_buffer: &NotifyBuffer` の 5 つで足りる前提。`Pod` への可変参照は不要(`notify_buffer` で代用可能)。
- 動作変化なし。既存の `Method::PodEvent` 挙動(in-flight / idle 両方)が完全に同一で続行すること。
## 完了条件
- `controller.rs` 内に `apply_event_side_effects` 呼び出しが 1 箇所だけ残り、`controller_loop``drive_turn``Method::PodEvent` アームはどちらも `handle_inbound_pod_event(...)` 呼び出し + idle 経路のみ auto-kick stage、という形になる。
- 既存の inbound PodEvent 関連テスト(特に `apply_event_side_effects` の idempotency や `notify_buffer` への typed push)が通る。
## 範囲外
- `apply_event_side_effects` 自体の中身変更。
- `NotifyBuffer` API のリネーム / 統合。
- `pod.push_pod_event_notify` の削除([[pod-interrupt-prep-internalize]] と同じく将来の整理対象だが、本チケットでは外向き API は触らない)。
@@ -0,0 +1,76 @@
---
id: 20260527-000007-pod-inbound-pod-event-dedup
slug: pod-inbound-pod-event-dedup
title: Inbound PodEvent ハンドリングの重複を統合する
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:07Z
updated_at: 2026-05-30T05:37:00Z
assignee: null
legacy_ticket: tickets/pod-inbound-pod-event-dedup.md
---
## Migration reference
- legacy_ticket: tickets/pod-inbound-pod-event-dedup.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# Inbound PodEvent ハンドリングの重複を統合する
## 背景
子 Pod から `Method::PodEvent(event)` を受けたときの処理が `controller_loop``drive_turn` の 2 箇所にコピーされている。
`controller.rs:693-720`idle / paused 中):
```rust
Method::PodEvent(event) => {
crate::ipc::event::apply_event_side_effects(
&event, &spawned_registry, &spawner_name, &self_parent_socket,
).await;
pod.push_pod_event_notify(event);
if shared_state.get_status() == PodStatus::Idle {
pending = Some(PendingRun::RunForNotification);
}
}
```
`controller.rs:861-879`in-flight turn 中):
```rust
Some(Method::PodEvent(event)) => {
let self_parent_socket = parent_socket.cloned();
crate::ipc::event::apply_event_side_effects(
&event, spawned_registry, self_name, &self_parent_socket,
).await;
notify_buffer.push_pod_event(event);
}
```
差分は 2 点:
1. **buffer への push 経路**: `pod.push_pod_event_notify(event)` vs `notify_buffer.push_pod_event(event)`。両者は同じ `NotifyBuffer` を叩く(`pod.rs:845-846``self.pending_notifies.push_pod_event(event)` を呼ぶだけで、`notify_buffer_handle()` はその `pending_notifies.clone()` を返す)。**完全に等価**。
2. **auto-kick**: idle 経路だけ `PendingRun::RunForNotification` を stage する。in-flight 経路は in-flight 自体が消化するので不要。
つまり「event の処理本体」(side-effects + notify buffer への push)は同一で、後段の auto-kick だけが state-dependent な分岐。にもかかわらず関数化されておらず、片方をいじってもう片方を忘れると挙動が割れる。
## 要件
- side-effects 適用 + NotifyBuffer への typed push の流れを単一関数 `handle_inbound_pod_event` に切り出す。
- `controller_loop` / `drive_turn` の両方からこのヘルパーを呼ぶ形に置き換える。
- auto-kick (`PendingRun::RunForNotification` の stage) は呼び出し側の責務として残す。これは Pod のライフサイクル状態に依存した判断で、ヘルパー内には押し込めない。
- 関数シグネチャは引数を最小化する。`event``spawned_registry``self_name: &str``self_parent_socket: &Option<PathBuf>` または `Option<&PathBuf>``notify_buffer: &NotifyBuffer` の 5 つで足りる前提。`Pod` への可変参照は不要(`notify_buffer` で代用可能)。
- 動作変化なし。既存の `Method::PodEvent` 挙動(in-flight / idle 両方)が完全に同一で続行すること。
## 完了条件
- `controller.rs` 内に `apply_event_side_effects` 呼び出しが 1 箇所だけ残り、`controller_loop``drive_turn``Method::PodEvent` アームはどちらも `handle_inbound_pod_event(...)` 呼び出し + idle 経路のみ auto-kick stage、という形になる。
- 既存の inbound PodEvent 関連テスト(特に `apply_event_side_effects` の idempotency や `notify_buffer` への typed push)が通る。
## 範囲外
- `apply_event_side_effects` 自体の中身変更。
- `NotifyBuffer` API のリネーム / 統合。
- `pod.push_pod_event_notify` の削除([[pod-interrupt-prep-internalize]] と同じく将来の整理対象だが、本チケットでは外向き API は触らない)。
@@ -0,0 +1,91 @@
<!-- event: migration author: tickets.sh-migration at: 2026-05-27T00:00:07Z -->
## Migrated
Migrated from tickets/pod-inbound-pod-event-dedup.md. No legacy review file was present at migration time.
---
<!-- event: close author: hare at: 2026-05-30T05:37:00Z status: closed -->
## Closed
---
id: 20260527-000007-pod-inbound-pod-event-dedup
slug: pod-inbound-pod-event-dedup
title: Inbound PodEvent ハンドリングの重複を統合する
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:07Z
updated_at: 2026-05-30T05:37:00Z
assignee: null
legacy_ticket: tickets/pod-inbound-pod-event-dedup.md
---
## Migration reference
- legacy_ticket: tickets/pod-inbound-pod-event-dedup.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# Inbound PodEvent ハンドリングの重複を統合する
## 背景
子 Pod から `Method::PodEvent(event)` を受けたときの処理が `controller_loop``drive_turn` の 2 箇所にコピーされている。
`controller.rs:693-720`idle / paused 中):
```rust
Method::PodEvent(event) => {
crate::ipc::event::apply_event_side_effects(
&event, &spawned_registry, &spawner_name, &self_parent_socket,
).await;
pod.push_pod_event_notify(event);
if shared_state.get_status() == PodStatus::Idle {
pending = Some(PendingRun::RunForNotification);
}
}
```
`controller.rs:861-879`in-flight turn 中):
```rust
Some(Method::PodEvent(event)) => {
let self_parent_socket = parent_socket.cloned();
crate::ipc::event::apply_event_side_effects(
&event, spawned_registry, self_name, &self_parent_socket,
).await;
notify_buffer.push_pod_event(event);
}
```
差分は 2 点:
1. **buffer への push 経路**: `pod.push_pod_event_notify(event)` vs `notify_buffer.push_pod_event(event)`。両者は同じ `NotifyBuffer` を叩く(`pod.rs:845-846``self.pending_notifies.push_pod_event(event)` を呼ぶだけで、`notify_buffer_handle()` はその `pending_notifies.clone()` を返す)。**完全に等価**。
2. **auto-kick**: idle 経路だけ `PendingRun::RunForNotification` を stage する。in-flight 経路は in-flight 自体が消化するので不要。
つまり「event の処理本体」(side-effects + notify buffer への push)は同一で、後段の auto-kick だけが state-dependent な分岐。にもかかわらず関数化されておらず、片方をいじってもう片方を忘れると挙動が割れる。
## 要件
- side-effects 適用 + NotifyBuffer への typed push の流れを単一関数 `handle_inbound_pod_event` に切り出す。
- `controller_loop` / `drive_turn` の両方からこのヘルパーを呼ぶ形に置き換える。
- auto-kick (`PendingRun::RunForNotification` の stage) は呼び出し側の責務として残す。これは Pod のライフサイクル状態に依存した判断で、ヘルパー内には押し込めない。
- 関数シグネチャは引数を最小化する。`event``spawned_registry``self_name: &str``self_parent_socket: &Option<PathBuf>` または `Option<&PathBuf>``notify_buffer: &NotifyBuffer` の 5 つで足りる前提。`Pod` への可変参照は不要(`notify_buffer` で代用可能)。
- 動作変化なし。既存の `Method::PodEvent` 挙動(in-flight / idle 両方)が完全に同一で続行すること。
## 完了条件
- `controller.rs` 内に `apply_event_side_effects` 呼び出しが 1 箇所だけ残り、`controller_loop``drive_turn``Method::PodEvent` アームはどちらも `handle_inbound_pod_event(...)` 呼び出し + idle 経路のみ auto-kick stage、という形になる。
- 既存の inbound PodEvent 関連テスト(特に `apply_event_side_effects` の idempotency や `notify_buffer` への typed push)が通る。
## 範囲外
- `apply_event_side_effects` 自体の中身変更。
- `NotifyBuffer` API のリネーム / 統合。
- `pod.push_pod_event_notify` の削除([[pod-interrupt-prep-internalize]] と同じく将来の整理対象だが、本チケットでは外向き API は触らない)。
---
@@ -0,0 +1,76 @@
---
id: 20260527-000008-pod-scope-persistence-authority
slug: pod-scope-persistence-authority
title: Pod: scope 永続化 authority の整理
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:08Z
updated_at: 2026-05-30T05:57:16Z
assignee: null
legacy_ticket: tickets/pod-scope-persistence-authority.md
---
## Migration reference
- legacy_ticket: tickets/pod-scope-persistence-authority.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# Pod: scope 永続化 authority の整理
## 背景
Pod の scope は複数の場所に関連情報が存在している。
- session log の `pod.scope` extension: Pod 自身の復元用 runtime scope snapshot
- Pod metadata: Pod 名から active session/segment への pointer と spawned child 情報
- spawned child 情報: child に委譲した scope
- runtime registry: live Pod の allocation / conflict detection 用 scope
- runtime mirror: `spawned_pods.json` 等の現在プロセス向け表示・制御用情報
これらは用途が異なるが、どの情報が durable authority で、どれが live mirror / derived state なのかが読み取りづらい。特に restore、compact/fork による segment 切替、child scope の委譲・reclaim、runtime registry の再構築で、scope の保存先と復元順序が曖昧だと権限の過大復元または過小復元につながる。
## 要件
- Pod scope に関する durable authority を明確に定義する。
- Pod 自身の base scope / effective runtime scope / deny による delegated-out 部分を区別する。
- spawned child に委譲した scope と、親 Pod 自身の effective scope を区別する。
- live registry / runtime mirror は durable authority ではないことを明確にする。
- Pod 名からの restore に必要な情報の保存先を一貫させる。
- Pod 名から active session/segment を解決できる。
- 解決した Pod が、前回終了時点の effective scope を過大に復元しない。
- child が生存・復元対象の場合、親の delegated-out scope が意図せず reclaim されない。
- segment 遷移で scope が失われない。
- compact / fork / resume / attach の後も、次にその segment を restore したとき同じ effective scope が得られる。
- 新 segment 作成時に scope authority が必要なら、初期状態として確実に引き継がれる。
- spawned child の scope 永続化を親 Pod の restore/reclaim 要件と整合させる。
- 親は child に委譲済みの scope を把握できる。
- child 停止・shutdown・restore 時の prune により、親の effective write scope が正しく reclaim される。
- explicit deny と delegated-out deny を混同しない。
- runtime registry 再構築時の入力と副作用を定義する。
- restore 時にどの durable state から allocation を再作成するかが明確である。
- stale / unreachable child を pruning した場合、durable state と runtime mirror が矛盾しない。
- 保存形式は inspect/debug しやすい。
- Pod ごとに「active pointer」「自身の scope」「spawned child と delegated scope」が追跡できる。
- restore 失敗時に、欠けている authority が何か分かる error になる。
- session log の conversation/history authority と scope authority の関係を明確にする。
- scope 更新が conversation history の意味内容を汚染しない。
- append-only session log に置く場合は、compact/fork と replay semantics 上の扱いが明示される。
- Pod metadata に置く場合は、session/segment lineage との整合と更新順序が明示される。
## 完了条件
- Pod scope に関する durable authority / runtime mirror / derived state の責務がコードとドキュメント上で一致している。
- Pod restore が、前回の effective scope を過大復元しない regression test を持つ。
- compact または fork 後の新 segment restore で scope が失われない regression test を持つ。
- spawned child に scope 委譲済みの親 Pod を restore しても、child 側の write scope が親に二重に戻らない regression test を持つ。
- child 停止・shutdown・restore pruning 後に、親の effective scope と durable state が一致する regression test を持つ。
- runtime registry / runtime mirror が durable authority と矛盾した場合の扱いが test で確認されている。
## 範囲外
- manifest scope 設定そのものの設計変更。
- tool permission policy の allow / ask / deny 挙動変更。
- UI 表示だけで scope 不整合を隠す対応。
- 既存の壊れた手元 session log を自動修復する migration。
@@ -0,0 +1,3 @@
後続の `session-pod-state-boundary` / `pod-store` / spawned registry work により、scope authority の主設計と restore/reclaim 実装は吸収済み。
残る小粒な責務重複は `KNOWN_ISSUES.md` に移したため、この migrated ticket は superseded として閉じる。
@@ -0,0 +1,17 @@
<!-- event: migration author: tickets.sh-migration at: 2026-05-27T00:00:08Z -->
## Migrated
Migrated from tickets/pod-scope-persistence-authority.md. No legacy review file was present at migration time.
---
<!-- event: close author: hare at: 2026-05-30T05:57:16Z status: closed -->
## Closed
後続の `session-pod-state-boundary` / `pod-store` / spawned registry work により、scope authority の主設計と restore/reclaim 実装は吸収済み。
残る小粒な責務重複は `KNOWN_ISSUES.md` に移したため、この migrated ticket は superseded として閉じる。
---
@@ -0,0 +1,80 @@
---
id: 20260527-000011-session-todo-reminder
slug: session-todo-reminder
title: セッション内 Task ツールの注意機構
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:11Z
updated_at: 2026-05-29T04:31:10Z
assignee: null
legacy_ticket: tickets/session-todo-reminder.md
---
## Migration reference
- legacy_ticket: tickets/session-todo-reminder.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# セッション内 Task ツールの注意機構
## 背景
`tickets/session-todo.md` で導入した Task ツール群があっても、LLM はそれを使わずに作業を続け得る。ツールを呼ばないまま会話が長引くと、
- 開始した作業の `inprogress` がずっと放置されたままになる
- 「やったつもり」になって `completed` への更新を忘れる
- そもそも TaskStore の存在を忘れて、構造化を諦めて自由記述に回帰する
OpenCode の todo は専用の注意機構を持たない(汎用 reminder 経由)。一方、一部の既存エージェント実装では todo reminder を「N リクエスト無アクティビティで初めて発火するナッジ型」として扱い、毎リクエスト押し戻しはしない。
Insomnia でも同方針を採り、active Task が残っているのに `TaskCreate` / `TaskUpdate` が一定リクエスト呼ばれていない場合に限り、`<system-reminder>` Item を 1件 history に append する。「やったつもり」抑止と、トークン浪費・LLM の自律性侵害のバランスを取るため、毎リクエスト押し戻しはしない。
## 前提
- `tickets/session-todo.md` の TaskStore と `TaskCreate` / `TaskUpdate` / `TaskList` / `TaskGet` ツールが利用可能
- `Interceptor::pending_history_appends` レーンが利用可能(`tickets/notify-history-persist.md` で導入済み)
## 方針
- **`pending_history_appends` で実装**。発火時に `<system-reminder>` ブロックを含む新規 system message Item を返し、Worker が `worker.history` に append する。Notify / PodEvent と同じレーンで永続化・resume・compaction が自動で揃う
- **揮発的注入は採らない**`AGENTS.md` 「LLM コンテキストの加工原則」で禁止。history に commit せずに context を変えると、resume 時に LLM の発言の根拠が再現できなくなる)
- **system-reminder 注入機構の汎用化はやらない**。利用者が Task 1機構しかない段階で抽象を立てない(`AGENTS.md`「概念の追加は不在が問題になってから」)。タグ形式 `<system-reminder>...</system-reminder>` の規約は本実装で踏襲する
- **発火はナッジ型**。N リクエスト無アクティビティで初めて発火し、cooldown も持つ
## 要件
### Interceptor
- `pending_history_appends` で以下を **AND** で満たす場合のみ発動し、`<system-reminder>` ブロックを含む `Item::system_message` を 1件返す。条件外なら空 `Vec<Item>` を返す
- active Task`pending` または `inprogress`)が 1件以上存在する
- 直近 N リクエスト(暫定 N=8`TaskCreate` / `TaskUpdate` のいずれも呼ばれていない
- 前回 reminder Item の append から M リクエスト(暫定 M=8)以上経過
- ここで言う「リクエスト」は LLM への 1回の推論呼び出し(assistant 応答 1回)の単位。1ユーザー発火内で tool ループが回れば、`tool_result` を受けて発火する次のリクエストもそれぞれ 1としてカウントする
- カウンタは Pod 側の session-lifetime 状態として保持する(`requests_since_last_task_management` / `requests_since_last_reminder`)。resume 時は worker.history の逆走査で再計算するか 0 リセットで再開する。後者でも「初回ナッジが最大 N リクエスト遅れる」だけで挙動として致命ではない
- 返す Item の本文は `<system-reminder>` で囲み、現在の active Task を `taskid` / `status` / `subject` を含む簡潔な形式で列挙する。`description` は長大化を避けるため省略してよい
- active Task が空の場合は何も append しない(思い出させる対象が無いなら不要)
## 完了条件
- 直近 N リクエスト連続で `TaskCreate` / `TaskUpdate` が呼ばれず、かつ active Task が残っている場合に限り、`pending_history_appends``<system-reminder>` を含む `Item::system_message` を 1件返す
- 返された Item が `worker.history` に append され、その後のリクエスト・`history.json`・resume 後の `get_history` でも同じ Item が見える(揮発レーンは持たない)
- `TaskCreate` / `TaskUpdate` のいずれかが呼ばれるとカウンタがリセットされ、再び N リクエスト経過するまでは reminder が出ない
- reminder が一度出たあとは、cooldown M リクエストが経過するまで再注入されない
- active Task が 0件の場合は reminder が出ない
- 単体テストで Interceptor の発火条件(リクエスト回数閾値、active 0件、cooldown)がカバーされる
## 範囲外
- inprogress 滞留検出 / 多重 inprogress 検出など、状態異常ベースの追加トリガ(必要になれば別チケットで追加)
- system-reminder 注入機構の汎用化(`TODO.md` に立項済み、別途検討)
- `TaskCreate` / `TaskUpdate` の戻り値に active Task 全件を埋め込む強化(必要に応じて Tool ticket 側で対応)
- サブエージェント / sidechain での独自 reminder 発火(main Pod の interceptor から動く構造のため自然に対象外)
## 参照
- 設計指針: `AGENTS.md`(LLM コンテキストの加工原則。揮発的注入は禁止、history に append してから commit する)
- 前提: `tickets/session-todo.md`Tool 群と TaskStore)、`tickets/notify-history-persist.md``pending_history_appends` レーン)
- 参考: 一部エージェント実装の todo reminder は、一定リクエスト無アクティビティ後に発火し、再通知にも cooldown を置くナッジ型として扱われている
@@ -0,0 +1,80 @@
---
id: 20260527-000011-session-todo-reminder
slug: session-todo-reminder
title: セッション内 Task ツールの注意機構
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:11Z
updated_at: 2026-05-29T04:31:10Z
assignee: null
legacy_ticket: tickets/session-todo-reminder.md
---
## Migration reference
- legacy_ticket: tickets/session-todo-reminder.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# セッション内 Task ツールの注意機構
## 背景
`tickets/session-todo.md` で導入した Task ツール群があっても、LLM はそれを使わずに作業を続け得る。ツールを呼ばないまま会話が長引くと、
- 開始した作業の `inprogress` がずっと放置されたままになる
- 「やったつもり」になって `completed` への更新を忘れる
- そもそも TaskStore の存在を忘れて、構造化を諦めて自由記述に回帰する
OpenCode の todo は専用の注意機構を持たない(汎用 reminder 経由)。一方、一部の既存エージェント実装では todo reminder を「N リクエスト無アクティビティで初めて発火するナッジ型」として扱い、毎リクエスト押し戻しはしない。
Insomnia でも同方針を採り、active Task が残っているのに `TaskCreate` / `TaskUpdate` が一定リクエスト呼ばれていない場合に限り、`<system-reminder>` Item を 1件 history に append する。「やったつもり」抑止と、トークン浪費・LLM の自律性侵害のバランスを取るため、毎リクエスト押し戻しはしない。
## 前提
- `tickets/session-todo.md` の TaskStore と `TaskCreate` / `TaskUpdate` / `TaskList` / `TaskGet` ツールが利用可能
- `Interceptor::pending_history_appends` レーンが利用可能(`tickets/notify-history-persist.md` で導入済み)
## 方針
- **`pending_history_appends` で実装**。発火時に `<system-reminder>` ブロックを含む新規 system message Item を返し、Worker が `worker.history` に append する。Notify / PodEvent と同じレーンで永続化・resume・compaction が自動で揃う
- **揮発的注入は採らない**`AGENTS.md` 「LLM コンテキストの加工原則」で禁止。history に commit せずに context を変えると、resume 時に LLM の発言の根拠が再現できなくなる)
- **system-reminder 注入機構の汎用化はやらない**。利用者が Task 1機構しかない段階で抽象を立てない(`AGENTS.md`「概念の追加は不在が問題になってから」)。タグ形式 `<system-reminder>...</system-reminder>` の規約は本実装で踏襲する
- **発火はナッジ型**。N リクエスト無アクティビティで初めて発火し、cooldown も持つ
## 要件
### Interceptor
- `pending_history_appends` で以下を **AND** で満たす場合のみ発動し、`<system-reminder>` ブロックを含む `Item::system_message` を 1件返す。条件外なら空 `Vec<Item>` を返す
- active Task`pending` または `inprogress`)が 1件以上存在する
- 直近 N リクエスト(暫定 N=8`TaskCreate` / `TaskUpdate` のいずれも呼ばれていない
- 前回 reminder Item の append から M リクエスト(暫定 M=8)以上経過
- ここで言う「リクエスト」は LLM への 1回の推論呼び出し(assistant 応答 1回)の単位。1ユーザー発火内で tool ループが回れば、`tool_result` を受けて発火する次のリクエストもそれぞれ 1としてカウントする
- カウンタは Pod 側の session-lifetime 状態として保持する(`requests_since_last_task_management` / `requests_since_last_reminder`)。resume 時は worker.history の逆走査で再計算するか 0 リセットで再開する。後者でも「初回ナッジが最大 N リクエスト遅れる」だけで挙動として致命ではない
- 返す Item の本文は `<system-reminder>` で囲み、現在の active Task を `taskid` / `status` / `subject` を含む簡潔な形式で列挙する。`description` は長大化を避けるため省略してよい
- active Task が空の場合は何も append しない(思い出させる対象が無いなら不要)
## 完了条件
- 直近 N リクエスト連続で `TaskCreate` / `TaskUpdate` が呼ばれず、かつ active Task が残っている場合に限り、`pending_history_appends``<system-reminder>` を含む `Item::system_message` を 1件返す
- 返された Item が `worker.history` に append され、その後のリクエスト・`history.json`・resume 後の `get_history` でも同じ Item が見える(揮発レーンは持たない)
- `TaskCreate` / `TaskUpdate` のいずれかが呼ばれるとカウンタがリセットされ、再び N リクエスト経過するまでは reminder が出ない
- reminder が一度出たあとは、cooldown M リクエストが経過するまで再注入されない
- active Task が 0件の場合は reminder が出ない
- 単体テストで Interceptor の発火条件(リクエスト回数閾値、active 0件、cooldown)がカバーされる
## 範囲外
- inprogress 滞留検出 / 多重 inprogress 検出など、状態異常ベースの追加トリガ(必要になれば別チケットで追加)
- system-reminder 注入機構の汎用化(`TODO.md` に立項済み、別途検討)
- `TaskCreate` / `TaskUpdate` の戻り値に active Task 全件を埋め込む強化(必要に応じて Tool ticket 側で対応)
- サブエージェント / sidechain での独自 reminder 発火(main Pod の interceptor から動く構造のため自然に対象外)
## 参照
- 設計指針: `AGENTS.md`(LLM コンテキストの加工原則。揮発的注入は禁止、history に append してから commit する)
- 前提: `tickets/session-todo.md`Tool 群と TaskStore)、`tickets/notify-history-persist.md``pending_history_appends` レーン)
- 参考: 一部エージェント実装の todo reminder は、一定リクエスト無アクティビティ後に発火し、再通知にも cooldown を置くナッジ型として扱われている
@@ -0,0 +1,95 @@
<!-- event: migration author: tickets.sh-migration at: 2026-05-27T00:00:11Z -->
## Migrated
Migrated from tickets/session-todo-reminder.md. No legacy review file was present at migration time.
---
<!-- event: close author: hare at: 2026-05-29T04:31:10Z status: closed -->
## Closed
---
id: 20260527-000011-session-todo-reminder
slug: session-todo-reminder
title: セッション内 Task ツールの注意機構
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:11Z
updated_at: 2026-05-29T04:31:10Z
assignee: null
legacy_ticket: tickets/session-todo-reminder.md
---
## Migration reference
- legacy_ticket: tickets/session-todo-reminder.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# セッション内 Task ツールの注意機構
## 背景
`tickets/session-todo.md` で導入した Task ツール群があっても、LLM はそれを使わずに作業を続け得る。ツールを呼ばないまま会話が長引くと、
- 開始した作業の `inprogress` がずっと放置されたままになる
- 「やったつもり」になって `completed` への更新を忘れる
- そもそも TaskStore の存在を忘れて、構造化を諦めて自由記述に回帰する
OpenCode の todo は専用の注意機構を持たない(汎用 reminder 経由)。一方、一部の既存エージェント実装では todo reminder を「N リクエスト無アクティビティで初めて発火するナッジ型」として扱い、毎リクエスト押し戻しはしない。
Insomnia でも同方針を採り、active Task が残っているのに `TaskCreate` / `TaskUpdate` が一定リクエスト呼ばれていない場合に限り、`<system-reminder>` Item を 1件 history に append する。「やったつもり」抑止と、トークン浪費・LLM の自律性侵害のバランスを取るため、毎リクエスト押し戻しはしない。
## 前提
- `tickets/session-todo.md` の TaskStore と `TaskCreate` / `TaskUpdate` / `TaskList` / `TaskGet` ツールが利用可能
- `Interceptor::pending_history_appends` レーンが利用可能(`tickets/notify-history-persist.md` で導入済み)
## 方針
- **`pending_history_appends` で実装**。発火時に `<system-reminder>` ブロックを含む新規 system message Item を返し、Worker が `worker.history` に append する。Notify / PodEvent と同じレーンで永続化・resume・compaction が自動で揃う
- **揮発的注入は採らない**`AGENTS.md` 「LLM コンテキストの加工原則」で禁止。history に commit せずに context を変えると、resume 時に LLM の発言の根拠が再現できなくなる)
- **system-reminder 注入機構の汎用化はやらない**。利用者が Task 1機構しかない段階で抽象を立てない(`AGENTS.md`「概念の追加は不在が問題になってから」)。タグ形式 `<system-reminder>...</system-reminder>` の規約は本実装で踏襲する
- **発火はナッジ型**。N リクエスト無アクティビティで初めて発火し、cooldown も持つ
## 要件
### Interceptor
- `pending_history_appends` で以下を **AND** で満たす場合のみ発動し、`<system-reminder>` ブロックを含む `Item::system_message` を 1件返す。条件外なら空 `Vec<Item>` を返す
- active Task`pending` または `inprogress`)が 1件以上存在する
- 直近 N リクエスト(暫定 N=8`TaskCreate` / `TaskUpdate` のいずれも呼ばれていない
- 前回 reminder Item の append から M リクエスト(暫定 M=8)以上経過
- ここで言う「リクエスト」は LLM への 1回の推論呼び出し(assistant 応答 1回)の単位。1ユーザー発火内で tool ループが回れば、`tool_result` を受けて発火する次のリクエストもそれぞれ 1としてカウントする
- カウンタは Pod 側の session-lifetime 状態として保持する(`requests_since_last_task_management` / `requests_since_last_reminder`)。resume 時は worker.history の逆走査で再計算するか 0 リセットで再開する。後者でも「初回ナッジが最大 N リクエスト遅れる」だけで挙動として致命ではない
- 返す Item の本文は `<system-reminder>` で囲み、現在の active Task を `taskid` / `status` / `subject` を含む簡潔な形式で列挙する。`description` は長大化を避けるため省略してよい
- active Task が空の場合は何も append しない(思い出させる対象が無いなら不要)
## 完了条件
- 直近 N リクエスト連続で `TaskCreate` / `TaskUpdate` が呼ばれず、かつ active Task が残っている場合に限り、`pending_history_appends``<system-reminder>` を含む `Item::system_message` を 1件返す
- 返された Item が `worker.history` に append され、その後のリクエスト・`history.json`・resume 後の `get_history` でも同じ Item が見える(揮発レーンは持たない)
- `TaskCreate` / `TaskUpdate` のいずれかが呼ばれるとカウンタがリセットされ、再び N リクエスト経過するまでは reminder が出ない
- reminder が一度出たあとは、cooldown M リクエストが経過するまで再注入されない
- active Task が 0件の場合は reminder が出ない
- 単体テストで Interceptor の発火条件(リクエスト回数閾値、active 0件、cooldown)がカバーされる
## 範囲外
- inprogress 滞留検出 / 多重 inprogress 検出など、状態異常ベースの追加トリガ(必要になれば別チケットで追加)
- system-reminder 注入機構の汎用化(`TODO.md` に立項済み、別途検討)
- `TaskCreate` / `TaskUpdate` の戻り値に active Task 全件を埋め込む強化(必要に応じて Tool ticket 側で対応)
- サブエージェント / sidechain での独自 reminder 発火(main Pod の interceptor から動く構造のため自然に対象外)
## 参照
- 設計指針: `AGENTS.md`(LLM コンテキストの加工原則。揮発的注入は禁止、history に append してから commit する)
- 前提: `tickets/session-todo.md`Tool 群と TaskStore)、`tickets/notify-history-persist.md``pending_history_appends` レーン)
- 参考: 一部エージェント実装の todo reminder は、一定リクエスト無アクティビティ後に発火し、再通知にも cooldown を置くナッジ型として扱われている
---
@@ -0,0 +1,84 @@
---
id: 20260527-000012-spawnpod-initial-run-confirmation
slug: spawnpod-initial-run-confirmation
title: SpawnPod: initial Run delivery confirmation
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:12Z
updated_at: 2026-05-28T13:24:48Z
assignee: null
legacy_ticket: tickets/spawnpod-initial-run-confirmation.md
---
## Migration reference
- legacy_ticket: tickets/spawnpod-initial-run-confirmation.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# SpawnPod: initial Run delivery confirmation
## 背景
`SpawnPod` は child Pod を起動し、初回 task を `Method::Run` として送る。しかし、実例として `impl-llm-worker-stream-continuation` を再作成した際、runtime registry / socket / process は生きている一方で、初回 task の session log が materialize されず、Pod は `idle` のままだった。
確認された状態:
- `<runtime-dir>/pods.json` に live allocation がある
- `<runtime-dir>/<pod>/status.json``state: "idle"` と runtime `segment_id` を持つ
- `<insomnia-sessions>/pods/<pod>/metadata.json` は pending segment のまま
- 対応する session / segment `.jsonl` が存在しない
- `ReadPodOutput` は no new assistant text
`SpawnPod` の送信側は `send_run``Method::Run` を write してすぐ切断し、`TurnStart` 等の ack を待っていない。一方 server 側は接続直後に `Snapshot` を書いてから method を読むため、client がすぐ close すると server が snapshot write で失敗し、method を読む前に connection handler が終了する race があり得る。
この場合 `SpawnPod` は成功を返すが、child Pod は初回 task を実行していない。
同種の問題は child Pod の通知経路でも既に踏んでおり、送信側が write 後にすぐ切断せず、receiver 側の acknowledgement / observable event を待つ形にして解消している。`SpawnPod` の初回 task delivery も同じ性質の race と見なす。
追加確認として、Pod socket server は接続直後に replayed `Alert` と connect-time `Snapshot` を送ってから client `Method` を読む。したがって one-shot / send-only client は初期 event を消化してから Method を送る必要がある。
- `send_run_and_confirm``Method::Run` を送った後に event を読む実装になっており、Snapshot が大きい場合や Run payload が大きい場合に双方向で詰まる余地がある。
- `connect_and_send` / `fetch_history` は既に Snapshot まで drain / read しており、この系統の問題は対策済み。
- `probe_socket` は最初の event だけを見て `Snapshot` でなければ status を取らないため、replayed `Alert` が先に来る live Pod で reachable だが status unknown になる可能性がある。
- `PodClient::connect` は background reader を起動するため、通常の TUI attach / interactive client では初期 Snapshot を詰まらせにくい。
## 方針
`SpawnPod` は child process / socket の起動だけでなく、初回 task が controller に受理され、少なくとも `UserMessage` または `TurnStart` が観測できるまで確認してから成功を返す。
既存の `SendToPod` / `SpawnPod` が使う run delivery confirmation ロジックを、接続直後の `Alert` / `Snapshot` drain を含む形へ共通化・安全化する。
## 要件
- `SpawnPod` の初回 task 送信は fire-and-forget にしない。
- `Method::Run` 送信後、`UserMessage` / `TurnStart` / `InvokeStart` など、run が受理されたことを示す event を待つ。
- timeout 時は `SpawnPod` を失敗扱いにする。
- 初回 task delivery に失敗した場合、process / registry / delegated scope の扱いを明確にする。
- cleanup するか、attach 可能な idle Pod として残すかを実装で決める。
- 少なくとも成功扱いで返さない。
- Server が connection 開始時に `Alert` / `Snapshot` を書く設計と競合しない。
- client 側が `Alert` / `Snapshot` を読みながら `Method::Run` ack を待つ形にする。
- `send_run_and_confirm` は connect-time `Snapshot` を消化してから `Method::Run` を送る。
- live Pod status probe は replayed `Alert` によって status 取得を落とさない。
- `probe_socket` は first event だけで判断せず、`Snapshot` まで初期 event を読む。
- `SpawnPod` 成功後は、child Pod の metadata が pending でも、初回 run が開始済みであることを確認できる。
- session log materialization のタイミングそのものは別設計でもよい。
- `SendToPod``SpawnPod` の run delivery confirmation ロジックを可能な範囲で共通化する。
## 完了条件
- `SpawnPod` が初回 task の受理確認を待つ。
- 初回 task が実行されない race を再現する test または regression test がある。
- connect-time `Alert` / `Snapshot` がある状態でも `send_run_and_confirm` が詰まらず、受理 event を観測する regression test がある。
- `probe_socket` が replayed `Alert` の後の `Snapshot` から status を取得できる regression test がある。
- `SpawnPod` が success を返した後、child Pod が idle pending のまま task 未実行になる状態が起きない。
- delivery timeout / failure 時の error message が人間に分かる。
- `cargo fmt --check` と関連 crate の test が通る。
## 範囲外
- `tui -r` picker に live pending Pod を表示する修正。
- session log の SegmentStart materialization 方針変更。
- spawned child Pod panel UI。
@@ -0,0 +1,84 @@
---
id: 20260527-000012-spawnpod-initial-run-confirmation
slug: spawnpod-initial-run-confirmation
title: SpawnPod: initial Run delivery confirmation
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:12Z
updated_at: 2026-05-28T13:24:48Z
assignee: null
legacy_ticket: tickets/spawnpod-initial-run-confirmation.md
---
## Migration reference
- legacy_ticket: tickets/spawnpod-initial-run-confirmation.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# SpawnPod: initial Run delivery confirmation
## 背景
`SpawnPod` は child Pod を起動し、初回 task を `Method::Run` として送る。しかし、実例として `impl-llm-worker-stream-continuation` を再作成した際、runtime registry / socket / process は生きている一方で、初回 task の session log が materialize されず、Pod は `idle` のままだった。
確認された状態:
- `<runtime-dir>/pods.json` に live allocation がある
- `<runtime-dir>/<pod>/status.json``state: "idle"` と runtime `segment_id` を持つ
- `<insomnia-sessions>/pods/<pod>/metadata.json` は pending segment のまま
- 対応する session / segment `.jsonl` が存在しない
- `ReadPodOutput` は no new assistant text
`SpawnPod` の送信側は `send_run``Method::Run` を write してすぐ切断し、`TurnStart` 等の ack を待っていない。一方 server 側は接続直後に `Snapshot` を書いてから method を読むため、client がすぐ close すると server が snapshot write で失敗し、method を読む前に connection handler が終了する race があり得る。
この場合 `SpawnPod` は成功を返すが、child Pod は初回 task を実行していない。
同種の問題は child Pod の通知経路でも既に踏んでおり、送信側が write 後にすぐ切断せず、receiver 側の acknowledgement / observable event を待つ形にして解消している。`SpawnPod` の初回 task delivery も同じ性質の race と見なす。
追加確認として、Pod socket server は接続直後に replayed `Alert` と connect-time `Snapshot` を送ってから client `Method` を読む。したがって one-shot / send-only client は初期 event を消化してから Method を送る必要がある。
- `send_run_and_confirm``Method::Run` を送った後に event を読む実装になっており、Snapshot が大きい場合や Run payload が大きい場合に双方向で詰まる余地がある。
- `connect_and_send` / `fetch_history` は既に Snapshot まで drain / read しており、この系統の問題は対策済み。
- `probe_socket` は最初の event だけを見て `Snapshot` でなければ status を取らないため、replayed `Alert` が先に来る live Pod で reachable だが status unknown になる可能性がある。
- `PodClient::connect` は background reader を起動するため、通常の TUI attach / interactive client では初期 Snapshot を詰まらせにくい。
## 方針
`SpawnPod` は child process / socket の起動だけでなく、初回 task が controller に受理され、少なくとも `UserMessage` または `TurnStart` が観測できるまで確認してから成功を返す。
既存の `SendToPod` / `SpawnPod` が使う run delivery confirmation ロジックを、接続直後の `Alert` / `Snapshot` drain を含む形へ共通化・安全化する。
## 要件
- `SpawnPod` の初回 task 送信は fire-and-forget にしない。
- `Method::Run` 送信後、`UserMessage` / `TurnStart` / `InvokeStart` など、run が受理されたことを示す event を待つ。
- timeout 時は `SpawnPod` を失敗扱いにする。
- 初回 task delivery に失敗した場合、process / registry / delegated scope の扱いを明確にする。
- cleanup するか、attach 可能な idle Pod として残すかを実装で決める。
- 少なくとも成功扱いで返さない。
- Server が connection 開始時に `Alert` / `Snapshot` を書く設計と競合しない。
- client 側が `Alert` / `Snapshot` を読みながら `Method::Run` ack を待つ形にする。
- `send_run_and_confirm` は connect-time `Snapshot` を消化してから `Method::Run` を送る。
- live Pod status probe は replayed `Alert` によって status 取得を落とさない。
- `probe_socket` は first event だけで判断せず、`Snapshot` まで初期 event を読む。
- `SpawnPod` 成功後は、child Pod の metadata が pending でも、初回 run が開始済みであることを確認できる。
- session log materialization のタイミングそのものは別設計でもよい。
- `SendToPod``SpawnPod` の run delivery confirmation ロジックを可能な範囲で共通化する。
## 完了条件
- `SpawnPod` が初回 task の受理確認を待つ。
- 初回 task が実行されない race を再現する test または regression test がある。
- connect-time `Alert` / `Snapshot` がある状態でも `send_run_and_confirm` が詰まらず、受理 event を観測する regression test がある。
- `probe_socket` が replayed `Alert` の後の `Snapshot` から status を取得できる regression test がある。
- `SpawnPod` が success を返した後、child Pod が idle pending のまま task 未実行になる状態が起きない。
- delivery timeout / failure 時の error message が人間に分かる。
- `cargo fmt --check` と関連 crate の test が通る。
## 範囲外
- `tui -r` picker に live pending Pod を表示する修正。
- session log の SegmentStart materialization 方針変更。
- spawned child Pod panel UI。
@@ -0,0 +1,99 @@
<!-- event: migration author: tickets.sh-migration at: 2026-05-27T00:00:12Z -->
## Migrated
Migrated from tickets/spawnpod-initial-run-confirmation.md. No legacy review file was present at migration time.
---
<!-- event: close author: hare at: 2026-05-28T13:24:48Z status: closed -->
## Closed
---
id: 20260527-000012-spawnpod-initial-run-confirmation
slug: spawnpod-initial-run-confirmation
title: SpawnPod: initial Run delivery confirmation
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:12Z
updated_at: 2026-05-28T13:24:48Z
assignee: null
legacy_ticket: tickets/spawnpod-initial-run-confirmation.md
---
## Migration reference
- legacy_ticket: tickets/spawnpod-initial-run-confirmation.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# SpawnPod: initial Run delivery confirmation
## 背景
`SpawnPod` は child Pod を起動し、初回 task を `Method::Run` として送る。しかし、実例として `impl-llm-worker-stream-continuation` を再作成した際、runtime registry / socket / process は生きている一方で、初回 task の session log が materialize されず、Pod は `idle` のままだった。
確認された状態:
- `<runtime-dir>/pods.json` に live allocation がある
- `<runtime-dir>/<pod>/status.json``state: "idle"` と runtime `segment_id` を持つ
- `<insomnia-sessions>/pods/<pod>/metadata.json` は pending segment のまま
- 対応する session / segment `.jsonl` が存在しない
- `ReadPodOutput` は no new assistant text
`SpawnPod` の送信側は `send_run``Method::Run` を write してすぐ切断し、`TurnStart` 等の ack を待っていない。一方 server 側は接続直後に `Snapshot` を書いてから method を読むため、client がすぐ close すると server が snapshot write で失敗し、method を読む前に connection handler が終了する race があり得る。
この場合 `SpawnPod` は成功を返すが、child Pod は初回 task を実行していない。
同種の問題は child Pod の通知経路でも既に踏んでおり、送信側が write 後にすぐ切断せず、receiver 側の acknowledgement / observable event を待つ形にして解消している。`SpawnPod` の初回 task delivery も同じ性質の race と見なす。
追加確認として、Pod socket server は接続直後に replayed `Alert` と connect-time `Snapshot` を送ってから client `Method` を読む。したがって one-shot / send-only client は初期 event を消化してから Method を送る必要がある。
- `send_run_and_confirm``Method::Run` を送った後に event を読む実装になっており、Snapshot が大きい場合や Run payload が大きい場合に双方向で詰まる余地がある。
- `connect_and_send` / `fetch_history` は既に Snapshot まで drain / read しており、この系統の問題は対策済み。
- `probe_socket` は最初の event だけを見て `Snapshot` でなければ status を取らないため、replayed `Alert` が先に来る live Pod で reachable だが status unknown になる可能性がある。
- `PodClient::connect` は background reader を起動するため、通常の TUI attach / interactive client では初期 Snapshot を詰まらせにくい。
## 方針
`SpawnPod` は child process / socket の起動だけでなく、初回 task が controller に受理され、少なくとも `UserMessage` または `TurnStart` が観測できるまで確認してから成功を返す。
既存の `SendToPod` / `SpawnPod` が使う run delivery confirmation ロジックを、接続直後の `Alert` / `Snapshot` drain を含む形へ共通化・安全化する。
## 要件
- `SpawnPod` の初回 task 送信は fire-and-forget にしない。
- `Method::Run` 送信後、`UserMessage` / `TurnStart` / `InvokeStart` など、run が受理されたことを示す event を待つ。
- timeout 時は `SpawnPod` を失敗扱いにする。
- 初回 task delivery に失敗した場合、process / registry / delegated scope の扱いを明確にする。
- cleanup するか、attach 可能な idle Pod として残すかを実装で決める。
- 少なくとも成功扱いで返さない。
- Server が connection 開始時に `Alert` / `Snapshot` を書く設計と競合しない。
- client 側が `Alert` / `Snapshot` を読みながら `Method::Run` ack を待つ形にする。
- `send_run_and_confirm` は connect-time `Snapshot` を消化してから `Method::Run` を送る。
- live Pod status probe は replayed `Alert` によって status 取得を落とさない。
- `probe_socket` は first event だけで判断せず、`Snapshot` まで初期 event を読む。
- `SpawnPod` 成功後は、child Pod の metadata が pending でも、初回 run が開始済みであることを確認できる。
- session log materialization のタイミングそのものは別設計でもよい。
- `SendToPod``SpawnPod` の run delivery confirmation ロジックを可能な範囲で共通化する。
## 完了条件
- `SpawnPod` が初回 task の受理確認を待つ。
- 初回 task が実行されない race を再現する test または regression test がある。
- connect-time `Alert` / `Snapshot` がある状態でも `send_run_and_confirm` が詰まらず、受理 event を観測する regression test がある。
- `probe_socket` が replayed `Alert` の後の `Snapshot` から status を取得できる regression test がある。
- `SpawnPod` が success を返した後、child Pod が idle pending のまま task 未実行になる状態が起きない。
- delivery timeout / failure 時の error message が人間に分かる。
- `cargo fmt --check` と関連 crate の test が通る。
## 範囲外
- `tui -r` picker に live pending Pod を表示する修正。
- session log の SegmentStart materialization 方針変更。
- spawned child Pod panel UI。
---
@@ -0,0 +1,211 @@
---
id: 20260527-000013-tickets-sh-workitem-thread-mvp
slug: tickets-sh-workitem-thread-mvp
title: Ticket 管理: tickets.sh による WorkItem / Thread MVP
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:13Z
updated_at: 2026-05-27T19:28:41Z
assignee: null
legacy_ticket: tickets/tickets-sh-workitem-thread-mvp.md
---
## Migration reference
- legacy_ticket: tickets/tickets-sh-workitem-thread-mvp.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# Ticket 管理: tickets.sh による WorkItem / Thread MVP
## 背景
現在の ticket 運用は `TODO.md``tickets/*.md`、必要に応じて `tickets/*.review.md` を Git 履歴で管理している。要件と完了条件を追うには機能しているが、multi-agent worktree workflow と組み合わせると review / 修正依頼 / 実装報告が扱いづらい。
特に `.review.md` は、review artifact を main workspace の ticket directory に作る必要がある。一方で実装 Pod は child worktree だけに write scope を持つため、review thread と実装 thread が分断されやすい。子 Pod を止めて scope を回収し、review file を作り、再度 restore / spawn するような運用になりがちで面倒である。
Git は履歴の保存層として有用だが、人間や AI maintainer が毎回 file move / delete / review file 作成 / git log 探索を直接操作するのは低級すぎる。repository 内の file backend を正本にしつつ、`tickets.sh` で create / list / show / comment / review / close などの意味的操作を提供する。
この ticket は `docs/plan/maintainer-work-items.md` の抽象メモを踏まえた最小実装である。既存 `TODO.md` / `tickets/` を併用したまま新規領域を試すのではなく、今回の MVP では既存 `TODO.md` / `tickets/*.md` を手動で `work-items/` に移し、`tickets.sh doctor` が通る状態までをゴールにする。
## 方針
- 新しい正本は repo root の `work-items/` に置く。
- 既存 `TODO.md` / `tickets/*.md` は手動 migration の入力として扱う。
- migration 完了後、`TODO.md` は残す場合でも legacy / generated view 相当の最小内容にする。少なくとも未完了 item の正本を `tickets/*.md` に残さない。
- `tickets.sh` は Git を内部保存層として前提にしてよいが、操作単位は file path ではなく WorkItem 操作にする。
- 初期実装では自動 commit しない。
- `tickets.sh` は file 操作まで。
- `git add/commit` は利用者または追加指示に任せる。
- `--help` だけで基本操作と migration 方針が分かるようにする。
- shell script なので依存は POSIX shell + 基本 Unix tool に寄せる。`jq` 必須にはしない。
- 既存 `tickets/*.review.md` がある場合は、対象 WorkItem の `thread.md` に review event として手動で移す。
## backend schema
```text
work-items/
README.md
open/
20260526-123456-short-slug/
item.md
thread.md
artifacts/
pending/
...
closed/
...
resolution.md
artifacts/
```
`item.md` は YAML frontmatter + Markdown body。
```yaml
---
id: 20260526-123456-short-slug
slug: short-slug
title: Human-readable title
status: open
kind: feature
priority: P2
labels: [maintainer, workflow]
created_at: 2026-05-26T12:34:56Z
updated_at: 2026-05-26T12:34:56Z
assignee: null
legacy_ticket: tickets/foo.md
---
## Background
...
## Acceptance criteria
- ...
```
`legacy_ticket` は migration 直後の追跡用 metadata とする。移行元 file は Git history で参照できるため、migration commit 後に `tickets/foo.md` を残し続けない。
`thread.md` は append-only Markdown event log とする。JSONL より人間が読みやすいことを優先する。
```md
<!-- event: comment author: hare at: 2026-05-26T12:40:00Z -->
## Comment
...
---
<!-- event: review author: orchestrator at: 2026-05-26T13:00:00Z status: request_changes -->
## Review: request changes
...
```
`tickets.sh` が必ず event header と separator を付ける。機械 parse は初期実装では簡易でよい。
## コマンド MVP
```text
./tickets.sh help
./tickets.sh list [--status open|pending|closed|all]
./tickets.sh show <id-or-slug>
./tickets.sh create --title <title> [--slug <slug>] [--kind <kind>] [--priority P2] [--label a,b]
./tickets.sh comment <id-or-slug> [--role comment|plan|decision|implementation_report] [--author <name>] [--file <path>]
./tickets.sh review <id-or-slug> --approve|--request-changes [--author <name>] [--file <path>]
./tickets.sh status <id-or-slug> open|pending|closed
./tickets.sh close <id-or-slug> [--resolution <text>|--file <path>]
./tickets.sh doctor
```
`help` / `--help` は同じ内容を出す。
### list
- `work-items/{open,pending,closed}/*/item.md` を scan する。
- status / id / slug / title / kind / priority / updated_at を一行で表示する。
- 初期実装では frontmatter parser は簡易でよい。
### show
- `item.md``thread.md` の末尾を読みやすく表示する。
- 完全な thread 全体を出すか、初期は tail 表示でもよい。`--all` は後続でよい。
### create
- ID は `YYYYMMDD-HHMMSS-<slug>`
- 同一 path が存在する場合は短い random suffix または pid suffix を付けて衝突回避する。
- `work-items/open/<id>/item.md`, `thread.md`, `artifacts/` を作る。
- central `SEQUENCE` は作らない。
### comment / review
- `thread.md` に append する。
- `item.md``updated_at` を更新する。
- review は role/comment の special case として、`approve` / `request_changes` が分かる event header を付ける。
- `.review.md` は作らない。
### status / close
- status directory を move する。
- `item.md` frontmatter の `status``updated_at` を更新する。
- `close``status closed` + optional `resolution.md` + close event append。
- 完了しても削除しない。
### doctor
- directory status と frontmatter `status` の一致を検査する。
- `item.md` / `thread.md` / `artifacts/` の存在を検査する。
- duplicate slug / duplicate id を検査する。
- `TODO.md` / `tickets/*.md` に未移行の未完了 ticket が残っていないことを検査する。
- `tickets/*.review.md` が残っていないことを検査する。
- work-items 配下の markdown frontmatter に必須 field があることを検査する。
- error は非ゼロ exit。
## 手動 migration 要件
この ticket の作業には既存運用からの手動 migration を含める。
- 現在 `TODO.md` に載っている未完了 ticket を `work-items/open/` に移す。
-`tickets/*.md` の本文を対応する `item.md` に移す。
- 既存 `tickets/*.review.md` があれば対応する `thread.md` に review event として移す。
- 移行元 ticket path は `legacy_ticket` metadata または本文の参照欄に残す。
- migration commit 後、未完了 work item の正本として `tickets/*.md` を残さない。
- `TODO.md` は legacy notice / generated view 相当の最小内容に更新する。
- `tickets.sh doctor` が repository の移行状態まで含めて 0 になることをゴールにする。
## 要件
- `tickets.sh --help` で使い方と migration 後の配置が分かる。
- `create/list/show/comment/review/status/close/doctor` が動く。
- WorkItem ID は timestamp-based で、central sequence file を使わない。
- close しても削除せず `work-items/closed/` に移動する。
- review は `.review.md` ではなく thread event として append できる。
- `doctor` が directory status と frontmatter status の不一致を検出する。
- `doctor` が未移行 `TODO.md` / `tickets/*.md` / `tickets/*.review.md` を検出する。
- 初期実装では自動 git commit しない。
- README 相当の usage は `--help` または `work-items/README.md` に含める。
## 完了条件
- repo root に `tickets.sh` が追加される。
- `work-items/README.md` で schema / migration 後の運用が説明される。
- `tickets.sh create` で WorkItem を作成できる。
- `tickets.sh comment` / `tickets.sh review` で thread event を append できる。
- `tickets.sh close` で closed に移動できる。
- 既存 `TODO.md` / `tickets/*.md` / `tickets/*.review.md` が手動で `work-items/` に移行される。
- migration 後、`tickets.sh doctor` が repository 全体の状態に対して 0 になる。
- 不整合 fixture または smoke test で `doctor` が非ゼロになることを確認する。
- shellcheck が利用可能なら通る。無い場合は少なくとも focused smoke test を実行する。
## 範囲外
- Rust crate / DB / remote backend 実装。
- LeaseStore / Pod run tracking の実装。
- Git commit の自動化。
- TUI 統合。
- WorkItem から TODO.md を自動生成する仕組み。
@@ -0,0 +1,211 @@
---
id: 20260527-000013-tickets-sh-workitem-thread-mvp
slug: tickets-sh-workitem-thread-mvp
title: Ticket 管理: tickets.sh による WorkItem / Thread MVP
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:13Z
updated_at: 2026-05-27T19:28:41Z
assignee: null
legacy_ticket: tickets/tickets-sh-workitem-thread-mvp.md
---
## Migration reference
- legacy_ticket: tickets/tickets-sh-workitem-thread-mvp.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# Ticket 管理: tickets.sh による WorkItem / Thread MVP
## 背景
現在の ticket 運用は `TODO.md``tickets/*.md`、必要に応じて `tickets/*.review.md` を Git 履歴で管理している。要件と完了条件を追うには機能しているが、multi-agent worktree workflow と組み合わせると review / 修正依頼 / 実装報告が扱いづらい。
特に `.review.md` は、review artifact を main workspace の ticket directory に作る必要がある。一方で実装 Pod は child worktree だけに write scope を持つため、review thread と実装 thread が分断されやすい。子 Pod を止めて scope を回収し、review file を作り、再度 restore / spawn するような運用になりがちで面倒である。
Git は履歴の保存層として有用だが、人間や AI maintainer が毎回 file move / delete / review file 作成 / git log 探索を直接操作するのは低級すぎる。repository 内の file backend を正本にしつつ、`tickets.sh` で create / list / show / comment / review / close などの意味的操作を提供する。
この ticket は `docs/plan/maintainer-work-items.md` の抽象メモを踏まえた最小実装である。既存 `TODO.md` / `tickets/` を併用したまま新規領域を試すのではなく、今回の MVP では既存 `TODO.md` / `tickets/*.md` を手動で `work-items/` に移し、`tickets.sh doctor` が通る状態までをゴールにする。
## 方針
- 新しい正本は repo root の `work-items/` に置く。
- 既存 `TODO.md` / `tickets/*.md` は手動 migration の入力として扱う。
- migration 完了後、`TODO.md` は残す場合でも legacy / generated view 相当の最小内容にする。少なくとも未完了 item の正本を `tickets/*.md` に残さない。
- `tickets.sh` は Git を内部保存層として前提にしてよいが、操作単位は file path ではなく WorkItem 操作にする。
- 初期実装では自動 commit しない。
- `tickets.sh` は file 操作まで。
- `git add/commit` は利用者または追加指示に任せる。
- `--help` だけで基本操作と migration 方針が分かるようにする。
- shell script なので依存は POSIX shell + 基本 Unix tool に寄せる。`jq` 必須にはしない。
- 既存 `tickets/*.review.md` がある場合は、対象 WorkItem の `thread.md` に review event として手動で移す。
## backend schema
```text
work-items/
README.md
open/
20260526-123456-short-slug/
item.md
thread.md
artifacts/
pending/
...
closed/
...
resolution.md
artifacts/
```
`item.md` は YAML frontmatter + Markdown body。
```yaml
---
id: 20260526-123456-short-slug
slug: short-slug
title: Human-readable title
status: open
kind: feature
priority: P2
labels: [maintainer, workflow]
created_at: 2026-05-26T12:34:56Z
updated_at: 2026-05-26T12:34:56Z
assignee: null
legacy_ticket: tickets/foo.md
---
## Background
...
## Acceptance criteria
- ...
```
`legacy_ticket` は migration 直後の追跡用 metadata とする。移行元 file は Git history で参照できるため、migration commit 後に `tickets/foo.md` を残し続けない。
`thread.md` は append-only Markdown event log とする。JSONL より人間が読みやすいことを優先する。
```md
<!-- event: comment author: hare at: 2026-05-26T12:40:00Z -->
## Comment
...
---
<!-- event: review author: orchestrator at: 2026-05-26T13:00:00Z status: request_changes -->
## Review: request changes
...
```
`tickets.sh` が必ず event header と separator を付ける。機械 parse は初期実装では簡易でよい。
## コマンド MVP
```text
./tickets.sh help
./tickets.sh list [--status open|pending|closed|all]
./tickets.sh show <id-or-slug>
./tickets.sh create --title <title> [--slug <slug>] [--kind <kind>] [--priority P2] [--label a,b]
./tickets.sh comment <id-or-slug> [--role comment|plan|decision|implementation_report] [--author <name>] [--file <path>]
./tickets.sh review <id-or-slug> --approve|--request-changes [--author <name>] [--file <path>]
./tickets.sh status <id-or-slug> open|pending|closed
./tickets.sh close <id-or-slug> [--resolution <text>|--file <path>]
./tickets.sh doctor
```
`help` / `--help` は同じ内容を出す。
### list
- `work-items/{open,pending,closed}/*/item.md` を scan する。
- status / id / slug / title / kind / priority / updated_at を一行で表示する。
- 初期実装では frontmatter parser は簡易でよい。
### show
- `item.md``thread.md` の末尾を読みやすく表示する。
- 完全な thread 全体を出すか、初期は tail 表示でもよい。`--all` は後続でよい。
### create
- ID は `YYYYMMDD-HHMMSS-<slug>`
- 同一 path が存在する場合は短い random suffix または pid suffix を付けて衝突回避する。
- `work-items/open/<id>/item.md`, `thread.md`, `artifacts/` を作る。
- central `SEQUENCE` は作らない。
### comment / review
- `thread.md` に append する。
- `item.md``updated_at` を更新する。
- review は role/comment の special case として、`approve` / `request_changes` が分かる event header を付ける。
- `.review.md` は作らない。
### status / close
- status directory を move する。
- `item.md` frontmatter の `status``updated_at` を更新する。
- `close``status closed` + optional `resolution.md` + close event append。
- 完了しても削除しない。
### doctor
- directory status と frontmatter `status` の一致を検査する。
- `item.md` / `thread.md` / `artifacts/` の存在を検査する。
- duplicate slug / duplicate id を検査する。
- `TODO.md` / `tickets/*.md` に未移行の未完了 ticket が残っていないことを検査する。
- `tickets/*.review.md` が残っていないことを検査する。
- work-items 配下の markdown frontmatter に必須 field があることを検査する。
- error は非ゼロ exit。
## 手動 migration 要件
この ticket の作業には既存運用からの手動 migration を含める。
- 現在 `TODO.md` に載っている未完了 ticket を `work-items/open/` に移す。
-`tickets/*.md` の本文を対応する `item.md` に移す。
- 既存 `tickets/*.review.md` があれば対応する `thread.md` に review event として移す。
- 移行元 ticket path は `legacy_ticket` metadata または本文の参照欄に残す。
- migration commit 後、未完了 work item の正本として `tickets/*.md` を残さない。
- `TODO.md` は legacy notice / generated view 相当の最小内容に更新する。
- `tickets.sh doctor` が repository の移行状態まで含めて 0 になることをゴールにする。
## 要件
- `tickets.sh --help` で使い方と migration 後の配置が分かる。
- `create/list/show/comment/review/status/close/doctor` が動く。
- WorkItem ID は timestamp-based で、central sequence file を使わない。
- close しても削除せず `work-items/closed/` に移動する。
- review は `.review.md` ではなく thread event として append できる。
- `doctor` が directory status と frontmatter status の不一致を検出する。
- `doctor` が未移行 `TODO.md` / `tickets/*.md` / `tickets/*.review.md` を検出する。
- 初期実装では自動 git commit しない。
- README 相当の usage は `--help` または `work-items/README.md` に含める。
## 完了条件
- repo root に `tickets.sh` が追加される。
- `work-items/README.md` で schema / migration 後の運用が説明される。
- `tickets.sh create` で WorkItem を作成できる。
- `tickets.sh comment` / `tickets.sh review` で thread event を append できる。
- `tickets.sh close` で closed に移動できる。
- 既存 `TODO.md` / `tickets/*.md` / `tickets/*.review.md` が手動で `work-items/` に移行される。
- migration 後、`tickets.sh doctor` が repository 全体の状態に対して 0 になる。
- 不整合 fixture または smoke test で `doctor` が非ゼロになることを確認する。
- shellcheck が利用可能なら通る。無い場合は少なくとも focused smoke test を実行する。
## 範囲外
- Rust crate / DB / remote backend 実装。
- LeaseStore / Pod run tracking の実装。
- Git commit の自動化。
- TUI 統合。
- WorkItem から TODO.md を自動生成する仕組み。
@@ -0,0 +1,226 @@
<!-- event: migration author: tickets.sh-migration at: 2026-05-27T00:00:13Z -->
## Migrated
Migrated from tickets/tickets-sh-workitem-thread-mvp.md. No legacy review file was present at migration time.
---
<!-- event: close author: hare at: 2026-05-27T19:28:41Z status: closed -->
## Closed
---
id: 20260527-000013-tickets-sh-workitem-thread-mvp
slug: tickets-sh-workitem-thread-mvp
title: Ticket 管理: tickets.sh による WorkItem / Thread MVP
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:13Z
updated_at: 2026-05-27T19:28:41Z
assignee: null
legacy_ticket: tickets/tickets-sh-workitem-thread-mvp.md
---
## Migration reference
- legacy_ticket: tickets/tickets-sh-workitem-thread-mvp.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# Ticket 管理: tickets.sh による WorkItem / Thread MVP
## 背景
現在の ticket 運用は `TODO.md``tickets/*.md`、必要に応じて `tickets/*.review.md` を Git 履歴で管理している。要件と完了条件を追うには機能しているが、multi-agent worktree workflow と組み合わせると review / 修正依頼 / 実装報告が扱いづらい。
特に `.review.md` は、review artifact を main workspace の ticket directory に作る必要がある。一方で実装 Pod は child worktree だけに write scope を持つため、review thread と実装 thread が分断されやすい。子 Pod を止めて scope を回収し、review file を作り、再度 restore / spawn するような運用になりがちで面倒である。
Git は履歴の保存層として有用だが、人間や AI maintainer が毎回 file move / delete / review file 作成 / git log 探索を直接操作するのは低級すぎる。repository 内の file backend を正本にしつつ、`tickets.sh` で create / list / show / comment / review / close などの意味的操作を提供する。
この ticket は `docs/plan/maintainer-work-items.md` の抽象メモを踏まえた最小実装である。既存 `TODO.md` / `tickets/` を併用したまま新規領域を試すのではなく、今回の MVP では既存 `TODO.md` / `tickets/*.md` を手動で `work-items/` に移し、`tickets.sh doctor` が通る状態までをゴールにする。
## 方針
- 新しい正本は repo root の `work-items/` に置く。
- 既存 `TODO.md` / `tickets/*.md` は手動 migration の入力として扱う。
- migration 完了後、`TODO.md` は残す場合でも legacy / generated view 相当の最小内容にする。少なくとも未完了 item の正本を `tickets/*.md` に残さない。
- `tickets.sh` は Git を内部保存層として前提にしてよいが、操作単位は file path ではなく WorkItem 操作にする。
- 初期実装では自動 commit しない。
- `tickets.sh` は file 操作まで。
- `git add/commit` は利用者または追加指示に任せる。
- `--help` だけで基本操作と migration 方針が分かるようにする。
- shell script なので依存は POSIX shell + 基本 Unix tool に寄せる。`jq` 必須にはしない。
- 既存 `tickets/*.review.md` がある場合は、対象 WorkItem の `thread.md` に review event として手動で移す。
## backend schema
```text
work-items/
README.md
open/
20260526-123456-short-slug/
item.md
thread.md
artifacts/
pending/
...
closed/
...
resolution.md
artifacts/
```
`item.md` は YAML frontmatter + Markdown body。
```yaml
---
id: 20260526-123456-short-slug
slug: short-slug
title: Human-readable title
status: open
kind: feature
priority: P2
labels: [maintainer, workflow]
created_at: 2026-05-26T12:34:56Z
updated_at: 2026-05-26T12:34:56Z
assignee: null
legacy_ticket: tickets/foo.md
---
## Background
...
## Acceptance criteria
- ...
```
`legacy_ticket` は migration 直後の追跡用 metadata とする。移行元 file は Git history で参照できるため、migration commit 後に `tickets/foo.md` を残し続けない。
`thread.md` は append-only Markdown event log とする。JSONL より人間が読みやすいことを優先する。
```md
<!-- event: comment author: hare at: 2026-05-26T12:40:00Z -->
## Comment
...
---
<!-- event: review author: orchestrator at: 2026-05-26T13:00:00Z status: request_changes -->
## Review: request changes
...
```
`tickets.sh` が必ず event header と separator を付ける。機械 parse は初期実装では簡易でよい。
## コマンド MVP
```text
./tickets.sh help
./tickets.sh list [--status open|pending|closed|all]
./tickets.sh show <id-or-slug>
./tickets.sh create --title <title> [--slug <slug>] [--kind <kind>] [--priority P2] [--label a,b]
./tickets.sh comment <id-or-slug> [--role comment|plan|decision|implementation_report] [--author <name>] [--file <path>]
./tickets.sh review <id-or-slug> --approve|--request-changes [--author <name>] [--file <path>]
./tickets.sh status <id-or-slug> open|pending|closed
./tickets.sh close <id-or-slug> [--resolution <text>|--file <path>]
./tickets.sh doctor
```
`help` / `--help` は同じ内容を出す。
### list
- `work-items/{open,pending,closed}/*/item.md` を scan する。
- status / id / slug / title / kind / priority / updated_at を一行で表示する。
- 初期実装では frontmatter parser は簡易でよい。
### show
- `item.md``thread.md` の末尾を読みやすく表示する。
- 完全な thread 全体を出すか、初期は tail 表示でもよい。`--all` は後続でよい。
### create
- ID は `YYYYMMDD-HHMMSS-<slug>`
- 同一 path が存在する場合は短い random suffix または pid suffix を付けて衝突回避する。
- `work-items/open/<id>/item.md`, `thread.md`, `artifacts/` を作る。
- central `SEQUENCE` は作らない。
### comment / review
- `thread.md` に append する。
- `item.md``updated_at` を更新する。
- review は role/comment の special case として、`approve` / `request_changes` が分かる event header を付ける。
- `.review.md` は作らない。
### status / close
- status directory を move する。
- `item.md` frontmatter の `status``updated_at` を更新する。
- `close``status closed` + optional `resolution.md` + close event append。
- 完了しても削除しない。
### doctor
- directory status と frontmatter `status` の一致を検査する。
- `item.md` / `thread.md` / `artifacts/` の存在を検査する。
- duplicate slug / duplicate id を検査する。
- `TODO.md` / `tickets/*.md` に未移行の未完了 ticket が残っていないことを検査する。
- `tickets/*.review.md` が残っていないことを検査する。
- work-items 配下の markdown frontmatter に必須 field があることを検査する。
- error は非ゼロ exit。
## 手動 migration 要件
この ticket の作業には既存運用からの手動 migration を含める。
- 現在 `TODO.md` に載っている未完了 ticket を `work-items/open/` に移す。
-`tickets/*.md` の本文を対応する `item.md` に移す。
- 既存 `tickets/*.review.md` があれば対応する `thread.md` に review event として移す。
- 移行元 ticket path は `legacy_ticket` metadata または本文の参照欄に残す。
- migration commit 後、未完了 work item の正本として `tickets/*.md` を残さない。
- `TODO.md` は legacy notice / generated view 相当の最小内容に更新する。
- `tickets.sh doctor` が repository の移行状態まで含めて 0 になることをゴールにする。
## 要件
- `tickets.sh --help` で使い方と migration 後の配置が分かる。
- `create/list/show/comment/review/status/close/doctor` が動く。
- WorkItem ID は timestamp-based で、central sequence file を使わない。
- close しても削除せず `work-items/closed/` に移動する。
- review は `.review.md` ではなく thread event として append できる。
- `doctor` が directory status と frontmatter status の不一致を検出する。
- `doctor` が未移行 `TODO.md` / `tickets/*.md` / `tickets/*.review.md` を検出する。
- 初期実装では自動 git commit しない。
- README 相当の usage は `--help` または `work-items/README.md` に含める。
## 完了条件
- repo root に `tickets.sh` が追加される。
- `work-items/README.md` で schema / migration 後の運用が説明される。
- `tickets.sh create` で WorkItem を作成できる。
- `tickets.sh comment` / `tickets.sh review` で thread event を append できる。
- `tickets.sh close` で closed に移動できる。
- 既存 `TODO.md` / `tickets/*.md` / `tickets/*.review.md` が手動で `work-items/` に移行される。
- migration 後、`tickets.sh doctor` が repository 全体の状態に対して 0 になる。
- 不整合 fixture または smoke test で `doctor` が非ゼロになることを確認する。
- shellcheck が利用可能なら通る。無い場合は少なくとも focused smoke test を実行する。
## 範囲外
- Rust crate / DB / remote backend 実装。
- LeaseStore / Pod run tracking の実装。
- Git commit の自動化。
- TUI 統合。
- WorkItem から TODO.md を自動生成する仕組み。
---
@@ -0,0 +1,66 @@
---
id: 20260527-000014-tui-actionbar-transient-notice-api
slug: tui-actionbar-transient-notice-api
title: TUI: actionbar transient notice API
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:14Z
updated_at: 2026-05-29T03:57:35Z
assignee: null
legacy_ticket: tickets/tui-actionbar-transient-notice-api.md
---
## Migration reference
- legacy_ticket: tickets/tui-actionbar-transient-notice-api.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# TUI: actionbar transient notice API
## 背景
TUI の actionbar は最下部の補助表示行として、現在の mode や一時的な操作フィードバックを出す場所になりつつある。
一方で、現在は `Ctrl-C` の二段階終了 guard のような一時通知も `app.push_error(...)` 等で view 上に残る message として扱われている。これは後から見返すログではなく、数秒だけ見えれば十分な操作フィードバックである。
また、memory audit log 実装では extract / consolidation worker の直近 event を actionbar に表示する予定であり、個別機能ごとに ad hoc な actionbar 表示を増やすと優先順位・寿命・表示競合の扱いが散らばる。
## 方針
Actionbar を「history / transcript に残さない transient UI state」の共通表示面として扱う API を App 側に用意する。
永続的に残すべき Pod event / model output / tool result / user-visible error と、一時的な操作フィードバックを分離する。actionbar notice は UI の補助表示であり、LLM context や session history へ暗黙注入しない。
## 要件
- App に actionbar transient notice を設定・期限切れ・取得するための API を追加する。
- 例: `flash_actionbar_notice(text, duration)` または `set_actionbar_notice(...)`
- notice には最低限 `text`, `level`, `source`, `expires_at` 相当を持たせる。
- time source はテストしやすい形にする。
- actionbar rendering は transient notice を優先表示できる。
- 既存の command mode marker、queued input hint、scroll indicator、view mode label と競合しない優先順位を定義する。
- notice が期限切れなら表示しない。
- `Ctrl-C` の二段階終了 guard の表示を view log から actionbar notice に移す。
- `Pod keeps running` などの一時説明は transcript/view 上に残さない。
- 二度押しの挙動自体は変えない。
- memory worker の actionbar 表示が既に実装済みの場合、可能な範囲でこの API に寄せる。
- 未実装・別 branch 上の場合は、この ticket の範囲では API 設計が衝突しないようにする。
- actionbar notice は通常の LLM context に暗黙注入しない。
- 必要な正本ログは各機能の audit/session log に残す。
## 完了条件
- actionbar transient notice 用 API が App/UI に追加されている。
- `Ctrl-C` 二段階終了 guard の一時メッセージが actionbar に表示され、view log には残らない。
- notice の期限切れと優先表示の挙動がテストされている。
- 既存の command mode / queued input / scroll / view mode actionbar 表示が破綻していない。
- `cargo fmt --check` と関連 TUI テストが通る。
## 範囲外
- actionbar の複数行化。
- 汎用 notification center / viewer UI。
- Pod / worker の正本ログ形式の変更。
- memory audit log 本体の実装。
@@ -0,0 +1,66 @@
---
id: 20260527-000014-tui-actionbar-transient-notice-api
slug: tui-actionbar-transient-notice-api
title: TUI: actionbar transient notice API
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:14Z
updated_at: 2026-05-29T03:57:34Z
assignee: null
legacy_ticket: tickets/tui-actionbar-transient-notice-api.md
---
## Migration reference
- legacy_ticket: tickets/tui-actionbar-transient-notice-api.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# TUI: actionbar transient notice API
## 背景
TUI の actionbar は最下部の補助表示行として、現在の mode や一時的な操作フィードバックを出す場所になりつつある。
一方で、現在は `Ctrl-C` の二段階終了 guard のような一時通知も `app.push_error(...)` 等で view 上に残る message として扱われている。これは後から見返すログではなく、数秒だけ見えれば十分な操作フィードバックである。
また、memory audit log 実装では extract / consolidation worker の直近 event を actionbar に表示する予定であり、個別機能ごとに ad hoc な actionbar 表示を増やすと優先順位・寿命・表示競合の扱いが散らばる。
## 方針
Actionbar を「history / transcript に残さない transient UI state」の共通表示面として扱う API を App 側に用意する。
永続的に残すべき Pod event / model output / tool result / user-visible error と、一時的な操作フィードバックを分離する。actionbar notice は UI の補助表示であり、LLM context や session history へ暗黙注入しない。
## 要件
- App に actionbar transient notice を設定・期限切れ・取得するための API を追加する。
- 例: `flash_actionbar_notice(text, duration)` または `set_actionbar_notice(...)`
- notice には最低限 `text`, `level`, `source`, `expires_at` 相当を持たせる。
- time source はテストしやすい形にする。
- actionbar rendering は transient notice を優先表示できる。
- 既存の command mode marker、queued input hint、scroll indicator、view mode label と競合しない優先順位を定義する。
- notice が期限切れなら表示しない。
- `Ctrl-C` の二段階終了 guard の表示を view log から actionbar notice に移す。
- `Pod keeps running` などの一時説明は transcript/view 上に残さない。
- 二度押しの挙動自体は変えない。
- memory worker の actionbar 表示が既に実装済みの場合、可能な範囲でこの API に寄せる。
- 未実装・別 branch 上の場合は、この ticket の範囲では API 設計が衝突しないようにする。
- actionbar notice は通常の LLM context に暗黙注入しない。
- 必要な正本ログは各機能の audit/session log に残す。
## 完了条件
- actionbar transient notice 用 API が App/UI に追加されている。
- `Ctrl-C` 二段階終了 guard の一時メッセージが actionbar に表示され、view log には残らない。
- notice の期限切れと優先表示の挙動がテストされている。
- 既存の command mode / queued input / scroll / view mode actionbar 表示が破綻していない。
- `cargo fmt --check` と関連 TUI テストが通る。
## 範囲外
- actionbar の複数行化。
- 汎用 notification center / viewer UI。
- Pod / worker の正本ログ形式の変更。
- memory audit log 本体の実装。
@@ -0,0 +1,81 @@
<!-- event: migration author: tickets.sh-migration at: 2026-05-27T00:00:14Z -->
## Migrated
Migrated from tickets/tui-actionbar-transient-notice-api.md. No legacy review file was present at migration time.
---
<!-- event: close author: hare at: 2026-05-29T03:57:35Z status: closed -->
## Closed
---
id: 20260527-000014-tui-actionbar-transient-notice-api
slug: tui-actionbar-transient-notice-api
title: TUI: actionbar transient notice API
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:14Z
updated_at: 2026-05-29T03:57:34Z
assignee: null
legacy_ticket: tickets/tui-actionbar-transient-notice-api.md
---
## Migration reference
- legacy_ticket: tickets/tui-actionbar-transient-notice-api.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# TUI: actionbar transient notice API
## 背景
TUI の actionbar は最下部の補助表示行として、現在の mode や一時的な操作フィードバックを出す場所になりつつある。
一方で、現在は `Ctrl-C` の二段階終了 guard のような一時通知も `app.push_error(...)` 等で view 上に残る message として扱われている。これは後から見返すログではなく、数秒だけ見えれば十分な操作フィードバックである。
また、memory audit log 実装では extract / consolidation worker の直近 event を actionbar に表示する予定であり、個別機能ごとに ad hoc な actionbar 表示を増やすと優先順位・寿命・表示競合の扱いが散らばる。
## 方針
Actionbar を「history / transcript に残さない transient UI state」の共通表示面として扱う API を App 側に用意する。
永続的に残すべき Pod event / model output / tool result / user-visible error と、一時的な操作フィードバックを分離する。actionbar notice は UI の補助表示であり、LLM context や session history へ暗黙注入しない。
## 要件
- App に actionbar transient notice を設定・期限切れ・取得するための API を追加する。
- 例: `flash_actionbar_notice(text, duration)` または `set_actionbar_notice(...)`
- notice には最低限 `text`, `level`, `source`, `expires_at` 相当を持たせる。
- time source はテストしやすい形にする。
- actionbar rendering は transient notice を優先表示できる。
- 既存の command mode marker、queued input hint、scroll indicator、view mode label と競合しない優先順位を定義する。
- notice が期限切れなら表示しない。
- `Ctrl-C` の二段階終了 guard の表示を view log から actionbar notice に移す。
- `Pod keeps running` などの一時説明は transcript/view 上に残さない。
- 二度押しの挙動自体は変えない。
- memory worker の actionbar 表示が既に実装済みの場合、可能な範囲でこの API に寄せる。
- 未実装・別 branch 上の場合は、この ticket の範囲では API 設計が衝突しないようにする。
- actionbar notice は通常の LLM context に暗黙注入しない。
- 必要な正本ログは各機能の audit/session log に残す。
## 完了条件
- actionbar transient notice 用 API が App/UI に追加されている。
- `Ctrl-C` 二段階終了 guard の一時メッセージが actionbar に表示され、view log には残らない。
- notice の期限切れと優先表示の挙動がテストされている。
- 既存の command mode / queued input / scroll / view mode actionbar 表示が破綻していない。
- `cargo fmt --check` と関連 TUI テストが通る。
## 範囲外
- actionbar の複数行化。
- 汎用 notification center / viewer UI。
- Pod / worker の正本ログ形式の変更。
- memory audit log 本体の実装。
---
@@ -0,0 +1,81 @@
---
id: 20260527-000016-tui-picker-live-pending-pods
slug: tui-picker-live-pending-pods
title: TUI picker: live pending Pod の表示優先と状態補完
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:16Z
updated_at: 2026-05-30T05:00:56Z
assignee: null
legacy_ticket: tickets/tui-picker-live-pending-pods.md
---
## Migration reference
- legacy_ticket: tickets/tui-picker-live-pending-pods.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# TUI picker: live pending Pod の表示優先と状態補完
## 背景
`tui -r` の Pod picker は session store の name-keyed Pod metadata と runtime registry の live allocation を合わせて表示している。しかし、spawned child Pod がまだ最初の user turn / SegmentStart を materialize していない場合、Pod metadata は pending segment のままになり、session log も存在しない。
実例として、`impl-llm-worker-stream-continuation` は live socket と runtime registry 上の segment_id を持っていたが、metadata は以下のように `session_id` のみだった。
```json
{
"pod_name": "impl-llm-worker-stream-continuation",
"active": {
"session_id": "019e5bc6-c3f3-7193-98a1-d64c635f86a1"
}
}
```
一方で runtime 側には segment_id が存在する。
```json
{
"pod_name": "impl-llm-worker-stream-continuation",
"segment_id": "019e5bc6-c3f3-7193-98a1-d6559bdc9cd6",
"state": "idle"
}
```
この状態の Pod は attach 可能だが、session log がないため `updated_at = 0` になり、picker の `updated_at desc` sort と `MAX_ROWS = 10` truncate によって一覧から漏れやすい。
## 方針
Live socket が reachable な Pod は、session log / metadata active segment が未確定でも attach 可能な対象として picker に表示する。restore 可能性と attach 可能性を分け、live pending Pod は restore 不能でも live attach 対象として扱う。
## 要件
- `tui -r` picker は reachable live Pod を stopped Pod より優先して表示する。
- `updated_at = 0` でも live row が `MAX_ROWS` truncate で落ちない。
- sort key は少なくとも live first, updated_at desc, pod_name になる。
- Live Pod の metadata が pending segment の場合でも picker row に表示する。
- preview は `[live, pending segment]` など、人間が状態を理解できる文言にする。
- debug id 表示では runtime registry の segment_id を可能なら表示する。
- Runtime registry / live status に segment_id があり、metadata に segment_id が無い場合、表示上は runtime segment_id を補完できるようにする。
- ただし session log が存在しない限り restore 可能とは扱わない。
- attach は live socket に対して行う。
- Existing stopped / corrupt Pod metadata rows の表示を壊さない。
- `ListVisiblePods` / discovery 側にも同様の pending live 表示不整合がある場合、必要なら後続 ticket に切り出す。
- この ticket の主対象は `tui -r` picker。
## 完了条件
- live pending Pod が `tui -r` に表示される。
- live pending Pod を選択すると live socket に attach する。
- live pending Pod が多数の stopped Pod によって `MAX_ROWS` truncate から漏れない。
- picker の sort / row build の unit test が追加または更新されている。
- `cargo fmt --check``cargo test -p tui picker` あるいは関連 TUI test が通る。
## 範囲外
- pending Pod metadata を runtime segment_id で永続的に書き換えること。
- session log が無い Pod を restore 可能にすること。
- spawned child Pod の first turn / SegmentStart materialization 方針の変更。
- 汎用 spawned Pod panel UI。
@@ -0,0 +1,81 @@
---
id: 20260527-000016-tui-picker-live-pending-pods
slug: tui-picker-live-pending-pods
title: TUI picker: live pending Pod の表示優先と状態補完
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:16Z
updated_at: 2026-05-30T05:00:56Z
assignee: null
legacy_ticket: tickets/tui-picker-live-pending-pods.md
---
## Migration reference
- legacy_ticket: tickets/tui-picker-live-pending-pods.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# TUI picker: live pending Pod の表示優先と状態補完
## 背景
`tui -r` の Pod picker は session store の name-keyed Pod metadata と runtime registry の live allocation を合わせて表示している。しかし、spawned child Pod がまだ最初の user turn / SegmentStart を materialize していない場合、Pod metadata は pending segment のままになり、session log も存在しない。
実例として、`impl-llm-worker-stream-continuation` は live socket と runtime registry 上の segment_id を持っていたが、metadata は以下のように `session_id` のみだった。
```json
{
"pod_name": "impl-llm-worker-stream-continuation",
"active": {
"session_id": "019e5bc6-c3f3-7193-98a1-d64c635f86a1"
}
}
```
一方で runtime 側には segment_id が存在する。
```json
{
"pod_name": "impl-llm-worker-stream-continuation",
"segment_id": "019e5bc6-c3f3-7193-98a1-d6559bdc9cd6",
"state": "idle"
}
```
この状態の Pod は attach 可能だが、session log がないため `updated_at = 0` になり、picker の `updated_at desc` sort と `MAX_ROWS = 10` truncate によって一覧から漏れやすい。
## 方針
Live socket が reachable な Pod は、session log / metadata active segment が未確定でも attach 可能な対象として picker に表示する。restore 可能性と attach 可能性を分け、live pending Pod は restore 不能でも live attach 対象として扱う。
## 要件
- `tui -r` picker は reachable live Pod を stopped Pod より優先して表示する。
- `updated_at = 0` でも live row が `MAX_ROWS` truncate で落ちない。
- sort key は少なくとも live first, updated_at desc, pod_name になる。
- Live Pod の metadata が pending segment の場合でも picker row に表示する。
- preview は `[live, pending segment]` など、人間が状態を理解できる文言にする。
- debug id 表示では runtime registry の segment_id を可能なら表示する。
- Runtime registry / live status に segment_id があり、metadata に segment_id が無い場合、表示上は runtime segment_id を補完できるようにする。
- ただし session log が存在しない限り restore 可能とは扱わない。
- attach は live socket に対して行う。
- Existing stopped / corrupt Pod metadata rows の表示を壊さない。
- `ListVisiblePods` / discovery 側にも同様の pending live 表示不整合がある場合、必要なら後続 ticket に切り出す。
- この ticket の主対象は `tui -r` picker。
## 完了条件
- live pending Pod が `tui -r` に表示される。
- live pending Pod を選択すると live socket に attach する。
- live pending Pod が多数の stopped Pod によって `MAX_ROWS` truncate から漏れない。
- picker の sort / row build の unit test が追加または更新されている。
- `cargo fmt --check``cargo test -p tui picker` あるいは関連 TUI test が通る。
## 範囲外
- pending Pod metadata を runtime segment_id で永続的に書き換えること。
- session log が無い Pod を restore 可能にすること。
- spawned child Pod の first turn / SegmentStart materialization 方針の変更。
- 汎用 spawned Pod panel UI。
@@ -0,0 +1,179 @@
<!-- event: migration author: tickets.sh-migration at: 2026-05-27T00:00:16Z -->
## Migrated
Migrated from tickets/tui-picker-live-pending-pods.md. No legacy review file was present at migration time.
---
<!-- event: plan author: hare at: 2026-05-30T04:54:03Z -->
## Plan
## Preflight implementation plan
Classification: implementation-ready.
No blocking preflight gap remains. The product rule is settled: reachable live Pods must be visible/attachable even if durable session-log metadata is incomplete, but missing session logs must not make them restorable.
Implementation detail to preserve:
- Treat “pending live” as a display/model condition, not persisted state.
- Use reachable `LivePodInfo` plus incomplete stored/session summary or runtime-only segment id to improve row order/preview/debug ids.
- Do not mark the Pod restorable unless stored metadata has a usable active segment/session under existing restore rules.
Current code map:
- `crates/tui/src/picker.rs`: picker construction, row rendering, live attach socket override.
- `crates/tui/src/pod_list.rs`: shared model merge/sort/truncation/actions; current sort is updated_at desc only; `merge_live` already supplements segment id from runtime.
- `crates/tui/src/main.rs`: selected live row attaches via socket override before restore fallback.
- `crates/tui/src/multi_pod.rs`: also uses `PodList`, so ordering effects should be checked.
- `crates/pod/src/discovery.rs`: List/Attach/Restore behavior is related but out of scope.
- `crates/pod-registry/src/table.rs`: runtime allocation segment id source.
- `crates/pod-store/src/lib.rs`: pending active segment metadata; do not persist runtime supplementation.
Implementation phases:
1. Change `PodList::from_sources` sorting to reachable-live first, then updated_at desc, then pod_name asc; truncation remains after sorting.
2. Make reachable live pending preview explicit, e.g. `[live, pending segment]`, when durable summary is incomplete.
3. Preserve and test runtime segment id supplementation for display/debug ids only.
4. Add focused `pod_list` tests for live-first-before-truncation, live pending runtime segment attach-only behavior, and live-only runtime segment attach-only behavior.
5. Adjust existing sort/multi-pod tests only as needed.
6. Keep `PodDiscovery::inspect` / `AttachOrRestorePod` behavior out of scope; record follow-up if needed.
Critical risks:
- Live attachability and restoreability must stay separate.
- Do not persist runtime segment supplementation to pod-store.
- Sort must happen before truncation.
- Do not duplicate picker-specific merge/sort logic; fix shared `PodList`.
- Rank reachable live rows, not unreachable registry allocations.
- Preview wording must not imply restoreability.
- Multi-Pod dashboard ordering may change; reviewer should check it remains intended.
Validation plan:
- `cargo test -p tui pod_list`
- `cargo test -p tui picker`
- `cargo test -p tui multi_pod`
- `cargo test -p tui`
- `cargo fmt --check`
---
<!-- event: review author: hare at: 2026-05-30T05:00:32Z status: approve -->
## Review: approve
Approve.
The change correctly moves the live-priority rule into shared `PodList` construction, so both the resume picker and multi-Pod dashboard consume the same merged/sorted model. Reachable live Pods now sort ahead of non-live/unreachable/stopped/corrupt rows before truncation, and live pending rows get display-only runtime segment supplementation plus clearer pending preview text without changing pod-store metadata or restore behavior.
Blocker findings: none.
Requirement coverage:
- Reachable live rows sort before stopped/corrupt/unreachable rows before truncation.
- Sorting remains deterministic inside groups: `updated_at` desc, then pod name asc.
- Live pending/runtime-only rows remain attachable/openable but not restorable.
- Runtime segment id supplementation is display/model-only; no pod-store write path is touched.
- Pending preview uses `[live, pending segment]` and does not imply restoreability.
- Shared `PodList` was fixed rather than duplicating picker-specific logic.
- Unreachable registry allocations are not promoted.
- PodDiscovery / AttachOrRestore behavior was not broadened.
Validation reviewed from coder report:
- `cargo test -p tui pod_list` — passed.
- `cargo test -p tui picker` — passed.
- `cargo test -p tui multi_pod` — passed.
- `cargo test -p tui` — passed.
- `cargo fmt --check` — passed.
Final verdict: approve.
---
<!-- event: close author: hare at: 2026-05-30T05:00:56Z status: closed -->
## Closed
---
id: 20260527-000016-tui-picker-live-pending-pods
slug: tui-picker-live-pending-pods
title: TUI picker: live pending Pod の表示優先と状態補完
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:16Z
updated_at: 2026-05-30T05:00:56Z
assignee: null
legacy_ticket: tickets/tui-picker-live-pending-pods.md
---
## Migration reference
- legacy_ticket: tickets/tui-picker-live-pending-pods.md
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# TUI picker: live pending Pod の表示優先と状態補完
## 背景
`tui -r` の Pod picker は session store の name-keyed Pod metadata と runtime registry の live allocation を合わせて表示している。しかし、spawned child Pod がまだ最初の user turn / SegmentStart を materialize していない場合、Pod metadata は pending segment のままになり、session log も存在しない。
実例として、`impl-llm-worker-stream-continuation` は live socket と runtime registry 上の segment_id を持っていたが、metadata は以下のように `session_id` のみだった。
```json
{
"pod_name": "impl-llm-worker-stream-continuation",
"active": {
"session_id": "019e5bc6-c3f3-7193-98a1-d64c635f86a1"
}
}
```
一方で runtime 側には segment_id が存在する。
```json
{
"pod_name": "impl-llm-worker-stream-continuation",
"segment_id": "019e5bc6-c3f3-7193-98a1-d6559bdc9cd6",
"state": "idle"
}
```
この状態の Pod は attach 可能だが、session log がないため `updated_at = 0` になり、picker の `updated_at desc` sort と `MAX_ROWS = 10` truncate によって一覧から漏れやすい。
## 方針
Live socket が reachable な Pod は、session log / metadata active segment が未確定でも attach 可能な対象として picker に表示する。restore 可能性と attach 可能性を分け、live pending Pod は restore 不能でも live attach 対象として扱う。
## 要件
- `tui -r` picker は reachable live Pod を stopped Pod より優先して表示する。
- `updated_at = 0` でも live row が `MAX_ROWS` truncate で落ちない。
- sort key は少なくとも live first, updated_at desc, pod_name になる。
- Live Pod の metadata が pending segment の場合でも picker row に表示する。
- preview は `[live, pending segment]` など、人間が状態を理解できる文言にする。
- debug id 表示では runtime registry の segment_id を可能なら表示する。
- Runtime registry / live status に segment_id があり、metadata に segment_id が無い場合、表示上は runtime segment_id を補完できるようにする。
- ただし session log が存在しない限り restore 可能とは扱わない。
- attach は live socket に対して行う。
- Existing stopped / corrupt Pod metadata rows の表示を壊さない。
- `ListVisiblePods` / discovery 側にも同様の pending live 表示不整合がある場合、必要なら後続 ticket に切り出す。
- この ticket の主対象は `tui -r` picker。
## 完了条件
- live pending Pod が `tui -r` に表示される。
- live pending Pod を選択すると live socket に attach する。
- live pending Pod が多数の stopped Pod によって `MAX_ROWS` truncate から漏れない。
- picker の sort / row build の unit test が追加または更新されている。
- `cargo fmt --check``cargo test -p tui picker` あるいは関連 TUI test が通る。
## 範囲外
- pending Pod metadata を runtime segment_id で永続的に書き換えること。
- session log が無い Pod を restore 可能にすること。
- spawned child Pod の first turn / SegmentStart materialization 方針の変更。
- 汎用 spawned Pod panel UI。
---
@@ -0,0 +1,64 @@
---
id: 20260527-000019-workspace-memory-lint-cli
slug: workspace-memory-lint-cli
title: ワークスペースのメモリーをLintするヘッドレスCLI
status: closed
kind: task
priority: P2
labels: [migrated, memory, cli]
created_at: 2026-05-27T00:00:19Z
updated_at: 2026-05-31T02:15:17Z
assignee: null
legacy_ticket: null
---
## Background
The memory linter currently exists as library/pre-write validation used by memory tools, but there is no headless command to check all existing workspace memory/knowledge records at once. This makes it hard to validate `.insomnia/memory` and `.insomnia/knowledge` before commits, migrations, or manual edits.
The installed user-facing binary is currently produced by the `tui` crate as `insomnia`. It is acceptable for this ticket to add the headless lint command to that crate/binary instead of introducing a separate binary. A future rename from `tui` crate to `insomnia`, or a more explicit single-binary CLI structure, can be handled separately.
## Requirements
- Add a headless CLI mode to the existing `insomnia` binary in the `tui` crate.
- Preferred invocation shape: `insomnia memory lint [--workspace <PATH>] [--json] [--warnings-as-errors]`.
- `insomnia memory` without `lint` should remain available as a normal positional Pod name if possible.
- If this shape is awkward with the current parser, keep the command unambiguous and document the chosen shape in tests/help text.
- Default workspace root is the current working directory.
- `--workspace <PATH>` overrides the workspace root passed to `memory::WorkspaceLayout::new`.
- Lint all existing records classified by `memory::WorkspaceLayout`:
- `.insomnia/memory/summary.md` when present;
- `.insomnia/memory/decisions/*.md`;
- `.insomnia/memory/requests/*.md`;
- `.insomnia/knowledge/*.md`.
- Do not lint subsystem-owned opaque trees such as `.insomnia/memory/_staging`, `_logs`, `_usage`.
- Use the existing `memory::Linter` and `WriteMode::Update` for existing files so the CLI matches tool pre-write validation semantics without triggering create-only duplicate slug checks on the file itself.
- Print a deterministic, human-readable report by default:
- file path;
- errors;
- warnings;
- summary counts.
- Exit status:
- `0` if no errors, and no warnings when `--warnings-as-errors` is set;
- `1` if lint errors are found, or warnings are found with `--warnings-as-errors`;
- `2` for CLI usage / I/O / unexpected runtime failures.
- `--json` may be simple but should be machine-readable and stable enough for scripts: include workspace, files, errors, warnings, and counts.
- The command must not start a Pod, connect to sockets, enter raw terminal mode, or mutate files.
## Non-goals
- Renaming the `tui` crate to `insomnia`.
- Adding a separate installed binary.
- Linting Workflow files; workflow linting can be a future command.
- Auto-fixing memory/knowledge records.
- Changing memory schema/linter rules.
## Acceptance criteria
- `insomnia memory lint` runs headlessly against the current directory and reports existing memory/knowledge lint results.
- `insomnia memory lint --workspace <PATH>` works in tests/fixtures.
- The command exits non-zero for lint errors.
- `--warnings-as-errors` makes warnings fail.
- `--json` returns valid JSON containing counts and per-file diagnostics.
- Existing Pod/TUI argument parsing behavior remains covered by tests, especially positional Pod names and `--multi`/`--resume` conflicts.
- `cargo fmt --check`, focused `cargo test -p tui` tests, `cargo check -p tui`, `./tickets.sh doctor`, and `git diff --check` pass.
@@ -0,0 +1 @@
Implemented `insomnia memory lint` as a headless command in the existing user-facing `insomnia` binary. The command lints workspace memory/knowledge records with the existing `memory::Linter` using `WriteMode::Update`, supports human and JSON output, handles warnings-as-errors, preserves `insomnia memory` as a positional Pod name, and returns before TUI/raw-terminal or Pod connection paths. External review approved and validation passed.
@@ -0,0 +1,105 @@
<!-- event: migration author: tickets.sh-migration at: 2026-05-27T00:00:19Z -->
## Migrated
Migrated from TODO.md entry without a legacy ticket file. No legacy review file was present at migration time.
---
<!-- event: plan author: hare at: 2026-05-31T00:51:55Z -->
## Plan
Planning note:
- Keep this in the existing user-facing `insomnia` binary implemented by the `tui` crate. Do not add another installed command for this ticket.
- The command should be headless: parse args, lint files, print report, exit. It must not initialize terminal UI or connect to a Pod.
- `insomnia memory lint` is preferred, but `insomnia memory` alone should continue to be a valid Pod-name attach/create path if practical with the current parser.
- Use `memory::Linter` directly so CLI behavior tracks tool pre-write validation. Existing files should be linted with `WriteMode::Update`.
- Keep crate rename / single-binary architecture as future cleanup, not part of this ticket.
---
<!-- event: implementation_report author: hare at: 2026-05-31T02:14:28Z -->
## Implementation report
Implementation report from coder Pod `workspace-memory-lint-coder-20260531`:
- Branch: `workspace-memory-lint-cli`
- Commit: `7a717f2d259563df562913e0c3ceb388b094b697` (`cli: add workspace memory lint`)
- Added `insomnia memory lint [--workspace <PATH>] [--json] [--warnings-as-errors]` as a headless mode in the existing `tui` crate/user-facing `insomnia` binary.
- `insomnia memory` alone remains a positional Pod name.
- The lint command resolves workspace root, collects existing summary/decisions/requests/knowledge records through `memory::WorkspaceLayout`, and lints with existing `memory::Linter` using `WriteMode::Update`.
- The command prints deterministic human output by default and stable JSON with workspace/files/errors/warnings/counts when `--json` is requested.
- Exit codes follow the ticket: 0 clean, 1 lint failures or warnings-as-errors, 2 usage/I/O/output/runtime failures.
- The headless path returns before raw terminal setup or Pod connection/spawn logic.
Validation reported by coder:
- `cargo fmt --check` passed
- `cargo test -p tui memory_lint -- --nocapture` passed
- `cargo test -p tui` passed
- `cargo check -p tui` passed
- `./tickets.sh doctor` passed
- `git diff --check` passed
Unresolved issues: none.
---
<!-- event: review author: hare at: 2026-05-31T02:14:28Z status: approve -->
## Review: approve
External review by reviewer Pod `workspace-memory-lint-reviewer-rerun-20260531`: approve.
The original reviewer Pod `workspace-memory-lint-reviewer-20260531` became non-visible to the parent before output could be recovered; this review was rerun with a replacement read-only reviewer Pod.
Reviewer summary:
- The implementation adds `insomnia memory lint` as a headless mode in the existing user-facing `insomnia` binary.
- The memory lint path branches before raw terminal setup and Pod connection/spawn logic.
- Parser tests preserve `insomnia memory` as positional Pod name behavior.
- The collector targets summary, decisions, requests, and knowledge records while ignoring opaque memory subsystem directories and workflow files.
- Existing `memory::Linter` and `WriteMode::Update` are used, and the code only reads files / writes reports.
- Human and JSON outputs are deterministic enough for the ticket, and exit code mapping matches requirements.
Blockers: none.
Non-blocking follow-ups:
- Add broader fixture coverage for `_staging`, `_usage`, knowledge, and decisions if desired.
- Add process-level exit-code integration tests if a CLI test harness is introduced later.
Validation adequacy: coder-reported validation is sufficient for this ticket. Reviewer additionally checked `git diff --check develop...HEAD` read-only.
---
<!-- event: implementation_report author: hare at: 2026-05-31T02:15:16Z -->
## Implementation report
Main workspace validation after merge:
- `cargo fmt --check` passed
- `cargo test -p tui memory_lint -- --nocapture` passed (10 passed)
- `cargo test -p tui` passed (224 passed)
- `cargo check -p tui` passed with pre-existing dead-code warnings in `llm-worker` and `tui`
- `./tickets.sh doctor` passed
- `git diff --check` passed
---
<!-- event: close author: hare at: 2026-05-31T02:15:17Z status: closed -->
## Closed
Implemented `insomnia memory lint` as a headless command in the existing user-facing `insomnia` binary. The command lints workspace memory/knowledge records with the existing `memory::Linter` using `WriteMode::Update`, supports human and JSON output, handles warnings-as-errors, preserves `insomnia memory` as a positional Pod name, and returns before TUI/raw-terminal or Pod connection paths. External review approved and validation passed.
---
@@ -0,0 +1,69 @@
---
id: 20260527-000020-system-reminder-injection-generalization
slug: system-reminder-injection-generalization
title: Generalize system-reminder history append lane
status: closed
kind: task
priority: P2
labels: [pod, llm-worker, history, system-reminder]
created_at: 2026-05-27T00:00:20Z
updated_at: 2026-05-29T05:05:43Z
assignee: null
legacy_ticket: null
---
## Background
`session-todo-reminder` established the first concrete `<system-reminder>...</system-reminder>` user: Task inactivity reminders are appended through `pending_history_appends` so the reminder is persisted in `worker.history` before the next LLM request. This follows the context-processing rule that new non-volatile input must be appended to history rather than injected only into request context.
The current implementation should now be generalized so future reminder producers do not each hand-roll XML tags, `SystemItem` construction, source labeling, cooldown/priority plumbing, or history-append integration.
This ticket is about making the system-reminder append lane a small typed facility. It is not about adding new reminder policies beyond existing Task reminders.
## Requirements
- Introduce a typed internal representation for pending system reminders.
- text/body
- source/kind, e.g. task inactivity
- optional priority/order key if needed
- helper that renders the body inside `<system-reminder>...</system-reminder>` exactly once
- Route reminders through the existing `Interceptor::pending_history_appends` lane.
- The final result must still be `Item::System(SystemItem { kind: InvokeKind::SystemReminder, ... })` or equivalent current protocol type.
- The reminder must be appended to `worker.history`; do not introduce hidden request-only context injection.
- Refactor `session-todo-reminder` to use this typed helper/facility.
- Task reminder behavior, thresholds, cooldown, and tests should remain unchanged.
- The helper should prevent double-wrapping if the body is already tagged, or the API should make double-wrapping impossible.
- Keep `Notify` / `PodEvent` behavior unchanged.
- Do not merge raw notify and system reminder semantics.
- If they share buffering mechanics, keep the public behavior and rendered tags distinct.
- Keep ordering deterministic.
- If multiple reminder producers are added later, ordering should be explicit or stable.
- For now, existing Task reminder order relative to Notify/PodEvent should be preserved unless there is a clear reason to change it.
- Add docs/comments near the facility explaining the rule:
- system reminders are durable input and must be appended through history.
- they are not transient UI notices.
- they are not prompt-cache/context-only injections.
## Acceptance criteria
- There is a typed system-reminder helper/facility rather than ad-hoc string construction in Task reminder code.
- Task inactivity reminders still appear as `<system-reminder>...</system-reminder>` in `pending_history_appends` output.
- The helper emits `InvokeKind::SystemReminder` / current system-reminder item kind.
- Existing Task reminder tests continue to pass.
- New focused tests cover:
- rendering wraps body once.
- source/kind is retained or observable where appropriate.
- Task reminder uses the helper and remains history-append based.
- no hidden context-only injection path is introduced.
- `cargo fmt --check`
- `cargo check -p pod -p llm-worker -p session-store`
- Relevant focused tests, e.g. `cargo test -p pod reminder --no-default-features`.
## Out of scope
- Adding a second reminder policy.
- Changing Task reminder thresholds/cooldown.
- Changing Notify/PodEvent user-visible behavior.
- UI actionbar notices.
- Prompt text changes.
- Generic notification center or reminder scheduling service.
@@ -0,0 +1,69 @@
---
id: 20260527-000020-system-reminder-injection-generalization
slug: system-reminder-injection-generalization
title: Generalize system-reminder history append lane
status: closed
kind: task
priority: P2
labels: [pod, llm-worker, history, system-reminder]
created_at: 2026-05-27T00:00:20Z
updated_at: 2026-05-29T05:05:43Z
assignee: null
legacy_ticket: null
---
## Background
`session-todo-reminder` established the first concrete `<system-reminder>...</system-reminder>` user: Task inactivity reminders are appended through `pending_history_appends` so the reminder is persisted in `worker.history` before the next LLM request. This follows the context-processing rule that new non-volatile input must be appended to history rather than injected only into request context.
The current implementation should now be generalized so future reminder producers do not each hand-roll XML tags, `SystemItem` construction, source labeling, cooldown/priority plumbing, or history-append integration.
This ticket is about making the system-reminder append lane a small typed facility. It is not about adding new reminder policies beyond existing Task reminders.
## Requirements
- Introduce a typed internal representation for pending system reminders.
- text/body
- source/kind, e.g. task inactivity
- optional priority/order key if needed
- helper that renders the body inside `<system-reminder>...</system-reminder>` exactly once
- Route reminders through the existing `Interceptor::pending_history_appends` lane.
- The final result must still be `Item::System(SystemItem { kind: InvokeKind::SystemReminder, ... })` or equivalent current protocol type.
- The reminder must be appended to `worker.history`; do not introduce hidden request-only context injection.
- Refactor `session-todo-reminder` to use this typed helper/facility.
- Task reminder behavior, thresholds, cooldown, and tests should remain unchanged.
- The helper should prevent double-wrapping if the body is already tagged, or the API should make double-wrapping impossible.
- Keep `Notify` / `PodEvent` behavior unchanged.
- Do not merge raw notify and system reminder semantics.
- If they share buffering mechanics, keep the public behavior and rendered tags distinct.
- Keep ordering deterministic.
- If multiple reminder producers are added later, ordering should be explicit or stable.
- For now, existing Task reminder order relative to Notify/PodEvent should be preserved unless there is a clear reason to change it.
- Add docs/comments near the facility explaining the rule:
- system reminders are durable input and must be appended through history.
- they are not transient UI notices.
- they are not prompt-cache/context-only injections.
## Acceptance criteria
- There is a typed system-reminder helper/facility rather than ad-hoc string construction in Task reminder code.
- Task inactivity reminders still appear as `<system-reminder>...</system-reminder>` in `pending_history_appends` output.
- The helper emits `InvokeKind::SystemReminder` / current system-reminder item kind.
- Existing Task reminder tests continue to pass.
- New focused tests cover:
- rendering wraps body once.
- source/kind is retained or observable where appropriate.
- Task reminder uses the helper and remains history-append based.
- no hidden context-only injection path is introduced.
- `cargo fmt --check`
- `cargo check -p pod -p llm-worker -p session-store`
- Relevant focused tests, e.g. `cargo test -p pod reminder --no-default-features`.
## Out of scope
- Adding a second reminder policy.
- Changing Task reminder thresholds/cooldown.
- Changing Notify/PodEvent user-visible behavior.
- UI actionbar notices.
- Prompt text changes.
- Generic notification center or reminder scheduling service.
@@ -0,0 +1,84 @@
<!-- event: migration author: tickets.sh-migration at: 2026-05-27T00:00:20Z -->
## Migrated
Migrated from TODO.md entry without a legacy ticket file. No legacy review file was present at migration time.
---
<!-- event: close author: hare at: 2026-05-29T05:05:43Z status: closed -->
## Closed
---
id: 20260527-000020-system-reminder-injection-generalization
slug: system-reminder-injection-generalization
title: Generalize system-reminder history append lane
status: closed
kind: task
priority: P2
labels: [pod, llm-worker, history, system-reminder]
created_at: 2026-05-27T00:00:20Z
updated_at: 2026-05-29T05:05:43Z
assignee: null
legacy_ticket: null
---
## Background
`session-todo-reminder` established the first concrete `<system-reminder>...</system-reminder>` user: Task inactivity reminders are appended through `pending_history_appends` so the reminder is persisted in `worker.history` before the next LLM request. This follows the context-processing rule that new non-volatile input must be appended to history rather than injected only into request context.
The current implementation should now be generalized so future reminder producers do not each hand-roll XML tags, `SystemItem` construction, source labeling, cooldown/priority plumbing, or history-append integration.
This ticket is about making the system-reminder append lane a small typed facility. It is not about adding new reminder policies beyond existing Task reminders.
## Requirements
- Introduce a typed internal representation for pending system reminders.
- text/body
- source/kind, e.g. task inactivity
- optional priority/order key if needed
- helper that renders the body inside `<system-reminder>...</system-reminder>` exactly once
- Route reminders through the existing `Interceptor::pending_history_appends` lane.
- The final result must still be `Item::System(SystemItem { kind: InvokeKind::SystemReminder, ... })` or equivalent current protocol type.
- The reminder must be appended to `worker.history`; do not introduce hidden request-only context injection.
- Refactor `session-todo-reminder` to use this typed helper/facility.
- Task reminder behavior, thresholds, cooldown, and tests should remain unchanged.
- The helper should prevent double-wrapping if the body is already tagged, or the API should make double-wrapping impossible.
- Keep `Notify` / `PodEvent` behavior unchanged.
- Do not merge raw notify and system reminder semantics.
- If they share buffering mechanics, keep the public behavior and rendered tags distinct.
- Keep ordering deterministic.
- If multiple reminder producers are added later, ordering should be explicit or stable.
- For now, existing Task reminder order relative to Notify/PodEvent should be preserved unless there is a clear reason to change it.
- Add docs/comments near the facility explaining the rule:
- system reminders are durable input and must be appended through history.
- they are not transient UI notices.
- they are not prompt-cache/context-only injections.
## Acceptance criteria
- There is a typed system-reminder helper/facility rather than ad-hoc string construction in Task reminder code.
- Task inactivity reminders still appear as `<system-reminder>...</system-reminder>` in `pending_history_appends` output.
- The helper emits `InvokeKind::SystemReminder` / current system-reminder item kind.
- Existing Task reminder tests continue to pass.
- New focused tests cover:
- rendering wraps body once.
- source/kind is retained or observable where appropriate.
- Task reminder uses the helper and remains history-append based.
- no hidden context-only injection path is introduced.
- `cargo fmt --check`
- `cargo check -p pod -p llm-worker -p session-store`
- Relevant focused tests, e.g. `cargo test -p pod reminder --no-default-features`.
## Out of scope
- Adding a second reminder policy.
- Changing Task reminder thresholds/cooldown.
- Changing Notify/PodEvent user-visible behavior.
- UI actionbar notices.
- Prompt text changes.
- Generic notification center or reminder scheduling service.
---
@@ -0,0 +1,28 @@
---
id: 20260527-000021-bash-tool-editing-guidance
slug: bash-tool-editing-guidance
title: Bashツールがファイル編集に常用されている問題をdesciptionで抑制
status: closed
kind: task
priority: P2
labels: [migrated]
created_at: 2026-05-27T00:00:21Z
updated_at: 2026-05-31T22:36:34Z
assignee: null
legacy_ticket: null
---
## Migration reference
- legacy_ticket: null
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# Bashツールがファイル編集に常用されている問題をdesciptionで抑制
## Background
This work item was migrated from an unfinished TODO.md entry that did not have a dedicated legacy ticket file.
## Acceptance criteria
- Define the concrete requirements before implementation.
@@ -0,0 +1 @@
Closed without implementation for now. Current Bash tool description already nudges agents toward Read/Edit/Glob/Grep over shell-based file edits, and this is not urgent enough to carry as an active work item. If the behavior becomes a recurring problem, reopen as a focused prompt-description polish ticket covering Bash child processes such as cat/tee/sed/perl/python rewrites.
@@ -0,0 +1,16 @@
<!-- event: migration author: tickets.sh-migration at: 2026-05-27T00:00:21Z -->
## Migrated
Migrated from TODO.md entry without a legacy ticket file. No legacy review file was present at migration time.
---
<!-- event: close author: hare at: 2026-05-31T22:36:34Z status: closed -->
## Closed
Closed without implementation for now. Current Bash tool description already nudges agents toward Read/Edit/Glob/Grep over shell-based file edits, and this is not urgent enough to carry as an active work item. If the behavior becomes a recurring problem, reopen as a focused prompt-description polish ticket covering Bash child processes such as cat/tee/sed/perl/python rewrites.
---
@@ -0,0 +1,116 @@
---
id: 20260527-000022-manifest-profiles
slug: manifest-profiles
title: Nix profile entrypoints that resolve to portable Pod manifests
status: closed
kind: feature
priority: P2
labels: [manifest, profiles, nix, tui]
created_at: 2026-05-27T00:00:22Z
updated_at: 2026-05-29T17:45:59Z
assignee: null
legacy_ticket: null
---
## Migration reference
- legacy_ticket: null
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# Nix profile entrypoints that resolve to portable Pod manifests
## Background
This work item was migrated from an unfinished TODO.md entry:
> 事前定義したManifestをProfile的に扱い、Orchestrator/Coder/Researcherで別々のモデル/設定を使わせる運用ができるようにする
The current manifest cascade is good at configuration defaults by location: built-in defaults, user manifest, workspace manifest, and explicit overlays. That is less suitable for operational role selection. Users want to choose between profiles such as Orchestrator, Coder, Researcher, Reviewer, or cheap/fast variants, and they want those profiles to be portable as a pure artifact rather than assembled implicitly from several ambient layers.
Another problem is authoring ergonomics. The current manifest exposes many low-level numeric parameters that require implementation-specific intuition, such as compaction thresholds, pruning protection sizes, memory thresholds, and feature-specific token limits. Profiles should let users express high-level intent and reusable presets while the resolver produces the precise runtime manifest.
## Related work
- `work-items/open/20260529-145355-manifest-profile-encrypted-secrets/item.md`: profiles should integrate with explicit encrypted secret references so API keys/tokens are not limited to process environment variables.
## Design direction
Use Nix as the default human-authored profile format. A profile is a Nix expression that produces the final Pod manifest/configuration artifact through an Insomnia-provided `mkProfile` / `mkManifest` style library.
The profile itself is the source of truth. Commonality, imports, role presets, and any cascade-like behavior should be expressed in Nix by the profile author instead of being implemented as an additional ambient manifest cascade in Insomnia.
The runtime boundary should be:
```text
selected Nix profile + explicit startup inputs
=> deterministic resolved manifest/config snapshot
=> Pod runtime
```
Do not introduce a three-layer authoring model where Nix generates TOML profiles that then merge into TOML manifests. That would make manifest/profile/Nix ownership unclear and hard to operate. Rust should consume the resolved artifact, ideally as a typed JSON/config representation, and preserve a snapshot for Pod restore.
## Requirements
- Add a Nix-based profile entrypoint as the default path for new Pod creation.
- Provide an Insomnia Nix library with `mkProfile` / `mkManifest` helpers.
- The helper should produce a pure resolved manifest/config artifact that Rust can deserialize and validate.
- Profile authors may use Nix imports/functions to share common settings, implement their own cascade, or build role presets.
- Treat the resolved manifest/config as the runtime contract.
- Persist the selected profile identity/source and the resolved snapshot in Pod/session metadata.
- Pod resume should prefer the saved resolved snapshot, not silently re-evaluate the Nix profile.
- Re-evaluating a profile for an existing Pod must be explicit because it may change model, tools, permissions, or thresholds.
- Move role-oriented authoring into profiles.
- Support profiles for roles such as Orchestrator, Coder, Researcher, Reviewer, and cost/performance variants.
- Profiles should be able to select model/provider settings, prompts, tools, permissions, memory behavior, web/search behavior, workflows, skills, and context/compaction strategy.
- Prefer semantic presets in the Nix library for values that are difficult to tune by raw numbers, e.g. context budget, compaction behavior, retention, autonomy, and tool policy.
- Keep raw low-level numeric overrides available as an advanced escape hatch, not the primary user-facing interface.
- Shrink ambient cascade to discovery/default selection rather than runtime config merging.
- User/project configuration may provide profile registries, aliases, defaults, and UI preferences.
- User/project configuration should not be required as intermediate runtime override layers for model IDs, compaction thresholds, or other behavior controlled by the selected profile.
- Existing TOML manifest cascade can remain as compatibility/debug/test infrastructure, but it should not be the main profile design.
- Add profile discovery and selection UX.
- New Pod creation UI should show a selectable profile field such as `profile: coder (default)`.
- The profile picker should list built-in/user/project/explicit profiles with enough source/default information to avoid ambiguity.
- CLI/TUI should support explicit profile selection by name/source and by path/flakeref where appropriate.
- Ambiguous profile names should fail closed or require source-qualified selection rather than being implicitly merged.
- Keep secrets as references, not plaintext values.
- Nix profiles may refer to credentials using typed secret references, e.g. `secrets.ref "brave.search.default"`.
- Nix evaluation output, resolved config serialization, diagnostics, session logs, and model context must not contain plaintext secrets.
- Secret dereferencing/decryption happens in Rust at the consumer boundary.
- Define compatibility and fallback behavior.
- `--manifest` / TOML manifest loading may continue to work for compatibility, tests, fixtures, and low-level debugging.
- If Nix is unavailable, diagnostics should clearly say that profile resolution requires Nix and point to the manifest/resolved-config fallback path.
- Existing manifest behavior should not be broken until the Nix profile path is implemented and documented.
## Open design points
- Exact Nix entrypoint shape:
- flake output names, e.g. `insomniaProfiles.<name>` / `profiles.<name>`
- path-based profiles, e.g. `.insomnia/profiles/coder/profile.nix`
- whether both are supported initially
- Exact Rust-facing artifact:
- JSON resolved config vs TOML manifest snapshot vs a new typed `ResolvedPodConfig`
- whether `PodManifest` remains the final runtime type or becomes the legacy/compatibility representation
- Profile registry/default storage:
- where user-level profile aliases live
- where project-level defaults live
- how built-in profiles are exposed
- How much Nix support is external-command based initially vs embedded/library-integrated later.
- How profile summaries are generated for the new Pod UI without exposing low-level internals or secrets.
## Acceptance criteria
- A Nix profile can be selected when creating a new Pod and resolves to the complete runtime manifest/config for that Pod.
- Insomnia provides a documented `mkProfile` / `mkManifest` Nix helper for producing a valid resolved profile artifact.
- Profile authors can share common settings and implement cascade-like composition in Nix without relying on ambient user/project manifest merging.
- New Pod UI includes profile selection and displays the effective default, e.g. `profile: coder (default)`.
- CLI/TUI profile selection supports at least one explicit path/flakeref flow and one discovered-name/default flow.
- Resolved profile artifacts are validated with clear diagnostics before Pod creation.
- Pod/session metadata persists the selected profile identity/source and the resolved snapshot.
- Pod resume uses the persisted resolved snapshot unless the user explicitly asks to reload/re-resolve the profile.
- Secret references are preserved as references through Nix evaluation and resolved config; plaintext secrets are not written to config snapshots, logs, diagnostics, or model context.
- Existing TOML manifest path remains available as a compatibility/debug/test path during the migration.
- Documentation explains the new profile model, why ambient cascade is no longer the primary runtime config mechanism, and how users should structure reusable Nix profiles.
- Focused tests cover Nix profile resolution, validation errors, profile default/source selection, ambiguity handling, snapshot persistence, and no-plaintext secret serialization paths.
- `cargo fmt --check`
- Relevant manifest/profile/pod/tui tests pass.
@@ -0,0 +1,116 @@
---
id: 20260527-000022-manifest-profiles
slug: manifest-profiles
title: Nix profile entrypoints that resolve to portable Pod manifests
status: closed
kind: feature
priority: P2
labels: [manifest, profiles, nix, tui]
created_at: 2026-05-27T00:00:22Z
updated_at: 2026-05-29T17:45:59Z
assignee: null
legacy_ticket: null
---
## Migration reference
- legacy_ticket: null
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# Nix profile entrypoints that resolve to portable Pod manifests
## Background
This work item was migrated from an unfinished TODO.md entry:
> 事前定義したManifestをProfile的に扱い、Orchestrator/Coder/Researcherで別々のモデル/設定を使わせる運用ができるようにする
The current manifest cascade is good at configuration defaults by location: built-in defaults, user manifest, workspace manifest, and explicit overlays. That is less suitable for operational role selection. Users want to choose between profiles such as Orchestrator, Coder, Researcher, Reviewer, or cheap/fast variants, and they want those profiles to be portable as a pure artifact rather than assembled implicitly from several ambient layers.
Another problem is authoring ergonomics. The current manifest exposes many low-level numeric parameters that require implementation-specific intuition, such as compaction thresholds, pruning protection sizes, memory thresholds, and feature-specific token limits. Profiles should let users express high-level intent and reusable presets while the resolver produces the precise runtime manifest.
## Related work
- `work-items/open/20260529-145355-manifest-profile-encrypted-secrets/item.md`: profiles should integrate with explicit encrypted secret references so API keys/tokens are not limited to process environment variables.
## Design direction
Use Nix as the default human-authored profile format. A profile is a Nix expression that produces the final Pod manifest/configuration artifact through an Insomnia-provided `mkProfile` / `mkManifest` style library.
The profile itself is the source of truth. Commonality, imports, role presets, and any cascade-like behavior should be expressed in Nix by the profile author instead of being implemented as an additional ambient manifest cascade in Insomnia.
The runtime boundary should be:
```text
selected Nix profile + explicit startup inputs
=> deterministic resolved manifest/config snapshot
=> Pod runtime
```
Do not introduce a three-layer authoring model where Nix generates TOML profiles that then merge into TOML manifests. That would make manifest/profile/Nix ownership unclear and hard to operate. Rust should consume the resolved artifact, ideally as a typed JSON/config representation, and preserve a snapshot for Pod restore.
## Requirements
- Add a Nix-based profile entrypoint as the default path for new Pod creation.
- Provide an Insomnia Nix library with `mkProfile` / `mkManifest` helpers.
- The helper should produce a pure resolved manifest/config artifact that Rust can deserialize and validate.
- Profile authors may use Nix imports/functions to share common settings, implement their own cascade, or build role presets.
- Treat the resolved manifest/config as the runtime contract.
- Persist the selected profile identity/source and the resolved snapshot in Pod/session metadata.
- Pod resume should prefer the saved resolved snapshot, not silently re-evaluate the Nix profile.
- Re-evaluating a profile for an existing Pod must be explicit because it may change model, tools, permissions, or thresholds.
- Move role-oriented authoring into profiles.
- Support profiles for roles such as Orchestrator, Coder, Researcher, Reviewer, and cost/performance variants.
- Profiles should be able to select model/provider settings, prompts, tools, permissions, memory behavior, web/search behavior, workflows, skills, and context/compaction strategy.
- Prefer semantic presets in the Nix library for values that are difficult to tune by raw numbers, e.g. context budget, compaction behavior, retention, autonomy, and tool policy.
- Keep raw low-level numeric overrides available as an advanced escape hatch, not the primary user-facing interface.
- Shrink ambient cascade to discovery/default selection rather than runtime config merging.
- User/project configuration may provide profile registries, aliases, defaults, and UI preferences.
- User/project configuration should not be required as intermediate runtime override layers for model IDs, compaction thresholds, or other behavior controlled by the selected profile.
- Existing TOML manifest cascade can remain as compatibility/debug/test infrastructure, but it should not be the main profile design.
- Add profile discovery and selection UX.
- New Pod creation UI should show a selectable profile field such as `profile: coder (default)`.
- The profile picker should list built-in/user/project/explicit profiles with enough source/default information to avoid ambiguity.
- CLI/TUI should support explicit profile selection by name/source and by path/flakeref where appropriate.
- Ambiguous profile names should fail closed or require source-qualified selection rather than being implicitly merged.
- Keep secrets as references, not plaintext values.
- Nix profiles may refer to credentials using typed secret references, e.g. `secrets.ref "brave.search.default"`.
- Nix evaluation output, resolved config serialization, diagnostics, session logs, and model context must not contain plaintext secrets.
- Secret dereferencing/decryption happens in Rust at the consumer boundary.
- Define compatibility and fallback behavior.
- `--manifest` / TOML manifest loading may continue to work for compatibility, tests, fixtures, and low-level debugging.
- If Nix is unavailable, diagnostics should clearly say that profile resolution requires Nix and point to the manifest/resolved-config fallback path.
- Existing manifest behavior should not be broken until the Nix profile path is implemented and documented.
## Open design points
- Exact Nix entrypoint shape:
- flake output names, e.g. `insomniaProfiles.<name>` / `profiles.<name>`
- path-based profiles, e.g. `.insomnia/profiles/coder/profile.nix`
- whether both are supported initially
- Exact Rust-facing artifact:
- JSON resolved config vs TOML manifest snapshot vs a new typed `ResolvedPodConfig`
- whether `PodManifest` remains the final runtime type or becomes the legacy/compatibility representation
- Profile registry/default storage:
- where user-level profile aliases live
- where project-level defaults live
- how built-in profiles are exposed
- How much Nix support is external-command based initially vs embedded/library-integrated later.
- How profile summaries are generated for the new Pod UI without exposing low-level internals or secrets.
## Acceptance criteria
- A Nix profile can be selected when creating a new Pod and resolves to the complete runtime manifest/config for that Pod.
- Insomnia provides a documented `mkProfile` / `mkManifest` Nix helper for producing a valid resolved profile artifact.
- Profile authors can share common settings and implement cascade-like composition in Nix without relying on ambient user/project manifest merging.
- New Pod UI includes profile selection and displays the effective default, e.g. `profile: coder (default)`.
- CLI/TUI profile selection supports at least one explicit path/flakeref flow and one discovered-name/default flow.
- Resolved profile artifacts are validated with clear diagnostics before Pod creation.
- Pod/session metadata persists the selected profile identity/source and the resolved snapshot.
- Pod resume uses the persisted resolved snapshot unless the user explicitly asks to reload/re-resolve the profile.
- Secret references are preserved as references through Nix evaluation and resolved config; plaintext secrets are not written to config snapshots, logs, diagnostics, or model context.
- Existing TOML manifest path remains available as a compatibility/debug/test path during the migration.
- Documentation explains the new profile model, why ambient cascade is no longer the primary runtime config mechanism, and how users should structure reusable Nix profiles.
- Focused tests cover Nix profile resolution, validation errors, profile default/source selection, ambiguity handling, snapshot persistence, and no-plaintext secret serialization paths.
- `cargo fmt --check`
- Relevant manifest/profile/pod/tui tests pass.
@@ -0,0 +1,250 @@
<!-- event: migration author: tickets.sh-migration at: 2026-05-27T00:00:22Z -->
## Migrated
Migrated from TODO.md entry without a legacy ticket file. No legacy review file was present at migration time.
---
<!-- event: plan author: hare at: 2026-05-29T16:09:27Z -->
## Plan
Implementation will proceed through a child orchestrator Pod in a dedicated worktree as an experiment in nested Pod delegation.
Initial implementation target:
- Introduce Nix profile resolution as a new manifest source before the existing manifest cascade.
- Start with explicit path-based profiles; discovered-name/default selection and rich TUI picker can be staged after the core resolver if necessary.
- Provide a minimal bundled Nix helper that can produce a typed resolved manifest/config artifact.
- Keep existing TOML manifest loading as compatibility/debug/test infrastructure.
- Persist enough profile identity and resolved snapshot data for future restore semantics; do not silently re-evaluate profiles on resume.
- Secret values must remain references only; plaintext secrets are out of scope for the profile resolver.
The child orchestrator may split implementation among sub-Pods, but final merge/close remains parent-side.
---
<!-- event: review author: hare at: 2026-05-29T16:52:47Z status: approve -->
## Review: approve
Reviewed the nested Pod implementation from branch `work/nix-manifest-profiles`.
Result: approved after blocking fix.
Findings:
- Initial review found one blocking issue: `--profile` rejected non-empty `INSOMNIA_USER_MANIFEST`. That contradicted the profile design because a selected Nix profile is a standalone runtime config artifact and ambient user/project manifest cascade should not affect it.
- The child orchestrator fixed this in commit `c9a175a fix: ignore user manifest for profiles` and added `profile_ignores_non_empty_user_manifest_env` without invoking real Nix.
- Profile foundation is intentionally a vertical slice: explicit path-based Nix profile resolution, minimal Nix helper, CLI/TUI spawn entrypoints, resolved snapshot metadata, and restore-from-snapshot behavior. Rich discovery/default picker remains future work.
Validation run by reviewer:
- `cargo fmt --check`
- `cargo test -p manifest profile -- --nocapture`
- `cargo test -p pod --bin insomnia-pod profile -- --nocapture`
- `cargo check -p session-store -p manifest -p pod -p client -p tui -p provider`
- `cargo check -p pod -p tui`
- `git diff --check`
- Manual `nix eval --json --file` smoke check for `resources/nix/profile-lib.nix`
Non-blocking follow-up candidates:
- Hide or narrow `ResolvedProfile::raw_artifact` if future call sites might log/persist accidental raw Nix output.
- Add a timeout around `nix eval` so profile startup cannot hang indefinitely.
- Validate direct `client::SpawnConfig` construction that combines `profile_path` with `resume_from`; TUI currently avoids it.
- Build richer profile discovery/default selection and the full TUI profile picker.
---
<!-- event: plan author: hare at: 2026-05-29T16:59:41Z -->
## Plan
Continue implementation beyond the merged Nix profile foundation. The previous nested delegation stopped at a reviewable vertical slice; this phase should keep iterating until the work item acceptance criteria are materially closer to completion or a real blocker is found.
Phase 2 target:
- Add profile discovery/default selection instead of requiring only explicit `--profile <path>`.
- Support discovered-name selection with source disambiguation where needed, e.g. builtin/user/project/path semantics.
- Add or substantially advance the new Pod profile selection UX so a default can be displayed as `profile: coder (default)` and changed before spawn.
- Preserve the core design: selected Nix profile resolves to a standalone manifest/config artifact; ambient user/project manifests do not merge into it.
- Keep Pod resume using resolved snapshots rather than silent Nix re-evaluation.
- Keep secrets as references only.
The delegated orchestrator should not return merely because one slice is reviewable. It should internally review acceptance criteria, delegate sub-Pods as needed, and continue with the next reachable slice unless it hits a concrete design or technical blocker. Parent-side merge/close remains reserved for this parent Pod.
---
<!-- event: review author: hare at: 2026-05-29T17:44:47Z status: approve -->
## Review: approve
Reviewed phase 2 implementation from branch `work/nix-manifest-profiles-phase2`.
Result: approved after two parent-review fixes.
Implemented scope:
- Profile registry/discovery for builtin/user/project sources.
- `[profiles]` metadata in user/project manifests for discovery/default/alias only; it is not merged into the selected runtime manifest.
- `--profile` selector parsing for explicit paths, `path:<path>`, discovered names, `default`, and source-qualified names such as `project:coder`.
- Ambiguous unqualified discovered names fail closed.
- TUI fresh-spawn UI now shows a selectable `profile:` row, uses discovered choices, marks defaults, and includes `manifest cascade` as opt-out.
- SpawnConfig passes selected profiles to `insomnia-pod --profile`; resume/attach paths do not re-evaluate profiles.
- Docs and focused tests updated.
Parent review findings fixed by child orchestrator:
1. Unqualified alias targets initially resolved globally. Fixed so aliases declared in a source resolve unqualified targets within that declaring source by default.
2. Defaults pointing at aliases initially did not mark the resolved target entry as default, causing TUI to fall back to `manifest cascade`. Fixed by resolving the default through `select_named()` before setting `is_default` flags.
Validation run by parent reviewer:
- `cargo fmt --check`
- `cargo check`
- `cargo test -p manifest profile -- --nocapture`
- `cargo test -p tui spawn -- --nocapture`
- `cargo test -p pod profile -- --nocapture`
- `cargo test -p client spawn -- --nocapture`
- `git diff --check`
All passed. Full `cargo test` was run by the child orchestrator and failed only in the unrelated existing/flaky `llm-worker` parallel timing test class.
Remaining polish/follow-up candidates, not blockers for this work item:
- A richer popup-style profile picker instead of inline cycling.
- Actual bundled builtin profile files once default builtin semantics are decided.
- `nix eval` timeout/robustness follow-up.
- Encrypted secret store integration remains tracked by the related encrypted-secrets work item.
---
<!-- event: close author: hare at: 2026-05-29T17:45:59Z status: closed -->
## Closed
---
id: 20260527-000022-manifest-profiles
slug: manifest-profiles
title: Nix profile entrypoints that resolve to portable Pod manifests
status: closed
kind: feature
priority: P2
labels: [manifest, profiles, nix, tui]
created_at: 2026-05-27T00:00:22Z
updated_at: 2026-05-29T17:45:59Z
assignee: null
legacy_ticket: null
---
## Migration reference
- legacy_ticket: null
- migrated_from: TODO.md / tickets directory migration on 2026-05-27
# Nix profile entrypoints that resolve to portable Pod manifests
## Background
This work item was migrated from an unfinished TODO.md entry:
> 事前定義したManifestをProfile的に扱い、Orchestrator/Coder/Researcherで別々のモデル/設定を使わせる運用ができるようにする
The current manifest cascade is good at configuration defaults by location: built-in defaults, user manifest, workspace manifest, and explicit overlays. That is less suitable for operational role selection. Users want to choose between profiles such as Orchestrator, Coder, Researcher, Reviewer, or cheap/fast variants, and they want those profiles to be portable as a pure artifact rather than assembled implicitly from several ambient layers.
Another problem is authoring ergonomics. The current manifest exposes many low-level numeric parameters that require implementation-specific intuition, such as compaction thresholds, pruning protection sizes, memory thresholds, and feature-specific token limits. Profiles should let users express high-level intent and reusable presets while the resolver produces the precise runtime manifest.
## Related work
- `work-items/open/20260529-145355-manifest-profile-encrypted-secrets/item.md`: profiles should integrate with explicit encrypted secret references so API keys/tokens are not limited to process environment variables.
## Design direction
Use Nix as the default human-authored profile format. A profile is a Nix expression that produces the final Pod manifest/configuration artifact through an Insomnia-provided `mkProfile` / `mkManifest` style library.
The profile itself is the source of truth. Commonality, imports, role presets, and any cascade-like behavior should be expressed in Nix by the profile author instead of being implemented as an additional ambient manifest cascade in Insomnia.
The runtime boundary should be:
```text
selected Nix profile + explicit startup inputs
=> deterministic resolved manifest/config snapshot
=> Pod runtime
```
Do not introduce a three-layer authoring model where Nix generates TOML profiles that then merge into TOML manifests. That would make manifest/profile/Nix ownership unclear and hard to operate. Rust should consume the resolved artifact, ideally as a typed JSON/config representation, and preserve a snapshot for Pod restore.
## Requirements
- Add a Nix-based profile entrypoint as the default path for new Pod creation.
- Provide an Insomnia Nix library with `mkProfile` / `mkManifest` helpers.
- The helper should produce a pure resolved manifest/config artifact that Rust can deserialize and validate.
- Profile authors may use Nix imports/functions to share common settings, implement their own cascade, or build role presets.
- Treat the resolved manifest/config as the runtime contract.
- Persist the selected profile identity/source and the resolved snapshot in Pod/session metadata.
- Pod resume should prefer the saved resolved snapshot, not silently re-evaluate the Nix profile.
- Re-evaluating a profile for an existing Pod must be explicit because it may change model, tools, permissions, or thresholds.
- Move role-oriented authoring into profiles.
- Support profiles for roles such as Orchestrator, Coder, Researcher, Reviewer, and cost/performance variants.
- Profiles should be able to select model/provider settings, prompts, tools, permissions, memory behavior, web/search behavior, workflows, skills, and context/compaction strategy.
- Prefer semantic presets in the Nix library for values that are difficult to tune by raw numbers, e.g. context budget, compaction behavior, retention, autonomy, and tool policy.
- Keep raw low-level numeric overrides available as an advanced escape hatch, not the primary user-facing interface.
- Shrink ambient cascade to discovery/default selection rather than runtime config merging.
- User/project configuration may provide profile registries, aliases, defaults, and UI preferences.
- User/project configuration should not be required as intermediate runtime override layers for model IDs, compaction thresholds, or other behavior controlled by the selected profile.
- Existing TOML manifest cascade can remain as compatibility/debug/test infrastructure, but it should not be the main profile design.
- Add profile discovery and selection UX.
- New Pod creation UI should show a selectable profile field such as `profile: coder (default)`.
- The profile picker should list built-in/user/project/explicit profiles with enough source/default information to avoid ambiguity.
- CLI/TUI should support explicit profile selection by name/source and by path/flakeref where appropriate.
- Ambiguous profile names should fail closed or require source-qualified selection rather than being implicitly merged.
- Keep secrets as references, not plaintext values.
- Nix profiles may refer to credentials using typed secret references, e.g. `secrets.ref "brave.search.default"`.
- Nix evaluation output, resolved config serialization, diagnostics, session logs, and model context must not contain plaintext secrets.
- Secret dereferencing/decryption happens in Rust at the consumer boundary.
- Define compatibility and fallback behavior.
- `--manifest` / TOML manifest loading may continue to work for compatibility, tests, fixtures, and low-level debugging.
- If Nix is unavailable, diagnostics should clearly say that profile resolution requires Nix and point to the manifest/resolved-config fallback path.
- Existing manifest behavior should not be broken until the Nix profile path is implemented and documented.
## Open design points
- Exact Nix entrypoint shape:
- flake output names, e.g. `insomniaProfiles.<name>` / `profiles.<name>`
- path-based profiles, e.g. `.insomnia/profiles/coder/profile.nix`
- whether both are supported initially
- Exact Rust-facing artifact:
- JSON resolved config vs TOML manifest snapshot vs a new typed `ResolvedPodConfig`
- whether `PodManifest` remains the final runtime type or becomes the legacy/compatibility representation
- Profile registry/default storage:
- where user-level profile aliases live
- where project-level defaults live
- how built-in profiles are exposed
- How much Nix support is external-command based initially vs embedded/library-integrated later.
- How profile summaries are generated for the new Pod UI without exposing low-level internals or secrets.
## Acceptance criteria
- A Nix profile can be selected when creating a new Pod and resolves to the complete runtime manifest/config for that Pod.
- Insomnia provides a documented `mkProfile` / `mkManifest` Nix helper for producing a valid resolved profile artifact.
- Profile authors can share common settings and implement cascade-like composition in Nix without relying on ambient user/project manifest merging.
- New Pod UI includes profile selection and displays the effective default, e.g. `profile: coder (default)`.
- CLI/TUI profile selection supports at least one explicit path/flakeref flow and one discovered-name/default flow.
- Resolved profile artifacts are validated with clear diagnostics before Pod creation.
- Pod/session metadata persists the selected profile identity/source and the resolved snapshot.
- Pod resume uses the persisted resolved snapshot unless the user explicitly asks to reload/re-resolve the profile.
- Secret references are preserved as references through Nix evaluation and resolved config; plaintext secrets are not written to config snapshots, logs, diagnostics, or model context.
- Existing TOML manifest path remains available as a compatibility/debug/test path during the migration.
- Documentation explains the new profile model, why ambient cascade is no longer the primary runtime config mechanism, and how users should structure reusable Nix profiles.
- Focused tests cover Nix profile resolution, validation errors, profile default/source selection, ambiguity handling, snapshot persistence, and no-plaintext secret serialization paths.
- `cargo fmt --check`
- Relevant manifest/profile/pod/tui tests pass.
---
@@ -0,0 +1,118 @@
---
id: 20260527-000023-multi-pod-view-ui
slug: multi-pod-view-ui
title: Multi-Pod view UI
status: closed
kind: task
priority: P2
labels: [tui, pod]
created_at: 2026-05-27T00:00:23Z
updated_at: 2026-05-28T16:09:01Z
assignee: null
legacy_ticket: null
---
## Background
This work item was migrated from an unfinished TODO.md entry that did not have a dedicated legacy ticket file.
The direction is to make TUI capable of treating multiple Pods as first-class targets instead of forcing the operator to attach/open one Pod at a time before sending input. The main view should be able to show live Pods by status, show stopped Pod history entries, and keep an editable composer available while the user moves selection across Pods.
This ticket is downstream of the shared TUI Pod list/view abstraction. The concrete multi-Pod view requirements should be defined after the common list/view model exists, so this ticket can focus on view switching and interaction policy rather than inventing another Pod list representation.
## Prerequisite
- `20260528-141602-tui-pod-list-view-abstraction`
## CLI entrypoint
- Add `tui --multi` as the explicit entrypoint for the multi-Pod dashboard.
- Do not change `tui -r` / `tui --resume` semantics; those remain the resume picker.
- Do not add a short `-m` alias yet.
- `--multi` conflicts with direct single-Pod/session selectors for this ticket:
- positional pod name
- `--pod <name>`
- `--session <UUID>`
- `-r` / `--resume`
- `--socket`
- Initial selected Pod for `--multi --pod <name>` is out of scope; add it later if the UX needs it.
## Current implementation notes
Current TUI is essentially single-Pod oriented:
- `crates/tui/src/main.rs` starts one `PodClient` and the event loop sends composer input to that attached Pod.
- `App` owns one conversation/history view, one composer, and one local queued-input state for the currently attached Pod.
- The existing picker can list/restore/attach Pods, but choosing an entry transitions the TUI into that Pod rather than keeping a multi-Pod dashboard active.
- Live/stopped Pod discovery already exists around picker/discovery code, and should be reused through the prerequisite abstraction rather than duplicated in this ticket.
Because of this, multi-Pod view should be designed as a new TUI mode/state over the shared Pod list abstraction, not as a small tweak to the current single attached-Pod event loop.
## Desired UX direction
The multi-Pod view should center on a Pod list and a persistent composer:
- Live Pods are grouped or visibly categorized by status.
- waiting / idle Pods: ready to receive input.
- working / running Pods: currently processing; input should not be sent as another immediate `Method::Run` unless the protocol can accept it.
- paused Pods: distinguish from both idle and working.
- Stopped Pods are shown as history/restorable entries.
- They are visible for review/restore/open actions.
- Direct message send is disabled until an explicit restore/attach/create flow exists for that entry.
- The text area/composer remains visible and retains its contents while the selected Pod changes.
- The selected Pod is the current send target.
- The UI must show the target Pod name/status near the composer so a message cannot be sent to the wrong Pod silently.
- Sending to an idle live Pod should be possible without opening/attaching that Pod as the main conversation view.
- Sending should clear the composer only after delivery is accepted or otherwise reported as queued according to the rule below.
- For a working/running Pod, the initial behavior should be conservative.
- Do not blindly issue `Method::Run` and surface `AlreadyRunning` as normal UX.
- Either disable direct send with an actionbar diagnostic, or implement target-specific local queueing that sends when that Pod becomes idle.
- If queueing is implemented, queues must be per-Pod, visibly attached to the target, and should not reuse the current single-Pod composer queue implicitly.
## Requirements
- Add the `tui --multi` CLI entrypoint and reject conflicting single-Pod/session selectors.
- Build on the completed `tui-pod-list-view-abstraction` for row/state/source modeling.
- Add or design a TUI mode for multi-Pod view that can show:
- live idle/waiting Pods.
- live working/running Pods.
- paused Pods.
- stopped/restorable Pod history entries.
- Preserve a composer/text area while the selection changes.
- Support direct send to the selected idle live Pod without switching the whole TUI into that Pod view.
- Delivery must use the same safety expectations as other socket send paths: no fire-and-forget success, and no connect-time `Alert` / `Snapshot` deadlock.
- Failed delivery must leave the text in the composer or an explicit per-target queue.
- Define interaction for non-idle targets.
- running: disabled or per-target queued.
- paused: resume/continue action is separate from normal send unless protocol semantics are explicitly defined.
- stopped: restore/open action is separate from send.
- Keep the single-Pod conversation view available.
- Opening/attaching a selected Pod remains an explicit action.
- Direct send from multi-Pod view must not imply that the selected Pod's full history is now loaded as the main conversation view.
- Avoid host-wide visibility expansion.
- The list source must be explicit and must respect the visibility model decided by the prerequisite ticket.
## Acceptance criteria
- `tui --multi` starts the multi-Pod view, and conflicting CLI argument combinations are rejected with clear errors.
- Multi-Pod view requirements are implemented against the shared Pod list/view abstraction, not a separate list model.
- The view can render live Pods with idle/running/paused distinctions and stopped/restorable history entries.
- A persistent composer remains available while moving selection.
- Sending from the composer targets the selected idle live Pod without opening it as the main conversation view.
- Non-idle and stopped targets have explicit, safe UX behavior.
- Delivery failure does not lose user input.
- The UI clearly indicates the selected send target and status.
- Existing single-Pod TUI attach/resume behavior continues to work.
- Tests cover selection-to-target mapping, disabled/queued non-idle behavior, and composer preservation across selection changes.
- `cargo fmt --check`
- `cargo check -p tui -p client -p pod`
- Relevant focused tests for TUI state/model behavior.
## Out of scope
- Implementing the prerequisite Pod list/view abstraction itself.
- Child Pod panel completion (`20260527-000017-tui-spawned-pod-panel`).
- Host-wide Pod browser.
- Changing Pod visibility, permission, registry, or discovery authority.
- Protocol changes for accepting concurrent user messages while a Pod is already running.
- Native GUI.
@@ -0,0 +1,118 @@
---
id: 20260527-000023-multi-pod-view-ui
slug: multi-pod-view-ui
title: Multi-Pod view UI
status: closed
kind: task
priority: P2
labels: [tui, pod]
created_at: 2026-05-27T00:00:23Z
updated_at: 2026-05-28T16:09:01Z
assignee: null
legacy_ticket: null
---
## Background
This work item was migrated from an unfinished TODO.md entry that did not have a dedicated legacy ticket file.
The direction is to make TUI capable of treating multiple Pods as first-class targets instead of forcing the operator to attach/open one Pod at a time before sending input. The main view should be able to show live Pods by status, show stopped Pod history entries, and keep an editable composer available while the user moves selection across Pods.
This ticket is downstream of the shared TUI Pod list/view abstraction. The concrete multi-Pod view requirements should be defined after the common list/view model exists, so this ticket can focus on view switching and interaction policy rather than inventing another Pod list representation.
## Prerequisite
- `20260528-141602-tui-pod-list-view-abstraction`
## CLI entrypoint
- Add `tui --multi` as the explicit entrypoint for the multi-Pod dashboard.
- Do not change `tui -r` / `tui --resume` semantics; those remain the resume picker.
- Do not add a short `-m` alias yet.
- `--multi` conflicts with direct single-Pod/session selectors for this ticket:
- positional pod name
- `--pod <name>`
- `--session <UUID>`
- `-r` / `--resume`
- `--socket`
- Initial selected Pod for `--multi --pod <name>` is out of scope; add it later if the UX needs it.
## Current implementation notes
Current TUI is essentially single-Pod oriented:
- `crates/tui/src/main.rs` starts one `PodClient` and the event loop sends composer input to that attached Pod.
- `App` owns one conversation/history view, one composer, and one local queued-input state for the currently attached Pod.
- The existing picker can list/restore/attach Pods, but choosing an entry transitions the TUI into that Pod rather than keeping a multi-Pod dashboard active.
- Live/stopped Pod discovery already exists around picker/discovery code, and should be reused through the prerequisite abstraction rather than duplicated in this ticket.
Because of this, multi-Pod view should be designed as a new TUI mode/state over the shared Pod list abstraction, not as a small tweak to the current single attached-Pod event loop.
## Desired UX direction
The multi-Pod view should center on a Pod list and a persistent composer:
- Live Pods are grouped or visibly categorized by status.
- waiting / idle Pods: ready to receive input.
- working / running Pods: currently processing; input should not be sent as another immediate `Method::Run` unless the protocol can accept it.
- paused Pods: distinguish from both idle and working.
- Stopped Pods are shown as history/restorable entries.
- They are visible for review/restore/open actions.
- Direct message send is disabled until an explicit restore/attach/create flow exists for that entry.
- The text area/composer remains visible and retains its contents while the selected Pod changes.
- The selected Pod is the current send target.
- The UI must show the target Pod name/status near the composer so a message cannot be sent to the wrong Pod silently.
- Sending to an idle live Pod should be possible without opening/attaching that Pod as the main conversation view.
- Sending should clear the composer only after delivery is accepted or otherwise reported as queued according to the rule below.
- For a working/running Pod, the initial behavior should be conservative.
- Do not blindly issue `Method::Run` and surface `AlreadyRunning` as normal UX.
- Either disable direct send with an actionbar diagnostic, or implement target-specific local queueing that sends when that Pod becomes idle.
- If queueing is implemented, queues must be per-Pod, visibly attached to the target, and should not reuse the current single-Pod composer queue implicitly.
## Requirements
- Add the `tui --multi` CLI entrypoint and reject conflicting single-Pod/session selectors.
- Build on the completed `tui-pod-list-view-abstraction` for row/state/source modeling.
- Add or design a TUI mode for multi-Pod view that can show:
- live idle/waiting Pods.
- live working/running Pods.
- paused Pods.
- stopped/restorable Pod history entries.
- Preserve a composer/text area while the selection changes.
- Support direct send to the selected idle live Pod without switching the whole TUI into that Pod view.
- Delivery must use the same safety expectations as other socket send paths: no fire-and-forget success, and no connect-time `Alert` / `Snapshot` deadlock.
- Failed delivery must leave the text in the composer or an explicit per-target queue.
- Define interaction for non-idle targets.
- running: disabled or per-target queued.
- paused: resume/continue action is separate from normal send unless protocol semantics are explicitly defined.
- stopped: restore/open action is separate from send.
- Keep the single-Pod conversation view available.
- Opening/attaching a selected Pod remains an explicit action.
- Direct send from multi-Pod view must not imply that the selected Pod's full history is now loaded as the main conversation view.
- Avoid host-wide visibility expansion.
- The list source must be explicit and must respect the visibility model decided by the prerequisite ticket.
## Acceptance criteria
- `tui --multi` starts the multi-Pod view, and conflicting CLI argument combinations are rejected with clear errors.
- Multi-Pod view requirements are implemented against the shared Pod list/view abstraction, not a separate list model.
- The view can render live Pods with idle/running/paused distinctions and stopped/restorable history entries.
- A persistent composer remains available while moving selection.
- Sending from the composer targets the selected idle live Pod without opening it as the main conversation view.
- Non-idle and stopped targets have explicit, safe UX behavior.
- Delivery failure does not lose user input.
- The UI clearly indicates the selected send target and status.
- Existing single-Pod TUI attach/resume behavior continues to work.
- Tests cover selection-to-target mapping, disabled/queued non-idle behavior, and composer preservation across selection changes.
- `cargo fmt --check`
- `cargo check -p tui -p client -p pod`
- Relevant focused tests for TUI state/model behavior.
## Out of scope
- Implementing the prerequisite Pod list/view abstraction itself.
- Child Pod panel completion (`20260527-000017-tui-spawned-pod-panel`).
- Host-wide Pod browser.
- Changing Pod visibility, permission, registry, or discovery authority.
- Protocol changes for accepting concurrent user messages while a Pod is already running.
- Native GUI.
@@ -0,0 +1,133 @@
<!-- event: migration author: tickets.sh-migration at: 2026-05-27T00:00:23Z -->
## Migrated
Migrated from TODO.md entry without a legacy ticket file. No legacy review file was present at migration time.
---
<!-- event: close author: hare at: 2026-05-28T16:09:01Z status: closed -->
## Closed
---
id: 20260527-000023-multi-pod-view-ui
slug: multi-pod-view-ui
title: Multi-Pod view UI
status: closed
kind: task
priority: P2
labels: [tui, pod]
created_at: 2026-05-27T00:00:23Z
updated_at: 2026-05-28T16:09:01Z
assignee: null
legacy_ticket: null
---
## Background
This work item was migrated from an unfinished TODO.md entry that did not have a dedicated legacy ticket file.
The direction is to make TUI capable of treating multiple Pods as first-class targets instead of forcing the operator to attach/open one Pod at a time before sending input. The main view should be able to show live Pods by status, show stopped Pod history entries, and keep an editable composer available while the user moves selection across Pods.
This ticket is downstream of the shared TUI Pod list/view abstraction. The concrete multi-Pod view requirements should be defined after the common list/view model exists, so this ticket can focus on view switching and interaction policy rather than inventing another Pod list representation.
## Prerequisite
- `20260528-141602-tui-pod-list-view-abstraction`
## CLI entrypoint
- Add `tui --multi` as the explicit entrypoint for the multi-Pod dashboard.
- Do not change `tui -r` / `tui --resume` semantics; those remain the resume picker.
- Do not add a short `-m` alias yet.
- `--multi` conflicts with direct single-Pod/session selectors for this ticket:
- positional pod name
- `--pod <name>`
- `--session <UUID>`
- `-r` / `--resume`
- `--socket`
- Initial selected Pod for `--multi --pod <name>` is out of scope; add it later if the UX needs it.
## Current implementation notes
Current TUI is essentially single-Pod oriented:
- `crates/tui/src/main.rs` starts one `PodClient` and the event loop sends composer input to that attached Pod.
- `App` owns one conversation/history view, one composer, and one local queued-input state for the currently attached Pod.
- The existing picker can list/restore/attach Pods, but choosing an entry transitions the TUI into that Pod rather than keeping a multi-Pod dashboard active.
- Live/stopped Pod discovery already exists around picker/discovery code, and should be reused through the prerequisite abstraction rather than duplicated in this ticket.
Because of this, multi-Pod view should be designed as a new TUI mode/state over the shared Pod list abstraction, not as a small tweak to the current single attached-Pod event loop.
## Desired UX direction
The multi-Pod view should center on a Pod list and a persistent composer:
- Live Pods are grouped or visibly categorized by status.
- waiting / idle Pods: ready to receive input.
- working / running Pods: currently processing; input should not be sent as another immediate `Method::Run` unless the protocol can accept it.
- paused Pods: distinguish from both idle and working.
- Stopped Pods are shown as history/restorable entries.
- They are visible for review/restore/open actions.
- Direct message send is disabled until an explicit restore/attach/create flow exists for that entry.
- The text area/composer remains visible and retains its contents while the selected Pod changes.
- The selected Pod is the current send target.
- The UI must show the target Pod name/status near the composer so a message cannot be sent to the wrong Pod silently.
- Sending to an idle live Pod should be possible without opening/attaching that Pod as the main conversation view.
- Sending should clear the composer only after delivery is accepted or otherwise reported as queued according to the rule below.
- For a working/running Pod, the initial behavior should be conservative.
- Do not blindly issue `Method::Run` and surface `AlreadyRunning` as normal UX.
- Either disable direct send with an actionbar diagnostic, or implement target-specific local queueing that sends when that Pod becomes idle.
- If queueing is implemented, queues must be per-Pod, visibly attached to the target, and should not reuse the current single-Pod composer queue implicitly.
## Requirements
- Add the `tui --multi` CLI entrypoint and reject conflicting single-Pod/session selectors.
- Build on the completed `tui-pod-list-view-abstraction` for row/state/source modeling.
- Add or design a TUI mode for multi-Pod view that can show:
- live idle/waiting Pods.
- live working/running Pods.
- paused Pods.
- stopped/restorable Pod history entries.
- Preserve a composer/text area while the selection changes.
- Support direct send to the selected idle live Pod without switching the whole TUI into that Pod view.
- Delivery must use the same safety expectations as other socket send paths: no fire-and-forget success, and no connect-time `Alert` / `Snapshot` deadlock.
- Failed delivery must leave the text in the composer or an explicit per-target queue.
- Define interaction for non-idle targets.
- running: disabled or per-target queued.
- paused: resume/continue action is separate from normal send unless protocol semantics are explicitly defined.
- stopped: restore/open action is separate from send.
- Keep the single-Pod conversation view available.
- Opening/attaching a selected Pod remains an explicit action.
- Direct send from multi-Pod view must not imply that the selected Pod's full history is now loaded as the main conversation view.
- Avoid host-wide visibility expansion.
- The list source must be explicit and must respect the visibility model decided by the prerequisite ticket.
## Acceptance criteria
- `tui --multi` starts the multi-Pod view, and conflicting CLI argument combinations are rejected with clear errors.
- Multi-Pod view requirements are implemented against the shared Pod list/view abstraction, not a separate list model.
- The view can render live Pods with idle/running/paused distinctions and stopped/restorable history entries.
- A persistent composer remains available while moving selection.
- Sending from the composer targets the selected idle live Pod without opening it as the main conversation view.
- Non-idle and stopped targets have explicit, safe UX behavior.
- Delivery failure does not lose user input.
- The UI clearly indicates the selected send target and status.
- Existing single-Pod TUI attach/resume behavior continues to work.
- Tests cover selection-to-target mapping, disabled/queued non-idle behavior, and composer preservation across selection changes.
- `cargo fmt --check`
- `cargo check -p tui -p client -p pod`
- Relevant focused tests for TUI state/model behavior.
## Out of scope
- Implementing the prerequisite Pod list/view abstraction itself.
- Child Pod panel completion (`20260527-000017-tui-spawned-pod-panel`).
- Host-wide Pod browser.
- Changing Pod visibility, permission, registry, or discovery authority.
- Protocol changes for accepting concurrent user messages while a Pod is already running.
- Native GUI.
---
@@ -0,0 +1,35 @@
---
id: 20260527-194421-pod-orchestration-system-guidance
slug: pod-orchestration-system-guidance
title: Pod orchestration tool availability に応じた system guidance
status: closed
kind: feature
priority: P2
labels: [pod, workflow, prompt]
created_at: 2026-05-27T19:44:21Z
updated_at: 2026-06-01T01:24:59Z
assignee: null
legacy_ticket: null
---
## Background
Child Pod completion/status notifications are delivered as non-blocking background signals. Parent Pods that have Pod management tools should treat notifications for Pods they spawned as actionable orchestration state, but should not block the active turn merely to wait for output.
Current guidance is too weak: agents may either ignore routine child-Pod follow-up until the user asks, or waste a turn with `sleep`/polling while waiting for a notification. The desired behavior is notification-driven follow-up at a natural stopping point.
Prompt text belongs under `resources/prompts`; Rust code should only assemble it conditionally.
## Acceptance criteria
- Pod management toolsが有効な Worker の system prompt に orchestration guidance が含まれる。
- Pod management tools が無効な Worker には含まれない。
- prompt 本文が `resources/prompts` にある。
- guidance includes:
- spawned Pod notifications are background signals the parent should handle at a natural stopping point;
- the parent does not need to keep a turn open or call tools solely to wait for a notification;
- do not use `sleep`/polling loops just to wait for Pod output;
- read child output/diff/test evidence before treating delegated work as complete;
- do not start scheduler/auto-maintain behavior or bypass user/workflow authorization.
- Prompt assembly tests cover conditional inclusion/exclusion.
- Related focused tests and `cargo fmt --check` pass.
@@ -0,0 +1,18 @@
Merged and completed.
Implementation:
- Added resource-backed Pod orchestration guidance at `resources/prompts/common/pod-orchestration.md`.
- Registered the guidance through the prompt catalog and internal prompt resources.
- Added conditional system prompt assembly based on registered Pod-management tool names.
- Guidance is included for Workers with Pod management tools and omitted otherwise.
- Guidance explicitly says Pod notifications are background signals handled at natural stopping points, that the parent does not need to keep a turn open solely to wait, and that agents should not use `sleep`/polling loops just to wait for Pod output.
- Guidance also preserves evidence-before-completion and no scheduler/authorization-bypass constraints.
Review:
- External reviewer approved with no blockers.
Validation after merge:
- `cargo test -p pod pod_orchestration` passed.
- `cargo test -p pod prompt::catalog` passed.
- `cargo fmt --check` passed.
- `./tickets.sh doctor` passed.
@@ -0,0 +1,177 @@
<!-- event: create author: tickets.sh at: 2026-05-27T19:44:21Z -->
## Created
Created by tickets.sh create.
---
<!-- event: plan author: orchestrator at: 2026-05-27T19:44:43Z -->
## Plan
## Background
Pod notification / notice によって child Pod の完了や状態変化が見えても、現状の assistant はユーザーから明示的に「レビューして」「確認して」と言われるまで自発的に消化しないことがある。
AGENTS.md や workflow に multi-agent の運用は書かれているが、これは知識として読めるだけで、Pod 管理ツールが利用可能な turn における runtime 行動規範としては弱い。特に、自分が spawn した child Pod の完了通知は background signal として扱い、自然な区切りで `ReadPodOutput` / worktree status / diff / test を確認して次の action に進むべきである。
一方で、notification は non-blocking であり、進行中の user request を不必要に中断してまで消化すべきではない。system instruction には「自発的に follow-up するが、現在の user task を壊さない」というバランスを明示する必要がある。
## Requirements
- Pod management tools が有効な Worker にだけ、Pod orchestration 用の system guidance を注入する。
- 例: `SpawnPod` / `ReadPodOutput` / `SendToPod` / `StopPod` / `AttachOrRestorePod` などが利用可能な場合。
- Pod 管理 tool がない通常 Worker / child Pod には不要な guidance を出さない。
- guidance 本文は `resources/prompts` 配下に置く。
- prompt 文字列を Rust code に直書きしない。
- guidance には以下を含める。
- Pod notification / notice は、自分が処理すべき background signal として扱う。
- 自分が spawn した child Pod の完了通知を受けたら、自然な区切りで `ReadPodOutput` を確認する。
- 委譲 task が完了していれば、報告・worktree status・diff・test 結果を確認し、修正依頼 / merge / ticket 完了処理 / Pod 停止のいずれかに進む。
- user が明示的に follow-up を要求するまで routine follow-up を放置しない。
- ただし進行中の user request を不用意に中断しない。
- output / diff / test を確認せずに完了扱いしない。
- この guidance は scheduler / auto-maintainer ではない。
- workflow を勝手に開始しない。
- project decision / merge / cleanup は既存 workflow と user authorization に従う。
- notification / PodEvent を context に載せる場合は、既存の history 永続化原則を破らない。
- turn を跨げない情報を history に残さず system context にだけ差し込まない。
## Acceptance criteria
- Pod management tools が有効な Worker の system prompt に orchestration guidance が含まれる。
- Pod management tools が無効な Worker には含まれない。
- prompt 本文が `resources/prompts` にある。
- prompt assembly の test で conditional inclusion が確認されている。
- guidance が user request の中断を促さず、natural stopping point での follow-up を促す文言になっている。
- `cargo fmt --check` と関連 crate の test が通る。
## Out of scope
- 自動 scheduler / auto-maintain loop の実装。
- PodEvent / notification の protocol 変更。
- spawned Pod registry restore の修正。
- TUI notification UI の変更。
---
<!-- event: comment author: hare at: 2026-06-01T00:57:03Z -->
## Comment
## Supplemental guidance from dogfooding
Add two explicit rules to the Pod orchestration/system guidance:
- A spawned Pod completion notification is delivered as a normal background signal. The parent does not need to keep the turn open or call tools solely to wait for it; it is acceptable to finish the current turn and handle the notification at the next natural point.
- Do not use `sleep`/polling loops just to wait for a Pod's output. If there is no other useful immediate work, return control to the user instead of blocking the turn; when the notification arrives, read the Pod output then.
Rationale: during multi-agent work, waiting with `sleep` wastes the active turn and fights the notification model. The desired behavior is notification-driven follow-up, not artificial polling.
---
<!-- event: plan author: hare at: 2026-06-01T01:10:57Z -->
## Plan
## Preflight classification
implementation-ready.
The ticket affects prompt/system guidance and conditional prompt assembly, but the desired product behavior is already specified in the ticket thread and item: include orchestration guidance only when Pod management tools are available, keep the prose in `resources/prompts`, and explicitly avoid `sleep`/polling or turn-blocking waits for child Pod output.
## Current code map
- `resources/prompts/`: prompt text sources; new guidance text should live here.
- Prompt assembly code/tests: locate the system prompt construction path that already conditionally includes memory/workflow/tool guidance and add a tool-availability gate for Pod orchestration guidance.
- Tool registry / available tool list: use existing tool availability rather than hard-coding a Worker kind if possible.
- Existing prompt assembly tests: add inclusion/exclusion coverage for Pod management tools available/unavailable.
## Requirements / invariants
- Guidance is conditional on Pod management tools being available.
- Guidance is not shown to Workers without Pod management tools.
- Guidance must not imply an auto scheduler or unauthorized workflow start.
- Guidance must say notifications can be handled at the next natural point and the parent need not keep the turn open just to wait.
- Guidance must say not to use `sleep`/polling loops merely to wait for Pod output.
- Do not change PodEvent/notification protocol, TUI notification UI, spawned registry restore, or workflow semantics.
## Escalate if
- The only available hook requires injecting notification-derived context without durable history.
- Conditional tool-availability detection would require broad ToolRegistry redesign.
- The implementation would change runtime notification delivery or Pod lifecycle behavior instead of prompt guidance.
## Validation
- Focused prompt assembly tests for conditional inclusion/exclusion.
- Any touched crate tests relevant to prompt loading/assembly.
- `cargo fmt --check`.
---
<!-- event: review author: hare at: 2026-06-01T01:24:27Z status: approve -->
## Review: approve
External reviewer recommendation: approve.
Summary:
- Static Pod orchestration guidance was added under `resources/prompts/common/pod-orchestration.md` and registered through the prompt catalog.
- The guidance is appended to the materialized system prompt only when available tool names include Pod-management capabilities.
- The gate uses registered tool definitions, not Worker kind, matching the ticket boundary.
- The prompt explicitly covers background notifications, natural stopping points, not keeping a turn open solely to wait, no `sleep`/polling loops for Pod output, evidence-before-completion, and no scheduler/authorization bypass.
Intent / requirement mapping:
- Included when Pod management tools are enabled: satisfied.
- Omitted when Pod management tools are disabled: satisfied.
- Prompt body lives under `resources/prompts`: satisfied.
- Conditional prompt assembly tests exist: satisfied.
Invariant check:
- No changes to PodEvent/notification protocol, TUI notification UI, spawned registry restore, Pod lifecycle behavior, scheduler/auto-maintain behavior, or notification-derived context injection.
- The implementation adds static guidance based on durable tool availability, not transient notification state.
Blockers: none.
Non-blocking follow-ups:
- A future small test could pin the intended "any Pod-management tool is enough" semantics with a single representative tool.
- Tool-name class recognition could be centralized later if more prompt gates need it.
Reported validation from coder was considered sufficient:
- `cargo test -p pod pod_orchestration`
- `cargo test -p pod prompt::catalog`
- `cargo fmt --check`
---
<!-- event: close author: hare at: 2026-06-01T01:24:59Z status: closed -->
## Closed
Merged and completed.
Implementation:
- Added resource-backed Pod orchestration guidance at `resources/prompts/common/pod-orchestration.md`.
- Registered the guidance through the prompt catalog and internal prompt resources.
- Added conditional system prompt assembly based on registered Pod-management tool names.
- Guidance is included for Workers with Pod management tools and omitted otherwise.
- Guidance explicitly says Pod notifications are background signals handled at natural stopping points, that the parent does not need to keep a turn open solely to wait, and that agents should not use `sleep`/polling loops just to wait for Pod output.
- Guidance also preserves evidence-before-completion and no scheduler/authorization-bypass constraints.
Review:
- External reviewer approved with no blockers.
Validation after merge:
- `cargo test -p pod pod_orchestration` passed.
- `cargo test -p pod prompt::catalog` passed.
- `cargo fmt --check` passed.
- `./tickets.sh doctor` passed.
---
@@ -0,0 +1,21 @@
---
id: 20260527-201313-openai-responses-unhandled-sse-observability
slug: openai-responses-unhandled-sse-observability
title: OpenAI Responses 未対応 SSE event を破棄せず観測する
status: closed
kind: feature
priority: P1
labels: [llm, openai, observability, trace]
created_at: 2026-05-27T20:13:13Z
updated_at: 2026-05-27T20:44:19Z
assignee: null
legacy_ticket: null
---
## Background
Created by tickets.sh.
## Acceptance criteria
- TBD
@@ -0,0 +1,21 @@
---
id: 20260527-201313-openai-responses-unhandled-sse-observability
slug: openai-responses-unhandled-sse-observability
title: OpenAI Responses 未対応 SSE event を破棄せず観測する
status: closed
kind: feature
priority: P1
labels: [llm, openai, observability, trace]
created_at: 2026-05-27T20:13:13Z
updated_at: 2026-05-27T20:44:19Z
assignee: null
legacy_ticket: null
---
## Background
Created by tickets.sh.
## Acceptance criteria
- TBD
@@ -0,0 +1,95 @@
<!-- event: create author: tickets.sh at: 2026-05-27T20:13:13Z -->
## Created
Created by tickets.sh create.
---
<!-- event: plan author: orchestrator at: 2026-05-27T20:13:30Z -->
## Plan
## Background
OpenAI Responses parser currently drops unsupported SSE event types by falling through to `_ => Ok(Vec::new())`. That means provider events that do not yet have a match arm are neither visible in stream trace nor preserved as diagnostics. This made it impossible to inspect the "unexpected event" class of logs after the fact.
Recent work preserved diagnostics for known error-like event types (`response.failed`, `response.incomplete`, top-level `error`), but it did not cover event types that are not matched at all. We need observability for those raw/unhandled SSE frames without turning them into conversation history or model-visible content.
## Requirements
- OpenAI Responses SSE event types that are not otherwise handled must be observable.
- Do not silently return `Ok(Vec::new())` without any traceable signal.
- Include the raw `event_type` and a bounded preview of `data`.
- Include full data length so truncation is visible.
- The signal must be visible in existing stream trace when `[session].record_event_trace = true`.
- The signal must not become assistant/user history and must not be sent back to the model as normal content.
- Timeline / collectors must ignore the signal for generation semantics.
- Known intentionally ignorable events may be classified separately if needed, but they must still be observable enough for debugging.
- Add tests for at least one unknown OpenAI Responses event type.
- Existing `unknown_event_is_ignored` should be replaced or updated.
- Verify event type and data preview are retained.
- Verify large data is bounded / marked by length.
## Suggested implementation shape
A small normalized event variant is acceptable, for example:
```rust
Event::UnhandledSse {
provider: "openai_responses",
event_type: String,
data_preview: String,
data_len: usize,
}
```
or equivalent. If adding a generic variant to `llm_client::event::Event`, make sure Timeline ignores it and trace serialization captures it.
Avoid plumbing raw SSE into session history. This is observability only.
## Acceptance criteria
- Unknown OpenAI Responses SSE event types appear in trace output instead of disappearing.
- Timeline semantics / assistant output are unchanged for unknown events.
- Large raw data is capped in the event payload but original byte length is recorded.
- Focused tests pass for OpenAI Responses parser and Timeline behavior if touched.
- `cargo fmt --check` and related crate tests pass.
## Out of scope
- Implementing semantics for every OpenAI Responses event type.
- Retrying or changing behavior based on unknown events.
- Raw SSE frame permanent audit log separate from trace.
---
<!-- event: close author: hare at: 2026-05-27T20:44:19Z status: closed -->
## Closed
---
id: 20260527-201313-openai-responses-unhandled-sse-observability
slug: openai-responses-unhandled-sse-observability
title: OpenAI Responses 未対応 SSE event を破棄せず観測する
status: closed
kind: feature
priority: P1
labels: [llm, openai, observability, trace]
created_at: 2026-05-27T20:13:13Z
updated_at: 2026-05-27T20:44:19Z
assignee: null
legacy_ticket: null
---
## Background
Created by tickets.sh.
## Acceptance criteria
- TBD
---
@@ -0,0 +1,143 @@
---
id: 20260528-001748-compact-session-log-exploration
slug: compact-session-log-exploration
title: Compact: session log 探索型の要約入力に変更する
status: closed
kind: task
priority: P2
labels: [compact, session-log]
created_at: 2026-05-28T00:17:48Z
updated_at: 2026-05-28T03:41:42Z
assignee: null
legacy_ticket: null
---
# Compact: session log 探索型の要約入力に変更する
## 背景
`insomnia-troubleshoot` Pod の手動 compact で、Compact Worker が入力トークン上限に到達して停止した。現行実装は `Pod::compact` で retained tail より前の `items_to_summarise``build_summary_input()` に渡し、`build_summary_prompt()` が user / assistant / system message と tool result summary を `## Conversation` に連結して Compact Worker の初回 input に載せている。
raw tool output や reasoning は落としているが、長い session では pruned transcript だけでも `compact_worker_max_input_tokens` を超える。Compact の目的は「全履歴を読ませる」ことではなく、次セッションに必要な構造化要約と file auto-read/reference を作ることなので、初期 input は軽量 overview に留め、必要箇所は Compact Worker が session log / workspace file を探索して確認できる形にする。
また、Compact Worker の健全性は「初期 input が小さいこと」だけでは保証できない。探索 tool の結果、assistant 出力、`write_summary` 呼び出しまでを含む Compact Worker 全体の context と、compact 後に作られる新 session 初期 context を別々に制御する必要がある。
## 方針
Compact Worker の初期 context は、全文 transcript ではなく決定的に生成した session overview / index を渡す。LLM には探索空間を狭めた上で、必要な session log 範囲や workspace file を tool で読む権限を与える。
基本方針:
- 初期 input は User / Assistant / System の継続に必要な情報を中心に、target size 内の overview として生成する。
- 初期 overview が target を超えた程度で compact を失敗させない。warning / trace に記録して続行する。
- 初期 overview deadline は通常運用の調整値ではなく、想定外の入力生成バグを検出する最悪ケースの安全網とする。deadline 超過時は、可能ならより粗い overview へ fallback し、それでも最低限の入力を作れない場合だけ失敗する。
- ToolCall / ToolResult は初期 input では本文を展開しない。
- tool 名、summary、対象 path、成否、大きな出力の有無、session log 上の位置などの index に留める。
- Compact Worker は session log の必要箇所を探索・再読できる。
- Compact Worker の探索量は、session-log/file-read 個別の総量 budget ではなく、Compact Worker session 全体の context budget で制御する。
- Compact Worker context が上限に近づいたら、`mark_read_required` とは独立に「探索を切り上げて `write_summary` へ進め」という勧告を Worker に渡し、人間にも警告を出す。
- 最終 summary と closing turn のための reserve を確保し、reserve を食い潰すほど大きい tool result は残 budget に合わせて抑制・切り詰め・再読指示にする。
- AutoRead 判断のため、workspace file は現行通り `read_file` で確認し、必要なものだけ `mark_read_required` / `add_reference` する。
- AutoRead budget は Compact Worker の探索 budget ではなく、compact 後の新 session 初期 context に注入される file content の合計上限として扱う。
- Compact Worker の出力は現行と同じく structured summary + auto-read + references を生成する。
## Compact Worker / compaction parameters
`[compaction]` 配下では `compact_` prefix を新規 parameter 名につけない。既存の `compact_*` key は、この ticket の実装時に同じ意味の prefix なし key へ整理する。
必要な parameter:
- `retained_tokens`
- compact 後に verbatim で残す history tail の token budget。
- `overview_target_tokens`
- 初期 overview / index 生成器が目指す通常サイズ。超過しても即失敗しない。
- `overview_warning_tokens`
- 初期 overview が想定より大きいことを記録・警告する閾値。compact は続行する。
- `overview_deadline_tokens`
- 初期 overview の最悪ケース deadline。超過時はより粗い overview へ deterministic fallback し、それでも無理な場合だけ compact を失敗させる。
- `worker_context_max_tokens`
- Compact Worker session 全体の context hard limit。system prompt、overview、assistant output、tool calls/results、session-log/file read results、`write_summary` 周辺の蓄積を含む。
- `finish_warning_remaining_tokens`
- 残り context がこの値以下になったら、Compact Worker に探索切り上げと `write_summary` を促す勧告を入れる。
- `final_reserve_tokens`
- 最終 summary と closing turn のために残す reserve。これを割り込みそうな tool result は full content を返さず、range 縮小や summary への移行を促す。
- `worker_max_turns`
- Compact Worker の tool-loop 最大 turn 数。budget 制御とは別の runaway guard。
- `summary_target_tokens`
- `write_summary` text の目標サイズ。prompt / nudge に使う。
- `summary_max_tokens`
- `write_summary` text の hard validation。超過した summary は縮約を促すか compact 成功扱いにしない。
- `auto_read_budget_tokens`
- `mark_read_required` によって compact 後の新 session に注入される file content の合計 token budget。
- `result_context_max_tokens`
- compact 成功前に dry-run する新 session 初期 context の上限。summary、auto-read contents、references、task snapshot、retained tail を含む。
- `model`
- compactor model。未指定なら main Worker の client を clone する。
Compact 発火条件の `threshold` / `request_threshold` は Compact Worker の健全性 parameter ではないが、既存の `compact_threshold` / `compact_request_threshold` を整理する場合は `[compaction]` 内の prefix なし key として扱う。
## 要件
- `build_summary_input()` / compact 入力生成を、prefix 全体の pruned transcript 一括投入から、bounded overview + index 生成に変更する。
- overview は `overview_target_tokens` を目指して生成する。
- `overview_warning_tokens` 超過時は警告・trace を記録しつつ続行する。
- `overview_deadline_tokens` 超過時はより粗い deterministic overview に fallback する。通常ケースの user-facing hard error にしない。
- User / Assistant / System message を優先し、古い detail は落としてよい。
- Tool output content は初期 input に載せない。
- Compact Worker 用の session log 探索 tool を追加する。
- 例: `search_session_log(query, filters, range)`
- 例: `read_session_items(range | item_ids, mode = compact/full)`
- 必要なら large tool result を個別に読む tool を追加する。
- 探索 tool は session-store の現在 segment / compact 対象 range を正本として読む。
- Compact 対象外の future/retained tail と混ざらないよう range 境界を明示する。
- tool result full content を返す場合は Compact Worker の残り context / `final_reserve_tokens` を守る。
- session-log/file-read 個別の総量 budget を user-facing parameter として増やさず、主制御は `worker_context_max_tokens` に寄せる。
- Compact Worker の context occupancy を request 前に見積もり、`worker_context_max_tokens` を最後の hard stop として扱う。
- Compact Worker の残り context が `finish_warning_remaining_tokens` 以下になったら、追加探索を切り上げて `write_summary` に進むよう Worker に勧告し、人間向け warning も出す。
- `final_reserve_tokens` を割り込む可能性がある tool result は、full content を返さず bounded/truncated result とし、range 縮小または `write_summary` への移行を促す。
- `write_summary` 後に `summary_max_tokens` を validation する。超過時は縮約を促し、改善できない場合は compact 成功扱いにしない。
- compact 成功前に、`summary + auto-read + references + retained tail + task snapshot` の新 session 初期 context を dry-run 見積もりし、`result_context_max_tokens` を超えないことを確認する。
- `mark_read_required` / `add_reference` の意味論は維持する。
- AutoRead は session log 上の過去 tool output ではなく、現在の workspace file を `read_file` で確認してから選ぶ。
- `auto_read_budget_tokens` は新 session 初期 context への file content 注入上限であり、Compact Worker の探索 budget ではない。
- `resources/prompts/internal/compact_system.md` の summary target は `summary_target_tokens` から反映する。
- 手動 compact / auto compact の双方で同じ経路を使う。
- 巨大 session でも Compact Worker が初回 input 上限で即停止しない。
## 完了条件
- 長い session で compact 初期 overview が transcript 全体を載せず、`overview_target_tokens` を目指して生成される unit test がある。
- `overview_warning_tokens` 超過時に compact が続行し、警告・trace が記録される test がある。
- `overview_deadline_tokens` 超過時に粗い deterministic overview へ fallback する test がある。
- Tool result content が初期 compact input に混入しないことを test で確認している。
- Compact Worker が session log overview から必要 range を tool で読み、`write_summary` まで到達できる test がある。
- `finish_warning_remaining_tokens` 到達時に Compact Worker へ探索切り上げ勧告が入り、人間向け warning も出る test がある。
- `final_reserve_tokens` を守るため、過大な tool result が bounded/truncated される test がある。
- `summary_max_tokens` 超過 summary が compact 成功扱いにならない、または縮約 nudge を受ける test がある。
- compact 後の新 session 初期 context が `result_context_max_tokens` で dry-run validation される test がある。
- `mark_read_required` / `add_reference` 既存 test が通り、auto-read budget の挙動が維持されている。
- `[compaction]` の新 parameter 名が docs / manifest schema / defaults に反映されている。
- `docs/compaction.md``resources/prompts/internal/compact_system.md` が新しい探索型 flow と budget/warning semantics に更新されている。
- `cargo fmt --check` と関連 crate の compact/session-store/pod/manifest tests が通る。
## 範囲外
- Compact summary 自体を deterministic summarizer に置き換えること。
- Memory extract / consolidation の入力方式変更。
- 過去の壊れた session log の migration。
- Compact 後の retained tail token policy の再設計。
- session-log/file-read ごとの user-facing 総量 budget を増やすこと。
## 実装メモ
現行コード上の主な起点:
- `crates/pod/src/pod.rs::compact`
- `crates/pod/src/pod.rs::build_summary_input`
- `crates/pod/src/pod.rs::build_summary_prompt`
- `crates/pod/src/compact/worker.rs`
- `crates/manifest/src/lib.rs::CompactionConfig`
- `crates/manifest/src/config.rs::CompactionConfigPartial`
- `crates/manifest/src/defaults.rs`
- `resources/prompts/internal/compact_system.md`
- `docs/compaction.md`
@@ -0,0 +1,143 @@
---
id: 20260528-001748-compact-session-log-exploration
slug: compact-session-log-exploration
title: Compact: session log 探索型の要約入力に変更する
status: closed
kind: task
priority: P2
labels: [compact, session-log]
created_at: 2026-05-28T00:17:48Z
updated_at: 2026-05-28T03:41:42Z
assignee: null
legacy_ticket: null
---
# Compact: session log 探索型の要約入力に変更する
## 背景
`insomnia-troubleshoot` Pod の手動 compact で、Compact Worker が入力トークン上限に到達して停止した。現行実装は `Pod::compact` で retained tail より前の `items_to_summarise``build_summary_input()` に渡し、`build_summary_prompt()` が user / assistant / system message と tool result summary を `## Conversation` に連結して Compact Worker の初回 input に載せている。
raw tool output や reasoning は落としているが、長い session では pruned transcript だけでも `compact_worker_max_input_tokens` を超える。Compact の目的は「全履歴を読ませる」ことではなく、次セッションに必要な構造化要約と file auto-read/reference を作ることなので、初期 input は軽量 overview に留め、必要箇所は Compact Worker が session log / workspace file を探索して確認できる形にする。
また、Compact Worker の健全性は「初期 input が小さいこと」だけでは保証できない。探索 tool の結果、assistant 出力、`write_summary` 呼び出しまでを含む Compact Worker 全体の context と、compact 後に作られる新 session 初期 context を別々に制御する必要がある。
## 方針
Compact Worker の初期 context は、全文 transcript ではなく決定的に生成した session overview / index を渡す。LLM には探索空間を狭めた上で、必要な session log 範囲や workspace file を tool で読む権限を与える。
基本方針:
- 初期 input は User / Assistant / System の継続に必要な情報を中心に、target size 内の overview として生成する。
- 初期 overview が target を超えた程度で compact を失敗させない。warning / trace に記録して続行する。
- 初期 overview deadline は通常運用の調整値ではなく、想定外の入力生成バグを検出する最悪ケースの安全網とする。deadline 超過時は、可能ならより粗い overview へ fallback し、それでも最低限の入力を作れない場合だけ失敗する。
- ToolCall / ToolResult は初期 input では本文を展開しない。
- tool 名、summary、対象 path、成否、大きな出力の有無、session log 上の位置などの index に留める。
- Compact Worker は session log の必要箇所を探索・再読できる。
- Compact Worker の探索量は、session-log/file-read 個別の総量 budget ではなく、Compact Worker session 全体の context budget で制御する。
- Compact Worker context が上限に近づいたら、`mark_read_required` とは独立に「探索を切り上げて `write_summary` へ進め」という勧告を Worker に渡し、人間にも警告を出す。
- 最終 summary と closing turn のための reserve を確保し、reserve を食い潰すほど大きい tool result は残 budget に合わせて抑制・切り詰め・再読指示にする。
- AutoRead 判断のため、workspace file は現行通り `read_file` で確認し、必要なものだけ `mark_read_required` / `add_reference` する。
- AutoRead budget は Compact Worker の探索 budget ではなく、compact 後の新 session 初期 context に注入される file content の合計上限として扱う。
- Compact Worker の出力は現行と同じく structured summary + auto-read + references を生成する。
## Compact Worker / compaction parameters
`[compaction]` 配下では `compact_` prefix を新規 parameter 名につけない。既存の `compact_*` key は、この ticket の実装時に同じ意味の prefix なし key へ整理する。
必要な parameter:
- `retained_tokens`
- compact 後に verbatim で残す history tail の token budget。
- `overview_target_tokens`
- 初期 overview / index 生成器が目指す通常サイズ。超過しても即失敗しない。
- `overview_warning_tokens`
- 初期 overview が想定より大きいことを記録・警告する閾値。compact は続行する。
- `overview_deadline_tokens`
- 初期 overview の最悪ケース deadline。超過時はより粗い overview へ deterministic fallback し、それでも無理な場合だけ compact を失敗させる。
- `worker_context_max_tokens`
- Compact Worker session 全体の context hard limit。system prompt、overview、assistant output、tool calls/results、session-log/file read results、`write_summary` 周辺の蓄積を含む。
- `finish_warning_remaining_tokens`
- 残り context がこの値以下になったら、Compact Worker に探索切り上げと `write_summary` を促す勧告を入れる。
- `final_reserve_tokens`
- 最終 summary と closing turn のために残す reserve。これを割り込みそうな tool result は full content を返さず、range 縮小や summary への移行を促す。
- `worker_max_turns`
- Compact Worker の tool-loop 最大 turn 数。budget 制御とは別の runaway guard。
- `summary_target_tokens`
- `write_summary` text の目標サイズ。prompt / nudge に使う。
- `summary_max_tokens`
- `write_summary` text の hard validation。超過した summary は縮約を促すか compact 成功扱いにしない。
- `auto_read_budget_tokens`
- `mark_read_required` によって compact 後の新 session に注入される file content の合計 token budget。
- `result_context_max_tokens`
- compact 成功前に dry-run する新 session 初期 context の上限。summary、auto-read contents、references、task snapshot、retained tail を含む。
- `model`
- compactor model。未指定なら main Worker の client を clone する。
Compact 発火条件の `threshold` / `request_threshold` は Compact Worker の健全性 parameter ではないが、既存の `compact_threshold` / `compact_request_threshold` を整理する場合は `[compaction]` 内の prefix なし key として扱う。
## 要件
- `build_summary_input()` / compact 入力生成を、prefix 全体の pruned transcript 一括投入から、bounded overview + index 生成に変更する。
- overview は `overview_target_tokens` を目指して生成する。
- `overview_warning_tokens` 超過時は警告・trace を記録しつつ続行する。
- `overview_deadline_tokens` 超過時はより粗い deterministic overview に fallback する。通常ケースの user-facing hard error にしない。
- User / Assistant / System message を優先し、古い detail は落としてよい。
- Tool output content は初期 input に載せない。
- Compact Worker 用の session log 探索 tool を追加する。
- 例: `search_session_log(query, filters, range)`
- 例: `read_session_items(range | item_ids, mode = compact/full)`
- 必要なら large tool result を個別に読む tool を追加する。
- 探索 tool は session-store の現在 segment / compact 対象 range を正本として読む。
- Compact 対象外の future/retained tail と混ざらないよう range 境界を明示する。
- tool result full content を返す場合は Compact Worker の残り context / `final_reserve_tokens` を守る。
- session-log/file-read 個別の総量 budget を user-facing parameter として増やさず、主制御は `worker_context_max_tokens` に寄せる。
- Compact Worker の context occupancy を request 前に見積もり、`worker_context_max_tokens` を最後の hard stop として扱う。
- Compact Worker の残り context が `finish_warning_remaining_tokens` 以下になったら、追加探索を切り上げて `write_summary` に進むよう Worker に勧告し、人間向け warning も出す。
- `final_reserve_tokens` を割り込む可能性がある tool result は、full content を返さず bounded/truncated result とし、range 縮小または `write_summary` への移行を促す。
- `write_summary` 後に `summary_max_tokens` を validation する。超過時は縮約を促し、改善できない場合は compact 成功扱いにしない。
- compact 成功前に、`summary + auto-read + references + retained tail + task snapshot` の新 session 初期 context を dry-run 見積もりし、`result_context_max_tokens` を超えないことを確認する。
- `mark_read_required` / `add_reference` の意味論は維持する。
- AutoRead は session log 上の過去 tool output ではなく、現在の workspace file を `read_file` で確認してから選ぶ。
- `auto_read_budget_tokens` は新 session 初期 context への file content 注入上限であり、Compact Worker の探索 budget ではない。
- `resources/prompts/internal/compact_system.md` の summary target は `summary_target_tokens` から反映する。
- 手動 compact / auto compact の双方で同じ経路を使う。
- 巨大 session でも Compact Worker が初回 input 上限で即停止しない。
## 完了条件
- 長い session で compact 初期 overview が transcript 全体を載せず、`overview_target_tokens` を目指して生成される unit test がある。
- `overview_warning_tokens` 超過時に compact が続行し、警告・trace が記録される test がある。
- `overview_deadline_tokens` 超過時に粗い deterministic overview へ fallback する test がある。
- Tool result content が初期 compact input に混入しないことを test で確認している。
- Compact Worker が session log overview から必要 range を tool で読み、`write_summary` まで到達できる test がある。
- `finish_warning_remaining_tokens` 到達時に Compact Worker へ探索切り上げ勧告が入り、人間向け warning も出る test がある。
- `final_reserve_tokens` を守るため、過大な tool result が bounded/truncated される test がある。
- `summary_max_tokens` 超過 summary が compact 成功扱いにならない、または縮約 nudge を受ける test がある。
- compact 後の新 session 初期 context が `result_context_max_tokens` で dry-run validation される test がある。
- `mark_read_required` / `add_reference` 既存 test が通り、auto-read budget の挙動が維持されている。
- `[compaction]` の新 parameter 名が docs / manifest schema / defaults に反映されている。
- `docs/compaction.md``resources/prompts/internal/compact_system.md` が新しい探索型 flow と budget/warning semantics に更新されている。
- `cargo fmt --check` と関連 crate の compact/session-store/pod/manifest tests が通る。
## 範囲外
- Compact summary 自体を deterministic summarizer に置き換えること。
- Memory extract / consolidation の入力方式変更。
- 過去の壊れた session log の migration。
- Compact 後の retained tail token policy の再設計。
- session-log/file-read ごとの user-facing 総量 budget を増やすこと。
## 実装メモ
現行コード上の主な起点:
- `crates/pod/src/pod.rs::compact`
- `crates/pod/src/pod.rs::build_summary_input`
- `crates/pod/src/pod.rs::build_summary_prompt`
- `crates/pod/src/compact/worker.rs`
- `crates/manifest/src/lib.rs::CompactionConfig`
- `crates/manifest/src/config.rs::CompactionConfigPartial`
- `crates/manifest/src/defaults.rs`
- `resources/prompts/internal/compact_system.md`
- `docs/compaction.md`
@@ -0,0 +1,189 @@
<!-- event: create author: tickets.sh at: 2026-05-28T00:17:48Z -->
## Created
Created by tickets.sh create.
---
<!-- event: review author: insomnia at: 2026-05-28T03:41:41Z status: approve -->
## Review: approve
実装を review し、approve する。
確認内容:
- Compact Worker 初期入力が bounded overview / index に変更され、ToolCall arguments / ToolResult full content / Reasoning body が初期 input に混入しない。
- `[compaction]` の prefix なし parameter と旧 `compact_*` alias が manifest/config/defaults に反映されている。
- `finish_warning_remaining_tokens` で Worker history に永続化される budget warning が入り、人間向け warning も出る。
- `final_reserve_tokens` 到達後は `write_summary` 以外の探索 tool が synthetic error になり、summary 用 reserve を守る。
- `search_session_log` / `read_session_items` が Compact Worker に登録され、bounded overview から漏れた履歴を探索できる。
- `summary_max_tokens``result_context_max_tokens` の validation が入っている。
- docs / compact system prompt が新 flow に更新されている。
検証:
- cargo fmt --check
- cargo check -p llm-worker -p pod -p manifest
- cargo test -p manifest compaction
- cargo test -p pod compact_worker_interceptor --no-default-features
- cargo test -p pod build_summary_prompt_tests --no-default-features
- cargo test -p pod session_log --no-default-features
- cargo test -p pod read_session_items --no-default-features
注意:
- `cargo test -p pod --no-default-features` 全体は master 上の trace commit だけでも controller empty-turn rollback 系 3 tests が失敗するため、この ticket の blocking とはしない。
- `cargo test -p manifest` 全体は環境依存の `runtime_dir_prefers_xdg_runtime_dir` が失敗するため、この ticket の blocking とはしない。
---
<!-- event: close author: hare at: 2026-05-28T03:41:42Z status: closed -->
## Closed
---
id: 20260528-001748-compact-session-log-exploration
slug: compact-session-log-exploration
title: Compact: session log 探索型の要約入力に変更する
status: closed
kind: task
priority: P2
labels: [compact, session-log]
created_at: 2026-05-28T00:17:48Z
updated_at: 2026-05-28T03:41:42Z
assignee: null
legacy_ticket: null
---
# Compact: session log 探索型の要約入力に変更する
## 背景
`insomnia-troubleshoot` Pod の手動 compact で、Compact Worker が入力トークン上限に到達して停止した。現行実装は `Pod::compact` で retained tail より前の `items_to_summarise``build_summary_input()` に渡し、`build_summary_prompt()` が user / assistant / system message と tool result summary を `## Conversation` に連結して Compact Worker の初回 input に載せている。
raw tool output や reasoning は落としているが、長い session では pruned transcript だけでも `compact_worker_max_input_tokens` を超える。Compact の目的は「全履歴を読ませる」ことではなく、次セッションに必要な構造化要約と file auto-read/reference を作ることなので、初期 input は軽量 overview に留め、必要箇所は Compact Worker が session log / workspace file を探索して確認できる形にする。
また、Compact Worker の健全性は「初期 input が小さいこと」だけでは保証できない。探索 tool の結果、assistant 出力、`write_summary` 呼び出しまでを含む Compact Worker 全体の context と、compact 後に作られる新 session 初期 context を別々に制御する必要がある。
## 方針
Compact Worker の初期 context は、全文 transcript ではなく決定的に生成した session overview / index を渡す。LLM には探索空間を狭めた上で、必要な session log 範囲や workspace file を tool で読む権限を与える。
基本方針:
- 初期 input は User / Assistant / System の継続に必要な情報を中心に、target size 内の overview として生成する。
- 初期 overview が target を超えた程度で compact を失敗させない。warning / trace に記録して続行する。
- 初期 overview deadline は通常運用の調整値ではなく、想定外の入力生成バグを検出する最悪ケースの安全網とする。deadline 超過時は、可能ならより粗い overview へ fallback し、それでも最低限の入力を作れない場合だけ失敗する。
- ToolCall / ToolResult は初期 input では本文を展開しない。
- tool 名、summary、対象 path、成否、大きな出力の有無、session log 上の位置などの index に留める。
- Compact Worker は session log の必要箇所を探索・再読できる。
- Compact Worker の探索量は、session-log/file-read 個別の総量 budget ではなく、Compact Worker session 全体の context budget で制御する。
- Compact Worker context が上限に近づいたら、`mark_read_required` とは独立に「探索を切り上げて `write_summary` へ進め」という勧告を Worker に渡し、人間にも警告を出す。
- 最終 summary と closing turn のための reserve を確保し、reserve を食い潰すほど大きい tool result は残 budget に合わせて抑制・切り詰め・再読指示にする。
- AutoRead 判断のため、workspace file は現行通り `read_file` で確認し、必要なものだけ `mark_read_required` / `add_reference` する。
- AutoRead budget は Compact Worker の探索 budget ではなく、compact 後の新 session 初期 context に注入される file content の合計上限として扱う。
- Compact Worker の出力は現行と同じく structured summary + auto-read + references を生成する。
## Compact Worker / compaction parameters
`[compaction]` 配下では `compact_` prefix を新規 parameter 名につけない。既存の `compact_*` key は、この ticket の実装時に同じ意味の prefix なし key へ整理する。
必要な parameter:
- `retained_tokens`
- compact 後に verbatim で残す history tail の token budget。
- `overview_target_tokens`
- 初期 overview / index 生成器が目指す通常サイズ。超過しても即失敗しない。
- `overview_warning_tokens`
- 初期 overview が想定より大きいことを記録・警告する閾値。compact は続行する。
- `overview_deadline_tokens`
- 初期 overview の最悪ケース deadline。超過時はより粗い overview へ deterministic fallback し、それでも無理な場合だけ compact を失敗させる。
- `worker_context_max_tokens`
- Compact Worker session 全体の context hard limit。system prompt、overview、assistant output、tool calls/results、session-log/file read results、`write_summary` 周辺の蓄積を含む。
- `finish_warning_remaining_tokens`
- 残り context がこの値以下になったら、Compact Worker に探索切り上げと `write_summary` を促す勧告を入れる。
- `final_reserve_tokens`
- 最終 summary と closing turn のために残す reserve。これを割り込みそうな tool result は full content を返さず、range 縮小や summary への移行を促す。
- `worker_max_turns`
- Compact Worker の tool-loop 最大 turn 数。budget 制御とは別の runaway guard。
- `summary_target_tokens`
- `write_summary` text の目標サイズ。prompt / nudge に使う。
- `summary_max_tokens`
- `write_summary` text の hard validation。超過した summary は縮約を促すか compact 成功扱いにしない。
- `auto_read_budget_tokens`
- `mark_read_required` によって compact 後の新 session に注入される file content の合計 token budget。
- `result_context_max_tokens`
- compact 成功前に dry-run する新 session 初期 context の上限。summary、auto-read contents、references、task snapshot、retained tail を含む。
- `model`
- compactor model。未指定なら main Worker の client を clone する。
Compact 発火条件の `threshold` / `request_threshold` は Compact Worker の健全性 parameter ではないが、既存の `compact_threshold` / `compact_request_threshold` を整理する場合は `[compaction]` 内の prefix なし key として扱う。
## 要件
- `build_summary_input()` / compact 入力生成を、prefix 全体の pruned transcript 一括投入から、bounded overview + index 生成に変更する。
- overview は `overview_target_tokens` を目指して生成する。
- `overview_warning_tokens` 超過時は警告・trace を記録しつつ続行する。
- `overview_deadline_tokens` 超過時はより粗い deterministic overview に fallback する。通常ケースの user-facing hard error にしない。
- User / Assistant / System message を優先し、古い detail は落としてよい。
- Tool output content は初期 input に載せない。
- Compact Worker 用の session log 探索 tool を追加する。
- 例: `search_session_log(query, filters, range)`
- 例: `read_session_items(range | item_ids, mode = compact/full)`
- 必要なら large tool result を個別に読む tool を追加する。
- 探索 tool は session-store の現在 segment / compact 対象 range を正本として読む。
- Compact 対象外の future/retained tail と混ざらないよう range 境界を明示する。
- tool result full content を返す場合は Compact Worker の残り context / `final_reserve_tokens` を守る。
- session-log/file-read 個別の総量 budget を user-facing parameter として増やさず、主制御は `worker_context_max_tokens` に寄せる。
- Compact Worker の context occupancy を request 前に見積もり、`worker_context_max_tokens` を最後の hard stop として扱う。
- Compact Worker の残り context が `finish_warning_remaining_tokens` 以下になったら、追加探索を切り上げて `write_summary` に進むよう Worker に勧告し、人間向け warning も出す。
- `final_reserve_tokens` を割り込む可能性がある tool result は、full content を返さず bounded/truncated result とし、range 縮小または `write_summary` への移行を促す。
- `write_summary` 後に `summary_max_tokens` を validation する。超過時は縮約を促し、改善できない場合は compact 成功扱いにしない。
- compact 成功前に、`summary + auto-read + references + retained tail + task snapshot` の新 session 初期 context を dry-run 見積もりし、`result_context_max_tokens` を超えないことを確認する。
- `mark_read_required` / `add_reference` の意味論は維持する。
- AutoRead は session log 上の過去 tool output ではなく、現在の workspace file を `read_file` で確認してから選ぶ。
- `auto_read_budget_tokens` は新 session 初期 context への file content 注入上限であり、Compact Worker の探索 budget ではない。
- `resources/prompts/internal/compact_system.md` の summary target は `summary_target_tokens` から反映する。
- 手動 compact / auto compact の双方で同じ経路を使う。
- 巨大 session でも Compact Worker が初回 input 上限で即停止しない。
## 完了条件
- 長い session で compact 初期 overview が transcript 全体を載せず、`overview_target_tokens` を目指して生成される unit test がある。
- `overview_warning_tokens` 超過時に compact が続行し、警告・trace が記録される test がある。
- `overview_deadline_tokens` 超過時に粗い deterministic overview へ fallback する test がある。
- Tool result content が初期 compact input に混入しないことを test で確認している。
- Compact Worker が session log overview から必要 range を tool で読み、`write_summary` まで到達できる test がある。
- `finish_warning_remaining_tokens` 到達時に Compact Worker へ探索切り上げ勧告が入り、人間向け warning も出る test がある。
- `final_reserve_tokens` を守るため、過大な tool result が bounded/truncated される test がある。
- `summary_max_tokens` 超過 summary が compact 成功扱いにならない、または縮約 nudge を受ける test がある。
- compact 後の新 session 初期 context が `result_context_max_tokens` で dry-run validation される test がある。
- `mark_read_required` / `add_reference` 既存 test が通り、auto-read budget の挙動が維持されている。
- `[compaction]` の新 parameter 名が docs / manifest schema / defaults に反映されている。
- `docs/compaction.md``resources/prompts/internal/compact_system.md` が新しい探索型 flow と budget/warning semantics に更新されている。
- `cargo fmt --check` と関連 crate の compact/session-store/pod/manifest tests が通る。
## 範囲外
- Compact summary 自体を deterministic summarizer に置き換えること。
- Memory extract / consolidation の入力方式変更。
- 過去の壊れた session log の migration。
- Compact 後の retained tail token policy の再設計。
- session-log/file-read ごとの user-facing 総量 budget を増やすこと。
## 実装メモ
現行コード上の主な起点:
- `crates/pod/src/pod.rs::compact`
- `crates/pod/src/pod.rs::build_summary_input`
- `crates/pod/src/pod.rs::build_summary_prompt`
- `crates/pod/src/compact/worker.rs`
- `crates/manifest/src/lib.rs::CompactionConfig`
- `crates/manifest/src/config.rs::CompactionConfigPartial`
- `crates/manifest/src/defaults.rs`
- `resources/prompts/internal/compact_system.md`
- `docs/compaction.md`
---
@@ -0,0 +1,167 @@
---
id: 20260528-141602-tui-pod-list-view-abstraction
slug: tui-pod-list-view-abstraction
title: TUI Pod list/view abstraction
status: closed
kind: task
priority: P2
labels: [tui, pod, architecture]
created_at: 2026-05-28T14:16:02Z
updated_at: 2026-05-28T15:40:30Z
assignee: null
legacy_ticket: null
---
## Background
TUI で扱う Pod 関連 UI は、少なくとも次の二つの後続 ticket から使われる。
- `20260527-000017-tui-spawned-pod-panel`: spawned child Pod の一覧と一時 attach。
- `20260527-000023-multi-pod-view-ui`: 複数 Pod view を行き来する UI。
両者は表示対象や操作範囲が異なる一方で、Pod の一覧取得、status 表示、visible / attachable 判定、row 表示、選択状態、view 切り替えの土台を共有する。これを各 ticket が個別に実装すると、TUI 内で Pod list / picker / view 管理が重複し、visibility model や attach 診断がずれやすい。
まず TUI 内で用いる複数 Pod の list/view model を抽象化し、後続 UI が同じ情報構造と操作プリミティブを使える状態にする。
## Design direction
Trait 階層ではなく、source ごとの data struct を name-keyed に合成した UI model を採用する。
- `StoredPod` / `LivingPod` trait は作らない。
- `LivePodInfo``StoredPodInfo` は plain data struct として扱う。
- UI は `Vec<PodListEntry>` / `PodList` を読む。
- `PodListEntry` は Pod name を primary key として、`live: Option<LivePodInfo>``stored: Option<StoredPodInfo>` を合成した normalized row にする。
- live / stored は排他的ではない。
- 起動中かつ stored metadata がある Pod。
- 起動中だが durable metadata / segment がまだ薄い pending Pod。
- stopped で stored metadata だけある Pod。
- stored metadata が壊れている Pod。
- registry にはあるが socket unreachable な Pod。
これらを enum の継承的分類へ押し込めず、entry の合成状態として扱う。
この ticket で抽象化するのは list/read/merge/selection/action eligibility の土台まで。`Method::Run` の送信、attach、restore の実行そのものは入れない。
## Requirement
- TUI crate 内に Pod list 用 module を用意する。
- 推奨名: `crates/tui/src/pod_list.rs`
- 既存 picker の private `Row` / `PodRowState` / `LivePodRecord` / `build_rows` / metadata + registry + session summary 読み取りを、この module の model / builder へ寄せる。
- TUI が Pod 一覧 UI を構成するための共通 model / state / helper を用意する。
- `PodList`
- `PodListEntry`
- `LivePodInfo`
- `StoredPodInfo`
- `PodVisibilitySource`
- `PodEntryActions` または同等の action eligibility model
- selection stateindex だけでなく Pod name を primary identity として維持できること)
- `PodListEntry` は表示情報と action eligibility を持つ。
- Pod name
- source / visibility kind(例: resume picker, current parent spawned child, future multi-view target
- live reachability / `PodStatus`
- socket path / attach target
- stored active session / segment id
- updated time / preview
- stopped / unreachable / missing state / corrupt metadata の診断情報
- `can_open`
- `can_restore`
- `can_send_now`
- `can_queue_send`
- disabled reason / diagnostic
- direct send 自体はこの ticket の範囲外だが、multi-pod view が send target 判定に使える情報は model に含める。
- live + reachable + `PodStatus::Idle` なら `can_send_now`
- running は send disabled または future queue eligible として区別できる。
- stopped は restore/open 可能だが direct send は不可。
- `tui -r` picker は新しい `PodList` / `PodListEntry` を最初の consumer として使う。
- picker の見た目・key binding・attach/restore outcome は変えない。
- existing picker-specific rendering は残してよいが、row data source は共有 model に寄せる。
- list row rendering / selection / refresh の責務境界を整理する。
- TUI widget は表示と選択に寄せる。
- Pod discovery / client protocol / registry state / session summary の取得詳細を UI 表示ロジックへ直接散らさない。
- child Pod panel と multi-Pod view UI が同じ抽象を使える設計にする。
- visibility model は変えない。
- host-wide Pod browser を新設しない。
- `tui -r` は既存 resume picker 相当の source だけを扱う。
- spawned child panel は current parent から見える child Pod のみを対象にする後続 consumer として想定する。
- multi-Pod view UI も、具体要件が決まるまではこの抽象に新しい可視範囲を勝手に足さない。
- 既存の `ListPods` / `ReadPodOutput` / `SendToPod` / `StopPod` tool semantics は変えない。
- 既存の TUI resume picker / attach flow を壊さない。
## Suggested model sketch
Exact names may differ, but implementation should keep this shape simple and data-oriented.
```rust
pub struct PodList {
pub entries: Vec<PodListEntry>,
pub selected_name: Option<String>,
}
pub struct PodListEntry {
pub name: String,
pub source: PodVisibilitySource,
pub live: Option<LivePodInfo>,
pub stored: Option<StoredPodInfo>,
pub summary: PodEntrySummary,
pub actions: PodEntryActions,
pub diagnostics: Vec<PodEntryDiagnostic>,
}
pub struct LivePodInfo {
pub socket_path: PathBuf,
pub status: Option<PodStatus>,
pub reachable: bool,
pub segment_id: Option<SegmentId>,
}
pub struct StoredPodInfo {
pub metadata_state: StoredMetadataState,
pub active_session_id: Option<SessionId>,
pub active_segment_id: Option<SegmentId>,
pub updated_at: Option<u64>,
pub preview: Option<String>,
}
pub struct PodEntryActions {
pub can_open: bool,
pub can_restore: bool,
pub can_send_now: bool,
pub can_queue_send: bool,
pub disabled_reason: Option<String>,
}
```
## Acceptance criteria
- TUI crate 内に、複数 Pod list/view UI で再利用できる typed abstraction がある。
- 既存 `tui -r` picker が、その abstraction を使って rows を構成する。
- spawned child Pod list と multi-Pod view UI の後続実装が、その abstraction を使う前提で説明できる。
- Pod row の status / reachability / attach target / diagnostic 表示に必要な情報が一箇所の model にまとまっている。
- visibility scope は caller が明示的に渡すか、source kind として表現され、UI helper が host-wide enumeration を暗黙に行わない。
- selection は refresh 後も Pod name を primary identity として維持できる。
- unit test で以下が確認されている。
- stored only row は restore/open 可能で direct send 不可。
- live idle reachable row は open/attach 可能かつ direct send 可能。
- live running reachable row は attach 可能だが direct send 可能とは扱わない。
- corrupt stored metadata は diagnostic を持つ。
- rows refresh / rebuild 後に selected Pod name が維持される。
- 既存 picker / attach 関連テストが通る。
- `cargo fmt --check`
- `cargo check -p tui -p client -p pod`
- 必要に応じて `cargo test -p tui -p pod -p protocol`
## Relationship
This is a prerequisite for:
- `20260527-000017-tui-spawned-pod-panel`
- `20260527-000023-multi-pod-view-ui`
## Out of scope
- spawned child Pod panel の完成。
- 複数 Pod view UI の完成。
- child Pod への interactive input。
- multi-Pod view からの direct send 実行。
- host-wide Pod browser。
- Pod discovery / permission / registry visibility model の変更。
- native GUI。
@@ -0,0 +1,167 @@
---
id: 20260528-141602-tui-pod-list-view-abstraction
slug: tui-pod-list-view-abstraction
title: TUI Pod list/view abstraction
status: closed
kind: task
priority: P2
labels: [tui, pod, architecture]
created_at: 2026-05-28T14:16:02Z
updated_at: 2026-05-28T15:40:30Z
assignee: null
legacy_ticket: null
---
## Background
TUI で扱う Pod 関連 UI は、少なくとも次の二つの後続 ticket から使われる。
- `20260527-000017-tui-spawned-pod-panel`: spawned child Pod の一覧と一時 attach。
- `20260527-000023-multi-pod-view-ui`: 複数 Pod view を行き来する UI。
両者は表示対象や操作範囲が異なる一方で、Pod の一覧取得、status 表示、visible / attachable 判定、row 表示、選択状態、view 切り替えの土台を共有する。これを各 ticket が個別に実装すると、TUI 内で Pod list / picker / view 管理が重複し、visibility model や attach 診断がずれやすい。
まず TUI 内で用いる複数 Pod の list/view model を抽象化し、後続 UI が同じ情報構造と操作プリミティブを使える状態にする。
## Design direction
Trait 階層ではなく、source ごとの data struct を name-keyed に合成した UI model を採用する。
- `StoredPod` / `LivingPod` trait は作らない。
- `LivePodInfo``StoredPodInfo` は plain data struct として扱う。
- UI は `Vec<PodListEntry>` / `PodList` を読む。
- `PodListEntry` は Pod name を primary key として、`live: Option<LivePodInfo>``stored: Option<StoredPodInfo>` を合成した normalized row にする。
- live / stored は排他的ではない。
- 起動中かつ stored metadata がある Pod。
- 起動中だが durable metadata / segment がまだ薄い pending Pod。
- stopped で stored metadata だけある Pod。
- stored metadata が壊れている Pod。
- registry にはあるが socket unreachable な Pod。
これらを enum の継承的分類へ押し込めず、entry の合成状態として扱う。
この ticket で抽象化するのは list/read/merge/selection/action eligibility の土台まで。`Method::Run` の送信、attach、restore の実行そのものは入れない。
## Requirement
- TUI crate 内に Pod list 用 module を用意する。
- 推奨名: `crates/tui/src/pod_list.rs`
- 既存 picker の private `Row` / `PodRowState` / `LivePodRecord` / `build_rows` / metadata + registry + session summary 読み取りを、この module の model / builder へ寄せる。
- TUI が Pod 一覧 UI を構成するための共通 model / state / helper を用意する。
- `PodList`
- `PodListEntry`
- `LivePodInfo`
- `StoredPodInfo`
- `PodVisibilitySource`
- `PodEntryActions` または同等の action eligibility model
- selection stateindex だけでなく Pod name を primary identity として維持できること)
- `PodListEntry` は表示情報と action eligibility を持つ。
- Pod name
- source / visibility kind(例: resume picker, current parent spawned child, future multi-view target
- live reachability / `PodStatus`
- socket path / attach target
- stored active session / segment id
- updated time / preview
- stopped / unreachable / missing state / corrupt metadata の診断情報
- `can_open`
- `can_restore`
- `can_send_now`
- `can_queue_send`
- disabled reason / diagnostic
- direct send 自体はこの ticket の範囲外だが、multi-pod view が send target 判定に使える情報は model に含める。
- live + reachable + `PodStatus::Idle` なら `can_send_now`
- running は send disabled または future queue eligible として区別できる。
- stopped は restore/open 可能だが direct send は不可。
- `tui -r` picker は新しい `PodList` / `PodListEntry` を最初の consumer として使う。
- picker の見た目・key binding・attach/restore outcome は変えない。
- existing picker-specific rendering は残してよいが、row data source は共有 model に寄せる。
- list row rendering / selection / refresh の責務境界を整理する。
- TUI widget は表示と選択に寄せる。
- Pod discovery / client protocol / registry state / session summary の取得詳細を UI 表示ロジックへ直接散らさない。
- child Pod panel と multi-Pod view UI が同じ抽象を使える設計にする。
- visibility model は変えない。
- host-wide Pod browser を新設しない。
- `tui -r` は既存 resume picker 相当の source だけを扱う。
- spawned child panel は current parent から見える child Pod のみを対象にする後続 consumer として想定する。
- multi-Pod view UI も、具体要件が決まるまではこの抽象に新しい可視範囲を勝手に足さない。
- 既存の `ListPods` / `ReadPodOutput` / `SendToPod` / `StopPod` tool semantics は変えない。
- 既存の TUI resume picker / attach flow を壊さない。
## Suggested model sketch
Exact names may differ, but implementation should keep this shape simple and data-oriented.
```rust
pub struct PodList {
pub entries: Vec<PodListEntry>,
pub selected_name: Option<String>,
}
pub struct PodListEntry {
pub name: String,
pub source: PodVisibilitySource,
pub live: Option<LivePodInfo>,
pub stored: Option<StoredPodInfo>,
pub summary: PodEntrySummary,
pub actions: PodEntryActions,
pub diagnostics: Vec<PodEntryDiagnostic>,
}
pub struct LivePodInfo {
pub socket_path: PathBuf,
pub status: Option<PodStatus>,
pub reachable: bool,
pub segment_id: Option<SegmentId>,
}
pub struct StoredPodInfo {
pub metadata_state: StoredMetadataState,
pub active_session_id: Option<SessionId>,
pub active_segment_id: Option<SegmentId>,
pub updated_at: Option<u64>,
pub preview: Option<String>,
}
pub struct PodEntryActions {
pub can_open: bool,
pub can_restore: bool,
pub can_send_now: bool,
pub can_queue_send: bool,
pub disabled_reason: Option<String>,
}
```
## Acceptance criteria
- TUI crate 内に、複数 Pod list/view UI で再利用できる typed abstraction がある。
- 既存 `tui -r` picker が、その abstraction を使って rows を構成する。
- spawned child Pod list と multi-Pod view UI の後続実装が、その abstraction を使う前提で説明できる。
- Pod row の status / reachability / attach target / diagnostic 表示に必要な情報が一箇所の model にまとまっている。
- visibility scope は caller が明示的に渡すか、source kind として表現され、UI helper が host-wide enumeration を暗黙に行わない。
- selection は refresh 後も Pod name を primary identity として維持できる。
- unit test で以下が確認されている。
- stored only row は restore/open 可能で direct send 不可。
- live idle reachable row は open/attach 可能かつ direct send 可能。
- live running reachable row は attach 可能だが direct send 可能とは扱わない。
- corrupt stored metadata は diagnostic を持つ。
- rows refresh / rebuild 後に selected Pod name が維持される。
- 既存 picker / attach 関連テストが通る。
- `cargo fmt --check`
- `cargo check -p tui -p client -p pod`
- 必要に応じて `cargo test -p tui -p pod -p protocol`
## Relationship
This is a prerequisite for:
- `20260527-000017-tui-spawned-pod-panel`
- `20260527-000023-multi-pod-view-ui`
## Out of scope
- spawned child Pod panel の完成。
- 複数 Pod view UI の完成。
- child Pod への interactive input。
- multi-Pod view からの direct send 実行。
- host-wide Pod browser。
- Pod discovery / permission / registry visibility model の変更。
- native GUI。
@@ -0,0 +1,182 @@
<!-- event: create author: tickets.sh at: 2026-05-28T14:16:02Z -->
## Created
Created by tickets.sh create.
---
<!-- event: close author: hare at: 2026-05-28T15:40:30Z status: closed -->
## Closed
---
id: 20260528-141602-tui-pod-list-view-abstraction
slug: tui-pod-list-view-abstraction
title: TUI Pod list/view abstraction
status: closed
kind: task
priority: P2
labels: [tui, pod, architecture]
created_at: 2026-05-28T14:16:02Z
updated_at: 2026-05-28T15:40:30Z
assignee: null
legacy_ticket: null
---
## Background
TUI で扱う Pod 関連 UI は、少なくとも次の二つの後続 ticket から使われる。
- `20260527-000017-tui-spawned-pod-panel`: spawned child Pod の一覧と一時 attach。
- `20260527-000023-multi-pod-view-ui`: 複数 Pod view を行き来する UI。
両者は表示対象や操作範囲が異なる一方で、Pod の一覧取得、status 表示、visible / attachable 判定、row 表示、選択状態、view 切り替えの土台を共有する。これを各 ticket が個別に実装すると、TUI 内で Pod list / picker / view 管理が重複し、visibility model や attach 診断がずれやすい。
まず TUI 内で用いる複数 Pod の list/view model を抽象化し、後続 UI が同じ情報構造と操作プリミティブを使える状態にする。
## Design direction
Trait 階層ではなく、source ごとの data struct を name-keyed に合成した UI model を採用する。
- `StoredPod` / `LivingPod` trait は作らない。
- `LivePodInfo``StoredPodInfo` は plain data struct として扱う。
- UI は `Vec<PodListEntry>` / `PodList` を読む。
- `PodListEntry` は Pod name を primary key として、`live: Option<LivePodInfo>``stored: Option<StoredPodInfo>` を合成した normalized row にする。
- live / stored は排他的ではない。
- 起動中かつ stored metadata がある Pod。
- 起動中だが durable metadata / segment がまだ薄い pending Pod。
- stopped で stored metadata だけある Pod。
- stored metadata が壊れている Pod。
- registry にはあるが socket unreachable な Pod。
これらを enum の継承的分類へ押し込めず、entry の合成状態として扱う。
この ticket で抽象化するのは list/read/merge/selection/action eligibility の土台まで。`Method::Run` の送信、attach、restore の実行そのものは入れない。
## Requirement
- TUI crate 内に Pod list 用 module を用意する。
- 推奨名: `crates/tui/src/pod_list.rs`
- 既存 picker の private `Row` / `PodRowState` / `LivePodRecord` / `build_rows` / metadata + registry + session summary 読み取りを、この module の model / builder へ寄せる。
- TUI が Pod 一覧 UI を構成するための共通 model / state / helper を用意する。
- `PodList`
- `PodListEntry`
- `LivePodInfo`
- `StoredPodInfo`
- `PodVisibilitySource`
- `PodEntryActions` または同等の action eligibility model
- selection stateindex だけでなく Pod name を primary identity として維持できること)
- `PodListEntry` は表示情報と action eligibility を持つ。
- Pod name
- source / visibility kind(例: resume picker, current parent spawned child, future multi-view target
- live reachability / `PodStatus`
- socket path / attach target
- stored active session / segment id
- updated time / preview
- stopped / unreachable / missing state / corrupt metadata の診断情報
- `can_open`
- `can_restore`
- `can_send_now`
- `can_queue_send`
- disabled reason / diagnostic
- direct send 自体はこの ticket の範囲外だが、multi-pod view が send target 判定に使える情報は model に含める。
- live + reachable + `PodStatus::Idle` なら `can_send_now`
- running は send disabled または future queue eligible として区別できる。
- stopped は restore/open 可能だが direct send は不可。
- `tui -r` picker は新しい `PodList` / `PodListEntry` を最初の consumer として使う。
- picker の見た目・key binding・attach/restore outcome は変えない。
- existing picker-specific rendering は残してよいが、row data source は共有 model に寄せる。
- list row rendering / selection / refresh の責務境界を整理する。
- TUI widget は表示と選択に寄せる。
- Pod discovery / client protocol / registry state / session summary の取得詳細を UI 表示ロジックへ直接散らさない。
- child Pod panel と multi-Pod view UI が同じ抽象を使える設計にする。
- visibility model は変えない。
- host-wide Pod browser を新設しない。
- `tui -r` は既存 resume picker 相当の source だけを扱う。
- spawned child panel は current parent から見える child Pod のみを対象にする後続 consumer として想定する。
- multi-Pod view UI も、具体要件が決まるまではこの抽象に新しい可視範囲を勝手に足さない。
- 既存の `ListPods` / `ReadPodOutput` / `SendToPod` / `StopPod` tool semantics は変えない。
- 既存の TUI resume picker / attach flow を壊さない。
## Suggested model sketch
Exact names may differ, but implementation should keep this shape simple and data-oriented.
```rust
pub struct PodList {
pub entries: Vec<PodListEntry>,
pub selected_name: Option<String>,
}
pub struct PodListEntry {
pub name: String,
pub source: PodVisibilitySource,
pub live: Option<LivePodInfo>,
pub stored: Option<StoredPodInfo>,
pub summary: PodEntrySummary,
pub actions: PodEntryActions,
pub diagnostics: Vec<PodEntryDiagnostic>,
}
pub struct LivePodInfo {
pub socket_path: PathBuf,
pub status: Option<PodStatus>,
pub reachable: bool,
pub segment_id: Option<SegmentId>,
}
pub struct StoredPodInfo {
pub metadata_state: StoredMetadataState,
pub active_session_id: Option<SessionId>,
pub active_segment_id: Option<SegmentId>,
pub updated_at: Option<u64>,
pub preview: Option<String>,
}
pub struct PodEntryActions {
pub can_open: bool,
pub can_restore: bool,
pub can_send_now: bool,
pub can_queue_send: bool,
pub disabled_reason: Option<String>,
}
```
## Acceptance criteria
- TUI crate 内に、複数 Pod list/view UI で再利用できる typed abstraction がある。
- 既存 `tui -r` picker が、その abstraction を使って rows を構成する。
- spawned child Pod list と multi-Pod view UI の後続実装が、その abstraction を使う前提で説明できる。
- Pod row の status / reachability / attach target / diagnostic 表示に必要な情報が一箇所の model にまとまっている。
- visibility scope は caller が明示的に渡すか、source kind として表現され、UI helper が host-wide enumeration を暗黙に行わない。
- selection は refresh 後も Pod name を primary identity として維持できる。
- unit test で以下が確認されている。
- stored only row は restore/open 可能で direct send 不可。
- live idle reachable row は open/attach 可能かつ direct send 可能。
- live running reachable row は attach 可能だが direct send 可能とは扱わない。
- corrupt stored metadata は diagnostic を持つ。
- rows refresh / rebuild 後に selected Pod name が維持される。
- 既存 picker / attach 関連テストが通る。
- `cargo fmt --check`
- `cargo check -p tui -p client -p pod`
- 必要に応じて `cargo test -p tui -p pod -p protocol`
## Relationship
This is a prerequisite for:
- `20260527-000017-tui-spawned-pod-panel`
- `20260527-000023-multi-pod-view-ui`
## Out of scope
- spawned child Pod panel の完成。
- 複数 Pod view UI の完成。
- child Pod への interactive input。
- multi-Pod view からの direct send 実行。
- host-wide Pod browser。
- Pod discovery / permission / registry visibility model の変更。
- native GUI。
---
@@ -0,0 +1,73 @@
---
id: 20260528-152959-nix-packaging
slug: nix-packaging
title: Package Insomnia with Nix
status: closed
kind: task
priority: P2
labels: [packaging, nix, distribution]
created_at: 2026-05-28T15:29:59Z
updated_at: 2026-05-28T16:42:08Z
assignee: null
legacy_ticket: null
---
## Background
Insomnia should be easy to install and run on Nix/NixOS systems without requiring each user to hand-roll a local derivation. Add a Nix packaging entry point suitable for development and user installation.
This ticket is about packaging and installability, not changing runtime behavior. The package should build the Rust workspace binaries and include the runtime resources needed by the installed commands.
## Existing Nix file layout
The repository already separates the Nix package definition from the developer shell:
- `package.nix` is the package derivation used for install/build outputs.
- `devshell.nix` is for the development shell only.
- `flake.nix` may remain the entry point, but package outputs should call/use `package.nix`.
Do not implement the installable package primarily in `devshell.nix`. Update `devshell.nix` only if the development shell genuinely needs small supporting changes.
## Requirement
- Add Nix packaging for the repository.
- Use `package.nix` for the installable derivation.
- `flake.nix` should expose package outputs by importing/calling `package.nix`.
- Keep `devshell.nix` scoped to development shell concerns.
- Provide package outputs for the user-facing binaries, at minimum the Pod CLI and TUI binaries produced by the workspace.
- Provide a dev shell or equivalent developer environment if it can be done without large scope creep.
- Ensure runtime resources are included or discoverable.
- Built-in prompts/resources required at runtime must be packaged in the derivation output.
- Installed binaries should not rely on the source checkout layout unless explicitly running in development mode.
- Keep local/user configuration separate from packaged resources.
- Packaging should not bake user manifests, provider keys, sessions, memory, or runtime state into the derivation.
- Existing XDG / `INSOMNIA_*` path behavior should remain the source of user config/data/runtime locations.
- Make the package reproducible and CI-friendly.
- Pin inputs through the flake lock if a flake is used.
- Avoid network access during the build.
- Vendor or hash Cargo dependencies through normal Nix Rust packaging mechanisms.
- Document usage.
- How to build the package.
- How to run TUI/Pod binaries from Nix.
- How user config is discovered.
- Known limitations.
## Acceptance criteria
- `package.nix` contains the installable package derivation and is used by `flake.nix` package outputs.
- `nix build` or the documented equivalent builds the package from a clean checkout.
- Installed binaries can find built-in resources/prompts at runtime.
- User config/data/runtime paths continue to resolve through existing path logic and are not stored in the Nix store.
- A minimal smoke test or check verifies at least command startup/help/version without requiring real provider credentials.
- Documentation exists for Nix users.
- Packaging files are formatted by the relevant Nix formatter if one is adopted.
- `cargo fmt --check`
- Existing Rust checks affected by packaging changes still pass, or packaging-only validation is clearly documented.
## Out of scope
- Publishing to nixpkgs.
- NixOS module / Home Manager module.
- Packaging external LLM providers or model runtimes.
- Secret management for provider API keys.
- Changing manifest/path semantics specifically for Nix unless a separate design decision is made.
@@ -0,0 +1,73 @@
---
id: 20260528-152959-nix-packaging
slug: nix-packaging
title: Package Insomnia with Nix
status: closed
kind: task
priority: P2
labels: [packaging, nix, distribution]
created_at: 2026-05-28T15:29:59Z
updated_at: 2026-05-28T16:42:08Z
assignee: null
legacy_ticket: null
---
## Background
Insomnia should be easy to install and run on Nix/NixOS systems without requiring each user to hand-roll a local derivation. Add a Nix packaging entry point suitable for development and user installation.
This ticket is about packaging and installability, not changing runtime behavior. The package should build the Rust workspace binaries and include the runtime resources needed by the installed commands.
## Existing Nix file layout
The repository already separates the Nix package definition from the developer shell:
- `package.nix` is the package derivation used for install/build outputs.
- `devshell.nix` is for the development shell only.
- `flake.nix` may remain the entry point, but package outputs should call/use `package.nix`.
Do not implement the installable package primarily in `devshell.nix`. Update `devshell.nix` only if the development shell genuinely needs small supporting changes.
## Requirement
- Add Nix packaging for the repository.
- Use `package.nix` for the installable derivation.
- `flake.nix` should expose package outputs by importing/calling `package.nix`.
- Keep `devshell.nix` scoped to development shell concerns.
- Provide package outputs for the user-facing binaries, at minimum the Pod CLI and TUI binaries produced by the workspace.
- Provide a dev shell or equivalent developer environment if it can be done without large scope creep.
- Ensure runtime resources are included or discoverable.
- Built-in prompts/resources required at runtime must be packaged in the derivation output.
- Installed binaries should not rely on the source checkout layout unless explicitly running in development mode.
- Keep local/user configuration separate from packaged resources.
- Packaging should not bake user manifests, provider keys, sessions, memory, or runtime state into the derivation.
- Existing XDG / `INSOMNIA_*` path behavior should remain the source of user config/data/runtime locations.
- Make the package reproducible and CI-friendly.
- Pin inputs through the flake lock if a flake is used.
- Avoid network access during the build.
- Vendor or hash Cargo dependencies through normal Nix Rust packaging mechanisms.
- Document usage.
- How to build the package.
- How to run TUI/Pod binaries from Nix.
- How user config is discovered.
- Known limitations.
## Acceptance criteria
- `package.nix` contains the installable package derivation and is used by `flake.nix` package outputs.
- `nix build` or the documented equivalent builds the package from a clean checkout.
- Installed binaries can find built-in resources/prompts at runtime.
- User config/data/runtime paths continue to resolve through existing path logic and are not stored in the Nix store.
- A minimal smoke test or check verifies at least command startup/help/version without requiring real provider credentials.
- Documentation exists for Nix users.
- Packaging files are formatted by the relevant Nix formatter if one is adopted.
- `cargo fmt --check`
- Existing Rust checks affected by packaging changes still pass, or packaging-only validation is clearly documented.
## Out of scope
- Publishing to nixpkgs.
- NixOS module / Home Manager module.
- Packaging external LLM providers or model runtimes.
- Secret management for provider API keys.
- Changing manifest/path semantics specifically for Nix unless a separate design decision is made.
@@ -0,0 +1,88 @@
<!-- event: create author: tickets.sh at: 2026-05-28T15:29:59Z -->
## Created
Created by tickets.sh create.
---
<!-- event: close author: hare at: 2026-05-28T16:42:08Z status: closed -->
## Closed
---
id: 20260528-152959-nix-packaging
slug: nix-packaging
title: Package Insomnia with Nix
status: closed
kind: task
priority: P2
labels: [packaging, nix, distribution]
created_at: 2026-05-28T15:29:59Z
updated_at: 2026-05-28T16:42:08Z
assignee: null
legacy_ticket: null
---
## Background
Insomnia should be easy to install and run on Nix/NixOS systems without requiring each user to hand-roll a local derivation. Add a Nix packaging entry point suitable for development and user installation.
This ticket is about packaging and installability, not changing runtime behavior. The package should build the Rust workspace binaries and include the runtime resources needed by the installed commands.
## Existing Nix file layout
The repository already separates the Nix package definition from the developer shell:
- `package.nix` is the package derivation used for install/build outputs.
- `devshell.nix` is for the development shell only.
- `flake.nix` may remain the entry point, but package outputs should call/use `package.nix`.
Do not implement the installable package primarily in `devshell.nix`. Update `devshell.nix` only if the development shell genuinely needs small supporting changes.
## Requirement
- Add Nix packaging for the repository.
- Use `package.nix` for the installable derivation.
- `flake.nix` should expose package outputs by importing/calling `package.nix`.
- Keep `devshell.nix` scoped to development shell concerns.
- Provide package outputs for the user-facing binaries, at minimum the Pod CLI and TUI binaries produced by the workspace.
- Provide a dev shell or equivalent developer environment if it can be done without large scope creep.
- Ensure runtime resources are included or discoverable.
- Built-in prompts/resources required at runtime must be packaged in the derivation output.
- Installed binaries should not rely on the source checkout layout unless explicitly running in development mode.
- Keep local/user configuration separate from packaged resources.
- Packaging should not bake user manifests, provider keys, sessions, memory, or runtime state into the derivation.
- Existing XDG / `INSOMNIA_*` path behavior should remain the source of user config/data/runtime locations.
- Make the package reproducible and CI-friendly.
- Pin inputs through the flake lock if a flake is used.
- Avoid network access during the build.
- Vendor or hash Cargo dependencies through normal Nix Rust packaging mechanisms.
- Document usage.
- How to build the package.
- How to run TUI/Pod binaries from Nix.
- How user config is discovered.
- Known limitations.
## Acceptance criteria
- `package.nix` contains the installable package derivation and is used by `flake.nix` package outputs.
- `nix build` or the documented equivalent builds the package from a clean checkout.
- Installed binaries can find built-in resources/prompts at runtime.
- User config/data/runtime paths continue to resolve through existing path logic and are not stored in the Nix store.
- A minimal smoke test or check verifies at least command startup/help/version without requiring real provider credentials.
- Documentation exists for Nix users.
- Packaging files are formatted by the relevant Nix formatter if one is adopted.
- `cargo fmt --check`
- Existing Rust checks affected by packaging changes still pass, or packaging-only validation is clearly documented.
## Out of scope
- Publishing to nixpkgs.
- NixOS module / Home Manager module.
- Packaging external LLM providers or model runtimes.
- Secret management for provider API keys.
- Changing manifest/path semantics specifically for Nix unless a separate design decision is made.
---
@@ -0,0 +1,84 @@
---
id: 20260528-163238-multi-pod-view-section-layout
slug: multi-pod-view-section-layout
title: Polish multi-Pod view section layout
status: closed
kind: task
priority: P2
labels: [tui, pod, ux]
created_at: 2026-05-28T16:32:38Z
updated_at: 2026-05-28T16:49:25Z
assignee: null
legacy_ticket: null
---
## Background
`20260527-000023-multi-pod-view-ui` implemented the initial `tui --multi` dashboard. The current layout should be polished before building more interaction on top of it.
The desired list shape is sectioned by Pod state rather than a flat row list. The list area should visually emphasize live work first and keep closed/stopped history compact.
Target shape:
```text
--pending---
a
b
--working---
c
d
--closed--
# only a few rows
```
The blank area between `working` and `closed` is intentional: the live sections should occupy the available vertical space, while the closed section stays compact at the bottom.
There is also a visual defect where the input-area separator and the list-area separator produce two adjacent separators. The multi-Pod view should have a single clean boundary between the Pod list/dashboard and the composer/input area.
## Requirements
- Change `tui --multi` list layout to explicit sections:
- `pending`: live Pods that are idle/waiting and ready for input.
- `working`: live Pods that are running/processing, plus paused Pods if a separate paused section is not introduced.
- `closed`: stopped/restorable history entries.
- Render section headers even when a section is empty only if that makes the view easier to understand; otherwise empty sections may be hidden. The choice should be consistent and tested/snapshotted where practical.
- Allocate vertical space so that:
- live sections (`pending` + `working`) take the main flexible area.
- `closed` is pinned near the bottom of the list/dashboard area.
- `closed` shows only a small fixed number of rows initially, with 3 visible rows as the target.
- excess height appears as blank space above the `closed` section rather than expanding closed history.
- Keep selection/navigation sane across sections.
- Selection should move through visible rows in display order.
- Direct send eligibility remains based on the selected `PodListEntry` action state.
- Hidden closed rows must not accidentally become selected unless scrolling/paging for closed entries is explicitly implemented.
- Fix the double-separator defect between the Pod list/dashboard and the composer/input area.
- There should be one visual boundary, not two adjacent horizontal rules/borders.
- Do not introduce the same double-border issue between section headers and rows.
- Preserve existing `tui --multi` behavior outside layout.
- `tui --multi` CLI entrypoint and conflicts remain unchanged.
- Composer contents are preserved across selection changes.
- Direct send to selected idle live Pod remains supported.
- running/paused/stopped targets remain safely disabled unless separately implemented.
## Acceptance criteria
- `tui --multi` renders Pod rows grouped into `pending`, `working`, and compact `closed` sections.
- The closed section is limited to about 3 visible rows and is visually anchored below the flexible live area.
- The blank/flexible space is placed above `closed`, not below it and not by expanding closed history.
- The boundary between list/dashboard and composer has a single separator/border.
- Selection and direct-send target mapping still use the underlying `PodListEntry` and remain correct after sectioning.
- Focused tests cover section classification, closed-row limiting, selection over visible section rows, and composer separator layout state where practical.
- `cargo fmt --check`
- `cargo test -p tui multi --no-default-features` or equivalent focused tests.
- `cargo check -p tui -p client -p pod`
## Out of scope
- Reopening the completed `multi-pod-view-ui` ticket.
- Adding per-section scrolling unless needed for a minimal correct implementation.
- Changing `PodList` discovery/visibility semantics.
- Changing direct-send delivery semantics.
- Adding new CLI flags.
@@ -0,0 +1,84 @@
---
id: 20260528-163238-multi-pod-view-section-layout
slug: multi-pod-view-section-layout
title: Polish multi-Pod view section layout
status: closed
kind: task
priority: P2
labels: [tui, pod, ux]
created_at: 2026-05-28T16:32:38Z
updated_at: 2026-05-28T16:49:25Z
assignee: null
legacy_ticket: null
---
## Background
`20260527-000023-multi-pod-view-ui` implemented the initial `tui --multi` dashboard. The current layout should be polished before building more interaction on top of it.
The desired list shape is sectioned by Pod state rather than a flat row list. The list area should visually emphasize live work first and keep closed/stopped history compact.
Target shape:
```text
--pending---
a
b
--working---
c
d
--closed--
# only a few rows
```
The blank area between `working` and `closed` is intentional: the live sections should occupy the available vertical space, while the closed section stays compact at the bottom.
There is also a visual defect where the input-area separator and the list-area separator produce two adjacent separators. The multi-Pod view should have a single clean boundary between the Pod list/dashboard and the composer/input area.
## Requirements
- Change `tui --multi` list layout to explicit sections:
- `pending`: live Pods that are idle/waiting and ready for input.
- `working`: live Pods that are running/processing, plus paused Pods if a separate paused section is not introduced.
- `closed`: stopped/restorable history entries.
- Render section headers even when a section is empty only if that makes the view easier to understand; otherwise empty sections may be hidden. The choice should be consistent and tested/snapshotted where practical.
- Allocate vertical space so that:
- live sections (`pending` + `working`) take the main flexible area.
- `closed` is pinned near the bottom of the list/dashboard area.
- `closed` shows only a small fixed number of rows initially, with 3 visible rows as the target.
- excess height appears as blank space above the `closed` section rather than expanding closed history.
- Keep selection/navigation sane across sections.
- Selection should move through visible rows in display order.
- Direct send eligibility remains based on the selected `PodListEntry` action state.
- Hidden closed rows must not accidentally become selected unless scrolling/paging for closed entries is explicitly implemented.
- Fix the double-separator defect between the Pod list/dashboard and the composer/input area.
- There should be one visual boundary, not two adjacent horizontal rules/borders.
- Do not introduce the same double-border issue between section headers and rows.
- Preserve existing `tui --multi` behavior outside layout.
- `tui --multi` CLI entrypoint and conflicts remain unchanged.
- Composer contents are preserved across selection changes.
- Direct send to selected idle live Pod remains supported.
- running/paused/stopped targets remain safely disabled unless separately implemented.
## Acceptance criteria
- `tui --multi` renders Pod rows grouped into `pending`, `working`, and compact `closed` sections.
- The closed section is limited to about 3 visible rows and is visually anchored below the flexible live area.
- The blank/flexible space is placed above `closed`, not below it and not by expanding closed history.
- The boundary between list/dashboard and composer has a single separator/border.
- Selection and direct-send target mapping still use the underlying `PodListEntry` and remain correct after sectioning.
- Focused tests cover section classification, closed-row limiting, selection over visible section rows, and composer separator layout state where practical.
- `cargo fmt --check`
- `cargo test -p tui multi --no-default-features` or equivalent focused tests.
- `cargo check -p tui -p client -p pod`
## Out of scope
- Reopening the completed `multi-pod-view-ui` ticket.
- Adding per-section scrolling unless needed for a minimal correct implementation.
- Changing `PodList` discovery/visibility semantics.
- Changing direct-send delivery semantics.
- Adding new CLI flags.
@@ -0,0 +1,99 @@
<!-- event: create author: tickets.sh at: 2026-05-28T16:32:38Z -->
## Created
Created by tickets.sh create.
---
<!-- event: close author: hare at: 2026-05-28T16:49:25Z status: closed -->
## Closed
---
id: 20260528-163238-multi-pod-view-section-layout
slug: multi-pod-view-section-layout
title: Polish multi-Pod view section layout
status: closed
kind: task
priority: P2
labels: [tui, pod, ux]
created_at: 2026-05-28T16:32:38Z
updated_at: 2026-05-28T16:49:25Z
assignee: null
legacy_ticket: null
---
## Background
`20260527-000023-multi-pod-view-ui` implemented the initial `tui --multi` dashboard. The current layout should be polished before building more interaction on top of it.
The desired list shape is sectioned by Pod state rather than a flat row list. The list area should visually emphasize live work first and keep closed/stopped history compact.
Target shape:
```text
--pending---
a
b
--working---
c
d
--closed--
# only a few rows
```
The blank area between `working` and `closed` is intentional: the live sections should occupy the available vertical space, while the closed section stays compact at the bottom.
There is also a visual defect where the input-area separator and the list-area separator produce two adjacent separators. The multi-Pod view should have a single clean boundary between the Pod list/dashboard and the composer/input area.
## Requirements
- Change `tui --multi` list layout to explicit sections:
- `pending`: live Pods that are idle/waiting and ready for input.
- `working`: live Pods that are running/processing, plus paused Pods if a separate paused section is not introduced.
- `closed`: stopped/restorable history entries.
- Render section headers even when a section is empty only if that makes the view easier to understand; otherwise empty sections may be hidden. The choice should be consistent and tested/snapshotted where practical.
- Allocate vertical space so that:
- live sections (`pending` + `working`) take the main flexible area.
- `closed` is pinned near the bottom of the list/dashboard area.
- `closed` shows only a small fixed number of rows initially, with 3 visible rows as the target.
- excess height appears as blank space above the `closed` section rather than expanding closed history.
- Keep selection/navigation sane across sections.
- Selection should move through visible rows in display order.
- Direct send eligibility remains based on the selected `PodListEntry` action state.
- Hidden closed rows must not accidentally become selected unless scrolling/paging for closed entries is explicitly implemented.
- Fix the double-separator defect between the Pod list/dashboard and the composer/input area.
- There should be one visual boundary, not two adjacent horizontal rules/borders.
- Do not introduce the same double-border issue between section headers and rows.
- Preserve existing `tui --multi` behavior outside layout.
- `tui --multi` CLI entrypoint and conflicts remain unchanged.
- Composer contents are preserved across selection changes.
- Direct send to selected idle live Pod remains supported.
- running/paused/stopped targets remain safely disabled unless separately implemented.
## Acceptance criteria
- `tui --multi` renders Pod rows grouped into `pending`, `working`, and compact `closed` sections.
- The closed section is limited to about 3 visible rows and is visually anchored below the flexible live area.
- The blank/flexible space is placed above `closed`, not below it and not by expanding closed history.
- The boundary between list/dashboard and composer has a single separator/border.
- Selection and direct-send target mapping still use the underlying `PodListEntry` and remain correct after sectioning.
- Focused tests cover section classification, closed-row limiting, selection over visible section rows, and composer separator layout state where practical.
- `cargo fmt --check`
- `cargo test -p tui multi --no-default-features` or equivalent focused tests.
- `cargo check -p tui -p client -p pod`
## Out of scope
- Reopening the completed `multi-pod-view-ui` ticket.
- Adding per-section scrolling unless needed for a minimal correct implementation.
- Changing `PodList` discovery/visibility semantics.
- Changing direct-send delivery semantics.
- Adding new CLI flags.
---
@@ -0,0 +1,80 @@
---
id: 20260528-233524-multi-pod-open-return
slug: multi-pod-open-return
title: Return to multi-Pod view after opening a Pod
status: closed
kind: task
priority: P2
labels: [tui, pod, ux]
created_at: 2026-05-28T23:35:24Z
updated_at: 2026-05-28T23:57:49Z
assignee: null
legacy_ticket: null
---
## Background
`tui --multi` can open the selected Pod with `o`. The current implementation treats this as leaving the multi-Pod dashboard and tail-calling the normal single-Pod TUI. Once the single-Pod screen is detached with `Ctrl+D` / `Ctrl+C`, the process exits instead of returning to the multi-Pod view.
For now, no special "back mode" or dedicated back key is needed. The desired behavior is simpler: when the user opens a Pod from the multi-Pod dashboard, the normal single-Pod attach screen runs as a nested attach session. When that session exits normally by detach/quit (`Ctrl+D`, `Ctrl+C`, or equivalent normal exit), control returns to the multi-Pod dashboard.
This should be implemented by abstracting the TUI launch/control flow, not by adding protocol features or making the single-Pod App deeply aware of multi-Pod mode.
## Requirements
- `tui --multi` remains the entrypoint for the multi-Pod dashboard.
- In `tui --multi`, pressing `o` on a selected openable Pod opens the normal single-Pod conversation screen.
- When that single-Pod screen exits normally, TUI returns to the multi-Pod dashboard instead of exiting the process.
- `Ctrl+D` / `Ctrl+C` detach/quit from the opened single-Pod screen should return to multi view.
- Normal single-Pod launches such as `tui <pod>` / `tui --pod <name>` should continue to exit the process on `Ctrl+D` / `Ctrl+C`.
- Avoid introducing a dedicated back key or back mode for this ticket.
- The caller loop determines whether a normal single-Pod exit returns to multi view or exits the process.
- Preserve multi-Pod dashboard state where practical.
- The selected Pod name should remain selected after returning, if still visible.
- The multi-Pod composer contents should be preserved across open/return.
- The Pod list should refresh after returning so status changes are visible.
- Keep terminal handling clean.
- Do not unnecessarily leave/re-enter alternate screen between multi view and the nested single-Pod screen if the existing terminal can be reused safely.
- If reusing the same `Terminal`, ensure cursor/mouse/raw-mode cleanup remains correct on final exit and on errors.
- Error handling should be explicit.
- If opening the selected Pod fails before the single-Pod screen starts, show a multi-view notice and keep the dashboard active.
- If the single-Pod session exits with a fatal error, return that error or show a clear diagnostic according to the existing TUI error behavior; do not silently swallow fatal failures.
- Existing `tui --multi` direct send behavior, section layout, and separator fix must continue to work.
## Suggested implementation direction
- Split the current single-Pod attach runner into a reusable function that accepts an existing `Terminal` and returns when the attached screen exits.
- Change `run_multi()` from one-shot `multi_pod::run(...).await -> Open -> run_pod_name(...)` into a controller loop:
```text
loop:
run multi dashboard with previous app state / selected Pod
Quit => exit process
Open(pod) => run single-Pod attach screen using the same terminal
on normal exit, refresh dashboard and continue loop
```
- Avoid adding a new protocol method. This is local TUI orchestration.
- Avoid making `App` carry a generic `BackToMulti` mode unless it is strictly necessary; prefer caller-owned control flow.
## Acceptance criteria
- From `tui --multi`, pressing `o` opens the selected Pod's normal conversation screen.
- Pressing `Ctrl+D` / `Ctrl+C` in that opened screen returns to the multi-Pod dashboard.
- Starting a single-Pod TUI directly still exits on `Ctrl+D` / `Ctrl+C`.
- Returning to multi view preserves multi composer contents and selected Pod name when possible.
- Returning to multi view refreshes Pod status/list.
- Opening failure from multi view leaves the user in multi view with a visible notice.
- Existing multi-Pod tests still pass.
- Focused tests cover the controller/runner behavior where possible, especially distinguishing direct single-Pod launch from multi-owned nested launch.
- `cargo fmt --check`
- `cargo test -p tui multi --no-default-features` or equivalent focused tests.
- `cargo check -p tui -p client -p pod`
## Out of scope
- Dedicated back key.
- Per-Pod detail panes inside the multi-Pod dashboard.
- Protocol changes.
- Changing direct-send semantics.
- Changing Pod visibility/discovery rules.
@@ -0,0 +1,80 @@
---
id: 20260528-233524-multi-pod-open-return
slug: multi-pod-open-return
title: Return to multi-Pod view after opening a Pod
status: closed
kind: task
priority: P2
labels: [tui, pod, ux]
created_at: 2026-05-28T23:35:24Z
updated_at: 2026-05-28T23:57:49Z
assignee: null
legacy_ticket: null
---
## Background
`tui --multi` can open the selected Pod with `o`. The current implementation treats this as leaving the multi-Pod dashboard and tail-calling the normal single-Pod TUI. Once the single-Pod screen is detached with `Ctrl+D` / `Ctrl+C`, the process exits instead of returning to the multi-Pod view.
For now, no special "back mode" or dedicated back key is needed. The desired behavior is simpler: when the user opens a Pod from the multi-Pod dashboard, the normal single-Pod attach screen runs as a nested attach session. When that session exits normally by detach/quit (`Ctrl+D`, `Ctrl+C`, or equivalent normal exit), control returns to the multi-Pod dashboard.
This should be implemented by abstracting the TUI launch/control flow, not by adding protocol features or making the single-Pod App deeply aware of multi-Pod mode.
## Requirements
- `tui --multi` remains the entrypoint for the multi-Pod dashboard.
- In `tui --multi`, pressing `o` on a selected openable Pod opens the normal single-Pod conversation screen.
- When that single-Pod screen exits normally, TUI returns to the multi-Pod dashboard instead of exiting the process.
- `Ctrl+D` / `Ctrl+C` detach/quit from the opened single-Pod screen should return to multi view.
- Normal single-Pod launches such as `tui <pod>` / `tui --pod <name>` should continue to exit the process on `Ctrl+D` / `Ctrl+C`.
- Avoid introducing a dedicated back key or back mode for this ticket.
- The caller loop determines whether a normal single-Pod exit returns to multi view or exits the process.
- Preserve multi-Pod dashboard state where practical.
- The selected Pod name should remain selected after returning, if still visible.
- The multi-Pod composer contents should be preserved across open/return.
- The Pod list should refresh after returning so status changes are visible.
- Keep terminal handling clean.
- Do not unnecessarily leave/re-enter alternate screen between multi view and the nested single-Pod screen if the existing terminal can be reused safely.
- If reusing the same `Terminal`, ensure cursor/mouse/raw-mode cleanup remains correct on final exit and on errors.
- Error handling should be explicit.
- If opening the selected Pod fails before the single-Pod screen starts, show a multi-view notice and keep the dashboard active.
- If the single-Pod session exits with a fatal error, return that error or show a clear diagnostic according to the existing TUI error behavior; do not silently swallow fatal failures.
- Existing `tui --multi` direct send behavior, section layout, and separator fix must continue to work.
## Suggested implementation direction
- Split the current single-Pod attach runner into a reusable function that accepts an existing `Terminal` and returns when the attached screen exits.
- Change `run_multi()` from one-shot `multi_pod::run(...).await -> Open -> run_pod_name(...)` into a controller loop:
```text
loop:
run multi dashboard with previous app state / selected Pod
Quit => exit process
Open(pod) => run single-Pod attach screen using the same terminal
on normal exit, refresh dashboard and continue loop
```
- Avoid adding a new protocol method. This is local TUI orchestration.
- Avoid making `App` carry a generic `BackToMulti` mode unless it is strictly necessary; prefer caller-owned control flow.
## Acceptance criteria
- From `tui --multi`, pressing `o` opens the selected Pod's normal conversation screen.
- Pressing `Ctrl+D` / `Ctrl+C` in that opened screen returns to the multi-Pod dashboard.
- Starting a single-Pod TUI directly still exits on `Ctrl+D` / `Ctrl+C`.
- Returning to multi view preserves multi composer contents and selected Pod name when possible.
- Returning to multi view refreshes Pod status/list.
- Opening failure from multi view leaves the user in multi view with a visible notice.
- Existing multi-Pod tests still pass.
- Focused tests cover the controller/runner behavior where possible, especially distinguishing direct single-Pod launch from multi-owned nested launch.
- `cargo fmt --check`
- `cargo test -p tui multi --no-default-features` or equivalent focused tests.
- `cargo check -p tui -p client -p pod`
## Out of scope
- Dedicated back key.
- Per-Pod detail panes inside the multi-Pod dashboard.
- Protocol changes.
- Changing direct-send semantics.
- Changing Pod visibility/discovery rules.
@@ -0,0 +1,95 @@
<!-- event: create author: tickets.sh at: 2026-05-28T23:35:24Z -->
## Created
Created by tickets.sh create.
---
<!-- event: close author: hare at: 2026-05-28T23:57:49Z status: closed -->
## Closed
---
id: 20260528-233524-multi-pod-open-return
slug: multi-pod-open-return
title: Return to multi-Pod view after opening a Pod
status: closed
kind: task
priority: P2
labels: [tui, pod, ux]
created_at: 2026-05-28T23:35:24Z
updated_at: 2026-05-28T23:57:49Z
assignee: null
legacy_ticket: null
---
## Background
`tui --multi` can open the selected Pod with `o`. The current implementation treats this as leaving the multi-Pod dashboard and tail-calling the normal single-Pod TUI. Once the single-Pod screen is detached with `Ctrl+D` / `Ctrl+C`, the process exits instead of returning to the multi-Pod view.
For now, no special "back mode" or dedicated back key is needed. The desired behavior is simpler: when the user opens a Pod from the multi-Pod dashboard, the normal single-Pod attach screen runs as a nested attach session. When that session exits normally by detach/quit (`Ctrl+D`, `Ctrl+C`, or equivalent normal exit), control returns to the multi-Pod dashboard.
This should be implemented by abstracting the TUI launch/control flow, not by adding protocol features or making the single-Pod App deeply aware of multi-Pod mode.
## Requirements
- `tui --multi` remains the entrypoint for the multi-Pod dashboard.
- In `tui --multi`, pressing `o` on a selected openable Pod opens the normal single-Pod conversation screen.
- When that single-Pod screen exits normally, TUI returns to the multi-Pod dashboard instead of exiting the process.
- `Ctrl+D` / `Ctrl+C` detach/quit from the opened single-Pod screen should return to multi view.
- Normal single-Pod launches such as `tui <pod>` / `tui --pod <name>` should continue to exit the process on `Ctrl+D` / `Ctrl+C`.
- Avoid introducing a dedicated back key or back mode for this ticket.
- The caller loop determines whether a normal single-Pod exit returns to multi view or exits the process.
- Preserve multi-Pod dashboard state where practical.
- The selected Pod name should remain selected after returning, if still visible.
- The multi-Pod composer contents should be preserved across open/return.
- The Pod list should refresh after returning so status changes are visible.
- Keep terminal handling clean.
- Do not unnecessarily leave/re-enter alternate screen between multi view and the nested single-Pod screen if the existing terminal can be reused safely.
- If reusing the same `Terminal`, ensure cursor/mouse/raw-mode cleanup remains correct on final exit and on errors.
- Error handling should be explicit.
- If opening the selected Pod fails before the single-Pod screen starts, show a multi-view notice and keep the dashboard active.
- If the single-Pod session exits with a fatal error, return that error or show a clear diagnostic according to the existing TUI error behavior; do not silently swallow fatal failures.
- Existing `tui --multi` direct send behavior, section layout, and separator fix must continue to work.
## Suggested implementation direction
- Split the current single-Pod attach runner into a reusable function that accepts an existing `Terminal` and returns when the attached screen exits.
- Change `run_multi()` from one-shot `multi_pod::run(...).await -> Open -> run_pod_name(...)` into a controller loop:
```text
loop:
run multi dashboard with previous app state / selected Pod
Quit => exit process
Open(pod) => run single-Pod attach screen using the same terminal
on normal exit, refresh dashboard and continue loop
```
- Avoid adding a new protocol method. This is local TUI orchestration.
- Avoid making `App` carry a generic `BackToMulti` mode unless it is strictly necessary; prefer caller-owned control flow.
## Acceptance criteria
- From `tui --multi`, pressing `o` opens the selected Pod's normal conversation screen.
- Pressing `Ctrl+D` / `Ctrl+C` in that opened screen returns to the multi-Pod dashboard.
- Starting a single-Pod TUI directly still exits on `Ctrl+D` / `Ctrl+C`.
- Returning to multi view preserves multi composer contents and selected Pod name when possible.
- Returning to multi view refreshes Pod status/list.
- Opening failure from multi view leaves the user in multi view with a visible notice.
- Existing multi-Pod tests still pass.
- Focused tests cover the controller/runner behavior where possible, especially distinguishing direct single-Pod launch from multi-owned nested launch.
- `cargo fmt --check`
- `cargo test -p tui multi --no-default-features` or equivalent focused tests.
- `cargo check -p tui -p client -p pod`
## Out of scope
- Dedicated back key.
- Per-Pod detail panes inside the multi-Pod dashboard.
- Protocol changes.
- Changing direct-send semantics.
- Changing Pod visibility/discovery rules.
---
@@ -0,0 +1,63 @@
---
id: 20260529-001326-rename-installed-binaries
slug: rename-installed-binaries
title: Rename installed binaries
status: closed
kind: task
priority: P2
labels: [cli, packaging, tui, pod]
created_at: 2026-05-29T00:13:26Z
updated_at: 2026-05-29T00:39:08Z
assignee: null
legacy_ticket: null
---
## Background
The workspace crate names `tui` and `pod` are useful internally, but the installed command names are too generic for user environments. `tui` does not identify the application, and `pod` collides with common terminology and other tooling.
Use application-specific binary names for installed commands:
- `insomnia`: the main terminal UI / user entrypoint, currently built from the `tui` crate.
- `insomnia-pod`: the Pod CLI/runtime command, currently built from the `pod` crate.
This is a command name change, not a crate rename. Keep the Rust crate/package names `tui` and `pod` unless there is a separate design decision to rename crates.
## Requirements
- Rename Cargo binary outputs:
- `crates/tui` binary name becomes `insomnia`.
- `crates/pod` binary name becomes `insomnia-pod`.
- Do not add legacy `tui` / `pod` installed aliases unless a concrete internal dependency requires it and is documented.
- Update Nix packaging to install and check the new binary names.
- `$out/bin/insomnia`
- `$out/bin/insomnia-pod`
- Update flake apps to use the new command names.
- default app should run `insomnia`.
- expose app entries for `insomnia` and `insomnia-pod`.
- Update docs that instruct users to run `tui` / `pod` as installed commands.
- Keep references to crate/package names where they are explicitly Cargo package names, e.g. `cargo check -p tui`.
- Prefer `cargo run -p tui -- ...` in development docs if referring to crate-based development invocation, but installed usage should use `insomnia`.
- Audit code/tests/scripts for assumptions that installed binary names are `tui` or `pod`.
- Internal runtime process spawning must still work.
- If code intentionally uses Cargo package names, leave them unchanged.
- Keep CLI semantics unchanged except for command names.
## Acceptance criteria
- `cargo build -p tui -p pod` produces runnable binaries named `insomnia` and `insomnia-pod`.
- `cargo run -p tui -- --help` and `cargo run -p pod -- --help` still work as development package invocations.
- Installed/Nix package smoke checks look for `insomnia` and `insomnia-pod`, not `tui` and `pod`.
- `flake.nix` app outputs use the new binary names.
- User-facing docs no longer tell users to run installed commands as `tui` / `pod`.
- No legacy aliases are installed unless explicitly justified.
- `cargo fmt --check`
- Focused cargo checks/tests for affected crates, at least `cargo check -p tui -p pod`.
- Nix validation that does not require network where possible, e.g. `nix flake check --no-build`.
## Out of scope
- Renaming crates/packages from `tui` / `pod`.
- Changing CLI argument semantics.
- Changing Pod protocol or socket behavior.
- Publishing or Home Manager module changes.
@@ -0,0 +1,63 @@
---
id: 20260529-001326-rename-installed-binaries
slug: rename-installed-binaries
title: Rename installed binaries
status: closed
kind: task
priority: P2
labels: [cli, packaging, tui, pod]
created_at: 2026-05-29T00:13:26Z
updated_at: 2026-05-29T00:39:08Z
assignee: null
legacy_ticket: null
---
## Background
The workspace crate names `tui` and `pod` are useful internally, but the installed command names are too generic for user environments. `tui` does not identify the application, and `pod` collides with common terminology and other tooling.
Use application-specific binary names for installed commands:
- `insomnia`: the main terminal UI / user entrypoint, currently built from the `tui` crate.
- `insomnia-pod`: the Pod CLI/runtime command, currently built from the `pod` crate.
This is a command name change, not a crate rename. Keep the Rust crate/package names `tui` and `pod` unless there is a separate design decision to rename crates.
## Requirements
- Rename Cargo binary outputs:
- `crates/tui` binary name becomes `insomnia`.
- `crates/pod` binary name becomes `insomnia-pod`.
- Do not add legacy `tui` / `pod` installed aliases unless a concrete internal dependency requires it and is documented.
- Update Nix packaging to install and check the new binary names.
- `$out/bin/insomnia`
- `$out/bin/insomnia-pod`
- Update flake apps to use the new command names.
- default app should run `insomnia`.
- expose app entries for `insomnia` and `insomnia-pod`.
- Update docs that instruct users to run `tui` / `pod` as installed commands.
- Keep references to crate/package names where they are explicitly Cargo package names, e.g. `cargo check -p tui`.
- Prefer `cargo run -p tui -- ...` in development docs if referring to crate-based development invocation, but installed usage should use `insomnia`.
- Audit code/tests/scripts for assumptions that installed binary names are `tui` or `pod`.
- Internal runtime process spawning must still work.
- If code intentionally uses Cargo package names, leave them unchanged.
- Keep CLI semantics unchanged except for command names.
## Acceptance criteria
- `cargo build -p tui -p pod` produces runnable binaries named `insomnia` and `insomnia-pod`.
- `cargo run -p tui -- --help` and `cargo run -p pod -- --help` still work as development package invocations.
- Installed/Nix package smoke checks look for `insomnia` and `insomnia-pod`, not `tui` and `pod`.
- `flake.nix` app outputs use the new binary names.
- User-facing docs no longer tell users to run installed commands as `tui` / `pod`.
- No legacy aliases are installed unless explicitly justified.
- `cargo fmt --check`
- Focused cargo checks/tests for affected crates, at least `cargo check -p tui -p pod`.
- Nix validation that does not require network where possible, e.g. `nix flake check --no-build`.
## Out of scope
- Renaming crates/packages from `tui` / `pod`.
- Changing CLI argument semantics.
- Changing Pod protocol or socket behavior.
- Publishing or Home Manager module changes.
@@ -0,0 +1,78 @@
<!-- event: create author: tickets.sh at: 2026-05-29T00:13:26Z -->
## Created
Created by tickets.sh create.
---
<!-- event: close author: hare at: 2026-05-29T00:39:08Z status: closed -->
## Closed
---
id: 20260529-001326-rename-installed-binaries
slug: rename-installed-binaries
title: Rename installed binaries
status: closed
kind: task
priority: P2
labels: [cli, packaging, tui, pod]
created_at: 2026-05-29T00:13:26Z
updated_at: 2026-05-29T00:39:08Z
assignee: null
legacy_ticket: null
---
## Background
The workspace crate names `tui` and `pod` are useful internally, but the installed command names are too generic for user environments. `tui` does not identify the application, and `pod` collides with common terminology and other tooling.
Use application-specific binary names for installed commands:
- `insomnia`: the main terminal UI / user entrypoint, currently built from the `tui` crate.
- `insomnia-pod`: the Pod CLI/runtime command, currently built from the `pod` crate.
This is a command name change, not a crate rename. Keep the Rust crate/package names `tui` and `pod` unless there is a separate design decision to rename crates.
## Requirements
- Rename Cargo binary outputs:
- `crates/tui` binary name becomes `insomnia`.
- `crates/pod` binary name becomes `insomnia-pod`.
- Do not add legacy `tui` / `pod` installed aliases unless a concrete internal dependency requires it and is documented.
- Update Nix packaging to install and check the new binary names.
- `$out/bin/insomnia`
- `$out/bin/insomnia-pod`
- Update flake apps to use the new command names.
- default app should run `insomnia`.
- expose app entries for `insomnia` and `insomnia-pod`.
- Update docs that instruct users to run `tui` / `pod` as installed commands.
- Keep references to crate/package names where they are explicitly Cargo package names, e.g. `cargo check -p tui`.
- Prefer `cargo run -p tui -- ...` in development docs if referring to crate-based development invocation, but installed usage should use `insomnia`.
- Audit code/tests/scripts for assumptions that installed binary names are `tui` or `pod`.
- Internal runtime process spawning must still work.
- If code intentionally uses Cargo package names, leave them unchanged.
- Keep CLI semantics unchanged except for command names.
## Acceptance criteria
- `cargo build -p tui -p pod` produces runnable binaries named `insomnia` and `insomnia-pod`.
- `cargo run -p tui -- --help` and `cargo run -p pod -- --help` still work as development package invocations.
- Installed/Nix package smoke checks look for `insomnia` and `insomnia-pod`, not `tui` and `pod`.
- `flake.nix` app outputs use the new binary names.
- User-facing docs no longer tell users to run installed commands as `tui` / `pod`.
- No legacy aliases are installed unless explicitly justified.
- `cargo fmt --check`
- Focused cargo checks/tests for affected crates, at least `cargo check -p tui -p pod`.
- Nix validation that does not require network where possible, e.g. `nix flake check --no-build`.
## Out of scope
- Renaming crates/packages from `tui` / `pod`.
- Changing CLI argument semantics.
- Changing Pod protocol or socket behavior.
- Publishing or Home Manager module changes.
---
@@ -0,0 +1,58 @@
---
id: 20260529-010200-tui-command-completion-apply
slug: tui-command-completion-apply
title: Apply command completions from keyboard
status: closed
kind: task
priority: P2
labels: [tui, commands, ux]
created_at: 2026-05-29T01:02:00Z
updated_at: 2026-05-29T02:08:56Z
assignee: null
legacy_ticket: null
---
## Background
The TUI command mode (`:`) can show completion candidates, but the candidates cannot currently be applied with keyboard completion keys such as Tab. Also, when there is an unambiguous or selected completion candidate, pressing Enter should be able to complete the command and execute it in one action.
This should make command mode behave like a small command palette rather than a read-only suggestion list.
## Requirements
- Add keyboard application for command completions in command mode.
- Tab should apply the currently selected completion candidate when a candidate exists.
- If there is no explicit selection but exactly one candidate exists, Tab should apply that candidate.
- Applying a command completion should replace the command name prefix with the canonical command name and preserve/position trailing argument editing sensibly.
- Enter behavior should use completion when appropriate.
- If the command input has completion candidates and the current command name is incomplete, Enter should apply the selected/unambiguous candidate and execute the completed command in one action when doing so yields a complete executable command.
- If applying a completion only fills the command name and arguments are still required, Enter should complete the command name and keep command mode active with a helpful state/notice rather than executing an invalid command.
- If no candidate applies, existing command execution/error behavior should remain.
- Completion selection/navigation should be keyboard-accessible.
- Existing up/down behavior should not regress.
- If Tab cycles candidates today for another completion surface, command mode should still have a clear apply path.
- Keep normal composer completion behavior unchanged.
- This ticket is for `:` command mode completion, not file-ref/chip completion in normal input.
- Keep command execution local.
- Commands must not be submitted as user messages.
## Acceptance criteria
- In command mode, typing a command prefix and pressing Tab fills the selected/unambiguous command completion.
- In command mode, typing a command prefix with a selected/unambiguous executable completion and pressing Enter completes and executes it in one action.
- Ambiguous completions do not execute the wrong command silently; they require selection or further typing.
- Commands requiring arguments are not executed with missing arguments just because Enter applied the command name.
- Existing command execution behavior for fully typed commands is unchanged.
- Normal composer/file-ref completion behavior is unchanged.
- Focused tests cover Tab apply, Enter complete-and-execute, ambiguous candidate handling, and argument-required behavior.
- `cargo fmt --check`
- Relevant TUI command tests, e.g. `cargo test -p tui command --no-default-features` or equivalent.
- `cargo check -p tui`
## Out of scope
- New commands.
- Fuzzy matching beyond current prefix/alias suggestions.
- Mouse selection in the completion popup.
- Normal input/file reference completion changes.
- Changing command registry semantics outside completion application.
@@ -0,0 +1,58 @@
---
id: 20260529-010200-tui-command-completion-apply
slug: tui-command-completion-apply
title: Apply command completions from keyboard
status: closed
kind: task
priority: P2
labels: [tui, commands, ux]
created_at: 2026-05-29T01:02:00Z
updated_at: 2026-05-29T02:08:56Z
assignee: null
legacy_ticket: null
---
## Background
The TUI command mode (`:`) can show completion candidates, but the candidates cannot currently be applied with keyboard completion keys such as Tab. Also, when there is an unambiguous or selected completion candidate, pressing Enter should be able to complete the command and execute it in one action.
This should make command mode behave like a small command palette rather than a read-only suggestion list.
## Requirements
- Add keyboard application for command completions in command mode.
- Tab should apply the currently selected completion candidate when a candidate exists.
- If there is no explicit selection but exactly one candidate exists, Tab should apply that candidate.
- Applying a command completion should replace the command name prefix with the canonical command name and preserve/position trailing argument editing sensibly.
- Enter behavior should use completion when appropriate.
- If the command input has completion candidates and the current command name is incomplete, Enter should apply the selected/unambiguous candidate and execute the completed command in one action when doing so yields a complete executable command.
- If applying a completion only fills the command name and arguments are still required, Enter should complete the command name and keep command mode active with a helpful state/notice rather than executing an invalid command.
- If no candidate applies, existing command execution/error behavior should remain.
- Completion selection/navigation should be keyboard-accessible.
- Existing up/down behavior should not regress.
- If Tab cycles candidates today for another completion surface, command mode should still have a clear apply path.
- Keep normal composer completion behavior unchanged.
- This ticket is for `:` command mode completion, not file-ref/chip completion in normal input.
- Keep command execution local.
- Commands must not be submitted as user messages.
## Acceptance criteria
- In command mode, typing a command prefix and pressing Tab fills the selected/unambiguous command completion.
- In command mode, typing a command prefix with a selected/unambiguous executable completion and pressing Enter completes and executes it in one action.
- Ambiguous completions do not execute the wrong command silently; they require selection or further typing.
- Commands requiring arguments are not executed with missing arguments just because Enter applied the command name.
- Existing command execution behavior for fully typed commands is unchanged.
- Normal composer/file-ref completion behavior is unchanged.
- Focused tests cover Tab apply, Enter complete-and-execute, ambiguous candidate handling, and argument-required behavior.
- `cargo fmt --check`
- Relevant TUI command tests, e.g. `cargo test -p tui command --no-default-features` or equivalent.
- `cargo check -p tui`
## Out of scope
- New commands.
- Fuzzy matching beyond current prefix/alias suggestions.
- Mouse selection in the completion popup.
- Normal input/file reference completion changes.
- Changing command registry semantics outside completion application.
@@ -0,0 +1,73 @@
<!-- event: create author: tickets.sh at: 2026-05-29T01:02:00Z -->
## Created
Created by tickets.sh create.
---
<!-- event: close author: hare at: 2026-05-29T02:08:56Z status: closed -->
## Closed
---
id: 20260529-010200-tui-command-completion-apply
slug: tui-command-completion-apply
title: Apply command completions from keyboard
status: closed
kind: task
priority: P2
labels: [tui, commands, ux]
created_at: 2026-05-29T01:02:00Z
updated_at: 2026-05-29T02:08:56Z
assignee: null
legacy_ticket: null
---
## Background
The TUI command mode (`:`) can show completion candidates, but the candidates cannot currently be applied with keyboard completion keys such as Tab. Also, when there is an unambiguous or selected completion candidate, pressing Enter should be able to complete the command and execute it in one action.
This should make command mode behave like a small command palette rather than a read-only suggestion list.
## Requirements
- Add keyboard application for command completions in command mode.
- Tab should apply the currently selected completion candidate when a candidate exists.
- If there is no explicit selection but exactly one candidate exists, Tab should apply that candidate.
- Applying a command completion should replace the command name prefix with the canonical command name and preserve/position trailing argument editing sensibly.
- Enter behavior should use completion when appropriate.
- If the command input has completion candidates and the current command name is incomplete, Enter should apply the selected/unambiguous candidate and execute the completed command in one action when doing so yields a complete executable command.
- If applying a completion only fills the command name and arguments are still required, Enter should complete the command name and keep command mode active with a helpful state/notice rather than executing an invalid command.
- If no candidate applies, existing command execution/error behavior should remain.
- Completion selection/navigation should be keyboard-accessible.
- Existing up/down behavior should not regress.
- If Tab cycles candidates today for another completion surface, command mode should still have a clear apply path.
- Keep normal composer completion behavior unchanged.
- This ticket is for `:` command mode completion, not file-ref/chip completion in normal input.
- Keep command execution local.
- Commands must not be submitted as user messages.
## Acceptance criteria
- In command mode, typing a command prefix and pressing Tab fills the selected/unambiguous command completion.
- In command mode, typing a command prefix with a selected/unambiguous executable completion and pressing Enter completes and executes it in one action.
- Ambiguous completions do not execute the wrong command silently; they require selection or further typing.
- Commands requiring arguments are not executed with missing arguments just because Enter applied the command name.
- Existing command execution behavior for fully typed commands is unchanged.
- Normal composer/file-ref completion behavior is unchanged.
- Focused tests cover Tab apply, Enter complete-and-execute, ambiguous candidate handling, and argument-required behavior.
- `cargo fmt --check`
- Relevant TUI command tests, e.g. `cargo test -p tui command --no-default-features` or equivalent.
- `cargo check -p tui`
## Out of scope
- New commands.
- Fuzzy matching beyond current prefix/alias suggestions.
- Mouse selection in the completion popup.
- Normal input/file reference completion changes.
- Changing command registry semantics outside completion application.
---
@@ -0,0 +1,55 @@
---
id: 20260529-010200-tui-composer-cursor-scroll
slug: tui-composer-cursor-scroll
title: Scroll TUI composer around cursor
status: closed
kind: task
priority: P2
labels: [tui, input, ux]
created_at: 2026-05-29T01:02:00Z
updated_at: 2026-05-29T02:08:04Z
assignee: null
legacy_ticket: null
---
## Background
The TUI composer/input area has a fixed visible height. When the input buffer grows beyond the visible area (for example 10+ lines), the rendered text is clipped instead of scrolling to keep the cursor visible.
This makes editing long messages unreliable: the user can continue typing or moving the cursor, but the relevant lines may be outside the visible area.
## Requirements
- Implement cursor-based vertical scrolling for the normal composer input area.
- The visible viewport should follow the cursor line when the input has more lines than the allocated input height.
- Moving the cursor above the viewport scrolls up.
- Moving the cursor below the viewport scrolls down.
- Typing new lines at the bottom keeps the cursor visible.
- Deleting lines clamps the scroll offset to valid bounds.
- Preserve existing input behavior:
- editing operations.
- cursor movement.
- selection/completion behavior for file refs if applicable.
- queued input behavior.
- command mode behavior unless command input shares the same rendering path and needs the same fix.
- The cursor's terminal position should correspond to the visible cursor location after scrolling.
- The implementation should not simply increase composer height or hide conversation content indefinitely.
- Keep visual separators/borders consistent with the existing TUI layout.
## Acceptance criteria
- A composer buffer longer than the visible input area renders a window around the cursor instead of clipping from a fixed origin.
- Cursor up/down/page movement updates the composer viewport correctly.
- Inserting/deleting lines keeps viewport bounds valid.
- Existing short single-line and small multi-line input rendering remains unchanged.
- Focused tests cover viewport calculation around cursor position and clamping.
- `cargo fmt --check`
- Relevant TUI focused tests, e.g. `cargo test -p tui input --no-default-features` or equivalent.
- `cargo check -p tui`
## Out of scope
- Resizable composer UX redesign.
- Mouse scrolling inside composer.
- Horizontal scrolling/wrapping redesign beyond what is needed to keep current behavior correct.
- Changing command completion behavior; see `20260529-010200-tui-command-completion-apply`.
@@ -0,0 +1,55 @@
---
id: 20260529-010200-tui-composer-cursor-scroll
slug: tui-composer-cursor-scroll
title: Scroll TUI composer around cursor
status: closed
kind: task
priority: P2
labels: [tui, input, ux]
created_at: 2026-05-29T01:02:00Z
updated_at: 2026-05-29T02:08:03Z
assignee: null
legacy_ticket: null
---
## Background
The TUI composer/input area has a fixed visible height. When the input buffer grows beyond the visible area (for example 10+ lines), the rendered text is clipped instead of scrolling to keep the cursor visible.
This makes editing long messages unreliable: the user can continue typing or moving the cursor, but the relevant lines may be outside the visible area.
## Requirements
- Implement cursor-based vertical scrolling for the normal composer input area.
- The visible viewport should follow the cursor line when the input has more lines than the allocated input height.
- Moving the cursor above the viewport scrolls up.
- Moving the cursor below the viewport scrolls down.
- Typing new lines at the bottom keeps the cursor visible.
- Deleting lines clamps the scroll offset to valid bounds.
- Preserve existing input behavior:
- editing operations.
- cursor movement.
- selection/completion behavior for file refs if applicable.
- queued input behavior.
- command mode behavior unless command input shares the same rendering path and needs the same fix.
- The cursor's terminal position should correspond to the visible cursor location after scrolling.
- The implementation should not simply increase composer height or hide conversation content indefinitely.
- Keep visual separators/borders consistent with the existing TUI layout.
## Acceptance criteria
- A composer buffer longer than the visible input area renders a window around the cursor instead of clipping from a fixed origin.
- Cursor up/down/page movement updates the composer viewport correctly.
- Inserting/deleting lines keeps viewport bounds valid.
- Existing short single-line and small multi-line input rendering remains unchanged.
- Focused tests cover viewport calculation around cursor position and clamping.
- `cargo fmt --check`
- Relevant TUI focused tests, e.g. `cargo test -p tui input --no-default-features` or equivalent.
- `cargo check -p tui`
## Out of scope
- Resizable composer UX redesign.
- Mouse scrolling inside composer.
- Horizontal scrolling/wrapping redesign beyond what is needed to keep current behavior correct.
- Changing command completion behavior; see `20260529-010200-tui-command-completion-apply`.

Some files were not shown because too many files have changed in this diff Show More