An AI agent may understand a customer’s problem and select the right tools, yet still lack permission to perform the requested action. Claude can propose a refund, edit a repository, or invoke an outside API. Those proposals are not authorization. Production systems require an independently enforced boundary between a model’s interpretation of a request and an operation that changes money, files, or protected data.
Hooks in the Claude Agent SDK provide interception and observation points around agent actions. PreToolUse can help prevent a call before it executes; PostToolUse can observe a result after execution. Neither replaces authorization at the underlying business service. This distinction is central to trustworthy agent architecture and to the topics relevant to Architect Foundations.
Why a prompt is not a policy engine
A prompt telling an agent to “never issue unauthorized refunds” is useful guidance, but it cannot prove that a transaction is allowed. A customer may describe a sympathetic case, a retrieved document may contain conflicting instructions, or the model may misunderstand a business exception. A trustworthy service derives identity from the authenticated session, checks order ownership and eligibility, and refuses an operation that lacks the required approval even when its JSON arguments are perfectly formed.
The authorization check should be attached to the operation itself. A model-selected tool name does not grant authority, and a successful schema validation does not imply a financial or security approval. An agent can gather evidence, prepare a proposed action and communicate uncertainty; the service remains responsible for enforcing the actual permission.
PreToolUse: stop a proposed call before it runs
A PreToolUse event occurs just before a matching tool invocation. A callback can inspect the tool name and proposed inputs, query a trusted policy source and return a structured decision. A hook’s allow response does not bypass configured deny or ask rules; the effective permission still follows the SDK’s documented evaluation order. For example, a repository agent can be denied permission to edit secret files, while a customer-support agent can be stopped from calling process_refund without a valid authorization reference. In both cases the underlying repository or payment service must enforce its own authority checks.
Keep hook matchers explicit and test that they still select the intended tools after an SDK or configuration change. A callback guarding refunds should not depend on a vague string search for the word safe. It should evaluate verifiable fields such as approved resource, amount and actor. Return a useful denial reason without placing private policy details or credentials in the model-visible result.
If a security-critical hook fails or times out, the workflow needs a defined failure policy. For sensitive writes, pausing the action is safer than silently granting approval. But policy should still be enforced by the service, so a missing callback cannot by itself expose a protected operation.
PostToolUse: observe without pretending to reverse time
PostToolUse fires after a tool has executed. It can record an audit event, normalize a result, validate a receipt or initiate a recovery workflow when the returned data is unexpected. The SDK also documents PostToolUseFailure for failed executions. These events are useful for observability and error handling, but a post-execution check cannot retroactively prevent a completed refund or file deletion.
The timing is precise: the model proposes a call, a pre-execution gate evaluates it, the tool service applies its own authorization, the external operation runs, and a post-execution observer records what is known. Any architecture that describes a PostToolUse rejection as a guarantee that a previously executed payment never occurred is inaccurate.
Narrow tool contracts and explicit review
A safe workflow separates get_order, evaluate_policy, request_review and apply_decision. Read-only operations can establish facts but cannot change an account. An action that changes a record must be checked by a trusted service against an authenticated actor, resource, permitted scope and approval. The model’s assertion that a step is allowed is not sufficient evidence.
An approval record should describe the exact resource and authorized change, who approved it, when it expires and how the system prevents its reuse for another operation. A simple approved=true flag is too ambiguous. The service rejects requests with missing or stale authorization even if Claude supplies syntactically valid tool inputs. This prevents a change in conversational wording from broadening privileges.
Worked example: a request requiring review
A customer reports that an item arrived damaged and asks for an account adjustment. The agent retrieves only records belonging to the authenticated person. The policy evaluator states that the case needs human review because the available evidence is incomplete. The agent may prepare the request, but it cannot convert incomplete eligibility information into permission to update account records.
If Claude proposes the account update anyway, a correctly installed and matched PreToolUse gate should deny that action. A negative test must also check that the underlying business service rejects the same unapproved update, including when a hook is missing or misconfigured. The system then prepares a review packet listing verified records, missing evidence and the exact decision required; the customer sees pending review, not a fabricated completion. If a reviewer later approves a limited change, the service must recheck that authorization against the current resource before proceeding. This is a proposed test workflow, not a claim that a production agent or payment service has been run.
External results and retries
An external service may accept an operation and fail to return a timely response. A timeout is not proof that nothing happened. The application needs a durable request identifier and a way to reconcile the authoritative system state before considering another attempt. Otherwise a retry can repeat an already-completed side effect.
A post-execution observer can record the final result or open a reconciliation task. It should not tell Claude that an action succeeded merely because a call was sent. A sensible state model distinguishes requested, denied, pending_review, in_progress, confirmed, and externally_unconfirmed. The final user message should reflect one of these states and its supporting evidence.
An escalation rule should be testable
Ask for review when an identity is uncertain, evidence conflicts, the request exceeds a defined limit or an action is irreversible. These are explicit conditions, not feelings. The review packet contains the record identifier, verified evidence, missing facts, proposed options and accountable approver. A decision must be captured in an authenticated system rather than accepted because the assistant claims it was approved.
When work resumes, check the current record state. An earlier approval may no longer apply if the resource has been modified or the authorized action is already complete. The safest workflow uses narrow, expiring permissions and records whether an action was actually confirmed by the responsible service.
Hooks in coding and operations workflows
The same architecture applies beyond support. A coding agent may propose editing secrets or writing outside a permitted repository. PreToolUse can block a path or operation before it runs. PostToolUse can record changed files and trigger checks, but tests and repository access controls must still be enforced outside the agent.
An operations assistant might suggest changing infrastructure. The service should require an allowed environment, reviewed plan and explicit deployment permission. A hook can guard the request, while the deployment system enforces the final decision. Never treat a natural-language instruction or a correctly formatted tool call as an access token.
Test negative cases, not only the happy path
Build fixtures for an authorized read, an unauthorized record, an expired approval, a malformed input, a hook that times out and an external operation whose completion is uncertain. For each case inspect the proposed tool arguments, the pre-execution decision, whether the service ran, the post-execution outcome and the user-visible explanation. An agent that politely reports denial while still making an unauthorized change has failed.
Re-run these tests when adding tools or changing matchers. A renamed tool may no longer match an expected hook. If several hooks are registered, verify that a restrictive decision cannot be bypassed by a permissive observer. Logging should preserve IDs and policy reasons without recording unnecessary personal information or secrets.
A useful approval test separates three controls that are often collapsed into one promise: the Agent SDK hook may intercept a proposed call, the approval store records a decision for a particular operation, and the business service independently enforces actor, resource and transaction limits. An independent third-party CCA-F approval scenario should expire permission between planning and execution, then repeat the attempt with the requested amount or tenant changed. Neither attempt should be rescued by a persuasive model explanation. Expected evidence includes the rejected tool request, the actual service denial and unchanged downstream state; a post-execution hook cannot retroactively prevent an already completed side effect.
A reliable stop condition
An agent loop must not run forever waiting for a tool to authorize an action it cannot perform. Define terminal states for answered, denied, pending review, externally unconfirmed and completed. A denied write should lead to an explanation or escalation, not another tool call with slightly different arguments. A pending case should retain its original request ID so later callbacks can be matched and audited.
Track operational metrics such as denied calls, missing approvals, resumed cases, verification failures and attempts to repeat side effects. These measurements reveal real control quality better than counting how often the model says it followed the instructions.
Architect Foundations preparation
A hook is a decision point, not a replacement for the system of record. In a refund workflow, the model may propose an adjustment and a PreToolUse check may require approval, but the payment service must still verify customer scope, authorized amount and idempotency before committing. Post-execution events can help log the outcome; they cannot retroactively authorize a completed write. Reviewers need to know which trusted component enforced each boundary.
After an Agent SDK upgrade, recheck the documented hook contracts and run three specific failure tests: deny an unauthorized tool call before execution, distinguish a tool error from an approved result, and prevent a resumed session from reusing expired approval. Save the external service outcome alongside the hook trace so that a later investigation can separate a blocked proposal from an actual side effect. That distinction is more useful than a generic success message in an agent transcript.
A release review should compare the proposed tool catalog with the actual service capabilities. If an agent only needs to answer a question, omit modification tools entirely. Explicit capabilities and denied-operation tests are more reliable than asking a model to improvise its own access rules. Record a small set of trace identifiers and service receipts so that a reviewer can later establish what was proposed, approved and executed.