Documentation

Build · Guide 12

Claude Agent SDK

Map Claude Agent SDK permission checks to Rulebook so governed tools cannot execute before a binding verdict.

12 min read

Pre-release documentation. This guide describes the current product design and evaluation build. Packaging, availability and commercial terms may change before release.

01

Use the permission boundary

Claude Agent SDK provides permission callbacks and pre-tool hooks that run before a tool executes. Map that boundary to Rulebook. An MCP server that merely exposes decide or ask is useful for policy-aware reasoning, but it remains advisory because the model chooses whether to call it.

The canUseTool callback is consulted only for tool calls that reach the SDK's permission decision. Do not auto-approve governed tools through allowedTools or a permissive permission mode, because that can bypass the callback.

  • canUseTool or PreToolUse: enforced when every governed tool is routed through it
  • Rulebook MCP server offered as a tool: advisory
  • Prompt instruction to consult policy: advisory
  • Gateway proxy before the destination: strongest framework-independent fallback
02

Connect canUseTool to Rulebook

The callback asks Rulebook about every proposed tool call. It returns the original or transformed input on allow and returns a denial for policy refusal, required approval or runtime failure. The callback contains no business policy.

import { query } from "@anthropic-ai/claude-agent-sdk";
import {
  AveryClient,
  GatewayDeniedError,
  ApprovalRequiredError,
} from "@avery-rulebook/sdk";

const avery = new AveryClient({
  baseUrl: process.env.AVERY_URL ?? "http://localhost:7171",
  apiKey: process.env.AVERY_TOKEN,
});
const guard = avery.gateway.hook({
  caller: { agent: "agt_claude_ops" },
  context: { environment: "production" },
});

const canUseTool = async (
  toolName: string,
  input: Record<string, unknown>,
) => {
  try {
    const checked = await guard(toolName, input);
    return { behavior: "allow" as const, updatedInput: checked.args };
  } catch (error) {
    if (error instanceof GatewayDeniedError) {
      return {
        behavior: "deny" as const,
        message: error.message + " Receipt " + error.receiptId,
      };
    }
    if (error instanceof ApprovalRequiredError) {
      return {
        behavior: "deny" as const,
        message: "Human approval required: " + error.approvalId,
      };
    }
    return {
      behavior: "deny" as const,
      message: "Rulebook is unavailable. The tool call was stopped.",
    };
  }
};

for await (const message of query({
  prompt: "Share the requested record with the service partner.",
  options: { canUseTool },
})) {
  console.log(message);
}
03

PreToolUse is the alternative

A PreToolUse hook provides the same architectural location when hooks fit the application better than a permission callback. The hook should call gateway/check, return an allow decision with any transformed input, or block with a receipt-backed reason. Use one mechanism as the mandatory path and test it with a real side-effect stub.

04

Production checklist

  • Remove alternate routes to protected tools
  • Keep governed tools out of automatic allowlists
  • Fail closed when Rulebook is unreachable or returns an unknown verdict
  • Forward only transformed arguments returned by the gateway
  • Surface required approval as a hold, never as an allow
  • Capture receipt IDs beside the Claude tool-use ID for incident review

Executive briefing

Apply the architecture to one consequential workflow.

Bring one consequential agent workflow. We will map the governing policies and regulations, runtime gate, human authority and auditable evidence path with your team.

Request demo