Skip to content

Guides

Hooks for Codex, Cursor, Windsurf and Gemini CLI

One command puts a fail-closed Immiscible hook in front of Codex, Cursor, Windsurf or Gemini CLI, for one person or for every person on a machine through the agent’s managed settings. Shell commands, MCP tool calls and file writes are decided by the same rules as Claude Code’s.

Claude Code has its own hook and immiscible init installs it. The other coding agents people run at work each have a hook system of their own, and each can be made to block a call. immiscible install writes the hook for them:

Shell
immiscible install codex      # or cursor, windsurf, gemini

Each asks Immiscible before a shell command and an MCP tool call, and before a file write where the agent has that event. The request is the one the Claude Code hook sends, so the same rule decides for every agent: a read goes ahead, an edit or a test run inside the project goes ahead once the agent is past its intern stage, a force push or a deploy waits for a person, and a secrets file leaving the machine is refused.

#What each agent gets

AgentEventsWhen a person must approve
CodexPreToolUse for Bash, apply_patch (each file of a patch is checked) and MCP toolsthe hook waits up to four minutes for an answer, then goes ahead or refuses
CursorbeforeShellExecution and beforeMCPExecution, with failClosed: trueCursor asks you, with the reasons and the approval link
Windsurfpre_run_command, pre_mcp_tool_use and pre_write_coderefused with the approval link; run it again once approved
Gemini CLIBeforeTool for run_shell_command, write_file, replace, web_fetch and MCP toolsthe hook waits up to four minutes for an answer, then goes ahead or refuses

Only Cursor’s hooks can ask the person at the keyboard. Codex and Gemini CLI can only allow or block, so the hook holds the call while someone answers in Slack, Teams, email or the console; the hook’s timeout in the agent’s settings is set above the wait. Windsurf documents no hook timeout, and a hook it stops is treated as a pass, so the Windsurf hook never waits. A call that is held and not answered in time is refused with the approval link; running it again makes a new request.

Immiscible’s own read-only MCP tools (check_action_status, explain_decision, spend_summary, find_waste, unwatched_keys) are never sent back to Immiscible. Its tools that act still are.

#For one person, or for a whole machine

Shell
immiscible install cursor --key ask_...                   # for you: ~/.cursor/hooks.json
sudo immiscible install cursor --scope managed            # for everyone on this machine
immiscible install codex --scope managed --dry-run        # show the files, write nothing
Agent--scope user--scope managed
Codex~/.codex/hooks.json ($CODEX_HOME if set)/etc/codex/requirements.toml on macOS and Linux, %ProgramData%\OpenAI\Codex\requirements.toml on Windows
Cursor~/.cursor/hooks.json/Library/Application Support/Cursor/hooks.json, /etc/cursor/hooks.json, C:\ProgramData\Cursor\hooks.json
Windsurf~/.codeium/windsurf/hooks.json/Library/Application Support/Windsurf/hooks.json, /etc/windsurf/hooks.json, C:\ProgramData\Windsurf\hooks.json; the Devin Desktop file in the same places when it already exists, since it hides the Windsurf one
Gemini CLI~/.gemini/settings.json/Library/Application Support/GeminiCli/settings.json, /etc/gemini-cli/settings.json, C:\ProgramData\gemini-cli\settings.json (or GEMINI_CLI_SYSTEM_SETTINGS_PATH)

The user scope puts the hook in ~/.immiscible; the managed scope puts it in an immiscible folder beside the managed file. What the managed scope adds:

  • Codex: allow_managed_hooks_only = true, so hooks from people’s own settings, projects and plugins do not run, and a [hooks] table naming the hook’s folder as managed_dir. Immiscible’s lines sit between # >>> immiscible and # <<< immiscible markers; everything else in the file is left as written. If the file turns hooks off ([features] hooks = false), install refuses rather than write a hook that never runs.
  • Cursor: enterprise hooks run before project and user hooks, and a deny from any hook wins.
  • Windsurf: system hooks run before user and workspace hooks.
  • Gemini CLI: hooksConfig.enabled: true in the system settings, which override user and project settings. A person can still list a hook by name in their own hooksConfig.disabled; install warns when the file it writes lists Immiscible’s.

Device management tools can deploy the same files: run with --dry-run --json to get them, or set IMMISCIBLE_MANAGED_ROOT to write them under one folder for packaging.

#The agent key

The hook reads IMMISCIBLE_URL and IMMISCIBLE_AGENT_KEY from the environment first, then from hook.env beside it. Install writes your server’s address there, and the key with --key. Cursor and Windsurf start hooks from the app rather than your shell, and Gemini CLI gives hooks a reduced environment, so hook.env is usually how the key arrives. In the user scope the file is readable by you alone. In the managed scope every person’s hook reads it, so a key there stands for the machine; leave --key out to have each person set IMMISCIBLE_AGENT_KEY themselves. Until there is a key, the hook refuses every call it checks.

#Failing closed

Every installed command ends in || exit 2. Codex, Windsurf and Gemini CLI block a call on exit code 2 and let it through on any other failure, so a missing node, a missing hook file or a crash blocks the call rather than passing it. Cursor’s entry also sets failClosed: true, because Cursor lets a call through when a hook crashes or times out otherwise. When Immiscible cannot be reached, answers with an error or takes longer than IMMISCIBLE_TIMEOUT_MS (10 seconds by default), the hook refuses the call and says why. If you need to work offline, remove the hook; do not teach it to allow on error.

Each agent reads its hooks when it starts, so restart it, or open a new session, after installing. Codex runs a hook from a person’s own settings only after they trust it under /hooks; until then it does not run at all, which is one reason to prefer the managed scope, whose hooks need no trust step.

#What has been tested

The installers are built to each vendor’s published documentation: Codex hooks, Cursor hooks, Windsurf Cascade hooks and Gemini CLI hooks, as of October 2026. The tests run the command each agent would run, in a shell with the event on standard input as each vendor documents it, against a real Immiscible server: a force push is held, a secrets file leaving the machine is refused, and an unreachable server or a missing hook blocks the call. They do not run Codex, Cursor, Windsurf or Gemini CLI themselves, and the Windows paths are taken from the documentation without being exercised.