Summary
The existing llm_input and llm_output plugin hooks are fire-and-forget (return void). This proposal requests making them mutable — allowing hook handlers to return modified prompt, systemPrompt, historyMessages, and assistantTexts — so plugins can transparently transform content before it reaches the LLM and after it comes back.
The primary use case is local data desensitization/resensitization: routing user input through a local model to strip PII before sending to a remote LLM, then restoring it in the output.
Problem to solve
Many enterprise and privacy-conscious users need to sanitize sensitive data (names, phone numbers, addresses, credentials) before it leaves the local environment. Currently:
llm_input hook receives prompt, systemPrompt, historyMessages but returns Promise — read-only, cannot mutate.
llm_output hook receives assistantTexts but also returns Promise — read-only.
before_prompt_build can only prepend/append to the system prompt (prependContext, appendSystemContext); the user's original prompt text is still passed to the LLM unmodified.
before_agent_start has the same limitation — no field to rewrite prompt.
Proposed solution
Extend llm_input and llm_output hook signatures to optionally return a mutation result:
// Current (read-only)
llm_input: (event: PluginHookLlmInputEvent, ctx: PluginHookAgentContext) => Promise | void;
// Proposed (mutable)
llm_input: (event: PluginHookLlmInputEvent, ctx: PluginHookAgentContext) =>
Promise<PluginHookLlmInputResult | void> | PluginHookLlmInputResult | void;
type PluginHookLlmInputResult = {
prompt?: string; // override user prompt
systemPrompt?: string; // override system prompt
historyMessages?: unknown[]; // override history (for context-level sanitization)
};
Alternatives considered
No response
Impact
Enterprise & regulated-industry users — financial services, healthcare, legal, and government teams where data residency and PII protection are mandatory compliance requirements (GDPR, HIPAA, SOC2, etc.).
Self-hosted / hybrid deployments — users running OpenClaw locally but connecting to remote LLM providers (OpenAI, Anthropic, etc.) who need to ensure no sensitive data leaves the local boundary.
All messaging channels — the gap affects every inbound channel (Telegram, Feishu, Slack, Matrix, etc.) equally, since sanitization must happen at the LLM transport layer, not the channel layer.
Plugin developers — anyone building privacy/compliance plugins is blocked from implementing a clean, composable solution within the existing hook system.
Evidence/examples
No response
Additional information
No response
Summary
The existing llm_input and llm_output plugin hooks are fire-and-forget (return void). This proposal requests making them mutable — allowing hook handlers to return modified prompt, systemPrompt, historyMessages, and assistantTexts — so plugins can transparently transform content before it reaches the LLM and after it comes back.
The primary use case is local data desensitization/resensitization: routing user input through a local model to strip PII before sending to a remote LLM, then restoring it in the output.
Problem to solve
Many enterprise and privacy-conscious users need to sanitize sensitive data (names, phone numbers, addresses, credentials) before it leaves the local environment. Currently:
llm_input hook receives prompt, systemPrompt, historyMessages but returns Promise — read-only, cannot mutate.
llm_output hook receives assistantTexts but also returns Promise — read-only.
before_prompt_build can only prepend/append to the system prompt (prependContext, appendSystemContext); the user's original prompt text is still passed to the LLM unmodified.
before_agent_start has the same limitation — no field to rewrite prompt.
Proposed solution
Extend llm_input and llm_output hook signatures to optionally return a mutation result:
// Current (read-only)
llm_input: (event: PluginHookLlmInputEvent, ctx: PluginHookAgentContext) => Promise | void;
// Proposed (mutable)
llm_input: (event: PluginHookLlmInputEvent, ctx: PluginHookAgentContext) =>
Promise<PluginHookLlmInputResult | void> | PluginHookLlmInputResult | void;
type PluginHookLlmInputResult = {
prompt?: string; // override user prompt
systemPrompt?: string; // override system prompt
historyMessages?: unknown[]; // override history (for context-level sanitization)
};
Alternatives considered
No response
Impact
Enterprise & regulated-industry users — financial services, healthcare, legal, and government teams where data residency and PII protection are mandatory compliance requirements (GDPR, HIPAA, SOC2, etc.).
Self-hosted / hybrid deployments — users running OpenClaw locally but connecting to remote LLM providers (OpenAI, Anthropic, etc.) who need to ensure no sensitive data leaves the local boundary.
All messaging channels — the gap affects every inbound channel (Telegram, Feishu, Slack, Matrix, etc.) equally, since sanitization must happen at the LLM transport layer, not the channel layer.
Plugin developers — anyone building privacy/compliance plugins is blocked from implementing a clean, composable solution within the existing hook system.
Evidence/examples
No response
Additional information
No response