A hook is basically a script the AI agent runs at a fixed point. The most useful one runs before the agent uses a tool.
The smallest example that works: a PreToolUse hook in Claude Code that receives what the agent is about to do and, if the command tries to read .env, says no. The agent doesn’t read the file, and it learns why. It’s very simple, and it’s a real control: it doesn’t depend on the model “behaving”, because the program runs it, not the model.
Hooks make very valuable things possible. Blocking dangerous commands, scanning for secrets before anything leaves, asking for a review before a git push, or keeping a record of every file the agent edited. Today Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI and Windsurf all have them, each with its own event names.
The problem: they live on the laptop
Hooks are configured in a file. In Claude Code, for example, in settings.json, which can sit in the project or in the user’s folder. And whoever uses the machine can edit that file.
In other words, the same developer the hook is meant to control can turn it off. They can delete the line, use the option that disables all hooks or, even simpler, open another agent that has none. No malice needed: a hook that slows them down when they’re in a hurry is enough.
For a bank this matters a lot. A control that the controlled person can switch off can’t be presented to an auditor as a control.
What each vendor offers
The vendors know this, and almost all of them offer a way for the company to enforce hooks. I went through each one’s documentation in October 2026:
| Agent | Central hook management | What enforces it |
|---|---|---|
| Claude Code | managed-settings.json via MDM, or settings from the claude.ai console. allowManagedHooksOnly ignores user and project hooks |
The file, protected by the operating system |
| Codex | requirements.toml via MDM or from the ChatGPT console. allow_managed_hooks_only keeps only the company’s hooks |
The file on the machine, or signing in with the company account |
| Cursor | System hooks.json via MDM, or team hooks from the dashboard (Enterprise) |
The system file, if the user isn’t an administrator |
| GitHub Copilot | Policy hooks in a system folder that disableAllHooks doesn’t turn off. Copilot CLI only |
Root-owned files the user can’t write |
| Gemini CLI | A system settings file that overrides the user’s | The file on the machine |
| Windsurf | System hooks.json, or hooks distributed from the team dashboard |
Files that can’t be changed without root |
It’s real progress. With allowManagedHooksOnly, for example, Claude Code ignores user and project hooks and runs only the ones the company set.
Why it still isn’t enough
The most honest statement comes from Anthropic itself. About its settings delivered from the console, it writes that they work as “a client-side control, not a security boundary”, and that on an unmanaged device “a user doesn’t need admin or sudo access to bypass them”. Google says something similar about Gemini CLI: that its controls should not be considered a foolproof security boundary.
That isn’t carelessness on their part; it’s that the control runs on a machine someone else operates. For it to really hold, the company needs several things at once:
- Every laptop managed by MDM, with the developer not an administrator. On many development teams that isn’t the case, because developers install tools all day long.
- Each agent configured separately, with its own format and names. Six agents, six policies.
- Making sure nobody uses a different agent, account or model provider. Claude Code’s documentation says it plainly: managed settings bind Claude Code only, and a developer who calls the API from another tool isn’t under them.
- Checking what happens when a hook fails. In several of these products, if the script errors out or times out, the action goes ahead.
And even with all of that, the agent runs on the laptop, with the repository and often the developer’s credentials within reach.
How Harkaq solves it
Harkaq’s idea is to move the control off the developer’s machine.
First, the agent doesn’t run on the laptop. It runs in a cell: an isolated workspace the company controls, with no passwords or keys inside. The agent’s configuration, including its hooks and its instructions, is set by Harkaq and stays read-only. The developer works freely inside the cell but is not its administrator, just as they aren’t the administrator of the production server. They can’t turn off what isn’t on their machine.
Second, and to me the most important: we don’t depend on the hook running. Everything that leaves the cell goes through the gateway, the only door. The gateway checks each action, scans for secrets, adds the keys without the agent seeing them, and logs it. If a hook didn’t run, or if the agent doesn’t even have hooks, the policy still applies, because it’s applied outside.
Third, there is one policy for every agent. Security defines it once in Harkaq and it applies equally to Claude Code and to Codex. No six formats to maintain.
And when the agent needs something outside the policy, it asks, and someone else decides. That is, if you like, the hardest hook to turn off: one that doesn’t live on the machine of whoever is asking for permission.
Hooks are still useful inside the cell. They give the agent fast feedback and explain why something isn’t allowed. But the guarantee can’t depend on them.
What I learned going through all of this is simple: a control that lives on the controlled person’s machine is a good habit, not a control. For a company to say yes to agents, the one who stops things has to be outside.