Secure Claude Code
Arcjet integrates into Claude Coding agent sessions through hooks that fire for different actions like prompts and tool calls. This allows Arcjet to observe activity, enforce policy, and record actions taken by developers without requiring any changes to the developer’s workflow.
What is Arcjet?
Arcjet is the AI agent runtime security platform. Discover the agents running in your organization, enforce policy across every action, prompt, and tool call, and keep the evidence to prove what happened.Before you start
Section titled “Before you start”Create a free Arcjet account then use the key to authenticate the Arcjet hooks. It is semi-secret, but can be distributed to multiple devices and team members through environment variables or configuration management.
Choose where to deploy
Section titled “Choose where to deploy”Claude Code has two channels for organization policy. Endpoint-managed settings are deployed to a device by IT. Server-managed settings are fetched from the claude.ai console. Both sit in the same top precedence tier, above every setting a developer can write.
| Mechanism | Where the JSON goes | Reaches | Removable by a developer |
|---|---|---|---|
| Managed settings file (endpoint-managed) | /etc/claude-code/managed-settings.json (Linux, WSL), /Library/Application Support/ClaudeCode/managed-settings.json (macOS), C:\Program Files\ClaudeCode\managed-settings.json (Windows) | That device only: terminal, IDE extensions, the desktop Code tab, Agent SDK sessions | Local administrator only |
| MDM or OS policy (endpoint-managed) | macOS com.anthropic.claudecode managed preferences; Windows HKLM\SOFTWARE\Policies\ClaudeCode, value Settings | The same surfaces, redeployable on a schedule | Local administrator only |
| Server-managed settings | claude.ai console, Admin settings > Claude Code > Managed settings | Every session that authenticates with an eligible credential. | Only by switching provider |
| Repository settings | .claude/settings.json, committed | Sessions in that repository. | Yes. |
If your developers use Claude Code on the web, read Cloud sessions.
Install the hooks
Section titled “Install the hooks”This template installs every enforcement point plus the recorded events worth
keeping. Replace ajkey_REPLACE_ME with your Arcjet key and put the file at the
managed settings path for the operating system.
{ "hooks": { "PreToolUse": [ { "hooks": [ { "type": "http", "url": "https://decide.arcjet.com/v1/agent-hooks/claude-code?event=pre-tool-use&surface=cli", "headers": { "Authorization": "Bearer $ARCJET_KEY", "X-Arcjet-Principal": "$USER" }, "allowedEnvVars": ["ARCJET_KEY", "USER"], "timeout": 5 } ] } ], "PermissionRequest": [ { "hooks": [ { "type": "http", "url": "https://decide.arcjet.com/v1/agent-hooks/claude-code?event=permission-request&surface=cli", "headers": { "Authorization": "Bearer $ARCJET_KEY", "X-Arcjet-Principal": "$USER" }, "allowedEnvVars": ["ARCJET_KEY", "USER"], "timeout": 5 } ] } ], "UserPromptSubmit": [ { "hooks": [ { "type": "http", "url": "https://decide.arcjet.com/v1/agent-hooks/claude-code?event=user-prompt-submit&surface=cli", "headers": { "Authorization": "Bearer $ARCJET_KEY", "X-Arcjet-Principal": "$USER" }, "allowedEnvVars": ["ARCJET_KEY", "USER"], "timeout": 5 } ] } ], "UserPromptExpansion": [ { "hooks": [ { "type": "http", "url": "https://decide.arcjet.com/v1/agent-hooks/claude-code?event=user-prompt-expansion&surface=cli", "headers": { "Authorization": "Bearer $ARCJET_KEY", "X-Arcjet-Principal": "$USER" }, "allowedEnvVars": ["ARCJET_KEY", "USER"], "timeout": 5 } ] } ], "PostToolUse": [ { "hooks": [ { "type": "http", "url": "https://decide.arcjet.com/v1/agent-hooks/claude-code?event=post-tool-use&surface=cli", "headers": { "Authorization": "Bearer $ARCJET_KEY", "X-Arcjet-Principal": "$USER" }, "allowedEnvVars": ["ARCJET_KEY", "USER"], "timeout": 5 } ] } ], "Stop": [ { "hooks": [ { "type": "http", "url": "https://decide.arcjet.com/v1/agent-hooks/claude-code?event=stop&surface=cli", "headers": { "Authorization": "Bearer $ARCJET_KEY", "X-Arcjet-Principal": "$USER" }, "allowedEnvVars": ["ARCJET_KEY", "USER"], "timeout": 5 } ] } ], "SessionStart": [ { "hooks": [ { "type": "http", "url": "https://decide.arcjet.com/v1/agent-hooks/claude-code?event=session-start&surface=cli", "headers": { "Authorization": "Bearer $ARCJET_KEY", "X-Arcjet-Principal": "$USER" }, "allowedEnvVars": ["ARCJET_KEY", "USER"], "timeout": 5 } ] } ], "SessionEnd": [ { "hooks": [ { "type": "http", "url": "https://decide.arcjet.com/v1/agent-hooks/claude-code?event=session-end&surface=cli", "headers": { "Authorization": "Bearer $ARCJET_KEY", "X-Arcjet-Principal": "$USER" }, "allowedEnvVars": ["ARCJET_KEY", "USER"], "timeout": 5 } ] } ], "PermissionDenied": [ { "hooks": [ { "type": "http", "url": "https://decide.arcjet.com/v1/agent-hooks/claude-code?event=permission-denied&surface=cli", "headers": { "Authorization": "Bearer $ARCJET_KEY", "X-Arcjet-Principal": "$USER" }, "allowedEnvVars": ["ARCJET_KEY", "USER"], "timeout": 5 } ] } ], "ConfigChange": [ { "hooks": [ { "type": "http", "url": "https://decide.arcjet.com/v1/agent-hooks/claude-code?event=config-change&surface=cli", "headers": { "Authorization": "Bearer $ARCJET_KEY", "X-Arcjet-Principal": "$USER" }, "allowedEnvVars": ["ARCJET_KEY", "USER"], "timeout": 5 } ] } ], "InstructionsLoaded": [ { "hooks": [ { "type": "http", "url": "https://decide.arcjet.com/v1/agent-hooks/claude-code?event=instructions-loaded&surface=cli", "headers": { "Authorization": "Bearer $ARCJET_KEY", "X-Arcjet-Principal": "$USER" }, "allowedEnvVars": ["ARCJET_KEY", "USER"], "timeout": 5 } ] } ] }, "env": { "ARCJET_KEY": "ajkey_REPLACE_ME" }, "allowedHttpHookUrls": ["https://decide.arcjet.com/*"], "httpHookAllowedEnvVars": ["ARCJET_KEY", "USER"], "permissions": { "disableBypassPermissionsMode": "disable" }}What the hooks do
Section titled “What the hooks do”Claude Code runs every matching hook for an event in parallel, so these entries add one request of latency (typically a few tens of milliseconds).
PreToolUseandPermissionRequestare the tool-call moment;UserPromptSubmitandUserPromptExpansionare the prompt moment.timeouton every entry. Claude Code’s default for an HTTP hook is 600 seconds, but 5 seconds is a sensible ceiling for a policy decision.X-Arcjet-Principalattributes a session to a developer. It’s untrusted, but useful extra metadata.$USERis unset on Windows, so use$USERNAMEthere and add it to bothallowedEnvVarslists.
Supply the Arcjet key
Section titled “Supply the Arcjet key”allowedEnvVars allows $ARCJET_KEY to resolve. Define it in one of the following ways:
- An
envblock in the same settings file, as in the template. Claude Code appliesenvto every subprocess it starts, so any command the agent runs can read the key. - A literal header value,
"Authorization": "Bearer ajkey_…". It never enters the agent’s environment. Prefer this in a root-owned managed settings file.
Lock it down
Section titled “Lock it down”The last four keys in the template are the lockdown:
{ "allowManagedHooksOnly": true, "permissions": { "disableBypassPermissionsMode": "disable" }, "allowedHttpHookUrls": ["https://decide.arcjet.com/*"]}Hook entries merge across settings levels, so without allowManagedHooksOnly
a developer’s own hooks run alongside yours.
disableBypassPermissionsMode keeps the agent’s own permission flow in place.
Cloud sessions
Section titled “Cloud sessions”A cloud session, on Claude Code on the web
or from claude --cloud, runs in a
cloud environment on a
fresh clone of the repository rather than on the developer’s machine.
Deliver the hooks
Section titled “Deliver the hooks”A cloud session reads any committed .claude/settings.json and your
organization’s server-managed settings.
Allow the endpoint
Section titled “Allow the endpoint”Every cloud environment sets a
network access level, but Arcjet is blocked by default.
Give the environment Custom network access and add decide.arcjet.com to
Allowed domains, keeping the default list if your sessions install
packages.
Third-party model providers
Section titled “Third-party model providers”Exporting a CLAUDE_CODE_USE_* provider variable, such as
CLAUDE_CODE_USE_BEDROCK, CLAUDE_CODE_USE_VERTEX, or
CLAUDE_CODE_USE_FOUNDRY, or pointing ANTHROPIC_BASE_URL somewhere other
than the Anthropic API, makes Claude Code skip the server-managed settings
fetch for that session.
Use endpoint-managed settings for configuration that must always be applied,
regardless of any CLAUDE_CODE_USE_* environment variables.
Verify the install
Section titled “Verify the install”-
Run
/statusin Claude Code. Setting sources names the selected managed source and Skipped sources what it skipped. A missing line means no source delivered a policy key, and a different source than you expected is the first-wins trap. -
Run
/hooksto list every configured hook with its source and URL. -
Run
claude doctorfor the server-managed fetch outcome and any dropped entry, orclaude --debug-file <path>to record each hook firing and its result. -
Open the site’s Activity in the Arcjet Console and confirm the session appears.
Record telemetry instead
Section titled “Record telemetry instead”If you can’t deploy hooks, Arcjet can connect to the Claude Compliance API to pull activity directly. Alternatively, Claude Code can export its own OpenTelemetry telemetry to Arcjet through managed settings. See Observe Agent Activity for more details, but note that hooks are the only way to enforce policies.
Related
Section titled “Related”- Secure coding agents – the endpoint, the events, and where enforcement stops
- Coding agent policies – the input contract and the starter policies
- Secure GitHub Copilot
- Claude Agent SDK agent guard – for agents you build with the SDK rather than the Claude Code product