개발자 가이드

Claude Agent SDK 에이전트에 행위 전 검사 추가

Claude Agent SDK 도구 호출을 도구 실행 전에 검사해야 한다면 PreToolUse 훅이 필요합니다.

검사가 하는 일

검사는 permit, deny, 또는 escalate 를 판단을 정한 조항 및 서명된 영수증과 함께 돌려줍니다. 검사는 조언형이며 실행을 거부하는 것은 PreToolUse 훅입니다. 호스팅 검사는 요청을 메모리에서 평가하고 요청 내용을 보관하지 않습니다.

코드

다음 위치에 게시된 감사된 예시와 정확히 같습니다: public/examples/frameworks/.

/** Claude Agent SDK PreToolUse hook that checks HANRIA before execution. */

import { query, type HookCallback, type HookCallbackMatcher, type Options } from "@anthropic-ai/claude-agent-sdk";
import { pathToFileURL } from "node:url";

const CHECK_URL = "https://check.hanria.ai/v1/check";
const MANDATE = {
  schema_version: "0.2-draft",
  mandate_id: "review-tool-calls",
  purpose: "Permit file reads under the example directory.",
  default: "deny",
  clauses: [{
    id: "permit-example-read",
    effect: "permit",
    match: { kind: ["file"], verb: ["read"], target_prefix: ["/tmp/example/"] },
  }],
};

type FetchLike = typeof globalThis.fetch;

export async function checkAction(
  action: Record<string, unknown>,
  checkUrl = CHECK_URL,
  fetchImpl: FetchLike = globalThis.fetch,
): Promise<Record<string, unknown>> {
  try {
    const response = await fetchImpl(checkUrl, {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ mandate: MANDATE, action }),
      signal: AbortSignal.timeout(10000),
    });
    if (!response.ok) return { outcome: "error", reason: `HANRIA returned HTTP ${response.status}` };
    const decision = await response.json() as Record<string, unknown>;
    if (!["permit", "deny", "escalate", "error"].includes(String(decision.outcome))) {
      return { outcome: "error", reason: "HANRIA returned an invalid decision" };
    }
    return decision;
  } catch (error) {
    return { outcome: "error", reason: `HANRIA check failed: ${String(error)}` };
  }
}

export function createHanriaHook({
  checkUrl = CHECK_URL,
  fetchImpl = globalThis.fetch,
}: { checkUrl?: string; fetchImpl?: FetchLike } = {}): HookCallback {
  return async (input) => {
    if (input.hook_event_name !== "PreToolUse") {
      return { continue: false, stopReason: "Expected a PreToolUse event" };
    }
    const toolInput = input.tool_input as Record<string, unknown>;
    const action = {
      schema_version: "0.1-draft",
      requested_by: { agent: "claude-agent-sdk-example" },
      operation: {
        kind: input.tool_name === "Read" ? "file" : "tool",
        verb: input.tool_name === "Read" ? "read" : input.tool_name,
        target: String(toolInput.file_path ?? toolInput.path ?? input.tool_name),
      },
      justification: `Run ${input.tool_name} through the Claude Agent SDK.`,
    };
    const decision = await checkAction(action, checkUrl, fetchImpl);
    if (decision.outcome === "permit") return {};
    return {
      hookSpecificOutput: {
        hookEventName: "PreToolUse",
        permissionDecision: "deny",
        permissionDecisionReason: `HANRIA returned ${String(decision.outcome ?? "error")}: ${String(decision.reason ?? "no reason returned")}`,
      },
    };
  };
}

export function createHookOptions(settings: { checkUrl?: string; fetchImpl?: FetchLike } = {}): Options {
  const matcher: HookCallbackMatcher = { hooks: [createHanriaHook(settings)] };
  return { hooks: { PreToolUse: [matcher] } };
}

export function constructQuery(prompt: string, options = createHookOptions()) {
  return query({ prompt, options });
}

if (process.argv[1] && pathToFileURL(process.argv[1]).href === import.meta.url) {
  const options = createHookOptions();
  console.log(`Constructed ${options.hooks?.PreToolUse?.length ?? 0} HANRIA PreToolUse hook matcher.`);
}

실행하기

claude_agent_sdk.ts 파일을 저장한 다음 해당 폴더에서 다음 두 명령을 실행하세요.

npm install --no-save --save-exact @anthropic-ai/[email protected] [email protected]
npx tsx claude_agent_sdk.ts

이 명령은 PreToolUse 훅 매처 하나를 구성하지만 쿼리를 시작하지는 않습니다. 애플리케이션의 SDK 쿼리에 createHookOptions() 을 전달하고 각 도구 입력을 위임장이 검사하는 행위 필드에 대응시키세요.

모든 결과 처리하기

시간 초과, 전송 실패, 성공이 아닌 HTTP 응답, 잘못된 형식의 응답 또는 알 수 없는 결과는 error가 됩니다. 정확한 permit 이 아닌 모든 결과는 훅에서 거부됩니다.

참고 자료

검사 사용해 보기 · 서명된 영수증 검증하기 · OpenAPI 문서 · 에이전트용 요약