From 28de94df5dcd7718cb334e2e793e9472f5b291c5 Mon Sep 17 00:00:00 2001 From: 0xfandom <50949929+0xfandom@users.noreply.github.com> Date: Wed, 22 Apr 2026 23:07:02 +0530 Subject: [PATCH] feat: add OPENCLAUDE_DISABLE_TOOL_REMINDERS env var to suppress hidden tool-output reminders (#837) Gates three injection sites behind OPENCLAUDE_DISABLE_TOOL_REMINDERS: - FileReadTool cyber-risk mitigation reminder (appended to every Read result when the model is not in MITIGATION_EXEMPT_MODELS) - todo_reminder attachment for TodoWrite usage - task_reminder attachment for TaskCreate/TaskUpdate usage All three reminders are model-only side-channel instructions the user cannot see today. Users who want full transparency over what the model receives can now opt out without patching dist/cli.mjs on every upgrade. Default behavior is unchanged when the flag is unset. Closes #809 --- .env.example | 5 +++++ src/tools/FileReadTool/FileReadTool.ts | 3 +++ src/utils/messages.ts | 7 +++++++ 3 files changed, 15 insertions(+) diff --git a/.env.example b/.env.example index 609cb1e1..540d1d07 100644 --- a/.env.example +++ b/.env.example @@ -272,6 +272,11 @@ ANTHROPIC_API_KEY=sk-ant-your-key-here # trigger "Extra required key ... supplied" errors from OpenAI-compatible endpoints # OPENCLAUDE_DISABLE_STRICT_TOOLS=1 +# Disable hidden messages injected into tool output +# Suppresses the file-read cyber-risk reminder and the todo/task tool nudges +# Useful for users who want full transparency over what the model sees +# OPENCLAUDE_DISABLE_TOOL_REMINDERS=1 + # Custom timeout for API requests in milliseconds (default: varies) # API_TIMEOUT_MS=60000 diff --git a/src/tools/FileReadTool/FileReadTool.ts b/src/tools/FileReadTool/FileReadTool.ts index 1ceed46d..90781ef6 100644 --- a/src/tools/FileReadTool/FileReadTool.ts +++ b/src/tools/FileReadTool/FileReadTool.ts @@ -733,6 +733,9 @@ export const CYBER_RISK_MITIGATION_REMINDER = const MITIGATION_EXEMPT_MODELS = new Set(['claude-opus-4-6']) function shouldIncludeFileReadMitigation(): boolean { + if (isEnvTruthy(process.env.OPENCLAUDE_DISABLE_TOOL_REMINDERS)) { + return false + } const shortName = getCanonicalName(getMainLoopModel()) return !MITIGATION_EXEMPT_MODELS.has(shortName) } diff --git a/src/utils/messages.ts b/src/utils/messages.ts index edc33ebd..0597fd86 100644 --- a/src/utils/messages.ts +++ b/src/utils/messages.ts @@ -75,6 +75,7 @@ import type { import { isAdvisorBlock } from './advisor.js' import { isAgentSwarmsEnabled } from './agentSwarmsEnabled.js' import { count } from './array.js' +import { isEnvTruthy } from './envUtils.js' import { type Attachment, type HookAttachment, @@ -3666,6 +3667,9 @@ Read the team config to discover your teammates' names. Check the task list peri ]) } case 'todo_reminder': { + if (isEnvTruthy(process.env.OPENCLAUDE_DISABLE_TOOL_REMINDERS)) { + return [] + } const todoItems = attachment.content .map((todo, index) => `${index + 1}. [${todo.status}] ${todo.content}`) .join('\n') @@ -3686,6 +3690,9 @@ Read the team config to discover your teammates' names. Check the task list peri if (!isTodoV2Enabled()) { return [] } + if (isEnvTruthy(process.env.OPENCLAUDE_DISABLE_TOOL_REMINDERS)) { + return [] + } const taskItems = attachment.content .map(task => `#${task.id}. [${task.status}] ${task.subject}`) .join('\n')