ANTHROPIC_BASE_URL, but coding assistants also perform work the model API never sees — running shell commands, editing files, and calling MCP tools. TrueFoundry governs that surface through Claude Code hooks: each hook payload is sent to a dedicated gateway endpoint that runs your configured guardrails and returns Claude Code’s native hook response, so a violation blocks the action (or rewrites it) directly in the client.
This is complementary to the standard Claude Code integration. That covers model requests (cost, routing, LLM guardrails on completions); this page covers prompt submissions and tool calls via hooks. You can use either or both.
How it works
- Claude Code fires a hook (e.g. before a tool runs) and sends the event payload on stdin.
- A hook command
POSTs that payload to the gateway endpointPOST /hooks/claude-code. - The gateway runs the guardrails you nominated for that hook and returns a JSON response containing Claude Code’s native hook fields (
decision,permissionDecision,updatedInput,updatedToolOutput). - Claude Code acts on that response — allowing, blocking, or applying the rewritten content.
What you can and can’t do
There are two things a guardrail can do at a hook:- Validation — decide block or allow. A block stops the prompt or tool call (or, for
PostToolUse, replaces the already-produced result — see caveats). - Mutation — rewrite the content in place (e.g. redact an email from a tool’s input or output) and let the action continue with the sanitized version.
In short:
- Validation works on all three events.
- Mutation works only on the MCP tool paths —
PreToolUse(tool input) andPostToolUse(tool result). The prompt path (UserPromptSubmit) is validation-only.
There is no LLM-output direction here: Claude Code has no hook for the assistant’s generated response. To guardrail model responses, use output guardrails on the model request path (see Guardrails).
Choosing which guardrails run
Guardrails for the hook endpoint are selected per request via thex-tfy-guardrails header (the same JSON format used elsewhere — see Applying guardrails via header). The endpoint does not read tenant Guardrail Config rules; the caller nominates the selectors.
Each selector is
group/guardrail-name. If no selector is nominated for a hook’s direction, that request passes through.
Prerequisites
- A guardrail group and at least one guardrail integration — see Create a guardrail. Note the selector string, e.g.
security/email-regex. - A TrueFoundry API key with access to that guardrail group.
- Claude Code installed and (optionally) already pointed at the gateway per the Claude Code integration.
Configure the hooks
Add the hooks to your project’s.claude/settings.json (or ~/.claude/settings.json). This example wires all three events to the endpoint and blocks anything the security/email-regex guardrail flags. Replace the selector with your own.
TFY_GUARDRAIL_URL is your gateway host root — the same host as ANTHROPIC_BASE_URL but without the /api/llm suffix (the hook endpoint is mounted at the root, e.g. https://your-gateway-host/hooks/claude-code).Verify
Send a payload through the endpoint directly before wiring it into Claude Code:decision: "block" (and, for PreToolUse, hookSpecificOutput.permissionDecision: "deny"). A passing request returns {"verdict": true, "transformed": false}.
Response contract
verdict: false— the guardrail blocked. The response carries Claude Code’s native block fields for the event (decision: "block", pluspermissionDecision: "deny"forPreToolUse; forPostToolUsethe flagged result is replaced with the guardrail message viaupdatedToolOutput).transformed: true— a mutating guardrail rewrote the content. The rewrite is applied through the native field for the event (updatedInputforPreToolUse,updatedToolOutputforPostToolUse).- Fail-closed — if the gateway hits an error (an internal failure, or a misconfigured/unresolvable guardrail selector) it returns
verdict: falsewith the event’s native block fields, so a request it couldn’t verify is blocked rather than let through.
Caveats
PostToolUsecannot prevent a tool from executing. It fires after the tool has run, so its side effects (a file written, a command executed, an API called) have already happened. Blocking atPostToolUseonly replaces the result the model sees — it does not undo the action. To actually stop a dangerous tool call, usePreToolUse.UserPromptSubmitis validation-only. You can block a prompt, but you cannot redact or rewrite it — Claude Code has no mechanism to substitute a modified prompt. If a prompt violates policy, it’s blocked, not sanitized.- No LLM-output guardrails via hooks. Claude Code exposes no hook for the assistant’s generated response, so model output can’t be scanned here. Use output guardrails on the model request path instead (Guardrails).
PreToolUsemutation auto-allows the call. When a guardrail rewrites the tool input, the response setspermissionDecision: "allow"alongsideupdatedInput, so the sanitized call proceeds without the usual permission prompt. This is intentional (the guardrail already vetted it), but it does bypass interactive approval for that call.- Selection is header-driven, not rule-based. The endpoint runs exactly the guardrails named in the
x-tfy-guardrailsheader; it does not consult tenant Guardrail Config rules. Each Claude Code hook config carries its own selector list. - Fail-closed on errors. If the gateway errors internally — including when a nominated guardrail selector can’t be resolved (unknown name, invalid placement, unsupported type) — it returns
verdict: falseand blocks the action, so a request that couldn’t be verified never slips through. This only applies when the gateway is actually reached: if it’s unreachable andcurlreturns nothing, Claude Code has no decision to act on and the action proceeds (see the next point) — so hooks still shouldn’t be your only control for hard-security requirements. - Command hooks depend on
curloutput. For"type": "command"hooks, Claude Code reads the guardrail decision from the command’s stdout (curl … -d @-). A network failure, wrong URL, or missingx-tfy-api-keyyields no decision and the action proceeds. matcher: "*"on the tool hooks runs the guardrail on every tool. Narrow it (e.g."Bash","Edit|Write", or a specific MCP tool) if you only want to guard certain tools.