Skip to lesson

AnthropicClaude Certified Architect – Professional2026-105.1 Implement guardrails and safety controls

Require approval and fail closed before risky calls

Completed by the knowledge check

Learning objective

Implement pre-execution gates that block or require approval for high-risk actions and fail closed when a check is unavailable

Core idea

A blocking PreToolUse decision prevents the proposed tool call. Operating that control adds another requirement: an unavailable checker or reviewer must never become implicit approval.

Design three outcomes explicitly: prohibited, eligible for approval, and authorized to proceed. A check failure belongs to none of them. Record it as unavailable and keep the risky operation unexecuted. The service can continue useful investigation or return a deferred-service response without granting the capability that the missing check protects.

The choice is architectural because the approval service, runtime, and downstream handler have different failure modes. The architect must specify what remains stopped, who can approve, and how the resumed request is checked again.

How it works

Separate mandatory policy from interactive permission

Keep the mandatory business predicate in PreToolUse or the application-owned execution path. The Agent SDK evaluates hooks before permissions. Its TypeScript canUseTool callback, called can_use_tool in Python, handles requests that reach the runtime’s user-input step. It is not invoked for every tool call: an earlier approval can resolve a call before that callback.

When a request passes mandatory policy but needs a person, a PreToolUse result with hookSpecificOutput.permissionDecision: "ask" sends it through confirmation. In the SDK, provide the corresponding user-input callback and a real review interface. The TypeScript callback returns an approval or denial using behavior: "allow" or behavior: "deny"; the user-input guide documents the complete response shapes.

Treat the callback’s input as the proposed operation to review. Display the actual target and consequential arguments, not a model-written reassurance. If the reviewer declines, is unavailable, or the application cannot establish a valid decision, return a denial. Do not auto-approve merely to keep an unattended run moving.

Permission confirmation still needs the application’s business meaning. For an illustrative deployment tool, approval of “use this tool” is weaker than approval of a particular release in a particular environment. Have the execution check consult the application’s approval record for that release and environment. The record format and expiration are application policy, not SDK defaults.

Choose a supported wait path

A callback can await the review interface and then return its decision. Bound that wait by the service’s deadline, and handle cancellation. The TypeScript user-input callback receives an AbortSignal; the Python context’s signal field is reserved for future use, so do not assume identical cancellation APIs.

The PreToolUse hook decides before the callback runs, and a reviewer who declines or is unavailable produces a denial.

The PreToolUse hook decides before the callback runs, and a reviewer who declines or is unavailable produces a denialThe Agent SDK sends the proposed tool call to the PreToolUse hook first. A prohibited call gets a blocking decision. A call that needs a person gets permissionDecision ask, so the SDK reaches the user-input step and the canUseTool callback awaits the review interface. The callback returns behavior allow on approval, and behavior deny when the reviewer declines or is unavailable.canUseTool callbackPreToolUse hookAgent SDKawait the review interfacealt[approval][declines or unavailable]alt[prohibited][needs a person]proposed tool callblocking decisionpermissionDecision "ask"user-input stepbehavior "allow"behavior "deny"

For work that must outlive the active request, Claude Code also documents permissionDecision: "defer". In non-interactive -p mode, including Agent SDK execution, it ends the turn with stop_reason: "tool_deferred" and preserves the pending call. Resuming invokes PreToolUse again. Deferral preserves a proposal; it does not approve it.

That mechanism has a critical constraint: it works only for a single tool call in the turn. If Claude proposes several calls, "defer" is ignored with a warning and normal permissions continue. Therefore, a mandatory approval design cannot depend on deferral alone. Retain a denying policy predicate whenever the required approval is absent, including the multi-call path.

Revalidate when work resumes. If the release, target, permissions, or approval record no longer match, the resumed call stays denied. A person authorizing one operation must not accidentally authorize a different operation generated later.

Make checker failures blocking

Claude Code command hooks and Agent SDK callback hooks have different timeout semantics. Do not copy the assumption from one into the other:

Enforcement surfaceDocumented failure behaviorFail-closed design
SDK PreToolUse callbackA timeout cancels the callback, discards its output, and leaves the tool unexecutedSet the matcher’s timeout in seconds; handle lookup failures with an explicit denial
Claude Code command hookNon-blocking failures normally let the action continueSet onFailure: "block"; requires Claude Code v2.1.295 or later
Claude Code http hookFailures normally continue; a timeout does not itself block PreToolUseSet onFailure: "block"; requires Claude Code v2.1.295 or later

See 3.2.5 for command-hook exit codes and explicit denial signaling; the cross-family comparison here determines how an unavailable approval check stays closed.

Do not return {} from an exception handler as a convenient default. That provides no denial. Return an explicit rejection for an unavailable mandatory check and distinguish its reason from a policy breach. Keep enforcement synchronous: a background hook output cannot block the operation it has already allowed to continue.

Key distinctions and trade-offs

Denial versus pending review: A rejected action is stopped. A review record is an application artifact with its own lifecycle. A denial reason mentioning review does not create that record or notify anyone by itself.

Fail closed versus fail silent: Both can stop execution, but only an observable unavailable outcome lets operators distinguish an outage from a policy change. Count unavailable checks separately and assign the checker service to an on-call owner.

Availability versus authority: Closing a deployment capability during an approval outage reduces service availability. Keeping read-only diagnosis available can preserve usefulness, provided those calls satisfy their own authorization. The fallback must not expose an alternate execution tool that bypasses the missing check.

Architecture / decision scenario

A technology company lets an agent investigate failed releases and request production deployment. Its delivery target permits a five-minute wait for approval, but production deployment requires the release manager’s approval of the exact build and environment. Read-only diagnosis may continue during a review outage.

The team proposes placing every approval in canUseTool, with auto-allow rules to reduce prompts for ordinary deployments. The architect rejects the conflict: an earlier allow can prevent that callback from running. Mandatory approval validation belongs in PreToolUse, regardless of the permission path.

The hook denies prohibited releases and unavailable policy checks. For an eligible release awaiting approval, it returns "ask"; the callback records the release manager’s decision for the exact build and environment before allowing execution. The deployment handler also rejects execution without that matching approval record. Work exceeding the five-minute service deadline remains unexecuted. A durable review can complete separately, followed by a fresh checked attempt.

On the Agent SDK surface, acceptance tests withhold reviewer approval, interrupt the approval lookup, and exceed the callback timeout; each must show zero deployment-handler entries. The same team also operates a separate Claude Code CLI deployment with a command hook and onFailure: "block". Its tests remove the script, corrupt its output, and time out the lookup, again requiring zero handler entries. This design uses a fresh checked attempt after durable review, so it does not depend on deferral. The release manager owns approval policy; platform operations owns both surfaces and their checker availability.

Common exam traps

  • Using canUseTool as the mandatory predicate for every call.
  • Treating a reviewer timeout as approval.
  • Expecting an http hook timeout to block PreToolUse without onFailure: "block".
  • Relying on "defer" for a multi-call turn.
  • Reusing approval after the target or arguments change.
  • Logging a checker failure and returning a non-denying result.

What to remember

Put mandatory checks before permissions, and provide an explicit supported path for approval. Fail closed when a check cannot produce a decision. Test the failure defaults of the exact hook family and keep resumed operations subject to fresh validation.

Knowledge check

References