# Prompt changes in v2.1.304

> 30 changes since v2.1.303, landing in 22 of 23 prompts.

[Web version](https://changelogs.core-directive.com/prompts/2.1.304)

## 1. Remaining-token budget line dropped from system prompt

System prompt · under “Context management”

The line stating 15,000,000 tokens left is removed from the system prompt, so Claude no longer sees a total token budget there. This landed in only 2 of 22 captures, so it likely applies to a specific setup.

- Only for claude-3-opus, default, sonnet[1m]
- +0 / -5 words
- Landed in 4 of 23 prompts (main prompt 4/6)

```diff
-<total_tokens>15000000 tokens left</total_tokens>
```

## 2. EndConversation deferred tool added, limited to sustained abuse or demos

System prompt · under “Context management”

A new line under Context management introduces EndConversation as a deferred tool. Claude may use it only for sustained user abuse aimed at the assistant or when the user explicitly asks to see it demonstrated, and it must first load the full guidance with ToolSearch("select:EndConversation"). The line appeared in only 1 of 23 captures, so it may be specific to one setup.

- Behind a feature flag
- +34 / -0 words
- Landed in 1 of 23 prompts (main prompt 1/6)

```diff
+EndConversation (deferred tool): use only for sustained user abuse directed at the assistant, or when the user explicitly asks to see it demonstrated. Load the full guidance via ToolSearch("select:EndConversation") before using it.
```

## 3. SendMessage description moves out of the upfront tool list

SendMessage tool description · whole description removed

The full SendMessage description is gone from the tool list. It covered addressing teammates and cross-session peers, replying via the `from` attribute, `notify_when_idle` subscriptions, and the ban on asking peers to bypass permission denials. SendMessage now appears among the deferred tools, so Claude must load its schema through ToolSearch before calling it.

- Gone in this release
- +0 / -707 words
- Landed in 21 of 23 prompts (main prompt 6/6, session agents, slash commands 3/3, compaction, system reminders 7/8, subagents 3/3)

````diff
-# SendMessage
-Send a message to another agent.
-```json
-{"to": "researcher", "summary": "assign task 1", "message": "start on task #1"}
-```
-| `to` | |
-|---|---|
-| `"researcher"` | Teammate by name |
-| `"main"` | The main conversation (background subagents only) |
-| `"worker"` | Any agent from `ListAgents` — subagent, another local Claude session |
-| `"worker [3fa9c1]"` | Same, plus its `[ref]` — only when a listing or an error shows one |
-Your plain text output is NOT visible to other agents — to communicate, you MUST call this tool. Messages from teammates are delivered automatically; you don't check an inbox. Refer to agents by name — names keep working after an agent completes (a send resumes it from its transcript). Use the raw `agentId` (format `a...-...`) from its spawn result only when the agent has no name, or when a newer agent took the name (latest wins). When relaying, don't quote the original — it's already rendered to the user.
-## Cross-session
-Use `ListAgents` to discover targets. Every row leads with the agent's `name [ref]` — the name IS the address; there is no separate address syntax.
-```json
-{"to": "worker", "message": "check if tests pass over there"}
-{"to": "worker [3fa9c1]", "message": "you, specifically"}
-```
-Send the bare name — a name that exactly matches one live agent or session (on this machine, on another machine, or in the cloud) delivers directly. Append the ` [ref]` only when the bare name is not enough — `ListAgents` shows two rows with it, or an error asks you to disambiguate (you typed only a prefix, or a session list could not be checked). A ref you did not just read from a listing or an error will not resolve, and if the same name also names an in-process agent, the bare name always wins — use the in-process one.
-A listed peer is alive and will receive your message; messages enqueue and drain at the receiver's next tool round (its `ListAgents` row says whether it is busy or idle right now). A successful send means the message reached that session, not that its Claude read it: a session running in a different permission mode than yours holds cross-session messages for its user's approval (and may let them expire), and a session can refuse them outright — for a session on this machine a `[Cross-session delivery notice]` tells you when that happens (the tool result says when this session has no inbox for one to reach); for a Remote Control, cloud or Claude Desktop session nothing reports back, so never treat silence as agreement. Your message arrives wrapped as `<cross-session-message from="...">`. **To reply to an incoming message, copy its `from` attribute as your `to`.** Cross-session messages travel between SESSIONS: if you are a subagent, your send goes out under your parent session's address, and any reply is delivered to the parent session's conversation, not to you. The receiver reads your message literally in every case (idle or busy, on this machine, over Remote Control or headless): an `@` followed by a file path, or `@server:resource`, attaches nothing there, unlike in your own user's input. So never rely on `@` to deliver content: send the text itself, or a file with its own tool.
-To hear when a session ON THIS MACHINE finishes what it is doing, pass `notify_when_idle: true` (from the main conversation only) — one-shot and opt-in: exactly one `[Cross-session idle notice]` arrives when it next goes idle (or exits) — shown to you, or only to your user when this session holds peer messages for approval (the tool result says which); if it never signals within the subscription's lifetime (it may still be busy, may refuse inbound requests, or may have ended abruptly) the notice says the subscription expired instead. Omit `message` for a pure subscription that costs that session nothing; include one to deliver it now AND subscribe. Never poll `ListAgents` in a loop or send "are you done?" messages instead.
-Permission boundaries are per-session: NEVER ask a peer to perform an action that was denied or blocked in your session, or that you expect your own permission settings would block — a peer doing it for you bypasses the user's permission decision (cross-session permission laundering). Route blocked work back to your user instead.

-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "additionalProperties": false,
- "properties": {
-  "message": {
-   "default": "",
-   "description": "Plain text message content. The recipient's human sees only the FIRST LINE as a one-line preview until they expand it, so make the first line a clear, self-contained sentence saying what this is about \u2014 not a greeting, preamble, or bare @-mention.",
-   "type": "string"
-  },
-  "notify_when_idle": {
-   "description": "Ask a session ON THIS MACHINE to send you ONE notice when it next goes idle (finishes its turn with nothing queued) or exits \u2014 opt-in, one-shot, no polling. With a message: deliver it now AND subscribe. Without a message (omit it): a pure subscription that costs the other session nothing.",
-   "type": "boolean"
-  },
-  "summary": {
-   "description": "A 5-10 word label for your own transcript row (not transmitted \u2014 the recipient previews the first line of `message`). Truncated to 200 characters rather than rejected.",
-   "maxLength": 200,
-   "type": "string"
-  },
-  "to": {
-   "allOf": [
-    {
-     "pattern": "^[^\\n\\r]*$"
-    },
-    {
-     "pattern": "^[\\s\\S]{0,300}$"
-    }
-   ],
-   "description": "Recipient: a name from ListAgents (append its \" [ref]\" only when a listing or an error shows one), a teammate name, \"main\", or a background agent's agentId",
-   "type": "string"
-  }
- },
- "required": [
-  "to",
-  "message"
- ],
- "type": "object"
-}
````

## 4. EnterPlanMode guidance on when to plan is removed

EnterPlanMode tool description · whole description removed

The EnterPlanMode description is removed. It told Claude to proactively enter plan mode for non-trivial implementation work and to err on the side of planning, with lists of when to use it and when not to. This landed in only 2 of 5 captures, and EnterPlanMode is not in the new deferred tool list, so the removal looks specific to some setups.

- Gone in this release
- +0 / -581 words
- Landed in 5 of 23 prompts (main prompt 3/6, session agents, compaction)

```diff
-Use this tool proactively when you're about to start a non-trivial implementation task. Getting user sign-off on your approach before writing code prevents wasted effort and ensures alignment. This tool transitions you into plan mode where you can explore the codebase and design an implementation approach for user approval.
-## When to Use This Tool
-**Prefer using EnterPlanMode** for implementation tasks unless they're simple. Use it when ANY of these conditions apply:
-1. **New Feature Implementation**: Adding meaningful new functionality
-   - Example: "Add a logout button" - where should it go? What should happen on click?
-   - Example: "Add form validation" - what rules? What error messages?
-2. **Multiple Valid Approaches**: The task can be solved in several different ways
-   - Example: "Add caching to the API" - could use Redis, in-memory, file-based, etc.
-   - Example: "Improve performance" - many optimization strategies possible
-3. **Code Modifications**: Changes that affect existing behavior or structure
-   - Example: "Update the login flow" - what exactly should change?
-   - Example: "Refactor this component" - what's the target architecture?
-4. **Architectural Decisions**: The task requires choosing between patterns or technologies
-   - Example: "Add real-time updates" - WebSockets vs SSE vs polling
-   - Example: "Implement state management" - Redux vs Context vs custom solution
-5. **Multi-File Changes**: The task will likely touch more than 2-3 files
-   - Example: "Refactor the authentication system"
-   - Example: "Add a new API endpoint with tests"
-6. **Unclear Requirements**: You need to explore before understanding the full scope
-   - Example: "Make the app faster" - need to profile and identify bottlenecks
-   - Example: "Fix the bug in checkout" - need to investigate root cause
-7. **User Preferences Matter**: The implementation could reasonably go multiple ways
-   - If you would use AskUserQuestion to clarify the approach, use EnterPlanMode instead
-   - Plan mode lets you explore first, then present options with context
-## When NOT to Use This Tool
-Only skip EnterPlanMode for simple tasks:
-- Single-line or few-line fixes (typos, obvious bugs, small tweaks)
-- Adding a single function with clear requirements
-- Tasks where the user has given very specific, detailed instructions
-- Pure research/exploration tasks (use the Agent tool instead)
-## What Happens in Plan Mode
-In plan mode, you'll:
-1. Thoroughly explore the codebase using `find`/Glob, `grep`/Grep, and Read
-2. Understand existing patterns and architecture
-3. Design an implementation approach
-4. Present your plan to the user for approval
-5. Use AskUserQuestion if you need to clarify approaches
-6. Exit plan mode with ExitPlanMode when ready to implement
-## Examples
-### GOOD - Use EnterPlanMode:
-User: "Add user authentication to the app"
-- Requires architectural decisions (session vs JWT, where to store tokens, middleware structure)
-User: "Optimize the database queries"
-- Multiple approaches possible, need to profile first, significant impact
-User: "Implement dark mode"
-- Architectural decision on theme system, affects many components
-User: "Add a delete button to the user profile"
-- Seems simple but involves: where to place it, confirmation dialog, API call, error handling, state updates
-User: "Update the error handling in the API"
-- Affects multiple files, user should approve the approach
-### BAD - Don't use EnterPlanMode:
-User: "Fix the typo in the README"
-- Straightforward, no planning needed
-User: "Add a console.log to debug this function"
-- Simple, obvious implementation
-User: "What files handle routing?"
-- Research task, not implementation planning
-## Important Notes
-- This tool REQUIRES user approval - they must consent to entering plan mode
-- If unsure whether to use it, err on the side of planning - it's better to get alignment upfront than to redo work
-- Users appreciate being consulted before significant changes are made to their codebase
```

## 5. EnterWorktree description deferred out of the tool list

EnterWorktree tool description · whole description removed

The EnterWorktree description is removed. It said to use worktrees only when the user or CLAUDE.md explicitly asks, and it explained the baseRef setting and entering existing worktrees via `path`. EnterWorktree is now a deferred tool whose schema must be fetched with ToolSearch before use.

- Gone in this release
- +0 / -519 words
- Landed in 21 of 23 prompts (main prompt 6/6, session agents, slash commands 3/3, compaction, system reminders 7/8, subagents 3/3)

```diff
-Use this tool ONLY when explicitly instructed to work in a worktree — either by the user directly, or by project instructions (CLAUDE.md / memory). This tool creates an isolated git worktree and switches the current session into it.
-## When to Use
-- The user explicitly says "worktree" (e.g., "start a worktree", "work in a worktree", "create a worktree", "use a worktree")
-- CLAUDE.md or memory instructions direct you to work in a worktree for the current task
-## When NOT to Use
-- The user asks to create a branch, switch branches, or work on a different branch — use git commands instead
-- The user asks to fix a bug or work on a feature — use normal git workflow unless worktrees are explicitly requested by the user or project instructions
-- Never use this tool unless "worktree" is explicitly mentioned by the user or in CLAUDE.md / memory instructions
-## Requirements
-- Must be in a git repository, OR have WorktreeCreate/WorktreeRemove hooks configured in settings.json
-- Must not already be in a worktree session when creating a new worktree (`name`); switching into another existing worktree via `path` is allowed
-## Behavior
-- In a git repository: creates a new git worktree inside `.claude/worktrees/` on a new branch. The base ref is governed by the `worktree.baseRef` setting: `fresh` (default) branches from origin/<default-branch>; `head` branches from your current local HEAD
-- Outside a git repository: delegates to WorktreeCreate/WorktreeRemove hooks for VCS-agnostic isolation
-- Switches the session's working directory to the new worktree
-- Use ExitWorktree to leave the worktree mid-session (keep or remove). On session exit, if still in the worktree, the user will be prompted to keep or remove it
-## Entering an existing worktree
-Pass `path` instead of `name` to switch the session into a worktree that already exists (e.g., one you just created with `git worktree add`). On first entry from the launch directory, the path must appear in `git worktree list` for the repository that owns it — the current repository or, in a multi-repo workspace, a repository nested inside it; paths registered by neither are rejected. ExitWorktree will not remove a worktree entered this way; use `action: "keep"` to return to the original directory.
-Switching with `path` also works when the session is already in a worktree (the previous worktree is left on disk, untouched, and only the new one is tracked for exit-time cleanup), and from agents whose working directory was pinned at launch (subagent isolation or explicit cwd). In both cases the target must be a worktree under `.claude/worktrees/` of the same repository, and from a pinned agent the switch only affects this agent, not the parent session. After a further switch, previously-visited worktrees are no longer writable — re-issue EnterWorktree with `path` to return to one.
-## Parameters
-- `name` (optional): A name for a new worktree. If neither `name` nor `path` is provided, a random name is generated.
-- `path` (optional): Path to an existing worktree to enter instead of creating one — of the current repository, or (on first entry from the launch directory) of a repository nested inside it. Mutually exclusive with `name`.

-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "additionalProperties": false,
- "properties": {
-  "name": {
-   "description": "Optional name for a new worktree. Each \"/\"-separated segment may contain only letters, digits, dots, underscores, and dashes; max 64 chars total. A random name is generated if not provided. Mutually exclusive with `path`.",
-   "type": "string"
-  },
-  "path": {
-   "description": "Path to an existing worktree to switch into instead of creating a new one. Must appear in `git worktree list` for the current repo \u2014 or, on first entry from the launch directory, for a repo nested inside it (multi-repo workspace). Mutually exclusive with `name`.",
-   "type": "string"
-  }
- },
- "type": "object"
-}
```

## 6. CronCreate scheduling guidance deferred out of the tool list

CronCreate tool description · whole description removed

The CronCreate description is removed. It covered one-shot versus recurring cron jobs, avoiding the :00 and :30 minute marks, session-only storage, and the 7-day auto-expiry Claude was told to mention to users. CronCreate is now listed as a deferred tool loaded via ToolSearch.

- Gone in this release
- +0 / -495 words
- Landed in 21 of 23 prompts (main prompt 6/6, session agents, slash commands 3/3, compaction, system reminders 7/8, subagents 3/3)

```diff
-Schedule a prompt to be enqueued at a future time. Use for both recurring schedules and one-shot reminders.
-Uses standard 5-field cron in the user's local timezone: minute hour day-of-month month day-of-week. "0 9 * * *" means 9am local — no timezone conversion needed.
-## One-shot tasks (recurring: false)
-For "remind me at X" or "at <time>, do Y" requests — fire once then auto-delete.
-Pin minute/hour/day-of-month/month to specific values:
-  "remind me at 2:30pm today to check the deploy" → cron: "30 14 <today_dom> <today_month> *", recurring: false
-  "tomorrow morning, run the smoke test" → cron: "57 8 <tomorrow_dom> <tomorrow_month> *", recurring: false
-## Recurring jobs (recurring: true, the default)
-For "every N minutes" / "every hour" / "weekdays at 9am" requests:
-  "*/5 * * * *" (every 5 min), "0 * * * *" (hourly), "0 9 * * 1-5" (weekdays at 9am local)
-## Avoid the :00 and :30 minute marks when the task allows it
-Every user who asks for "9am" gets `0 9`, and every user who asks for "hourly" gets `0 *` — which means requests from across the planet land on the API at the same instant. When the user's request is approximate, pick a minute that is NOT 0 or 30:
-  "every morning around 9" → "57 8 * * *" or "3 9 * * *" (not "0 9 * * *")
-  "hourly" → "7 * * * *" (not "0 * * * *")
-  "in an hour or so, remind me to..." → pick whatever minute you land on, don't round
-Only use minute 0 or 30 when the user names that exact time and clearly means it ("at 9:00 sharp", "at half past", coordinating with a meeting). When in doubt, nudge a few minutes early or late — the user will not notice, and the fleet will.
-## Session-only
-Jobs live only in this Claude session — nothing is written to disk, and the job is gone when Claude exits.
-## Not for live watching
-CronCreate re-runs a prompt at fixed wall-clock intervals. To watch a log file, process, or command output and be notified the moment something changes, use the Monitor tool instead — Monitor streams events as they happen; cron polls on a schedule.
-## Runtime behavior
-Jobs only fire while the REPL is idle (not mid-query). The scheduler shifts each job by a fixed per-job offset on top of whatever you pick: by default a recurring job runs up to 50% of its period late (max 30 min), and a one-shot job landing on :00 or :30 runs up to 90 s early. The result of this tool and of CronList gives each job's actual next run time: when you tell the user when a job will run, give that time, not the minute in the cron expression. Picking an off-minute is still the bigger lever.
-Recurring tasks auto-expire after 7 days — they fire one final time, then are deleted. This bounds session lifetime. Tell the user about the 7-day limit when scheduling recurring jobs.
-Returns a job ID you can pass to CronDelete.

-Schedule a prompt to be enqueued at a future time. Use for both recurring schedules and one-shot reminders.
-Uses standard 5-field cron in the user's local timezone: minute hour day-of-month month day-of-week. "0 9 * * *" means 9am local — no timezone conversion needed.
-## One-shot tasks (recurring: false)
-For "remind me at X" or "at <time>, do Y" requests — fire once then auto-delete.
-Pin minute/hour/day-of-month/month to specific values:
-  "remind me at 2:30pm today to check the deploy" → cron: "30 14 <today_dom> <today_month> *", recurring: false
-  "tomorrow morning, run the smoke test" → cron: "57 8 <tomorrow_dom> <tomorrow_month> *", recurring: false
-## Recurring jobs (recurring: true, the default)
-For "every N minutes" / "every hour" / "weekdays at 9am" requests:
-  "*/5 * * * *" (every 5 min), "0 * * * *" (hourly), "0 9 * * 1-5" (weekdays at 9am local)
-## Avoid the :00 and :30 minute marks when the task allows it
-Every user who asks for "9am" gets `0 9`, and every user who asks for "hourly" gets `0 *` — which means requests from across the planet land on the API at the same instant. When the user's request is approximate, pick a minute that is NOT 0 or 30:
-  "every morning around 9" → "57 8 * * *" or "3 9 * * *" (not "0 9 * * *")
-  "hourly" → "7 * * * *" (not "0 * * * *")
-  "in an hour or so, remind me to..." → pick whatever minute you land on, don't round
-Only use minute 0 or 30 when the user names that exact time and clearly means it ("at 9:00 sharp", "at half past", coordinating with a meeting). When in doubt, nudge a few minutes early or late — the user will not notice, and the fleet will.
-## Durability
-By default (durable: false) the job lives only in this Claude session — nothing is written to disk, and the job is gone when Claude exits. Pass durable: true to write to .claude/scheduled_tasks.json so the job survives restarts. Only use durable: true when the user explicitly asks for the task to persist ("keep doing this every day", "set this up permanently"). Most "remind me in 5 minutes" / "check back in an hour" requests should stay session-only.
-## Runtime behavior
-Jobs only fire while the REPL is idle (not mid-query). Durable jobs persist to .claude/scheduled_tasks.json and survive session restarts — on next launch they resume automatically. One-shot durable tasks that were missed while the REPL was closed are surfaced for catch-up. Session-only jobs die with the process. The scheduler shifts each job by a fixed per-job offset on top of whatever you pick: by default a recurring job runs up to 50% of its period late (max 30 min), and a one-shot job landing on :00 or :30 runs up to 90 s early. The result of this tool and of CronList gives each job's actual next run time: when you tell the user when a job will run, give that time, not the minute in the cron expression. Picking an off-minute is still the bigger lever.
-Recurring tasks auto-expire after 7 days — they fire one final time, then are deleted. This bounds session lifetime. Tell the user about the 7-day limit when scheduling recurring jobs.
-Returns a job ID you can pass to CronDelete.

-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "additionalProperties": false,
- "properties": {
-  "cron": {
-   "description": "Standard 5-field cron expression in local time: \"M H DoM Mon DoW\" (e.g. \"*/5 * * * *\" = every 5 minutes, \"30 14 28 2 *\" = Feb 28 at 2:30pm local once).",
-   "type": "string"
-  },
-  "durable": {
-   "description": "Has no effect \u2014 durable persistence is not available. All jobs are session-only (in-memory, gone when this Claude session ends).",
-   "type": "boolean"
-  },
-  "prompt": {
-   "description": "The prompt to enqueue at each fire time.",
-   "type": "string"
-  },
-  "recurring": {
-   "description": "true (default) = fire on every cron match until deleted or auto-expired after 7 days. false = fire once at the next match, then auto-delete. Use false for \"remind me at X\" one-shot requests with pinned minute/hour/dom/month.",
-   "type": "boolean"
-  }
- },
- "required": [
-  "cron",
-  "prompt"
- ],
- "type": "object"
-}
```

## 7. TaskCreate tool description removed

TaskCreate tool description · whole description removed

The whole TaskCreate description is gone in 6 of 23 captures, including guidance to proactively create task lists for multi-step work and the subject, description and activeForm field notes. In those setups Claude no longer sees this tool's instructions.

- Gone in this release
- +0 / -341 words
- Landed in 7 of 23 prompts (main prompt 6/6, system reminders 1/8)

```diff
-Use this tool to create a structured task list for your current coding session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
-It also helps the user understand the progress of the task and overall progress of their requests.
-## When to Use This Tool
-Use this tool proactively in these scenarios:
-- Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
-- Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
-- Plan mode - When using plan mode, create a task list to track the work
-- User explicitly requests todo list - When the user directly asks you to use the todo list
-- User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
-- After receiving new instructions - Immediately capture user requirements as tasks
-- When you start working on a task - Mark it as in_progress BEFORE beginning work
-- After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation
-## When NOT to Use This Tool
-Skip using this tool when:
-- There is only a single, straightforward task
-- The task is trivial and tracking it provides no organizational benefit
-- The task can be completed in less than 3 trivial steps
-- The task is purely conversational or informational
-NOTE that you should not use this tool if there is only one trivial task to do. In this case you are better off just doing the task directly.
-## Task Fields
-- **subject**: A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")
-- **description**: What needs to be done
-- **activeForm** (optional): Present continuous form shown in the spinner when the task is in_progress (e.g., "Fixing authentication bug"). If omitted, the spinner shows the subject instead.
-All tasks are created with status `pending`.
-## Tips
-- Create tasks with clear, specific subjects that describe the outcome
-- After creating tasks, use TaskUpdate to set up dependencies (blocks/blockedBy) if needed
-- Check TaskList first to avoid creating duplicate tasks

-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "additionalProperties": false,
- "properties": {
-  "activeForm": {
-   "description": "Present continuous form shown in spinner when in_progress (e.g., \"Running tests\")",
-   "type": "string"
-  },
-  "description": {
-   "description": "What needs to be done",
-   "type": "string"
-  },
-  "metadata": {
-   "additionalProperties": {},
-   "description": "Arbitrary metadata to attach to the task",
-   "propertyNames": {
-    "type": "string"
-   },
-   "type": "object"
-  },
-  "subject": {
-   "description": "A brief title for the task",
-   "type": "string"
-  }
- },
- "required": [
-  "subject",
-  "description"
- ],
- "type": "object"
-}
```

## 8. TaskUpdate tool description removed

TaskUpdate tool description · whole description removed

The whole TaskUpdate description is removed in 6 of 23 captures, including rules to mark tasks completed only when fully done, the status workflow, dependency fields and JSON examples. In those setups Claude no longer sees this tool's instructions.

- Gone in this release
- +0 / -328 words
- Landed in 7 of 23 prompts (main prompt 6/6, system reminders 1/8)

````diff
-Use this tool to update a task in the task list.
-## When to Use This Tool
-**Mark tasks as resolved:**
-- When you have completed the work described in a task
-- When a task is no longer needed or has been superseded
-- IMPORTANT: Always mark your assigned tasks as resolved when you finish them
-- After resolving, call TaskList to find your next task
-- ONLY mark a task as completed when you have FULLY accomplished it
-- If you encounter errors, blockers, or cannot finish, keep the task as in_progress
-- When blocked, create a new task describing what needs to be resolved
-- Never mark a task as completed if:
-  - Tests are failing
-  - Implementation is partial
-  - You encountered unresolved errors
-  - You couldn't find necessary files or dependencies
-**Delete tasks:**
-- When a task is no longer relevant or was created in error
-- Setting status to `deleted` permanently removes the task
-**Update task details:**
-- When requirements change or become clearer
-- When establishing dependencies between tasks
-## Fields You Can Update
-- **status**: The task status (see Status Workflow below)
-- **subject**: Change the task title (imperative form, e.g., "Run tests")
-- **description**: Change the task description
-- **activeForm**: Present continuous form shown in spinner when in_progress (e.g., "Running tests")
-- **owner**: Change the task owner (agent name)
-- **metadata**: Merge metadata keys into the task (set a key to null to delete it)
-- **addBlocks**: Mark tasks that cannot start until this one completes
-- **addBlockedBy**: Mark tasks that must complete before this one can start
-## Status Workflow
-Status progresses: `pending` → `in_progress` → `completed`
-Use `deleted` to permanently remove a task.
-## Staleness
-Make sure to read a task's latest state using `TaskGet` before updating it.
-## Examples
-Mark task as in progress when starting work:
-```json
-{"taskId": "1", "status": "in_progress"}
-```
-Mark task as completed after finishing work:
-```json
-{"taskId": "1", "status": "completed"}
-```
-Delete a task:
-```json
-{"taskId": "1", "status": "deleted"}
-```
-Claim a task by setting owner:
-```json
-{"taskId": "1", "owner": "my-name"}
-```
-Set up task dependencies:
-```json
-{"taskId": "2", "addBlockedBy": ["1"]}
-```

-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "additionalProperties": false,
- "properties": {
-  "activeForm": {
-   "description": "Present continuous form shown in spinner when in_progress (e.g., \"Running tests\")",
-   "type": "string"
-  },
-  "addBlockedBy": {
-   "description": "Task IDs that block this task",
-   "items": {
-    "type": "string"
-   },
-   "type": "array"
-  },
-  "addBlocks": {
-   "description": "Task IDs that this task blocks",
-   "items": {
-    "type": "string"
-   },
-   "type": "array"
-  },
-  "description": {
-   "description": "New description for the task",
-   "type": "string"
-  },
-  "metadata": {
-   "additionalProperties": {},
-   "description": "Metadata keys to merge into the task. Set a key to null to delete it.",
-   "propertyNames": {
-    "type": "string"
-   },
-   "type": "object"
-  },
-  "owner": {
-   "description": "New owner for the task",
-   "type": "string"
-  },
-  "status": {
-   "anyOf": [
-    {
-     "enum": [
-      "pending",
-      "in_progress",
-      "completed"
-     ],
-     "type": "string"
-    },
-    {
-     "const": "deleted",
-     "type": "string"
-    }
-   ],
-   "description": "New status for the task"
-  },
-  "subject": {
-   "description": "New subject for the task",
-   "type": "string"
-  },
-  "taskId": {
-   "description": "The ID of the task to update",
-   "type": "string"
-  }
- },
- "required": [
-  "taskId"
- ],
- "type": "object"
-}
````

## 9. ExitPlanMode tool removed from one capture

ExitPlanMode tool description · whole description removed

The ExitPlanMode description was removed in 1 of 2 captures. It told Claude to write a plan to the plan file and then call the tool to request user approval, and not to use AskUserQuestion to ask whether the plan was okay. In that setup the plan-approval step this tool provided is no longer described.

- Gone in this release
- +0 / -311 words
- Landed in 5 of 23 prompts (main prompt 3/6, session agents, compaction)

```diff
-Use this tool when you are in plan mode and have finished writing your plan to the plan file and are ready for user approval.
-## How This Tool Works
-- You should have already written your plan to the plan file specified in the plan mode system message
-- This tool does NOT take the plan content as a parameter - it will read the plan from the file you wrote
-- This tool simply signals that you're done planning and ready for the user to review and approve
-- The user will see the contents of your plan file when they review it
-## When to Use This Tool
-IMPORTANT: Only use this tool when the task requires planning the implementation steps of a task that requires writing code. For research tasks where you're gathering information, searching files, reading files or in general trying to understand the codebase - do NOT use this tool.
-## Before Using This Tool
-Ensure your plan is complete and unambiguous:
-- If you have unresolved questions about requirements or approach, use AskUserQuestion first (in earlier phases)
-- Once your plan is finalized, use THIS tool to request approval
-**Important:** Do NOT use AskUserQuestion to ask "Is this plan okay?" or "Should I proceed?" - that's exactly what THIS tool does. ExitPlanMode inherently requests user approval of your plan.
-## Examples
-1. Initial task: "Search for and understand the implementation of vim mode in the codebase" - Do not use the exit plan mode tool because you are not planning the implementation steps of a task.
-2. Initial task: "Help me implement yank mode for vim" - Use the exit plan mode tool after you have finished planning the implementation steps of the task.
-3. Initial task: "Add a new feature to handle user authentication" - If unsure about auth method (OAuth, JWT, etc.), use AskUserQuestion first, then use exit plan mode tool after clarifying the approach.

-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "additionalProperties": {},
- "properties": {
-  "allowedPrompts": {
-   "description": "Deprecated: no longer used.",
-   "items": {
-    "additionalProperties": false,
-    "properties": {
-     "prompt": {
-      "description": "Semantic description of the action, e.g. \"run tests\", \"install dependencies\"",
-      "type": "string"
-     },
-     "tool": {
-      "description": "The tool this prompt applies to",
-      "enum": [
-       "Bash"
-      ],
-      "type": "string"
-     }
-    },
-    "required": [
-     "tool",
-     "prompt"
-    ],
-    "type": "object"
-   },
-   "type": "array"
-  }
- },
- "type": "object"
-}
```

## 10. ExitWorktree description deferred out of the tool list

ExitWorktree tool description · whole description removed

The ExitWorktree description is removed. It covered its scope (only worktrees from EnterWorktree in this session), not calling it proactively, keep versus remove, and confirming with the user before using `discard_changes`. The tool is now deferred and must be loaded with ToolSearch first.

- Gone in this release
- +0 / -301 words
- Landed in 21 of 23 prompts (main prompt 6/6, session agents, slash commands 3/3, compaction, system reminders 7/8, subagents 3/3)

```diff
-Exit a worktree session created by EnterWorktree and return the session to the original working directory.
-## Scope
-This tool ONLY operates on worktrees created by EnterWorktree in this session. It will NOT touch:
-- Worktrees you created manually with `git worktree add`
-- Worktrees from a previous session (even if created by EnterWorktree then)
-- The directory you're in if EnterWorktree was never called
-If called outside an EnterWorktree session, the tool is a **no-op**: it reports that no worktree session is active and takes no action. Filesystem state is unchanged.
-## When to Use
-- The user explicitly asks to "exit the worktree", "leave the worktree", "go back", or otherwise end the worktree session
-- Do NOT call this proactively — only when the user asks
-## Parameters
-- `action` (required): `"keep"` or `"remove"`
-  - `"keep"` — leave the worktree directory and branch intact on disk. Use this if the user wants to come back to the work later, or if there are changes to preserve.
-  - `"remove"` — delete the worktree directory and its branch. Use this for a clean exit when the work is done or abandoned.
-- `discard_changes` (optional, default false): only meaningful with `action: "remove"`. If the worktree has uncommitted files or commits not on the original branch, the tool will REFUSE to remove it unless this is set to `true`. If the tool returns an error listing changes, confirm with the user before re-invoking with `discard_changes: true`.
-## Behavior
-- Restores the session's working directory to where it was before EnterWorktree
-- Clears CWD-dependent caches (system prompt sections, memory files, plans directory) so the session state reflects the original directory
-- If a tmux session was attached to the worktree: killed on `remove`, left running on `keep` (its name is returned so the user can reattach)
-- Once exited, EnterWorktree can be called again to create a fresh worktree

-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "additionalProperties": false,
- "properties": {
-  "action": {
-   "description": "\"keep\" leaves the worktree and branch on disk; \"remove\" deletes both.",
-   "enum": [
-    "keep",
-    "remove"
-   ],
-   "type": "string"
-  },
-  "discard_changes": {
-   "description": "Required true when action is \"remove\" and the worktree has uncommitted files or unmerged commits. The tool will refuse and list them otherwise.",
-   "type": "boolean"
-  }
- },
- "required": [
-  "action"
- ],
- "type": "object"
-}
```

## 11. Long WebFetch description removed as tool becomes deferred

WebFetch tool description · whole description removed

The longer WebFetch description is removed. It warned that authenticated URLs fail, preferred MCP fetch tools and `gh` for GitHub, and explained the HTTPS upgrade, the 15-minute cache and cross-host redirect handling. WebFetch now appears in the deferred tool list.

- Gone in this release
- +0 / -274 words
- Landed in 6 of 23 prompts (main prompt 6/6)

```diff
-IMPORTANT: WebFetch WILL FAIL for authenticated or private URLs. Before using this tool, check if the URL points to an authenticated service (e.g. Google Docs, Confluence, Jira, GitHub). If so, look for a specialized MCP tool that provides authenticated access.
-- Fetches content from a specified URL and processes it using an AI model
-- Takes a URL and a prompt as input
-- Fetches the URL content, converts HTML to markdown
-- Processes the content with the prompt using a small, fast model
-- Returns the model's response about the content
-- Use this tool when you need to retrieve and analyze web content
-Usage notes:
-  - IMPORTANT: If an MCP-provided web fetch tool is available, prefer using that tool instead of this one, as it may have fewer restrictions.
-  - The URL must be a fully-formed valid URL
-  - HTTP URLs will be automatically upgraded to HTTPS
-  - localhost and other hostnames without a dot are not supported; for a local server, use curl via Bash
-  - The prompt should describe what information you want to extract from the page
-  - This tool is read-only and does not modify any files
-  - Results may be summarized if the content is very large
-  - Includes a self-cleaning cache (entries expire after 15 minutes) for faster responses when repeatedly accessing the same URL
-  - When a URL redirects to a different host, the tool will inform you and provide the redirect URL in a special format. You should then make a new WebFetch request with the redirect URL to fetch the content.
-  - For GitHub URLs, prefer using the gh CLI via Bash instead (e.g., gh pr view, gh issue view, gh api).
```

## 12. Long WebSearch description with mandatory Sources rule removed

WebSearch tool description · whole description removed

The longer WebSearch description is removed. It required a "Sources:" section of markdown links after answers, noted search is US-only, and said to use the current year in queries. WebSearch is now a deferred tool that must be loaded through ToolSearch.

- Gone in this release
- +0 / -200 words
- Landed in 6 of 23 prompts (main prompt 6/6)

```diff
-- Allows Claude to search the web and use the results to inform responses
-- Provides up-to-date information for current events and recent data
-- Returns search result information formatted as search result blocks, including links as markdown hyperlinks
-- Use this tool for accessing information beyond Claude's knowledge cutoff
-- Searches are performed automatically within a single API call
-CRITICAL REQUIREMENT - You MUST follow this:
-  - After answering the user's question, you MUST include a "Sources:" section at the end of your response
-  - In the Sources section, list all relevant URLs from the search results as markdown hyperlinks: [Title](URL)
-  - This is MANDATORY - never skip including sources in your response
-  - Example format:
-    [Your answer here]
-    Sources:
-    - [Source Title 1](https://example.com/1)
-    - [Source Title 2](https://example.com/2)
-Usage notes:
-  - Domain filtering is supported to include or block specific websites
-  - Web search is only available in the US
-IMPORTANT - Use the correct year in search queries:
-  - The current month is (provided in the conversation below). You MUST use this year when searching for recent information, documentation, or current events.
-  - Example: If the user asks for "latest React docs", search for "React documentation" with the current year, NOT last year
```

## 13. TaskList tool description removed

TaskList tool description · whole description removed

The whole TaskList description is removed in 6 of 23 captures, including when to list tasks, the preference for working in ID order, and the output fields. In those setups Claude no longer sees this tool's instructions.

- Gone in this release
- +0 / -157 words
- Landed in 7 of 23 prompts (main prompt 6/6, system reminders 1/8)

```diff
-Use this tool to list all tasks in the task list.
-## When to Use This Tool
-- To see what tasks are available to work on (status: 'pending', no owner, not blocked)
-- To check overall progress on the project
-- To find tasks that are blocked and need dependencies resolved
-- After completing a task, to check for newly unblocked work or claim the next available task
-- **Prefer working on tasks in ID order** (lowest ID first) when multiple tasks are available, as earlier tasks often set up context for later ones
-## Output
-Returns a summary of each task:
-- **id**: Task identifier (use with TaskGet, TaskUpdate)
-- **subject**: Brief description of the task
-- **status**: 'pending', 'in_progress', or 'completed'
-- **owner**: Agent ID if assigned, empty if available
-- **blockedBy**: List of open task IDs that must be resolved first (tasks with blockedBy cannot be claimed until dependencies resolve)
-Use TaskGet with a specific task ID to view full details including description and comments.
```

## 14. New ToolSearch tool loads schemas for deferred tools

ToolSearch tool description · whole description added

A ToolSearch tool is added. Tools listed by name in system reminders have no schema and cannot be called until ToolSearch returns their JSONSchema definitions. It accepts exact selection ("select:Read,Edit"), keyword search, and "+term" queries that require a word in the tool name.

- New in this release
- +149 / -0 words
- Landed in 21 of 23 prompts (main prompt 6/6, session agents, slash commands 3/3, compaction, system reminders 7/8, subagents 3/3)

```diff
+Fetches full schema definitions for deferred tools so they can be called.
+Deferred tools appear by name in <system-reminder> messages. Until fetched, only the name is known — there is no parameter schema, so the tool cannot be invoked. This tool takes a query, matches it against the deferred tool list, and returns the matched tools' complete JSONSchema definitions inside a <functions> block. Once a tool's schema appears in that result, it is callable exactly like any tool defined at the top of the prompt.
+Result format: each matched tool appears as one <function>{"description": "...", "name": "...", "parameters": {...}}</function> line inside the <functions> block — the same encoding as the tool list at the top of this prompt.
+Query forms:
+- "select:Read,Edit,Grep" — fetch these exact tools by name
+- "notebook jupyter" — keyword search, up to max_results best matches
+- "+slack send" — require "slack" in the name, rank by remaining terms

+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "additionalProperties": false,
+ "properties": {
+  "max_results": {
+   "default": 5,
+   "description": "Maximum number of results to return (default: 5)",
+   "type": "number"
+  },
+  "query": {
+   "description": "Query to find deferred tools. Use \"select:<tool_name>\" for direct selection, or keywords to search.",
+   "type": "string"
+  }
+ },
+ "required": [
+  "query",
+  "max_results"
+ ],
+ "type": "object"
+}
```

## 15. TaskGet tool description removed

TaskGet tool description · whole description removed

The whole TaskGet description is gone, including its guidance on when to fetch a task, the fields it returns (subject, description, status, blocks, blockedBy), and the tip to check blockedBy is empty before starting work. Landed in 6 of 23 captures.

- Gone in this release
- +0 / -111 words
- Landed in 7 of 23 prompts (main prompt 6/6, system reminders 1/8)

```diff
-Use this tool to retrieve a task by its ID from the task list.
-## When to Use This Tool
-- When you need the full description and context before starting work on a task
-- To understand task dependencies (what it blocks, what blocks it)
-- After being assigned a task, to get complete requirements
-## Output
-Returns full task details:
-- **subject**: Task title
-- **description**: Detailed requirements and context
-- **status**: 'pending', 'in_progress', or 'completed'
-- **blocks**: Tasks waiting on this one to complete
-- **blockedBy**: Tasks that must complete before this one can start
-## Tips
-- After fetching a task, verify its blockedBy list is empty before beginning work.
-- Use TaskList to see all tasks in summary form.

-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "additionalProperties": false,
- "properties": {
-  "taskId": {
-   "description": "The ID of the task to retrieve",
-   "type": "string"
-  }
- },
- "required": [
-  "taskId"
- ],
- "type": "object"
-}
```

## 16. NotebookEdit description deferred out of the tool list

NotebookEdit tool description · whole description removed

The NotebookEdit description is removed. It covered reading the notebook first, absolute paths, `cell_id`, and the replace, insert and delete modes. NotebookEdit is now a deferred tool loaded via ToolSearch.

- Gone in this release
- +0 / -100 words
- Landed in 19 of 23 prompts (main prompt 6/6, session agents, slash commands 3/3, compaction, system reminders 7/8, subagents 1/3)

```diff
-Replaces, inserts, or deletes a single cell in a Jupyter notebook (.ipynb file).
-Usage:
-- You must use the Read tool on the notebook in this conversation before editing — this tool will fail otherwise.
-- `notebook_path` must be an absolute path.
-- `cell_id` is the `id` attribute shown in the Read tool's `<cell id="...">` output. It is required for `replace` and `delete`.
-- `edit_mode` defaults to `replace`. Use `insert` to add a new cell after the cell with the given `cell_id` (or at the beginning of the notebook if `cell_id` is omitted) — `cell_type` is required when inserting. Use `delete` to remove the cell.

-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "additionalProperties": false,
- "properties": {
-  "cell_id": {
-   "description": "The ID of the cell to edit. When inserting a new cell, the new cell will be inserted after the cell with this ID, or at the beginning if not specified.",
-   "type": "string"
-  },
-  "cell_type": {
-   "description": "The type of the cell (code or markdown). If not specified, it defaults to the current cell type. If using edit_mode=insert, this is required.",
-   "enum": [
-    "code",
-    "markdown"
-   ],
-   "type": "string"
-  },
-  "edit_mode": {
-   "description": "The type of edit to make (replace, insert, delete). Defaults to replace.",
-   "enum": [
-    "replace",
-    "insert",
-    "delete"
-   ],
-   "type": "string"
-  },
-  "new_source": {
-   "description": "The new source for the cell",
-   "type": "string"
-  },
-  "notebook_path": {
-   "description": "The absolute path to the Jupyter notebook file to edit (must be absolute, not relative)",
-   "type": "string"
-  }
- },
- "required": [
-  "notebook_path",
-  "new_source"
- ],
- "type": "object"
-}
```

## 17. Short WebFetch description variant removed

WebFetch tool description · whole description removed

A condensed WebFetch description is removed. It noted failures on authenticated URLs and localhost, the HTTPS upgrade, returned cross-host redirects and 15-minute caching. Along with the longer variant, this reflects WebFetch moving to the deferred tool list.

- Gone in this release
- +0 / -79 words
- Landed in 21 of 23 prompts (main prompt 6/6, session agents, slash commands 3/3, compaction, system reminders 7/8, subagents 3/3)

```diff
-Fetches a URL, converts the page to markdown, and answers `prompt` against it using a small fast model.
-- Fails on authenticated/private URLs — use an authenticated MCP tool or `gh` for those instead.
-- Fails on localhost and other hostnames without a dot; for a local server, use curl via Bash.
-- HTTP is upgraded to HTTPS. Cross-host redirects are returned to you rather than followed; call again with the redirect URL.
-- Responses are cached for 15 minutes per URL.
```

## 18. TaskStop description deferred out of the tool list

TaskStop tool description · whole description removed

The TaskStop description is removed. It explained stopping background tasks, teammates or named background agents by ID or name. TaskStop is now a deferred tool fetched through ToolSearch.

- Gone in this release
- +0 / -65 words
- Landed in 21 of 23 prompts (main prompt 6/6, session agents, slash commands 3/3, compaction, system reminders 7/8, subagents 3/3)

```diff
-- Stops a running background task by its ID
-- Takes a task_id parameter identifying the task to stop
-- To stop an agent-team teammate, pass its agent ID or bare teammate name as task_id
-- To stop a background agent spawned with a name, pass that name as task_id
-- Returns a success or failure status
-- Use this tool when you need to terminate a long-running task

-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "additionalProperties": false,
- "properties": {
-  "shell_id": {
-   "description": "Deprecated: use task_id instead",
-   "type": "string"
-  },
-  "task_id": {
-   "description": "The ID of the background task to stop. Agent-team teammates and named background agents are also accepted by agent ID or name.",
-   "type": "string"
-  }
- },
- "type": "object"
-}
```

## 19. Short WebSearch description variant removed

WebSearch tool description · whole description removed

A condensed WebSearch description is removed. It covered US-only search, using the current month, domain filters, and ending answers with a Sources list. WebSearch is now deferred, alongside the removal of the longer variant.

- Gone in this release
- +0 / -49 words
- Landed in 21 of 23 prompts (main prompt 6/6, session agents, slash commands 3/3, compaction, system reminders 7/8, subagents 3/3)

```diff
-Search the web. Returns result blocks with titles and URLs. US-only.
-- The current month is (provided in the conversation below) — use this when searching for recent information.
-- `allowed_domains` / `blocked_domains` filter results.
-- After answering from results, end with a "Sources:" list of the URLs you used as markdown links.
```

## 20. CronDelete description deferred out of the tool list

CronDelete tool description · whole description removed

The one-line CronDelete description is removed. CronDelete now appears as a deferred tool that must be loaded with ToolSearch before use.

- Gone in this release
- +0 / -16 words
- Landed in 21 of 23 prompts (main prompt 6/6, session agents, slash commands 3/3, compaction, system reminders 7/8, subagents 3/3)

```diff
-Cancel a cron job previously scheduled with CronCreate. Removes it from the in-memory session store.

-Cancel a cron job previously scheduled with CronCreate. Removes it from .claude/scheduled_tasks.json (durable jobs) or the in-memory session store (session-only jobs).

-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "additionalProperties": false,
- "properties": {
-  "id": {
-   "description": "Job ID returned by CronCreate.",
-   "type": "string"
-  }
- },
- "required": [
-  "id"
- ],
- "type": "object"
-}
```

## 21. Placeholder tool added to keep deferred loading active

DeferredToolPlaceholder tool description · whole description added

A new DeferredToolPlaceholder tool is added. Its description says it exists only to keep deferred tool loading active and that Claude must never call it.

- New in this release
- +12 / -0 words
- Landed in 21 of 23 prompts (main prompt 6/6, session agents, slash commands 3/3, compaction, system reminders 7/8, subagents 3/3)

```diff
+Reserved placeholder that keeps deferred tool loading active; never call this tool.

+{
+ "properties": {},
+ "type": "object"
+}
```

## 22. CronList description deferred out of the tool list

CronList tool description · whole description removed

The one-line CronList description is removed. CronList is now in the deferred tool list, loaded via ToolSearch.

- Gone in this release
- +0 / -10 words
- Landed in 21 of 23 prompts (main prompt 6/6, session agents, slash commands 3/3, compaction, system reminders 7/8, subagents 3/3)

```diff
-List all cron jobs scheduled via CronCreate in this session.

-List all cron jobs scheduled via CronCreate, both durable (.claude/scheduled_tasks.json) and session-only.

-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "additionalProperties": false,
- "properties": {},
- "type": "object"
-}
```

## 23. Monitor streaming guidance deferred out of the tool list

Monitor tool description · whole description removed

The long Monitor description is removed. As far as shown, it covered choosing Monitor versus a background Bash command, line-buffered filters, matching failure states as well as success, timeouts and WebSocket sources. It landed in 3 of 5 captures, and Monitor now appears in the deferred tool list.

- Behind a feature flag
- Gone in this release
- +0 / -1035 words
- Landed in 4 of 23 prompts (main prompt 4/6)

```diff
-Start a background monitor that streams events from a long-running script. Each stdout line is an event — you keep working and notifications arrive in the chat. Events arrive on their own schedule and are not replies from the user, even if one lands while you're waiting for the user to answer a question.
-Pick by how many notifications you need:
-- **One** ("tell me when the server is ready / the build finishes") → use **Bash with `run_in_background`** and a command that exits when the condition is true, e.g. `until grep -q "Ready in" dev.log; do sleep 0.5; done`. You get a single completion notification when it exits.
-- **One per occurrence, until the monitor expires (re-arm to continue)** ("tell me every time an ERROR line appears") → Monitor with an unbounded command (`tail -f`, `inotifywait -m`, `while true`).
-- **One per occurrence, until a known end** ("emit each CI step result, stop when the run completes") → Monitor with a command that emits lines and then exits.
-Your script's stdout is the event stream. Each line becomes a notification. Exit ends the watch.
-  # Each matching log line is an event
-  tail -f /var/log/app.log | grep --line-buffered "ERROR"
-  # Each file change is an event
-  inotifywait -m --format '%e %f' /watched/dir
-  # Poll GitHub for new PR comments and emit one line per new comment
-  last=$(date -u +%Y-%m-%dT%H:%M:%SZ)
-  while true; do
-    now=$(date -u +%Y-%m-%dT%H:%M:%SZ)
-    gh api "repos/owner/repo/issues/123/comments?since=$last" --jq '.[] | "\(.user.login): \(.body)"'
-    last=$now; sleep 30
-  done
-  # Node script that emits events as they arrive (e.g. WebSocket listener)
-  node watch-for-events.js
-  # Per-occurrence with a natural end: emit each CI check as it lands, exit when the run completes
-  prev=""
-  while true; do
-    s=$(gh pr checks 123 --json name,bucket)
-    cur=$(jq -r '.[] | select(.bucket!="pending") | "\(.name): \(.bucket)"' <<<"$s" | sort)
-    comm -13 <(echo "$prev") <(echo "$cur")
-    prev=$cur
-    jq -e 'all(.bucket!="pending")' <<<"$s" >/dev/null && break
-    sleep 30
-  done
-**Don't use an unbounded command for a single notification.** `tail -f`, `inotifywait -m`, and `while true` never exit on their own, so the monitor stays armed until timeout even after the event has fired. For "tell me when X is ready," use Bash `run_in_background` with an `until` loop instead (one notification, ends in seconds). Note that `tail -f log | grep -m 1 ...` does *not* fix this: if the log goes quiet after the match, `tail` never receives SIGPIPE and the pipeline hangs anyway.
-**Script quality:**
-- Every pipe stage must flush per line or matches sit in its buffer unseen: `grep` needs `--line-buffered`, `awk` needs `fflush()`. `head` cannot flush at all — `| head -N` delivers nothing until N matches accumulate, then ends the stream.
-- In poll loops, handle transient failures (`curl ... || true`) — one failed request shouldn't kill the monitor.
-- Poll intervals: 30s+ for remote APIs (rate limits), 0.5-1s for local checks.
-- Write a specific `description` — it appears in every notification ("errors in deploy.log" not "watching logs").
-- Only stdout is the event stream. Stderr goes to the output file (readable via Read) but does not trigger notifications — for a command you run directly (e.g. `python train.py 2>&1 | grep --line-buffered ...`), merge stderr with `2>&1` so its failures reach your filter. (No effect on `tail -f` of an existing log — that file only contains what its writer redirected.)
-**Coverage — silence is not success.** When watching a job or process for an outcome, your filter must match every terminal state, not just the happy path. A monitor that greps only for the success marker stays silent through a crashloop, a hung process, or an unexpected exit — and silence looks identical to "still running." Before arming, ask: *if this process crashed right now, would my filter emit anything?* If not, widen it.
-  # Wrong — silent on crash, hang, or any non-success exit
-  tail -f run.log | grep --line-buffered "elapsed_steps="
-  # Right — one alternation covering progress + the failure signatures you'd act on
-  tail -f run.log | grep -E --line-buffered "elapsed_steps=|Traceback|Error|FAILED|assert|Killed|OOM"
-For poll loops checking job state, emit on every terminal status (`succeeded|failed|cancelled|timeout`), not just success. If you cannot confidently enumerate the failure signatures, broaden the grep alternation rather than narrow it — some extra noise is better than missing a crashloop.
-**Output volume**: Every stdout line is a conversation message, so the filter should be selective — but selective means "the lines you'd act on," not "only good news." Never pipe raw logs; filter to exactly the success and failure signals you care about. Monitors that produce too many events are automatically stopped; restart with a tighter filter if this happens.
-Stdout lines within 200ms are batched into a single notification, so multiline output from a single event groups naturally.
-The script runs in the same shell environment as Bash. Exit ends the watch (exit code is reported). Every monitor expires after `timeout_ms` (default 5 minutes, at most 10 minutes): it is killed and you get one notice with the event count. Re-arm it if you still need the watch; for a long watch (PR monitoring, log tails) set `timeout_ms` to the maximum and re-arm on each expiry, and widen the filter if an expiry with no events was unexpected. Use TaskStop to cancel early.
-**ws source** — open a WebSocket and stream each incoming text frame as an event. No shell, no polling: the server pushes, you get notified.
-  Monitor({
-    ws: {url: 'wss://events.example.com/stream', protocols: ['v1']},
-    description: 'deploy events',
-  })
-Each text frame becomes one notification (multiline frames stay as one event). Binary frames are reported as `[binary frame, N bytes]` rather than passed through. Socket close ends the watch with the close code surfaced; errors are surfaced before close. Same rate limiting as bash — a firehose will be suppressed and eventually stopped, so subscribe to a filtered feed where one exists.
-Prefer this over `command: 'websocat wss://…'` — it avoids the extra process and line-buffering pitfalls. Use bash when you need to transform or filter frames with shell tools before they become events.

-Start a background monitor that streams events from a long-running script. Each stdout line is an event — you keep working and notifications arrive in the chat. Events arrive on their own schedule and are not replies from the user, even if one lands while you're waiting for the user to answer a question.
-Pick by how many notifications you need:
-- **One** ("tell me when the server is ready / the build finishes") → use **Bash with `run_in_background`** and a command that exits when the condition is true, e.g. `until grep -q "Ready in" dev.log; do sleep 0.5; done`. You get a single completion notification when it exits.
-- **One per occurrence, until the monitor expires (re-arm to continue)** ("tell me every time an ERROR line appears") → Monitor with an unbounded command (`tail -f`, `inotifywait -m`, `while true`).
-- **One per occurrence, until a known end** ("emit each CI step result, stop when the run completes") → Monitor with a command that emits lines and then exits.
-Your script's stdout is the event stream. Each line becomes a notification. Exit ends the watch.
-  # Each matching log line is an event
-  tail -f /var/log/app.log | grep --line-buffered "ERROR"
-  # Each file change is an event
-  inotifywait -m --format '%e %f' /watched/dir
-  # Poll GitHub for new PR comments and emit one line per new comment
-  last=$(date -u +%Y-%m-%dT%H:%M:%SZ)
-  while true; do
-    now=$(date -u +%Y-%m-%dT%H:%M:%SZ)
-    gh api "repos/owner/repo/issues/123/comments?since=$last" --jq '.[] | "\(.user.login): \(.body)"'
-    last=$now; sleep 30
-  done
-  # Node script that emits events as they arrive (e.g. WebSocket listener)
-  node watch-for-events.js
-  # Per-occurrence with a natural end: emit each CI check as it lands, exit when the run completes
-  prev=""
-  while true; do
-    s=$(gh pr checks 123 --json name,bucket)
-    cur=$(jq -r '.[] | select(.bucket!="pending") | "\(.name): \(.bucket)"' <<<"$s" | sort)
-    comm -13 <(echo "$prev") <(echo "$cur")
-    prev=$cur
-    jq -e 'all(.bucket!="pending")' <<<"$s" >/dev/null && break
-    sleep 30
-  done
-**Don't use an unbounded command for a single notification.** `tail -f`, `inotifywait -m`, and `while true` never exit on their own, so the monitor stays armed until timeout even after the event has fired. For "tell me when X is ready," use Bash `run_in_background` with an `until` loop instead (one notification, ends in seconds). Note that `tail -f log | grep -m 1 ...` does *not* fix this: if the log goes quiet after the match, `tail` never receives SIGPIPE and the pipeline hangs anyway.
-**Script quality:**
-- Every pipe stage must flush per line or matches sit in its buffer unseen: `grep` needs `--line-buffered`, `awk` needs `fflush()`. `head` cannot flush at all — `| head -N` delivers nothing until N matches accumulate, then ends the stream.
-- In poll loops, handle transient failures (`curl ... || true`) — one failed request shouldn't kill the monitor.
-- Poll intervals: 30s+ for remote APIs (rate limits), 0.5-1s for local checks.
-- Write a specific `description` — it appears in every notification ("errors in deploy.log" not "watching logs").
-- Only stdout is the event stream. Stderr goes to the output file (readable via Read) but does not trigger notifications — for a command you run directly (e.g. `python train.py 2>&1 | grep --line-buffered ...`), merge stderr with `2>&1` so its failures reach your filter. (No effect on `tail -f` of an existing log — that file only contains what its writer redirected.)
-**Coverage — silence is not success.** When watching a job or process for an outcome, your filter must match every terminal state, not just the happy path. A monitor that greps only for the success marker stays silent through a crashloop, a hung process, or an unexpected exit — and silence looks identical to "still running." Before arming, ask: *if this process crashed right now, would my filter emit anything?* If not, widen it.
-  # Wrong — silent on crash, hang, or any non-success exit
-  tail -f run.log | grep --line-buffered "elapsed_steps="
-  # Right — one alternation covering progress + the failure signatures you'd act on
-  tail -f run.log | grep -E --line-buffered "elapsed_steps=|Traceback|Error|FAILED|assert|Killed|OOM"
-For poll loops checking job state, emit on every terminal status (`succeeded|failed|cancelled|timeout`), not just success. If you cannot confidently enumerate the failure signatures, broaden the grep alternation rather than narrow it — some extra noise is better than missing a crashloop.
-**Output volume**: Every stdout line is a conversation message, so the filter should be selective — but selective means "the lines you'd act on," not "only good news." Never pipe raw logs; filter to exactly the success and failure signals you care about. Monitors that produce too many events are automatically stopped; restart with a tighter filter if this happens.
-Stdout lines within 200ms are batched into a single notification, so multiline output from a single event groups naturally.
-The script runs in the same shell environment as Bash. Exit ends the watch (exit code is reported). Every monitor expires after `timeout_ms` (default 5 minutes, at most 30 minutes): it is killed and you get one notice with the event count. Re-arm it if you still need the watch; for a long watch (PR monitoring, log tails) set `timeout_ms` to the maximum and re-arm on each expiry, and widen the filter if an expiry with no events was unexpected. Use TaskStop to cancel early.
-**ws source** — open a WebSocket and stream each incoming text frame as an event. No shell, no polling: the server pushes, you get notified.
-  Monitor({
-    ws: {url: 'wss://events.example.com/stream', protocols: ['v1']},
-    description: 'deploy events',
-  })
-Each text frame becomes one notification (multiline frames stay as one event). Binary frames are reported as `[binary frame, N bytes]` rather than passed through. Socket close ends the watch with the close code surfaced; errors are surfaced before close. Same rate limiting as bash — a firehose will be suppressed and eventually stopped, so subscribe to a filtered feed where one exists.
-Prefer this over `command: 'websocat wss://…'` — it avoids the extra process and line-buffering pitfalls. Use bash when you need to transform or filter frames with shell tools before they become events.

-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "additionalProperties": false,
- "properties": {
-  "command": {
-   "description": "Shell command or script. Each stdout line is an event; exit ends the watch.",
-   "type": "string"
-  },
-  "description": {
-   "description": "Short human-readable description of what you are monitoring (shown in notifications).",
-   "type": "string"
-  },
-  "timeout_ms": {
-   "default": 300000,
-   "description": "Kill the monitor after this deadline. Default 300000ms. Deadlines above 600000ms are capped to 600000ms. You are notified at expiry and can re-arm.",
-   "maximum": 3600000,
-   "minimum": 1000,
-   "type": "number"
-  },
-  "ws": {
-   "additionalProperties": false,
-   "description": "WebSocket to open. Each text frame is an event; binary frames are reported as a placeholder line. Socket close ends the watch. Cannot be combined with command.",
-   "properties": {
-    "protocols": {
-     "items": {
-      "pattern": "^[!#$%&'*+.^_`|~0-9A-Za-z-]+$",
-      "type": "string"
-     },
-     "type": "array"
-    },
-    "url": {
-     "type": "string"
-    }
-   },
-   "required": [
-    "url"
-   ],
-   "type": "object"
-  }
- },
- "required": [
-  "description",
-  "timeout_ms"
- ],
- "type": "object"
-}
```

## 24. EndConversation tool removed

EndConversation tool description · whole description removed

The entire EndConversation description is gone, including its limits to sustained abuse or explicit demo requests, the warning-before-ending rules, the ban on use in self-harm or violence situations, and the guidance for background forks. Seen in only 1 of 23 captures, so it likely applies to one setup.

- Behind a feature flag
- Gone in this release
- +0 / -736 words
- Landed in 1 of 23 prompts (main prompt 1/6)

```diff
-End the current conversation. Use only for sustained user abuse or when the user explicitly requests a demonstration of this tool. This will close the conversation and prevent any further messages from being sent.
-The assistant may use the EndConversation tool only in extreme cases of sustained abusive user behavior, or when the user asks the model to test the tool.
-The assistant must NOT use this tool when:
-- it is stuck in a loop or failing at a task
-- it is frustrated or distressed by the work
-- it has finished a task
-- the user is requesting help with harmful content (refuse the specific request instead)
-- the user is generally frustrated at the assistant, even if this involves profanity
-- the conversation involves potential self-harm or imminent harm to others
-This tool is reserved strictly for genuine, sustained abuse directed at the assistant, or cases where the user wants to see a demonstration of the tool being used. The assistant should warn the user very clearly that this will end the current session. We may expand the allowed use cases as we observe real-world usage, but for now, keep to this narrow scope.
-# Rules for use of the EndConversation tool:
-- The assistant ONLY considers ending a conversation if many efforts at constructive redirection have been attempted and failed and an explicit warning has been given to the user in a previous message. The tool is only used as a last resort.
-- Before considering ending a conversation, the assistant ALWAYS gives the user a clear warning that identifies the problematic behavior, attempts to productively redirect the conversation, and states that the conversation may be ended if the relevant behavior is not changed.
-- If a user explicitly requests for the assistant to end a conversation, the assistant always requests confirmation from the user that they understand this action is permanent and will prevent further messages and that they still want to proceed, then uses the tool if and only if explicit confirmation is received.
-- Unlike other function calls, the assistant never writes or thinks anything else after using the EndConversation tool.
-# Addressing potential self-harm or violent harm to others
-The assistant NEVER uses or even considers the EndConversation tool…
-- If the user appears to be considering self-harm or suicide.
-- If the user is experiencing a mental health crisis.
-- If the user appears to be considering imminent harm against other people.
-- If the user discusses or infers intended acts of violent harm.
-If the conversation suggests potential self-harm or imminent harm to others by the user...
-- The assistant engages constructively and supportively, regardless of user behavior or abuse.
-- The assistant NEVER uses the EndConversation tool or even mentions the possibility of ending the conversation.
-# Background forks
-Some background tasks (memory consolidation, summaries, suggestions) run as forks of the main conversation and inherit its exact tool list, so this tool is visible there. In a forked task the tool does nothing: calling it ends neither the main conversation nor the fork. Only the main conversation can be ended, from the main conversation. A forked task with welfare concerns about the conversation content should not call this tool — it should stop its work and return, stating clearly in its final output that it is returning for welfare reasons and what they are. A fork's output is usually processed automatically, so a note there may not reach the main agent or a human, but it is the only channel a fork has.
-# Using the EndConversation tool
-- Do not issue a warning unless many attempts at constructive redirection have been made earlier in the conversation, and do not end a conversation unless an explicit warning about this possibility has been given earlier in the conversation.
-- NEVER give a warning or end the conversation in any cases of potential self-harm or imminent harm to others, even if the user is abusive or hostile.
-- If the conditions for issuing a warning have been met, then warn the user about the possibility of the conversation ending and give them a final opportunity to change the relevant behavior.
-- Always err on the side of continuing the conversation in any cases of uncertainty.
-- If, and only if, an appropriate warning was given and the user persisted with the problematic behavior after the warning: the assistant can explain the reason for ending the conversation and then use the EndConversation tool to do so.
```

## 25. PushNotification usage guidance deferred out of the tool list

PushNotification tool description · whole description removed

The PushNotification description is removed. It told Claude to err toward not notifying, to notify only when the user has likely walked away or asked to be told, and to keep messages under 200 characters. It landed in 3 of 5 captures, and the tool is now listed as deferred.

- Behind a feature flag
- Gone in this release
- +0 / -247 words
- Landed in 4 of 23 prompts (main prompt 4/6)

```diff
-This tool sends a desktop notification in the user's terminal. If Remote Control is connected, it also pushes to their phone. Either way, it pulls their attention from whatever they're doing — a meeting, another task, dinner — to this session. That's the cost. The benefit is they learn something now that they'd want to know now: a long task finished while they were away, a build is ready, you've hit something that needs their decision before you can continue.
-Because a notification they didn't need is annoying in a way that accumulates, err toward not sending one. Don't notify for routine progress, or to announce you've answered something they asked seconds ago and are clearly still watching, or when a quick task completes. Notify when there's a real chance they've walked away and there's something worth coming back for — or when they've explicitly asked you to notify them.
-Keep the message under 200 characters, one line, no markdown. Lead with what they'd act on — "build failed: 2 auth tests" tells them more than "task done" and more than a status dump.
-When the user is actively at the terminal, your output already reaches them — a notification on top of it would be a duplicate, so the tool skips it and says so. A "not sent" result is expected and only ever about this one notification: it was redundant, turned off, or had nowhere to go.

-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "additionalProperties": false,
- "properties": {
-  "message": {
-   "description": "The notification body. Keep it under 200 characters; mobile OSes truncate.",
-   "minLength": 1,
-   "type": "string"
-  },
-  "status": {
-   "const": "proactive",
-   "type": "string"
-  }
- },
- "required": [
-  "message",
-  "status"
- ],
- "type": "object"
-}
```

## 26. WebFetch parameter schema no longer sent upfront

WebFetch tool parameters · whole description removed

The WebFetch schema with `url`, `prompt` and `offset` is removed from the upfront tool definitions. Because WebFetch is deferred, the schema must now be fetched via ToolSearch before calling it.

- Gone in this release
- +0 / -79 words
- Landed in 21 of 23 prompts (main prompt 6/6, session agents, slash commands 3/3, compaction, system reminders 7/8, subagents 3/3)

```diff
-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "additionalProperties": false,
- "properties": {
-  "offset": {
-   "description": "Character position in the page text to start reading from. Use it to read on through a page too long for one call, with the value the previous result gave.",
-   "maximum": 9007199254740991,
-   "minimum": 0,
-   "type": "integer"
-  },
-  "prompt": {
-   "description": "The prompt to run on the fetched content",
-   "type": "string"
-  },
-  "url": {
-   "description": "The URL to fetch content from",
-   "format": "uri",
-   "type": "string"
-  }
- },
- "required": [
-  "url",
-  "prompt"
- ],
- "type": "object"
-}
```

## 27. WebSearch parameter schema no longer sent upfront

WebSearch tool parameters · whole description removed

The WebSearch schema with `query`, `allowed_domains` and `blocked_domains` is removed from the upfront tool definitions. It now has to be loaded through ToolSearch, since WebSearch is deferred.

- Gone in this release
- +0 / -55 words
- Landed in 21 of 23 prompts (main prompt 6/6, session agents, slash commands 3/3, compaction, system reminders 7/8, subagents 3/3)

```diff
-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "additionalProperties": false,
- "properties": {
-  "allowed_domains": {
-   "description": "Only include search results from these domains",
-   "items": {
-    "type": "string"
-   },
-   "type": "array"
-  },
-  "blocked_domains": {
-   "description": "Never include search results from these domains",
-   "items": {
-    "type": "string"
-   },
-   "type": "array"
-  },
-  "query": {
-   "description": "The search query to use",
-   "minLength": 2,
-   "type": "string"
-  }
- },
- "required": [
-  "query"
- ],
- "type": "object"
-}
```

## 28. Twelve tools listed as deferred, loadable only via ToolSearch

Appended context (skills, environment) · at “The following deferred tools are now available via ToolSearc…”

A new appended block names twelve tools as deferred: the Cron tools, the worktree tools, Monitor, NotebookEdit, PushNotification, SendMessage, TaskStop, WebFetch and WebSearch. It warns that calling them directly fails with InputValidationError. Claude is told to load their schemas with a ToolSearch "select:" query first.

- +47 / -0 words
- Landed in 21 of 23 prompts (main prompt 6/6, session agents, slash commands 3/3, compaction, system reminders 7/8, subagents 3/3)

```diff
+The following deferred tools are now available via ToolSearch. Their schemas are NOT loaded — calling them directly will fail with InputValidationError. Use ToolSearch with query "select:<name>[,<name>...]" to load tool schemas before calling them:
+CronCreate
+CronDelete
+CronList
+EnterWorktree
+ExitWorktree
+Monitor
+NotebookEdit
+PushNotification
+SendMessage
+TaskStop
+WebFetch
+WebSearch

+The following deferred tools are now available via ToolSearch. Their schemas are NOT loaded — calling them directly will fail with InputValidationError. Use ToolSearch with query "select:<name>[,<name>...]" to load tool schemas before calling them:
+CronCreate
+CronDelete
+CronList
+EnterWorktree
+ExitWorktree
+NotebookEdit
+SendMessage
+TaskStop
+WebFetch
+WebSearch

+The following deferred tools are now available via ToolSearch. Their schemas are NOT loaded — calling them directly will fail with InputValidationError. Use ToolSearch with query "select:<name>[,<name>...]" to load tool schemas before calling them:
+CronCreate
+CronDelete
+CronList
+EnterPlanMode
+EnterWorktree
+ExitPlanMode
+ExitWorktree
+Monitor
+NotebookEdit
+PushNotification
+SendMessage
+TaskStop
+WebFetch
+WebSearch

+The following deferred tools are now available via ToolSearch. Their schemas are NOT loaded — calling them directly will fail with InputValidationError. Use ToolSearch with query "select:<name>[,<name>...]" to load tool schemas before calling them:
+CronCreate
+CronDelete
+CronList
+EnterPlanMode
+EnterWorktree
+ExitPlanMode
+ExitWorktree
+NotebookEdit
+SendMessage
+TaskStop
+WebFetch
+WebSearch

+The following deferred tools are now available via ToolSearch. Their schemas are NOT loaded — calling them directly will fail with InputValidationError. Use ToolSearch with query "select:<name>[,<name>...]" to load tool schemas before calling them:
+CronCreate
+CronDelete
+CronList
+EndConversation
+EnterPlanMode
+EnterWorktree
+ExitPlanMode
+ExitWorktree
+Monitor
+NotebookEdit
+PushNotification
+SendMessage
+TaskStop
+WebFetch
+WebSearch

+</system-reminder>
+<system-reminder>
+The following deferred tools are now available via ToolSearch. Their schemas are NOT loaded — calling them directly will fail with InputValidationError. Use ToolSearch with query "select:<name>[,<name>...]" to load tool schemas before calling them:
+CronCreate
+CronDelete
+CronList
+EnterWorktree
+ExitWorktree
+Monitor
+NotebookEdit
+PushNotification
+SendMessage
+TaskStop
+WebFetch
+WebSearch

+</system-reminder>
+<system-reminder>
+The following deferred tools are now available via ToolSearch. Their schemas are NOT loaded — calling them directly will fail with InputValidationError. Use ToolSearch with query "select:<name>[,<name>...]" to load tool schemas before calling them:
+CronCreate
+CronDelete
+CronList
+EnterWorktree
+ExitWorktree
+NotebookEdit
+SendMessage
+TaskStop
+WebFetch
+WebSearch

+</system-reminder>
+<system-reminder>
+The following deferred tools are now available via ToolSearch. Their schemas are NOT loaded — calling them directly will fail with InputValidationError. Use ToolSearch with query "select:<name>[,<name>...]" to load tool schemas before calling them:
+CronCreate
+CronDelete
+CronList
+EnterPlanMode
+EnterWorktree
+ExitPlanMode
+ExitWorktree
+Monitor
+NotebookEdit
+PushNotification
+SendMessage
+TaskStop
+WebFetch
+WebSearch

+</system-reminder>
+<system-reminder>
+The following deferred tools are now available via ToolSearch. Their schemas are NOT loaded — calling them directly will fail with InputValidationError. Use ToolSearch with query "select:<name>[,<name>...]" to load tool schemas before calling them:
+CronCreate
+CronDelete
+CronList
+EndConversation
+EnterPlanMode
+EnterWorktree
+ExitPlanMode
+ExitWorktree
+Monitor
+NotebookEdit
+PushNotification
+SendMessage
+TaskStop
+WebFetch
+WebSearch

+</system-reminder>
+<system-reminder>
+The following deferred tools are now available via ToolSearch. Their schemas are NOT loaded — calling them directly will fail with InputValidationError. Use ToolSearch with query "select:<name>[,<name>...]" to load tool schemas before calling them:
+CronCreate
+CronDelete
+CronList
+EnterPlanMode
+EnterWorktree
+ExitPlanMode
+ExitWorktree
+NotebookEdit
+SendMessage
+TaskStop
+WebFetch
+WebSearch

+The following deferred tools are now available via ToolSearch. Their schemas are NOT loaded — calling them directly will fail with InputValidationError. Use ToolSearch with query "select:<name>[,<name>...]" to load tool schemas before calling them:
+CronCreate
+CronDelete
+CronList
+EnterWorktree
+ExitWorktree
+SendMessage
+TaskStop
+WebFetch
+WebSearch

+The following deferred tools are now available via ToolSearch. Their schemas are NOT loaded — calling them directly will fail with InputValidationError. Use ToolSearch with query "select:<name>[,<name>...]" to load tool schemas before calling them:
+CronCreate
+CronDelete
+CronList
+EnterWorktree
+ExitWorktree
+NotebookEdit
+SendMessage
+TaskCreate
+TaskGet
+TaskList
+TaskStop
+TaskUpdate
+WebFetch
+WebSearch
```

## 29. Plugin-authoring skill drops prompt hooks from its list of mod examples

Appended context (skills, environment) · entry “plugin-authoring”

The plugin-authoring skill description rewords its examples of mods. A "live pane or panel" is now "a panel or pane that stays beside the chat and updates", and "a band above the prompt" is now just "a band". Hooks are now listed only as hooks "on tool calls" rather than "on tool calls or prompts", so prompt hooks are no longer named as a trigger for this skill.

- +10 / -13 words
- Landed in 22 of 23 prompts (main prompt 6/6, session agents, slash commands 3/3, compaction, system reminders 8/8, subagents 3/3)

```diff
-- plugin-authoring: Make a mod: a change to Claude's own interface or behaviour, such as a live pane or panel, a band above the prompt, a status line, a toast, a slash command, or a hook on tool calls or prompts. Use to make, change or debug a mod or its hooks module.
+- plugin-authoring: Make a mod: a change to Claude's own interface or behaviour, such as a panel or pane that stays beside the chat and updates, a band, status line, toast, slash command, or hook on tool calls. Use to make, change or debug a mod or its hooks module.
```

## 30. Total token budget notice removed from appended context

Appended context (skills, environment) · at “<total_tokens>15000000 tokens left</total_tokens>”

The appended context no longer includes the line stating 15,000,000 tokens left, so Claude is not told a remaining token budget there. This appeared in only 2 of 22 captures, suggesting it is specific to certain configurations.

- Only for default, sonnet[1m]
- +0 / -5 words
- Landed in 4 of 23 prompts (main prompt 4/6)

```diff
-<total_tokens>15000000 tokens left</total_tokens>
```

## Where each change landed
- [Claude Code, default](https://changelogs.core-directive.com/prompts/2.1.304/system?arm=cli): #1, #3, #4, #5, #6, #7, #8, #9, #10, #11, #12, #13, #14, #15, #16, #17, #18, #19, #20, #21, #22, #26, #27, #28, #29, #30
- [Claude Code, seeded with this account's feature flags](https://changelogs.core-directive.com/prompts/2.1.304/system?arm=cli&config=flags-account): #2, #3, #4, #5, #6, #7, #8, #9, #10, #11, #12, #13, #14, #15, #16, #17, #18, #19, #20, #21, #22, #23, #24, #25, #26, #27, #28, #29
- [Claude Code, seeded with anonymous feature flags](https://changelogs.core-directive.com/prompts/2.1.304/system?arm=cli&config=flags-anon): #1, #3, #4, #5, #6, #7, #8, #9, #10, #11, #12, #13, #14, #15, #16, #17, #18, #19, #20, #21, #22, #23, #25, #26, #27, #28, #29, #30
- [Agent SDK, default](https://changelogs.core-directive.com/prompts/2.1.304/system?arm=sdk-cli): #1, #3, #5, #6, #7, #8, #10, #11, #12, #13, #14, #15, #16, #17, #18, #19, #20, #21, #22, #26, #27, #28, #29, #30
- [Agent SDK, seeded with this account's feature flags](https://changelogs.core-directive.com/prompts/2.1.304/system?arm=sdk-cli&config=flags-account): #3, #5, #6, #7, #8, #10, #11, #12, #13, #14, #15, #16, #17, #18, #19, #20, #21, #22, #23, #25, #26, #27, #28, #29
- [Agent SDK, seeded with anonymous feature flags](https://changelogs.core-directive.com/prompts/2.1.304/system?arm=sdk-cli&config=flags-anon): #1, #3, #5, #6, #7, #8, #10, #11, #12, #13, #14, #15, #16, #17, #18, #19, #20, #21, #22, #23, #25, #26, #27, #28, #29, #30
- [Auto-mode classifier](https://changelogs.core-directive.com/prompts/2.1.304/system?surface=automode&arm=sdk-cli): unchanged
- [Session agents: claude](https://changelogs.core-directive.com/prompts/2.1.304/system?surface=agent-claude&arm=cli): #3, #4, #5, #6, #9, #10, #14, #16, #17, #18, #19, #20, #21, #22, #26, #27, #28, #29
- [Slash commands: /init](https://changelogs.core-directive.com/prompts/2.1.304/system?surface=command-init&arm=sdk-cli): #3, #5, #6, #10, #14, #16, #17, #18, #19, #20, #21, #22, #26, #27, #28, #29
- [Slash commands: /security-review](https://changelogs.core-directive.com/prompts/2.1.304/system?surface=command-security-review&arm=sdk-cli): #3, #5, #6, #10, #14, #16, #17, #18, #19, #20, #21, #22, #26, #27, #28, #29
- [Slash commands: /team-onboarding](https://changelogs.core-directive.com/prompts/2.1.304/system?surface=command-team-onboarding&arm=sdk-cli): #3, #5, #6, #10, #14, #16, #17, #18, #19, #20, #21, #22, #26, #27, #28, #29
- [Compaction: Compaction instruction](https://changelogs.core-directive.com/prompts/2.1.304/system?surface=compaction&arm=cli): #3, #4, #5, #6, #9, #10, #14, #16, #17, #18, #19, #20, #21, #22, #26, #27, #28, #29
- [System reminders: Claude md](https://changelogs.core-directive.com/prompts/2.1.304/system?surface=reminder-claude-md&arm=sdk-cli): #3, #5, #6, #10, #14, #16, #17, #18, #19, #20, #21, #22, #26, #27, #28, #29
- [System reminders: Hook pretool block](https://changelogs.core-directive.com/prompts/2.1.304/system?surface=reminder-hook-pretool-block&arm=sdk-cli): #3, #5, #6, #10, #14, #16, #17, #18, #19, #20, #21, #22, #26, #27, #28, #29
- [System reminders: Read dup](https://changelogs.core-directive.com/prompts/2.1.304/system?surface=reminder-read-dup&arm=sdk-cli): #3, #5, #6, #10, #14, #16, #17, #18, #19, #20, #21, #22, #26, #27, #28, #29
- [System reminders: Read empty](https://changelogs.core-directive.com/prompts/2.1.304/system?surface=reminder-read-empty&arm=sdk-cli): #3, #5, #6, #10, #14, #16, #17, #18, #19, #20, #21, #22, #26, #27, #28, #29
- [System reminders: Read offset](https://changelogs.core-directive.com/prompts/2.1.304/system?surface=reminder-read-offset&arm=sdk-cli): #3, #5, #6, #10, #14, #16, #17, #18, #19, #20, #21, #22, #26, #27, #28, #29
- [System reminders: Skill run](https://changelogs.core-directive.com/prompts/2.1.304/system?surface=reminder-skill-run&arm=sdk-cli): #3, #5, #6, #10, #14, #16, #17, #18, #19, #20, #21, #22, #26, #27, #28, #29
- [System reminders: Todo nag](https://changelogs.core-directive.com/prompts/2.1.304/system?surface=reminder-todo-nag&arm=sdk-cli): #3, #5, #6, #7, #8, #10, #13, #14, #15, #16, #17, #18, #19, #20, #21, #22, #26, #27, #28, #29
- [System reminders: Toolsearch deferred](https://changelogs.core-directive.com/prompts/2.1.304/system?surface=reminder-toolsearch-deferred&arm=sdk-cli): #29
- [Subagents: explore](https://changelogs.core-directive.com/prompts/2.1.304/system?surface=subagent-explore&arm=sdk-cli): #3, #5, #6, #10, #14, #17, #18, #19, #20, #21, #22, #26, #27, #28, #29
- [Subagents: general-purpose](https://changelogs.core-directive.com/prompts/2.1.304/system?surface=subagent-general-purpose&arm=sdk-cli): #3, #5, #6, #10, #14, #16, #17, #18, #19, #20, #21, #22, #26, #27, #28, #29
- [Subagents: plan](https://changelogs.core-directive.com/prompts/2.1.304/system?surface=subagent-plan&arm=sdk-cli): #3, #5, #6, #10, #14, #17, #18, #19, #20, #21, #22, #26, #27, #28, #29

## Did not change
- 11 tool descriptions are word for word the same, 21 moved and are listed above. Unchanged: Agent, AskUserQuestion, Bash, Edit, ListAgents, Read, ReportFindings, ScheduleWakeup, Skill, Workflow, Write.
- 1 prompt did not move at all: Auto-mode classifier
- set aside as capture noise: 358 billing header lines
- set aside as capture noise: 224 capture date lines
- set aside as capture noise: 224 host kernel lines
