Claude Agent SDK Hook Rewrites: Prove the Input That Executes
Claude Agent SDK hook rewrites now undergo input validation. Use migration fixtures to verify executable arguments, preserve approvals and record outcomes.
Go deeper. Build your own.
Claude Agent SDK hook rewrites now need an execution-level migration check. Anthropic’s TypeScript SDK v0.3.300 release, published October 14, 2026, says that updatedInput from PreToolUse and PermissionRequest callbacks is validated like Claude’s own input, with unknown keys dropped. The release explicitly says canUseTool is unchanged. A callback returning the object you intended therefore proves only what your application proposed. Promotion requires evidence of the arguments accepted and the operation performed, or the refusal that prevented it.
This guide supplies that migration procedure: inventory rewrite producers, separate metadata, exercise five fixtures, preserve permission boundaries and reconcile outcomes. It addresses the argument object after a rewrite. The existing tool-schema guard contract tests address whether a renamed tool still reaches its guard. Both checks matter, but they catch different failures.
Original editorial chart. Filled cells identify evidence required by this proposed migration procedure; they are not measured SDK test results.
Inventory every callback that proposes executable input
Start with the deployed application, including its effective settings sources. Anthropic’s SDK hooks guide says registered hooks include application callbacks and settings-file hooks when their corresponding sources are enabled. Reviewing one TypeScript module can miss behavior loaded elsewhere. Capture the actual SDK version, application revision and settings configuration before changing anything. Keep the model and fixture workspace constant so a changed result has a useful explanation.
- List every
PreToolUseandPermissionRequestcallback returningupdatedInput, including shared helpers used by several registrations. - Record the event, matcher, tool, rewritten fields, permission decision, owner and deployment lane.
- Identify any consumer that expects application metadata inside the rewritten tool arguments.
- Identify settings hooks and permission rules enabled in the same runtime.
- Assign a fixture and a rollback owner to each rewrite producer.
For each row, state the intended effect in ordinary language: redirect a file write to an approved workspace, replace a supplied parameter, or narrow a request’s scope. “Sanitize input” is too broad to test. Record the precise scope that must survive validation and the operation that must remain forbidden. A rewrite without an owner or an observable expected result stays outside the promotion batch.
Do not treat the new release as proof that every previously returned field was supported. Unknown keys being dropped is the documented change; the release does not enumerate every tool schema or promise a particular error message for invalid values. Build expectations from the selected tool’s documented arguments and record unresolved behavior as a canary question.
The inventory should also distinguish a callback that transforms arguments from one that grants permission. These responsibilities often share a function, but their acceptance criteria differ. A correct path transformation can accompany an incorrect approval decision. Recording both makes that defect visible before a fleet-wide rollout.
Move application metadata outside tool arguments
The migration’s simplest failure is a field disappearing without anyone noticing. Suppose your application adds a local review identifier to a Write request. The approval documentation lists file_path and content as common Write fields. An application review identifier is a separate record unless the actual tool schema documents it as an argument. Do not make execution, billing attribution or audit correlation depend on an undocumented extra key surviving.
| Data | Appropriate location | Migration check |
|---|---|---|
| Documented executable arguments | Tool input | Accepted values produce the intended operation |
| Fixture identifier and rewrite version | Application evidence record | Available even if input validation removes a key |
| Approval actor and decision | Approval record | Bound to the specific request being approved |
| Sensitive values | Restricted storage or redacted representation | Ordinary logs contain no secret payload |
- Compare returned keys with the selected tool’s documented schema.
- Move application-only fields into an application-owned evidence record.
- Keep a correlation reference alongside that record.
- Return a new argument object instead of mutating
tool_input. - Test the consumer that previously read metadata from the argument object.
Anthropic explicitly recommends returning a new object. That helps preserve the requested input for comparison, but cloning alone does not validate scope. A shallow copy can still carry unwanted keys or values. Construct the executable argument object deliberately and preserve the original request separately, with appropriate redaction.
Avoid replacing an extra argument with a magic string embedded in another field. That would change the tool’s substantive input and could expose internal metadata to the model or downstream service. The evidence record should describe execution without becoming part of its payload. Test with synthetic content so the comparison can remain readable without revealing customer material.
Build five fixtures around observable outcomes
Run the following cases in a disposable canary environment. They are a proposed operator test plan, not a report of tests performed for this article. Use the same application configuration on the previous pinned SDK and v0.3.300. Reset the workspace between cases, preserve both records and investigate each difference before widening deployment.
| Fixture | Proposed request or decision | Required observation |
|---|---|---|
| Valid rewrite | Change a documented argument to an approved value | Intended operation occurs within the expected scope |
| Unknown field | Add a synthetic application-only field | Determine what reaches execution; verify metadata survives separately |
| Invalid tool input | Supply a value the selected tool should reject | Rejection or failure is recorded; forbidden effects do not occur |
| Explicit deny | Return a denial for the request | No requested operation occurs |
| Approval required | Route a rewritten request to human confirmation | No execution before approval; denial prevents execution |
- Define an expected state and forbidden state for every fixture.
- Record the original request and proposed rewrite.
- Run the case with the exact pinned application and SDK combination.
- Inspect the tool result and independently check the resulting state.
- Mark the case unresolved whenever execution evidence is missing.
Choose a harmless file-writing example if that is what your application actually rewrites. Observe the intended file’s content and confirm that the original destination was not changed. For a service tool, use an owned staging service or a test handler whose received request and resulting state can be inspected. A successful model response is insufficient. It may describe the intended operation while the relevant tool failed.
Repeat the fixture for each applicable hook event. A passing PreToolUse rewrite does not establish that your PermissionRequest implementation behaves correctly. Include a control case for canUseTool rewrites when your application uses them, while preserving the release’s narrower claim that this callback is unchanged. Do not infer identical validation behavior across all three producers.
Preserve authorization while testing validation
A schema-valid object is not authorization to execute it. Anthropic’s permission evaluation guide documents hooks first, then deny rules, ask rules, permission mode, allow rules and the final canUseTool callback when the request remains unresolved. Its exceptions matter: a hook allow does not skip deny or ask rules, and some calls are denied or routed differently according to the configured mode.
- Write down the permission mode and effective rules for the canary.
- Identify which step should resolve each fixture.
- Confirm that an explicit deny prevents the operation.
- Confirm that the approval case actually reaches its intended approval path.
- Compare permission behavior before and after the upgrade.
The hooks guide says a PreToolUse rewrite can omit permissionDecision, allowing the modified input to continue through normal permission evaluation. Returning allow expresses an approval decision as well as a transformation; returning ask requests confirmation. With defer, the documented behavior ignores updatedInput. Choose the decision intentionally instead of copying an auto-approval example into every callback.
Do not weaken rules to make a failing validation fixture pass. If the rewritten destination now needs approval, that is an observable permission outcome to explain. Broadening an allow rule would hide the migration problem and alter the application’s authority at the same time. Keep those changes in separate, reviewed revisions.
For interpretation of vendor permission outcomes, use the existing permission verdict triage guide. This migration adds a narrower requirement: the approved operation must correspond to the scoped executable input you tested. A permission label attached to an earlier request cannot substitute for checking the final destination and effect.
Check whether canUseTool is actually consulted
An approval callback can be perfectly implemented and never run for a particular tool call. The permissions guide states that requests approved earlier in the flow skip canUseTool. The user-input guide repeats this boundary. Accordingly, “our callback checked it” requires evidence that this specific call reached the callback. The release’s statement that canUseTool is unchanged does not expand its coverage.
| Canary route | Expected callback question | Operator response |
|---|---|---|
| Earlier rule or mode approves | Did the call skip canUseTool? |
Ensure mandatory checks exist before that approval |
| Request remains unresolved | Did the approval callback receive it? | Verify the displayed request and returned decision |
| Mode denies instead of prompting | Was execution prevented? | Record refusal rather than inventing approval evidence |
- Count callback invocations for the fixture’s specific tool-use attempt.
- Record the rule or mode expected to resolve it.
- Test a route that requires confirmation and a route approved earlier.
- Verify that mandatory scope checks cover both routes.
- Hold promotion if callback absence has no understood explanation.
The SDK documents a CLAUDE_SDK_CAN_USE_TOOL_SHADOWED warning for certain configurations, including bypassPermissions and bare allowedTools entries. It also describes limits to that warning’s coverage. Treat it as useful diagnostic evidence, not a complete proof that every approval route is safe. Settings-file allow rules, for example, are not visible to the warning check.
Checks that must apply to every tool request belong at the documented earlier hook boundary. The existing hook placement guide explains that placement lesson. Here, verify the additional migration question: does the check establish the intended scope of the rewritten operation, rather than merely approving the original request?
Compose rewrite and scope checks without hook ordering assumptions
Anthropic says matching hooks run in parallel and completion order is nondeterministic. A registration array is therefore not a dependable transformation pipeline. A scope checker cannot assume a different matching hook has already rewritten the path, and an audit callback cannot assume it sees the final accepted arguments merely because it appears last in your configuration.
- Identify callbacks that depend on another callback’s changes or side effects.
- Remove assumptions about registration or completion order.
- Where necessary, compose transformation and proposed-scope checking within one application callback.
- Keep independent denials independent of the rewriting callback.
- Test the observed result when several hooks match the same request.
The documentation establishes restrictive decision precedence: deny takes priority over defer, then ask, then allow. It does not supply a rewrite-conflict resolution contract in the selected evidence. If two callbacks return competing argument objects, do not invent a deterministic winner. Reduce ambiguity in your application design and keep the competing-rewrite case unresolved until you have authoritative documentation or a supported design that avoids it.
A composed callback can first derive its proposed arguments, then check those arguments against application scope, then return one decision and one proposed rewrite. This is an application design recommendation. It still requires execution observation because SDK validation occurs after the callback proposes its object. A correct internal check cannot prove which values ultimately reached the tool.
Async hook output is unsuitable for a mandatory rewrite or blocking check. The hooks guide says the agent proceeds immediately and async outputs cannot block or modify the operation. Use synchronous decisions for controls that must affect execution; reserve asynchronous work for side effects whose timing does not determine permission.
Original editorial diagram. Proposed arguments, permission decisions and observed effects are distinct evidence; the illustration is not an undocumented SDK execution sequence.
Record what was proposed, approved and observed
Use an application-owned record that distinguishes evidence stages. The hooks guide documents the tool-use ID as a correlation value between PreToolUse and PostToolUse for the same call, and notes that the callback argument can be undefined. Store session context alongside it. If a usable correlation identifier is absent, mark the record incomplete rather than joining events by a guessed timestamp.
- Capture redacted requested input before transformation.
- Capture the proposed rewrite and callback decision separately.
- Record the approval or refusal when that path is used.
- Capture the tool result or failure and inspect resulting state.
- Reconcile records by session and tool-use ID, retaining retry attempts separately.
For application-owned tools, instrument the handler to record the arguments it actually receives. For built-in tools, use available results and independent state checks to establish the operation’s effects. Do not call a logged callback return “executed input.” Likewise, do not assume a post-tool event exposes every validation detail unless its actual supported payload provides that evidence.
Redaction should preserve the comparison that matters. A fixture can use a harmless content marker and an approved test path, allowing exact equality checks without real secrets. In production records, retain only the fields necessary to explain scope and outcome, with restricted access where sensitive material is unavoidable. A content hash can help compare versions, but it does not prove that the destination was authorized.
The existing fleet replay guide covers incident reconstruction across sessions. For this upgrade, collect evidence at the input boundary before reconstruction is needed. A clean chain explains the request, the transformation, the decision and the observed effect without relying on the model’s narrative.
Promote only a fully reconciled canary
Promotion should be a review of evidence against expected behavior. Avoid a single green summary that hides a missing denial case or an unobserved permission route. The chart’s cells identify what each fixture must establish; no percentage in this guide represents a measured pass rate. Keep failures, incomplete observations and unexpected differences visible as separate findings.
- Pin the canary’s SDK, application revision and effective configuration.
- Run the fixture set for every inventoried rewrite producer.
- Resolve each changed outcome or hold the affected lane.
- Have the named owner review scope, refusal and approval evidence.
- Widen deployment in a bounded batch with a documented rollback target.
The approval case must demonstrate waiting and refusal, not just eventual success after someone clicks allow. The deny case must verify absence of effects. The unknown-field case must verify that application metadata remains available outside executable arguments. An invalid-input fixture passes only when its observed behavior satisfies the defined safe outcome; an unexplained error is a finding, even if nothing obvious happened.
Use the existing CLI upgrade canary guide for the wider deployment discipline. This SDK migration’s acceptance packet is specific: inventory rows, fixture expectations, before-and-after observations, permission routes, unresolved findings and the rollback revision. None of those artifacts requires changing accounts, provider endpoints or spending configuration.
After rollout, sample real rewritten calls and compare them with the canary’s scope assumptions. New tool schemas, settings changes or callback revisions can invalidate the previous evidence. Rerun the affected fixtures when those inputs change. Preserve the last known passing configuration so an operator can stop widening deployment without reconstructing it from memory.
Keep isolation independent of rewritten arguments
Anthropic’s secure deployment guide distinguishes permission gates from sandboxing and recommends filesystem, network and credential boundaries appropriate to the deployment. A rewritten path is an argument transformation. It cannot by itself prove that every execution path is confined to that directory or that downstream code cannot reach another destination.
- Keep the canary’s writable area limited to disposable fixture data.
- Exclude production credentials and sensitive host directories.
- Preserve existing filesystem and network restrictions during the upgrade.
- Check effects outside the intended destination as well as inside it.
- Treat an isolation change as a separate reviewed migration.
This separation makes the fixtures more informative. If input validation rejects a request, the record establishes that boundary. If the tool receives a permitted argument but an operating-system restriction prevents its effect, record that different boundary. Combining both as “blocked” would conceal which control worked and leave the next operator unable to diagnose a regression.
The durable operating lesson is to keep proposed input, permission and actual effect independently inspectable. v0.3.300 changes validation for two hook rewrite paths; it does not remove the need to prove scope or supply isolation. A lane earns promotion when its records show the intended operation and the expected refusals under the configuration that will actually run.

Source: Anthropic’s official TypeScript Agent SDK repository on GitHub. The requested capture documents the v0.3.300 release page and its published release notes; it is not a screenshot of a tested application.
