Skip to content

Commit 5862bd6

Browse files
docs: align Claude hook redesign plan
1 parent 8a5deaa commit 5862bd6

14 files changed

Lines changed: 230 additions & 45 deletions

docs/plans/tracedecay-v2/00-plan-set-index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Core product surfaces:
3939
| [`11-dashboard-frontend.md`](11-dashboard-frontend.md) | Concept-led Evidence Cartography product; stable profile atlas, linked Atlas/Trace/Compare/Lab/Triage compositions, complete memory/skill/automation navigation in Brain and Explorer, Loom replay player, composable lenses, hermetic experiment cockpit, visual ontology/renderers/charts, accessibility/mobile/export, perceptual and comprehension gates. |
4040
| [`12-root-compatibility-migration.md`](12-root-compatibility-migration.md) | Root binary/daemon/CLI/MCP composition and deployment/probe/config/service effect adapters; application-owned integration lifecycle execution; V1 data migration, cutover/rollback/retirement. |
4141
| [`13-research-provenance-and-context-anchors.md`](13-research-provenance-and-context-anchors.md) | Research manifest, durable retrieval anchors, subagent context, corpus hashes/cutoff, source recovery, future implementation handoff. |
42-
| [`14-historical-failure-regression-matrix.md`](14-historical-failure-regression-matrix.md) | Historical problem -> prevention owner -> visible detection/recovery -> cutover regression gate; 148 stable rows (`FM-001` through `FM-148`) with no gaps. |
42+
| [`14-historical-failure-regression-matrix.md`](14-historical-failure-regression-matrix.md) | Historical problem -> prevention owner -> visible detection/recovery -> cutover regression gate; 150 stable rows (`FM-001` through `FM-150`) with no gaps. |
4343
| [`15-search-quality-evaluation-and-retrieval-research.md`](15-search-quality-evaluation-and-retrieval-research.md) | Real local precision corpus, primary retrieval research, hybrid pipeline, qrels/metrics/holdouts, shadow/online evaluation, Search Quality Lab. |
4444
| [`16-cross-project-repository-worktree-scope.md`](16-cross-project-repository-worktree-scope.md) | Exceptional multi-repo/project/worktree/ref/store behavior, `ScopeSelectorV2`, routed retrieval, graph federation, CLI/MCP UX, Rspack/Rsbuild/React Router corpus. |
4545
| [`17-official-public-api-and-sdks.md`](17-official-public-api-and-sdks.md) | Official direct-agent/public API, contract IR/OpenAPI/JSON Schema, stable IDs/errors/cursors/batch/SSE, Rust/TS/Python SDKs, docs/sandbox/conformance. |

docs/plans/tracedecay-v2/01-domain-crate.md

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -481,9 +481,9 @@ pub struct HostCapabilitySnapshotV1 {
481481
pub fresh_until: UtcMicros,
482482
pub snapshot_digest: ManifestDigest, // canonical subject/capabilities/times only; excludes this field
483483
}
484-
pub enum HookInvocationScopeV1 { ThreadStart, SubagentStart, Turn }
485-
pub enum HookDefinitionRepresentationV1 { JsonFile, InlineToml, PluginDefaultFile, PluginManifestPath, PluginManifestPathArray, PluginManifestInline, PluginManifestInlineArray, ManagedInline }
486-
pub enum HostConfigLayerV1 { System, Cloud, Mdm, ManagedRequirements, User, Project, Session, Plugin }
484+
pub enum HookInvocationScopeV1 { SessionLifecycle, Setup, Turn, ToolCall, ToolBatch, SubagentLifecycle, TaskLifecycle, TeamLifecycle, WorktreeLifecycle, ComponentLifecycle, Elicitation, AsyncObservation, DisplayStream }
485+
pub enum HookDefinitionRepresentationV1 { JsonFile, JsonSettings, InlineToml, PluginDefaultFile, PluginManifestPath, PluginManifestPathArray, PluginManifestInline, PluginManifestInlineArray, SkillFrontmatter, AgentFrontmatter, ManagedInline, SessionMemory, BuiltIn }
486+
pub enum HostConfigLayerV1 { System, Cloud, Mdm, ManagedRequirements, ManagedPolicy, User, Project, Local, Session, Plugin, Skill, Agent, BuiltIn }
487487
pub struct HostConfigSourceV1 {
488488
pub source_id: EntityId,
489489
pub layer: HostConfigLayerV1,
@@ -512,11 +512,32 @@ pub struct HookInvocationGroupRefV1 { pub group_id: EntityId, pub host_event_ide
512512
pub enum PermissionBehaviorV1 { Allow, Deny, NoDecision }
513513
pub enum HookContinuationTargetV1 { Turn, Subagent }
514514
pub enum HookHandlerResultV1 { Succeeded, TimedOut, Exited { code: i32 }, InvalidOutput { reason: RegistryEntryId }, SkippedUnsupported, SkippedTrust }
515-
pub enum HostHookTrustStateV1 { NeedsReview, Trusted, ManagedTrusted, Unknown }
515+
pub enum ClaudePermissionDestinationV1 { Session, LocalSettings, ProjectSettings, UserSettings }
516+
pub enum ClaudePermissionUpdateV1 {
517+
AddRules { behavior: RegistryEntryId, rules: PayloadRef, destination: ClaudePermissionDestinationV1 },
518+
ReplaceRules { behavior: RegistryEntryId, rules: PayloadRef, destination: ClaudePermissionDestinationV1 },
519+
RemoveRules { behavior: RegistryEntryId, rules: PayloadRef, destination: ClaudePermissionDestinationV1 },
520+
SetMode { mode: RegistryEntryId, destination: ClaudePermissionDestinationV1 },
521+
AddDirectories { directories: PayloadRef, destination: ClaudePermissionDestinationV1 },
522+
RemoveDirectories { directories: PayloadRef, destination: ClaudePermissionDestinationV1 },
523+
}
524+
pub struct ClaudePermissionRequestDecisionV1 { pub behavior: PermissionBehaviorV1, pub updated_input: Option<PayloadRef>, pub updates: BoundedVec<ClaudePermissionUpdateV1, 32>, pub message: Option<LogSafeText>, pub interrupt: bool }
525+
pub struct ProtectedHostLocatorHandleV1 { pub handle_id: EntityId, pub access_digest: AccessPolicyDigest, pub expires_at: UtcMicros }
526+
pub struct ProtectedHostLocatorRefV1 { pub handle: ProtectedHostLocatorHandleV1, pub locator_digest: PrivacyDomainBoundLocatorDigest }
527+
pub struct ValidatedHostDirectoryV1 { pub locator: ProtectedHostLocatorRefV1, pub validation_receipt: EntityRef }
528+
pub struct WatchPathSetV1 { pub paths: BoundedVec<ProtectedHostLocatorRefV1, 64>, pub coverage: CoverageReportV1 }
529+
pub enum ClaudeElicitationActionV1 { Accept, Decline, Cancel }
530+
pub struct ClaudeElicitationDecisionV1 { pub action: ClaudeElicitationActionV1, pub form_content: Option<PayloadRef>, pub sanitization_receipt: SanitizationReceiptId }
531+
pub struct ClaudeSessionBootstrapV1 { pub initial_user_message: Option<PayloadRef>, pub session_title: Option<PromptEligibleText>, pub watch_paths: Option<WatchPathSetV1>, pub reload_skills: bool }
532+
pub enum HostHookTrustStateV1 { NeedsReview, Trusted, ManagedTrusted, NotApplicable, Unknown }
516533
pub enum HostHookEligibilityStateV1 { Eligible, DisabledByUser, SkippedUntrustedProject, SkippedManagedOnly, SkippedFeatureDisabled }
517-
pub enum HostHookHandlerSupportV1 { SupportedCommand, UnsupportedPrompt, UnsupportedAgent, UnsupportedAsync }
534+
pub enum HostHookControlStateV1 { Enabled, DisabledAll, SuppressedManagedOnly, ManagedExempt, ComponentInactive }
535+
pub enum HostHookHandlerKindV1 { Command, Http, McpTool, Prompt, Agent }
536+
pub enum HostHookHandlerSupportV1 { Supported, VersionGated, Unsupported, Experimental }
537+
pub enum HostHookExecutionModeV1 { Synchronous, Async, AsyncRewake }
538+
pub enum HostHookHostDedupeV1 { NotApplicable, Executed, DedupedIdentical, Unobservable }
518539
pub enum HostHookDefinitionFreshnessV1 { Current, ChangedSinceReview }
519-
pub enum HostHookTrustRequirementV1 { ExactHashUserReview, ManagedPolicy }
540+
pub enum HostHookTrustRequirementV1 { ExactHashUserReview, ManagedPolicy, NotApplicable }
520541
pub enum HostHookRunVisibilityV1 { TraceDecayOwned, HostObserved, Unobservable }
521542
pub struct HostHookTrustReceiptRefV1 {
522543
pub receipt_id: EntityId,
@@ -528,12 +549,16 @@ pub struct HostHookTrustReceiptRefV1 {
528549
}
529550
pub struct HostHookDefinitionObservationV1 {
530551
pub definition: HookDefinitionRefV1,
552+
pub handler_kind: HostHookHandlerKindV1,
553+
pub execution_mode: HostHookExecutionModeV1,
531554
pub trust: HostHookTrustStateV1,
555+
pub control: HostHookControlStateV1,
532556
pub eligibility: HostHookEligibilityStateV1,
533557
pub handler_support: HostHookHandlerSupportV1,
534558
pub freshness: HostHookDefinitionFreshnessV1,
535559
pub trust_receipt: Option<HostHookTrustReceiptRefV1>,
536560
pub run_visibility: HostHookRunVisibilityV1,
561+
pub host_dedupe: HostHookHostDedupeV1,
537562
}
538563
pub struct SkillVersionRef {
539564
pub skill_id: SkillId,

docs/plans/tracedecay-v2/03-capture-crate.md

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -318,27 +318,47 @@ pub struct WorkClaimDraft {
318318

319319
pub enum HookEventV1 {
320320
SessionStarted { source: NativeKindCode },
321-
PromptSubmitted { turn_id: AliasRef, content: ProviderFieldValue },
321+
SetupStarted { trigger: NativeKindCode },
322+
InstructionsLoaded { load_reason: NativeKindCode, metadata: ProviderFieldValue },
323+
PromptSubmitted { prompt_id: Option<AliasRef>, content: ProviderFieldValue },
324+
PromptExpanded { prompt_id: Option<AliasRef>, expansion: ProviderFieldValue },
325+
AssistantMessageDisplayed { turn_id: AliasRef, message_id: AliasRef, index: u32, final_chunk: bool, delta: ProviderFieldValue },
322326
AgentSpawned { child: NativeAgentId, task: ProviderFieldValue },
323-
AgentStopped { child: NativeAgentId, stop_hook_active: bool, last_message: Option<ProviderFieldValue> },
327+
AgentStopped { child: NativeAgentId, stop_hook_active: bool, last_message: Option<ProviderFieldValue>, background_tasks: Option<ProviderFieldValue>, session_crons: Option<ProviderFieldValue>, terminal_coverage: CoverageReportV1 },
324328
AgentMessage { recipient: NativeAgentId, content: ProviderFieldValue },
325329
AgentHandoff { recipient: NativeAgentId, state: ProviderFieldValue },
326330
AgentPresenceHeartbeat { status: PresenceStatus },
327331
WorkClaimDeclared { claim: WorkClaimDraft },
328332
WorkClaimScopeChanged { claim_id: String, scope: WorkClaimScopeDraft },
329333
WorkClaimAcknowledged { claim_id: String, redundancy: RedundancyMode },
330334
CoordinationOutcomeObserved { claim_id: String, outcome: CoordinationOutcome },
331-
PermissionRequested { turn_id: AliasRef, native_request_id: Option<AliasRef>, tool: String, input: ProviderFieldValue },
335+
PermissionRequested { prompt_id: Option<AliasRef>, native_request_id: Option<AliasRef>, tool: String, input: ProviderFieldValue },
332336
PermissionDecisionObserved { permission_request: AliasRef, behavior: PermissionBehaviorV1 },
337+
PermissionDenied { prompt_id: Option<AliasRef>, tool_use_id: Option<AliasRef>, tool: String, input: ProviderFieldValue, reason: ProviderFieldValue },
333338
ToolStarted { call_id: String, tool: String, input: ProviderFieldValue },
334-
ToolFinished { call_id: String, outcome: ToolOutcome, output: ProviderFieldValue },
335-
CompactStarted { trigger: NativeKindCode },
336-
CompactFinished { trigger: NativeKindCode },
337-
TurnStopRequested { turn_id: AliasRef, stop_hook_active: bool, last_message: Option<ProviderFieldValue> },
339+
ToolFinished { call_id: String, outcome: ToolOutcome, output: ProviderFieldValue, duration_ms: Option<u64> },
340+
ToolFailed { call_id: String, tool: String, error: ProviderFieldValue, is_interrupt: Option<bool>, duration_ms: Option<u64> },
341+
ToolBatchFinished { prompt_id: Option<AliasRef>, results: ProviderFieldValue },
342+
NotificationObserved { kind: NativeKindCode, message: ProviderFieldValue },
343+
TaskCreated { task: ProviderFieldValue },
344+
TaskCompleted { task: ProviderFieldValue },
345+
TeammateIdle { teammate: ProviderFieldValue },
346+
ConfigurationChanged { source: NativeKindCode, change: ProviderFieldValue },
347+
CwdChanged { previous: ProviderFieldValue, current: ProviderFieldValue },
348+
FileChanged { file: ProviderFieldValue, change: ProviderFieldValue },
349+
WorktreeCreateRequested { request: ProviderFieldValue },
350+
WorktreeCreated { worktree: ProviderFieldValue },
351+
WorktreeRemoved { worktree: ProviderFieldValue },
352+
CompactStarted { trigger: NativeKindCode, custom_instructions: Option<ProviderFieldValue> },
353+
CompactFinished { trigger: NativeKindCode, compact_summary: Option<ProviderFieldValue> },
354+
TurnStopRequested { prompt_id: Option<AliasRef>, stop_hook_active: bool, last_message: Option<ProviderFieldValue>, background_tasks: Option<ProviderFieldValue>, session_crons: Option<ProviderFieldValue>, terminal_coverage: CoverageReportV1 },
355+
TurnStopFailed { prompt_id: Option<AliasRef>, error_type: NativeKindCode, error: ProviderFieldValue },
356+
ElicitationRequested { server: AliasRef, request: ProviderFieldValue },
357+
ElicitationAnswered { server: AliasRef, response: ProviderFieldValue },
338358
ContinuationDecisionObserved { target: HookContinuationTargetV1, continued: bool, reason: Option<ProviderFieldValue> },
339359
HookHandlerRunObserved { definition: HookDefinitionRefV1, run: HookHandlerRunRefV1, result: HookHandlerResultV1 },
340360
HintTerminal { hint_id: String, terminal: HintTerminalState },
341-
SessionStopped { outcome: Option<String> },
361+
SessionStopped { outcome: Option<String>, reason: Option<NativeKindCode> },
342362
}
343363

344364
pub struct HookSpool;
@@ -358,6 +378,8 @@ Every TraceDecay-owned source adapter and hook draft carries the originating `Tr
358378

359379
Codex lowering preserves the exact parent-session `session_id`, Turn, agent, tool-use, hook-definition binding, matcher-group, handler, run/attempt, bundle, trust/source-layer evidence, producer-build, and optional collector-build identities available at that surface. `PermissionRequest` has no mandatory native call ID: capture accepts an optional native alias, while application persists a deterministic request identity over session/Turn/tool/sanitized-input digest and source generation. It appends every concurrently launched observable TraceDecay handler run; an invocation-group projection relates them and records host aggregation evidence separately. Shared definition/run/result/trust/source refs are owned by `tracedecay-domain`; capture imports them and never depends on root hook/config composition. `transcript_path`, `agent_transcript_path`, cwd, prompt, tool input/response, and last assistant message remain transient unclassified inputs and may persist only as sanitized payload refs or privacy-domain locator fingerprints. Stop/SubagentStop terminal observations asynchronously dirty only their exact thread/subagent automation scope; the hook never waits for reflection/curation, and unchanged terminal inputs remain fenced by plans 09/26.
360380

381+
Claude lowering preserves the native 30-event identity, only the native correlation fields actually supplied (`prompt_id`, `tool_use_id`, MessageDisplay `turn_id`, and event-specific IDs), conditional effort, session/agent/task/team/tool/batch/worktree/MCP identities, event-specific duration/failure/interrupt/continuation fields, handler kind/execution mode, configured-definition versus host-deduped versus actual-run evidence, and produced-at versus later-delivered context time. It never manufactures a Turn ID from session/timing/text. `transcript_path` is explicitly lagging and never used to infer current-turn completeness. `MessageDisplay` is metadata-only by default—delta text is discarded after sanitizer classification unless a versioned bounded capture purpose passes privacy/performance evaluation. Version-gated background-task/session-cron fields are optional with coverage; missing/unreachable evidence cannot satisfy the Stop/SubagentStop terminal predicate. `StopFailure` remains a distinct non-controllable event.
382+
361383
Capture owns the one hook spool and its drainer. There is exactly one spool implementation, one hash-chained frame format (below), and one always-spool ingress protocol; the store exposes only append transactions and never runs a handoff-first or fallback ingress spool of its own ([`02-store-crate.md`](02-store-crate.md) drains capture's spool through `ObservationJournal` appends). Plan [`07-hooks-crate.md`](07-hooks-crate.md) hook hosts write exclusively through capture's spool client (`spool/client.rs`) and receive durability acks carrying the domain `SpoolReceipt` from [`01-domain-crate.md`](01-domain-crate.md); no crate mints a spool-receipt variant.
362384

363385
Under dedicated-service isolation, that client is an authenticated connect-only call to a socket-activated, service-owned capture-ingress helper that sanitizes/validates and `fdatasync`s the canonical capture spool without opening an application store. It stays available while the main daemon is stopped or draining and hands segments to the normal daemon drainer after restart. Client hooks never receive spool paths or keys and never create a second user-owned spool; if the ingress service itself is unavailable, the hook reports a non-content degraded receipt and never claims durability. Remote-authority mode uses the same local service-owned ingress spool until a verified remote commit receipt retires the frame.

0 commit comments

Comments
 (0)