Skip to main content
Endor Labs hooks for Snowflake Cortex Code send a structured event for every session, prompt, shell command, file operation, and MCP tool call. The hook also enforces your Coding Agent Governance policies locally before each tool call runs. Cortex Code reads hooks in the Claude Code hooks format, so the configuration has the same shape as a Claude Code configuration with its own command.

Before you begin

Confirm the following requirements before you install the hook:
  • An admin has completed the prerequisites, including creating an API key with the AI Audit User role.
  • The target machine runs macOS with the Cortex Code CLI (cortex) installed. Endor Labs hasn’t verified Cortex Code on Linux or native Windows yet.
  • endorctl is on PATH.
  • The environment that launches Cortex Code has these environment variables set:
    • ENDOR_API (for example, https://api.endorlabs.com)
    • ENDOR_NAMESPACE
    • ENDOR_API_CREDENTIALS_KEY
    • ENDOR_API_CREDENTIALS_SECRET
Do not export ENDOR_TOKEN in the environment that runs the hook. Hooks authenticate with the API key and secret only, and on older versions of endorctl the extra token triggered a mixed-authentication error that blocked endorctl ai-audit.
Every event runs endorctl ai-audit cortexcode with no flags, so endorctl reads the credentials from the environment. Use the following hook configuration.
The event cache is on by default, so you don’t need to set ENDOR_AI_AUDIT_CACHE_ENABLED. The hook queues events locally and sends them on its next run after 30 seconds, at SessionEnd, and at the next SessionStart. The configuration registers no Stop hook, so events from the end of a session can arrive late, but they are not lost. The timeout value is the longest Cortex Code waits for each hook. endorctl sets its own shorter time limit, 5 seconds by default. If the hook runs out of time, Cortex Code allows the tool call.

Install for one developer

Use this for a single-machine trial or a personal install.
  1. Open ~/.snowflake/cortex/hooks.json in a text editor. Create the file if it does not exist.
  2. Paste the configuration shown in Before you begin. If the file already has hooks, add the Endor Labs entries under its existing hooks key.
  3. Save the file and start a new Cortex Code session.
Cortex Code uses $CORTEX_HOME if set, else $SNOWFLAKE_HOME/cortex, else ~/.snowflake/cortex. Put hooks.json in the first folder that applies. See Known limitations for how a custom home affects inventory.

Install for a repository

Add the Endor Labs entries from the configuration under the hooks key of <repository>/.cortex/settings.json, and commit the file. Every developer who runs Cortex Code in that repository then runs the hook.

Install on a managed fleet

Cortex Code has no managed hooks path, so an administrator can’t lock the hooks in place. A developer can edit or remove both the user file and the repository file. You can’t guarantee coverage on every machine, so combine the following:
  • Use your MDM, such as Jamf, Intune, Kandji, or JumpCloud, to deliver ~/.snowflake/cortex/hooks.json and the four environment variables to each developer.
  • Commit .cortex/settings.json with the hooks to the repositories your developers work in.
The in-browser generator and the mdm-scripts repository don’t cover Cortex Code yet, so maintain the file by hand.
On macOS, environment variables set in ~/.zshrc reach apps launched from a terminal but not apps launched from Spotlight. Ship the variables through your MDM payload (for example, a launchctl setenv profile or an ~/.zprofile snippet) for full coverage.
If your MDM’s deployment script rejects the inline JSON payload, encode the configuration in Base64 in the script, and decode it on the target machine. This avoids the quoting and escaping issues that some MDMs introduce when publishing JSON.

Configuration the hook reads at session start

At SessionStart, the hook takes a snapshot of the Cortex Code configuration for inventory and session policies. It reads the snapshot once per session and doesn’t rescan during the session.
  • User level: settings.json, hooks.json, mcp.json, and permissions.json under $SNOWFLAKE_HOME/cortex (default ~/.snowflake/cortex). The hook also reads hooks from ~/.claude/settings.json and MCP servers from ~/.claude.json.
  • Project level: .cortex/settings.json, .cortex/settings.local.json, .claude/settings.json, and .claude/settings.local.json. The .claude files contribute hooks only. The project directory is CORTEX_PROJECT_DIR when set, otherwise the hook’s working directory, not the Git root.
  • MCP servers: The hook merges servers by name, and the last source wins. The order is the top level of ~/.claude.json, then its entry for the project directory, then $SNOWFLAKE_HOME/cortex/mcp.json.
  • Enterprise MCP servers: Servers from the managed files.mcpFile setting stay separate from the merged list. The setting must be an absolute path.
The hook reads ~/.claude.json only when importClaudeMcpServers is on, which is the default. A project-level importClaudeMcpServers value overrides the user-level one.

Managed settings and MDM policy

Cortex Code accepts a managed settings file and an MDM policy from your administrator. Neither one delivers hooks, but the hook reads both at SessionStart to report sandbox posture, permission bypass, and enterprise MCP servers.

Managed settings file

The hook reads the managed settings file from a fixed path on each platform. The hook ignores the whole file and reports the sandbox posture as Unknown when the file fails its trust check or any of the following validations:
  • version is exactly "1.0".
  • permissions.defaultMode is allow or deny.
  • sql.defaultMode is read-only or write.
  • sql.lockMode appears only together with sql.defaultMode.
  • settings.forceSandboxMode is regular or autoAllow.
  • defaults.theme is dark, light, or pro.
  • required.minimumVersion is a semantic version without a v prefix.

MDM policy

On macOS and Windows, the hook also reads a Cortex Code MDM policy. The policy holds the managed settings JSON as a Base64-encoded value.
  • macOS: Preference domain com.snowflake.coco. The hook reads /Library/Managed Preferences/<username>/com.snowflake.coco.plist, then /Library/Managed Preferences/com.snowflake.coco.plist. For each key, the first file that sets it wins.
  • Windows: Registry key HKLM\SOFTWARE\Policies\Microsoft\CortexCode.
The MDM policy wins over the managed settings file for settings.forceSandboxEnabled, the whole permissions block, and files.mcpFile. Every other setting comes from the file. Any of the following MDM policy failures reports the sandbox posture as Unknown:
  • The value is unreadable or larger than 256 KiB.
  • The value isn’t valid Base64, isn’t valid JSON, or fails schema validation.
  • The property list is larger than 1 MiB, or plutil times out.

Sandbox posture

The hook resolves each session’s sandbox posture in the following order, and the first rule that applies wins:
  1. A trusted managed settings.forceSandboxEnabled: true reports Sandboxed.
  2. Any warning while reading the configuration, such as an ignored managed file or a failed MDM policy, reports Unknown.
  3. The first explicit sandbox.enabled value in the project .cortex/settings.json, then in $SNOWFLAKE_HOME/cortex/settings.json, sets the posture.
  4. Otherwise, the posture is Not sandboxed.
A managed forceSandboxEnabled: false doesn’t force the sandbox off. On Windows, forceSandboxEnabled: true in the managed settings file alone reports Unknown, never Sandboxed, because the hook can’t trust the file. An MDM policy that forces the sandbox reports Sandboxed. See Sandbox posture to read the posture in inventory, and Session sandbox policies to act on it.

Permission bypass

The hook reports permission bypass (dangerouslyAllowAll) from the managed level only. When managed settings are present, the hook reports bypass as disabled unless they set dangerouslyAllowAll: true. A user-level dangerouslyAllowAll value never reports, and the Windows managed settings file alone never reports bypass state.

Cortex Code hook events used by Coding Agent Governance

The following table lists every event the hook processes. The hook accepts and ignores Stop, Notification, PermissionRequest, and SubagentStop if a configuration registers them. Those events record nothing.

How Cortex Code tools map to policies

The hook maps each Cortex Code tool to a policy template by tool name. No policy template inspects the SQL that sql_execute runs. Cortex Code names its sub-agent tool Task, so policies written for the Claude Code Agent tool don’t match it.

Enforcement behavior

If the hook can’t run or doesn’t finish in time, Cortex Code allows the tool call and keeps working, so a hook problem never blocks a developer. The usual cause of a hook that can’t run is a missing binary. endorctl gives each hook run a time limit of 5 seconds by default, or 10 seconds when your policies use the AI judge. ENDOR_AI_AUDIT_HOOK_TIMEOUT overrides the limit. An unreadable local policy cache does not disable enforcement, because the hook falls back to the built-in system policies. A successfully evaluated Block policy still stops the tool call. On a policy match at PreToolUse, a Block policy denies the tool call, and Cortex Code shows the reason from the policy. An Ask Permission policy shows Cortex Code’s own permission prompt, without the reason from the policy. An Alert policy lets the call proceed and shows the developer nothing, so only Endor Labs records the match.

User attribution

The hook attributes Cortex Code events to the value of ENDOR_ACTOR when the hook environment sets it. Otherwise, it uses the operating system login.

Tune the hook

For an audit-only rollout, set ENDOR_AI_AUDIT_NO_BLOCKING=true in the Snowflake Cortex Code hook environment. endorctl ai-audit then downgrades every Block action to Alert at evaluation time. For Cursor, set it in the shell that launches the IDE. For Claude Code, set it in the env block of settings.json. Policies still record violations under Policy Violations, but the hook never denies a tool call. Use audit-only mode to seed a new policy without interrupting developers, then unset the variable when you’re ready to enforce. Any value that Go parses as a bool (such as true, 1, or t) turns the option on. Unset, empty, or unparseable values keep enforcement on.

Verify hooks are firing

  1. Start a session in Snowflake Cortex Code and ask the agent to run a benign shell command, such as ls.
  2. Select Agent Governance from the left sidebar, then select Inventory. The page opens on the Workstation Inventory tab.
  3. Confirm the developer’s Snowflake Cortex Code row shows a recent value under Last Active.
If no row appears, see Troubleshoot missing events.

What developers see when a policy fires

When a policy with the Block action matches an event, the hook returns a deny response to Snowflake Cortex Code. Snowflake Cortex Code stops the tool call and shows the User Message to the developer when the hook response can carry it. A response that includes a message also explains that a governance policy denied the action and tells the agent not to work around the block. When a policy with the Ask Permission action matches, Snowflake Cortex Code asks the developer to confirm or deny, where it can pause at that event. Where it cannot, the outcome depends on the event. Endor Labs records the match under Policy Violations as Ask either way. See Enforcement behavior to review the per-agent behavior. When a policy with the Alert action matches, the hook allows the action to proceed. Endor Labs records the event under Policy Violations for your security team to review.

Troubleshoot missing events

Run these checks if a developer’s actions never appear under Workstation Inventory or Policy Violations:
  • Confirm the developer has started at least one session. With the event cache enabled, the hook batches events and sends them to Endor Labs within about 30 seconds of hook activity. The hook also sends every queued event at session start and end. Inventory Sessions, Last Active, and counts can therefore lag the newest actions by that interval.
  • Hook errors never block the developer. If the hook cannot run or reach the Endor Labs API, Snowflake Cortex Code allows the tool call. The event is missing from inventory, and no error appears. The remaining checks rule out the common causes.
  • Confirm endorctl is on PATH in the environment that runs the hook. If the binary is not found, the hook does nothing and shows no error. Run endorctl version from the same shell to verify.
  • Confirm only one endorctl installation is active. If endorctl ai-audit fails with Failed with non-blocking status code: No stderr output, conflicting installations are the likely cause, such as an npx-provisioned endorctl alongside a Homebrew install. Keep one installation method per machine, remove the others, then run endorctl version to confirm.
  • Confirm ENDOR_API, ENDOR_NAMESPACE, ENDOR_API_CREDENTIALS_KEY, and ENDOR_API_CREDENTIALS_SECRET are set for the process that runs the hook. Cursor reads them from the shell that launched it. Claude Code reads them from the env block in settings.json.
  • Confirm ENDOR_TOKEN is not also exported alongside your Coding Agent Governance API key credentials in the hook environment. Hooks rely only on ENDOR_API_CREDENTIALS_KEY and ENDOR_API_CREDENTIALS_SECRET. ENDOR_TOKEN is redundant and, on older versions of endorctl, triggered a mixed-authentication error that blocked endorctl ai-audit.
  • Confirm the API key has the AI Audit User role and has not expired.
  • Confirm the developer restarted Snowflake Cortex Code after the hooks file changed. Snowflake Cortex Code reads the configuration at session start.
  • Confirm the developer restarted Snowflake Cortex Code after a policy edit. The local policy cache refreshes at session start.
  • Confirm the JSON file parses. A trailing comma silently disables every hook in the file.
  • Confirm the Endor Labs API is reachable from the environment that runs the hook. Network failures appear as gaps in the inventory.

Known limitations

Cortex Code support has the following limitations:
  • Session policies: A Block or Ask Permission session policy doesn’t stop a Cortex Code session, because Cortex Code ignores continue: false at SessionStart. A match on a Cortex Code session only records the violation.
  • Claude Code hooks in Cortex Code sessions: Cortex Code also runs hooks from ~/.claude/settings.json, .claude/settings.json, and .claude/settings.local.json. Events from an endorctl ai-audit claudecode hook there record as Claude Code, so one Cortex Code session can appear under both agents.
  • Custom home directory: The hook reads configuration under SNOWFLAKE_HOME but ignores CORTEX_HOME, and AI tool discovery looks only in ~/.snowflake/cortex.
  • Two inventory rows on one device: A device can show both a governed Snowflake Cortex Code agent and a discovered cortex-code-cli AI tool.
  • Skills: Endor Labs doesn’t collect Cortex Code skills, so they don’t appear on the Skills tab.
  • Project MCP servers and permissions: The hook doesn’t read MCP servers or permissions declared at the project level. Those servers can appear in inventory from their tool calls, without an Endor Score.
  • Windows managed settings file: The hook doesn’t check the file’s access control list, so the file alone can’t make the posture Sandboxed. Use the MDM policy to force the sandbox on Windows.
  • Headless runs: Endor Labs hasn’t verified the hook with headless cortex -p and cortex exec runs.

Next steps

With hooks deployed, continue with the following pages: