From d5b919e0d6bc9e4f22f564add2c2094f045f1d41 Mon Sep 17 00:00:00 2001 From: Hare Date: Fri, 5 Jun 2026 09:50:03 +0900 Subject: [PATCH] task: plan hook task state ownership --- .../hook-context-authority-handles.md | 14 ++++ .../item.md | 2 +- .../thread.md | 22 +++++ .../artifacts/.gitkeep | 0 .../artifacts/task-hook-investigation.md | 18 ++++ .../item.md | 73 ++++++++++++++++ .../thread.md | 33 ++++++++ .../artifacts/.gitkeep | 0 .../item.md | 84 +++++++++++++++++++ .../thread.md | 33 ++++++++ 10 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 work-items/open/20260604-234844-feature-api-authority-separation/artifacts/hook-context-authority-handles.md create mode 100644 work-items/open/20260605-004807-hook-context-system-item-sink/artifacts/.gitkeep create mode 100644 work-items/open/20260605-004807-hook-context-system-item-sink/artifacts/task-hook-investigation.md create mode 100644 work-items/open/20260605-004807-hook-context-system-item-sink/item.md create mode 100644 work-items/open/20260605-004807-hook-context-system-item-sink/thread.md create mode 100644 work-items/open/20260605-004807-task-feature-own-store-reminder-hooks/artifacts/.gitkeep create mode 100644 work-items/open/20260605-004807-task-feature-own-store-reminder-hooks/item.md create mode 100644 work-items/open/20260605-004807-task-feature-own-store-reminder-hooks/thread.md diff --git a/work-items/open/20260604-234844-feature-api-authority-separation/artifacts/hook-context-authority-handles.md b/work-items/open/20260604-234844-feature-api-authority-separation/artifacts/hook-context-authority-handles.md new file mode 100644 index 00000000..be21dd9d --- /dev/null +++ b/work-items/open/20260604-234844-feature-api-authority-separation/artifacts/hook-context-authority-handles.md @@ -0,0 +1,14 @@ +# Decision: authority handles live in Hook contexts, not Hook return effects + +The internal-module and external-plugin authority split should treat host-authority APIs as handles supplied by the host, including inside Hooks. + +Implications: + +- Hook return values remain per-hook-point flow-control actions. +- Side effects such as durable model-visible SystemItem append are performed through typed host handles on event-specific Hook contexts. +- Built-in internal modules may receive handles according to host policy without user-facing external-plugin approval. +- Future external plugins receive only the handles allowed by their approved host authorities. +- The main API should not be “return an effect and let the host reject it at runtime.” Rejection remains defense-in-depth for malformed calls, missing handles, bounds, and policy violations. +- Do not model every authority combination as a distinct Hook context type. Use event-specific context types with authority-specific handles whose constructors are host-owned. + +This preserves the clean distinction: contribution declarations are descriptor-locked; dangerous host APIs are represented by host-created handles; normal tool permission remains the per-call execution gate. diff --git a/work-items/open/20260604-234844-feature-api-authority-separation/item.md b/work-items/open/20260604-234844-feature-api-authority-separation/item.md index ff1adbfc..ad036cad 100644 --- a/work-items/open/20260604-234844-feature-api-authority-separation/item.md +++ b/work-items/open/20260604-234844-feature-api-authority-separation/item.md @@ -7,7 +7,7 @@ kind: task priority: P1 labels: [plugin, feature-registry, permissions, architecture] created_at: 2026-06-04T23:48:44Z -updated_at: 2026-06-04T23:50:15Z +updated_at: 2026-06-05T00:49:53Z assignee: null legacy_ticket: null --- diff --git a/work-items/open/20260604-234844-feature-api-authority-separation/thread.md b/work-items/open/20260604-234844-feature-api-authority-separation/thread.md index 2bef2448..e0ad2b42 100644 --- a/work-items/open/20260604-234844-feature-api-authority-separation/thread.md +++ b/work-items/open/20260604-234844-feature-api-authority-separation/thread.md @@ -27,4 +27,26 @@ The external-plugin authority model remains necessary for sandbox/object-capabil This split should be implemented separately from the Task tools extraction. The Task tools extraction should validate the contribution-only built-in module path without solving external plugin approval. +--- + + + +## Decision + +# Decision: authority handles live in Hook contexts, not Hook return effects + +The internal-module and external-plugin authority split should treat host-authority APIs as handles supplied by the host, including inside Hooks. + +Implications: + +- Hook return values remain per-hook-point flow-control actions. +- Side effects such as durable model-visible SystemItem append are performed through typed host handles on event-specific Hook contexts. +- Built-in internal modules may receive handles according to host policy without user-facing external-plugin approval. +- Future external plugins receive only the handles allowed by their approved host authorities. +- The main API should not be “return an effect and let the host reject it at runtime.” Rejection remains defense-in-depth for malformed calls, missing handles, bounds, and policy violations. +- Do not model every authority combination as a distinct Hook context type. Use event-specific context types with authority-specific handles whose constructors are host-owned. + +This preserves the clean distinction: contribution declarations are descriptor-locked; dangerous host APIs are represented by host-created handles; normal tool permission remains the per-call execution gate. + + --- diff --git a/work-items/open/20260605-004807-hook-context-system-item-sink/artifacts/.gitkeep b/work-items/open/20260605-004807-hook-context-system-item-sink/artifacts/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/work-items/open/20260605-004807-hook-context-system-item-sink/artifacts/task-hook-investigation.md b/work-items/open/20260605-004807-hook-context-system-item-sink/artifacts/task-hook-investigation.md new file mode 100644 index 00000000..ab1b6248 --- /dev/null +++ b/work-items/open/20260605-004807-hook-context-system-item-sink/artifacts/task-hook-investigation.md @@ -0,0 +1,18 @@ +# Investigation: Task state and Hook side-effect boundary + +## Findings + +- Hook action types are already separated per hook point after Hook hardening. The next design should preserve that: flow-control actions stay event-specific rather than becoming one global `HookDecision`. +- Hook inputs are still summary structs, not contexts with host-created handles. That is the missing abstraction for feature-owned behavior that needs durable host side effects. +- `TaskStore` is still owned by `Pod`, and `TaskReminderState`/reminder emission is still owned by `PodInterceptor`. +- The Task built-in feature module currently contributes only the four Task tools and receives `TaskStore` from Pod. This is an incomplete internal-module boundary: Task-specific state still remains on the Pod side. +- `SystemItem::TaskReminder` is currently appended through `PodInterceptor::pending_history_appends()`, which is the correct durable history direction but the wrong ownership location for Task-specific logic. + +## Decision + +Split follow-up into two steps: + +1. Add Hook context host handles, especially a durable `SystemItem` append handle. Hook returns remain per-hook-point flow-control actions. No raw `Item` injection and no generic effect/event channel. +2. Move TaskStore and Task reminder logic into the Task feature module, implemented as Task-owned tools plus hooks that use the host-provided SystemItem append handle. + +This keeps Pod responsible for generic host surfaces and history authority, while Task owns Task-specific state and policy. diff --git a/work-items/open/20260605-004807-hook-context-system-item-sink/item.md b/work-items/open/20260605-004807-hook-context-system-item-sink/item.md new file mode 100644 index 00000000..91fe66c9 --- /dev/null +++ b/work-items/open/20260605-004807-hook-context-system-item-sink/item.md @@ -0,0 +1,73 @@ +--- +id: 20260605-004807-hook-context-system-item-sink +slug: hook-context-system-item-sink +title: Hook: add context handles for host-mediated SystemItem append +status: open +kind: feature +priority: P1 +labels: [hooks, feature-registry, history, task-reminder] +created_at: 2026-06-05T00:48:07Z +updated_at: 2026-06-05T00:49:53Z +assignee: null +legacy_ticket: null +--- + +## Issue + +Built-in feature modules need a closed way to influence Pod-side behavior without adding feature-specific logic back into `Pod` / `PodInterceptor`. Task reminders are the immediate example: a Task feature should be able to observe request/tool activity and append a `SystemItem::TaskReminder`, but it should not receive `Pod`, `Worker`, raw history writers, raw `llm_worker::Item` injection, or a generic effect channel. + +The current Hook surface already has per-hook-point action types after `hook-public-surface-hardening`, and those action types should remain flow-control oriented. The missing piece is event-specific Hook context carrying host-owned handles for allowed side effects, especially a durable `SystemItem` append path. + +## Current findings + +- `crates/pod/src/hook.rs` already distinguishes hook point output types such as `HookPromptAction`, `HookPreRequestAction`, `HookPreToolAction`, `HookPostToolAction`, and `HookTurnEndAction`. +- `PreLlmRequest` / `OnTurnEnd` public actions no longer expose raw `Item` injection. +- Hook inputs are currently summary structs (`PreRequestInfo`, `ToolCallSummary`, etc.), not context objects with host handles. +- `TaskReminder` emission currently lives in `PodInterceptor::pending_history_appends()` and uses Pod-owned `TaskStore` / `TaskReminderState`. +- Existing durable model-visible path is `SystemItem` commit -> `LogEntry::SystemItem` -> `Event::SystemItem` / model context, and this path must remain the only model-visible append mechanism. + +## Direction + +Introduce event-specific Hook context objects that carry narrow, host-created handles. Keep Hook return values as per-hook-point flow-control actions. + +- Side effects are not returned as arbitrary `HookEffect` enums. +- Side effects are requested through typed handles on the Hook context. +- Handles have private constructors and are created only by the Pod host. +- Missing authority/handle should prevent installation or make the handle unavailable; runtime rejection is defense-in-depth, not the normal API path. + +## Requirements + +- Define event-specific Hook context types, or evolve `HookEventKind::Input` into context values without losing the existing per-event action types. + - `PreLlmRequest` context should be able to carry request summary plus a SystemItem append handle where the host grants it. + - Tool hook contexts should continue to expose bounded call/result summaries. +- Add a host-owned `SystemItemAppendHandle` / sink concept for model-visible durable system items. + - It must not expose raw `llm_worker::Item` or raw history writer access. + - It should append/push only approved `SystemItem` request kinds, initially including TaskReminder/Notification-like system items as needed. + - Actual commit timing remains host-controlled through the existing pending history append / `LogEntry::SystemItem` / `Event::SystemItem` path. +- Preserve per-hook-point flow-control action types. + - Do not collapse every hook into one generic `HookDecision`. + - Do not reintroduce `ContinueWith(Vec)`, no-result tool skip, arbitrary `ToolResult` construction, or hidden context mutation. +- Keep internal built-in module usage distinct from external-plugin authority approval. + - Built-in modules may receive host handles according to host policy. + - Future external plugins receive model-visible append handles only when the external-plugin authority model grants them. +- Provide tests showing: + - Hook actions remain flow-control only; + - model-visible side effects use the SystemItem append handle; + - no raw `Item` / raw history writer / raw event sender is exposed through public Hook context; + - missing/unavailable handles do not produce invisible context injection. + +## Non-goals + +- Moving TaskStore/reminder state into the Task feature; that is tracked by `task-feature-own-store-reminder-hooks`. +- TUI dialog/custom UI work. +- Generic plugin event channels. +- External plugin loading/WASM boundary implementation. +- Changing ToolRegistry / PreToolCall permission behavior. + +## Acceptance criteria + +- Hook contexts can carry host-owned typed handles for allowed side effects, starting with durable SystemItem append. +- Hook return values remain event-specific flow-control actions. +- Model-visible additions through Hooks are committed through the durable SystemItem path and are user-inspectable. +- Public Hook APIs still do not expose raw `Item` injection, raw Pod/Worker/session internals, or generic UI/event payload channels. +- The resulting API is sufficient for a later Task reminder Hook to append `SystemItem::TaskReminder` without Pod-specific Task logic in `PodInterceptor`. diff --git a/work-items/open/20260605-004807-hook-context-system-item-sink/thread.md b/work-items/open/20260605-004807-hook-context-system-item-sink/thread.md new file mode 100644 index 00000000..e5a9786d --- /dev/null +++ b/work-items/open/20260605-004807-hook-context-system-item-sink/thread.md @@ -0,0 +1,33 @@ + + +## Created + +Created by tickets.sh create. + +--- + + + +## Decision + +# Investigation: Task state and Hook side-effect boundary + +## Findings + +- Hook action types are already separated per hook point after Hook hardening. The next design should preserve that: flow-control actions stay event-specific rather than becoming one global `HookDecision`. +- Hook inputs are still summary structs, not contexts with host-created handles. That is the missing abstraction for feature-owned behavior that needs durable host side effects. +- `TaskStore` is still owned by `Pod`, and `TaskReminderState`/reminder emission is still owned by `PodInterceptor`. +- The Task built-in feature module currently contributes only the four Task tools and receives `TaskStore` from Pod. This is an incomplete internal-module boundary: Task-specific state still remains on the Pod side. +- `SystemItem::TaskReminder` is currently appended through `PodInterceptor::pending_history_appends()`, which is the correct durable history direction but the wrong ownership location for Task-specific logic. + +## Decision + +Split follow-up into two steps: + +1. Add Hook context host handles, especially a durable `SystemItem` append handle. Hook returns remain per-hook-point flow-control actions. No raw `Item` injection and no generic effect/event channel. +2. Move TaskStore and Task reminder logic into the Task feature module, implemented as Task-owned tools plus hooks that use the host-provided SystemItem append handle. + +This keeps Pod responsible for generic host surfaces and history authority, while Task owns Task-specific state and policy. + + +--- diff --git a/work-items/open/20260605-004807-task-feature-own-store-reminder-hooks/artifacts/.gitkeep b/work-items/open/20260605-004807-task-feature-own-store-reminder-hooks/artifacts/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/work-items/open/20260605-004807-task-feature-own-store-reminder-hooks/item.md b/work-items/open/20260605-004807-task-feature-own-store-reminder-hooks/item.md new file mode 100644 index 00000000..c89eb0d3 --- /dev/null +++ b/work-items/open/20260605-004807-task-feature-own-store-reminder-hooks/item.md @@ -0,0 +1,84 @@ +--- +id: 20260605-004807-task-feature-own-store-reminder-hooks +slug: task-feature-own-store-reminder-hooks +title: Task: move TaskStore and reminders into Task feature +status: open +kind: task +priority: P1 +labels: [tasks, hooks, feature-registry, history] +created_at: 2026-06-05T00:48:07Z +updated_at: 2026-06-05T00:49:53Z +assignee: null +legacy_ticket: null +--- + +## Issue + +`TaskCreate` / `TaskUpdate` / `TaskGet` / `TaskList` have been extracted into a built-in internal feature module, but Task state is still Pod-owned. `Pod` owns `TaskStore`, `PodInterceptor` owns `TaskReminderState`, and `PodInterceptor::pending_history_appends()` contains Task-specific reminder logic. + +For the feature/module boundary to be meaningful, Task-specific state and behavior should live in the Task feature module. Pod should provide generic host surfaces: tool registration, hook dispatch, and durable `SystemItem` append. Pod should not know about TaskStore or Task reminder rules. + +## Current findings + +- `crates/pod/src/feature/builtin/task.rs` currently constructs the Task tool feature with a host-provided `tools::TaskStore`. +- `crates/pod/src/pod.rs` still stores `task_store: tools::TaskStore` and `task_reminder_state: Arc`. +- `crates/pod/src/ipc/interceptor.rs` still stores `TaskStore` and `TaskReminderState`, detects task-management tool calls, and emits `SystemItem::TaskReminder` from `pending_history_appends()`. +- `crates/pod/src/pod.rs` also uses TaskStore snapshots for session restore/compaction/reminder context. Those uses must be audited before removing Pod ownership. +- TUI-facing Task visibility is intentionally out of scope here; if TUI needs a compatibility/status surface, create a follow-up instead of keeping Task ownership in Pod. + +## Direction + +Move TaskStore and Task reminder state into the Task feature module after `hook-context-system-item-sink` provides a host-mediated SystemItem append handle for Hook contexts. + +Target shape: + +- `TaskFeature` owns: + - `tools::TaskStore` + - Task reminder/cooldown state + - Task tool contribution construction + - hooks that track Task tool usage and decide when to emit reminders +- Pod owns: + - feature registry + - Hook dispatch + - ToolRegistry integration + - durable SystemItem append/commit authority + - generic history/session machinery +- Pod does not own or special-case TaskStore / TaskReminderState. + +## Requirements + +- Depend on or first implement `hook-context-system-item-sink`. +- Move TaskStore construction/ownership from `Pod` into the built-in Task feature module. + - Preserve session restore behavior by giving Task feature whatever history snapshot or restore input it needs, rather than keeping TaskStore in Pod. + - Preserve one session-lifetime TaskStore shared by all Task tools and reminder hooks. +- Move TaskReminderState and reminder decision logic out of `PodInterceptor` and into Task feature-owned hooks. + - A tool hook records Task tool usage. + - A `PreLlmRequest` hook evaluates inactivity/cooldown and appends `SystemItem::TaskReminder` through the host-provided SystemItem append handle. +- Remove Task-specific checks from `PodInterceptor` such as direct `is_task_management_tool` handling for reminder state. +- Preserve current observable behavior: + - Task tool names/schemas/descriptions/outputs; + - TaskStore snapshot/restore semantics; + - task reminder threshold/cooldown/body/source behavior; + - model-visible history path via `LogEntry::SystemItem` / `Event::SystemItem`; + - normal ToolRegistry / PreToolCall permission path. +- Audit compaction/session snapshot code that currently reads `self.task_store`. + - Either route this through a Task feature status/snapshot service, or leave a documented temporary compatibility façade with no Task ownership in Pod. + - Do not silently drop TaskStore snapshot/resume behavior. +- Keep external-plugin authority model out of this ticket except insofar as the Hook SystemItem append handle is used by a trusted built-in module. + +## Non-goals + +- TUI UI changes. +- External plugin loading or package approval. +- Generic event channels or dialogs. +- Changing Task tool behavior or adding/removing Task tools. +- Reworking Memory/WorkItem/Pod-management modules. + +## Acceptance criteria + +- Task feature module owns TaskStore and Task reminder state. +- Pod and PodInterceptor no longer contain Task-specific store/reminder state or task-tool special-casing. +- Task reminder emission is implemented as Task feature Hook logic using host-mediated SystemItem append, not raw `Item` injection. +- TaskStore snapshot/restore/compaction behavior is preserved or explicitly routed through a new feature-owned status/snapshot surface. +- Existing Task tool and Task reminder tests are moved/updated and pass. +- Workspace validation passes. diff --git a/work-items/open/20260605-004807-task-feature-own-store-reminder-hooks/thread.md b/work-items/open/20260605-004807-task-feature-own-store-reminder-hooks/thread.md new file mode 100644 index 00000000..e5a9786d --- /dev/null +++ b/work-items/open/20260605-004807-task-feature-own-store-reminder-hooks/thread.md @@ -0,0 +1,33 @@ + + +## Created + +Created by tickets.sh create. + +--- + + + +## Decision + +# Investigation: Task state and Hook side-effect boundary + +## Findings + +- Hook action types are already separated per hook point after Hook hardening. The next design should preserve that: flow-control actions stay event-specific rather than becoming one global `HookDecision`. +- Hook inputs are still summary structs, not contexts with host-created handles. That is the missing abstraction for feature-owned behavior that needs durable host side effects. +- `TaskStore` is still owned by `Pod`, and `TaskReminderState`/reminder emission is still owned by `PodInterceptor`. +- The Task built-in feature module currently contributes only the four Task tools and receives `TaskStore` from Pod. This is an incomplete internal-module boundary: Task-specific state still remains on the Pod side. +- `SystemItem::TaskReminder` is currently appended through `PodInterceptor::pending_history_appends()`, which is the correct durable history direction but the wrong ownership location for Task-specific logic. + +## Decision + +Split follow-up into two steps: + +1. Add Hook context host handles, especially a durable `SystemItem` append handle. Hook returns remain per-hook-point flow-control actions. No raw `Item` injection and no generic effect/event channel. +2. Move TaskStore and Task reminder logic into the Task feature module, implemented as Task-owned tools plus hooks that use the host-provided SystemItem append handle. + +This keeps Pod responsible for generic host surfaces and history authority, while Task owns Task-specific state and policy. + + +---