Rune Gurd docs

Harness hooks

Rune Guard's hooks check what AI agents do inside their harness, before a tool call runs and after it returns.

What hooks do

Guard adds its own entries to each harness's hook configuration. The harness then asks Guard about prompts, tool calls and tool output. We monitor agents, not developers.

  • Tool calls. Reads of credential files and directories, credential commands (such as security find-generic-password) and MCP tool arguments that name credential paths are denied.
  • Risky actions. Persistence writes, guardrail lowering, destructive commands, droppers, risky package installs, encoded secrets and credential writes are blocked, confirmed with the user or reported. See risky actions.
  • Tool output. Critical and high secrets in output are replaced or reported, where the harness allows it.
  • Prompts. Checked only when your organization turns on human-to-AI sharing detection (privacy.human_ai_sharing) in its signed catalog. Without it, a prompt goes through unchanged and Guard records only that a prompt was submitted. See the privacy statement.
  • MCP tool access. When the signed catalog has tool access rules, MCP calls are checked against them. See MCP tools.
  • Sessions. Calls are linked into agent sessions, so chains such as untrusted input, then a credential read, then an upload can be caught. Output from one MCP server followed by a sending, writing or deleting call on another is recorded too (cross_server_mcp_flow, in detect mode by default). A call without a session ID gets no session rules.

Messages name secret types and rules, never secret values. Hooks also deny any tool call that reads or writes the Guard home, so an agent can't grant itself an exception.

Warning: Hooks are voluntary checks, not endpoint-wide enforcement. A user can edit or remove them, and in several harnesses a hook that fails or times out lets the action proceed. Guard's endpoint sensor reports the file opens and process launches that hooks miss, including agent CLIs started with a bypass flag or a variable that moves their configuration directory, only after the fact, and the native macOS sensor can't yet run on customer Macs (see Install).

Install

guard hooks install all
guard hooks status
  • all selects known harness configuration locations and supported official extension manifests. Incomplete discovery can skip automatic setup. Name a supported harness to choose explicitly: guard hooks install claude_code cursor.
  • Entries run the guard binary you ran install with, by absolute path. Use --binary PATH for another one.
  • Catalog flags given before hooks are added to every entry: guard --catalog PATH --catalog-key KEYS hooks install all.
  • Your other hooks are kept. The first time Guard changes a file, it saves the original with a .before-runeward-guard suffix.
  • Codex asks you to trust new hooks: run /hooks in Codex after installing.
  • guard hooks uninstall all removes Guard's entries only.

status reports each harness as one of:

State Meaning
installed All of Guard's entries are present.
partial Some events have no Guard entry.
broken An entry starts a binary that is missing or not executable.
not_installed No Guard entries.
invalid The file or vendor hook schema is invalid, or a native runtime home disagrees with the configured path.

guard doctor and the Guard Cloud health report show the same states, without paths.

Repair

Harness updates and settings editors sometimes drop Guard's entries. Repair puts them back:

guard hooks repair all

Repair only touches harnesses in the partial or broken state. A harness with no Guard entries is left alone, because removing them all is how you turn Guard off for it. The last 20 repairs show in guard doctor as hook_repairs.

Scheduled repair is opt-in:

  • macOS: guard setup-launch-agent --binary /path/to/guard --repair-hooks writes the com.runeward.guard.hooks-repair launch agent. It runs at login and hourly; --repair-interval SECONDS sets 300 to 86400. Load it with launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.runeward.guard.hooks-repair.plist.
  • Linux: the packages ship a user timer, off by default. Each user enables it with systemctl --user enable --now runeward-guard-hooks-repair.timer.
  • Windows: install.ps1 -RepairHooks or the MSI's REPAIRHOOKS=1 registers a scheduled task that runs guard.exe hooks repair all as each user, two minutes after logon and then hourly. Administrators can also run guard hooks repair-task register, remove or status. It restores entries a user removed on purpose (to opt a harness out, remove the task) and can overwrite an edit saved while it runs. Windows hook install and repair aren't yet qualified.

A signed catalog can also repair JSON hooks automatically with a hooks_repair remediation playbook. Kimi TOML needs explicit repair; it is excluded from JSON-snapshot remediation.

Exceptions

Exceptions let named paths, MCP servers or commands through specific checks, such as test fixtures with fake keys. They come from:

  • hook_exceptions in the signed catalog, which Guard Cloud can send to every enrolled device;
  • policy.json in the Guard home (~/.runeward-guard by default), for one user. A catalog can turn these off with "local_hook_exceptions": false.
{
  "version": 1,
  "exceptions": [
    {
      "paths": ["~/src/payments/tests/fixtures/"],
      "secrets": ["stripe_key", "jwt"],
      "reason": "Fake keys used by the payments test suite"
    },
    {
      "mcp_servers": ["sentry"],
      "commands": [["npm", "test"], ["cargo", "test"]],
      "secrets": ["github_token"],
      "reason": "Test suites and error reports print fake tokens",
      "expires": "2026-12-31T00:00:00Z"
    }
  ]
}
Field Rules
paths Catalog path patterns. Each must name at least two literal directories or files before any **, so ~/src/** is refused.
mcp_servers Exact server names as configured. No wildcards.
commands Argument-list prefixes. ["npm", "test"] covers npm test -- --watch=false but not npm run test. Pipes, lists and redirections never match. Broad prefixes such as ["bash"] are refused.
secrets Catalog secret rules, or "*".
actions Risky action rules, such as rules_file or git_reset_hard. Guardrail lowering, droppers and blocklisted packages can't be exempted.
credentials Credential file kinds, such as dot_env, that may be read at paths. Reading whole credential directories and running credential commands can't be exempted.
reason Required.
expires Optional. Expired exceptions stop applying.

Each exception needs at least one of paths, mcp_servers and commands. Exceptions never apply to prompts.

Validate the file with guard policy check. If it's invalid, hooks ignore it and every check still applies. It must be owned by you or root and not writable by others.

Risky actions

Each rule in the catalog has a decision:

  • block denies the call.
  • ask asks the user to confirm, where the harness can. Elsewhere Guard warns instead.
  • warn lets the call run and tells the user, and in some harnesses the agent.

A rule in detect mode is recorded but not applied, so a new rule can be measured before it enforces.

Action Examples Built-in decision
Persistence Writes to CLAUDE.md, AGENTS.md, .cursor/rules/, skills, hook files, .git/hooks, scheduled tasks; crontab, launchctl load ask
Persistence Writes to shell startup files and authorized_keys warn
Guardrail lowering Turning on bypassPermissions, Codex danger-full-access, removing Guard's hook entries, --dangerously-skip-permissions or --yolo block
Destructive Recursive deletes outside the workspace, git push --force, git reset --hard, terraform destroy, kubectl delete ask
Dropper Downloaded content piped into an interpreter, such as curl … | base64 -d | node block
Package install A package on the catalog blocklist block
Package install A name resembling a popular npm, PyPI, crates.io, NuGet or RubyGems package, such as expresss; the built-in look-alike rule records it in detect mode warn; not applied in the default detect mode
Package install An npm, PyPI or crates.io name the registry doesn't have, going by a signed name snapshot or, where policy turns them on, registry lookups; names it can't settle are unknown and change nothing warn; not applied in the default detect mode
Package install Installs from a URL or Git repository; npx, uvx or npm install -g without an exact version warn
Encoded secret A base64 or hex string that decodes to a critical or high secret, in a command, a tool argument or, with the human-to-AI sharing opt-in, a prompt warn
Credential write Writing a critical or high secret into a file that didn't already hold it warn
Untrusted model load Handing Python or torchrun a pickle file (.pkl, .pt, .joblib and similar) that an agent session downloaded or wrote after taking in untrusted content. Only files named in the command or -c code are seen, and the file is never read Reported only

Look-alike and not-on-registry findings send package names to Guard Cloud only when they match public data: a look-alike of a name on the built-in public reference list, or a name a public registry snapshot or lookup showed missing. A name your policy added to the reference list, or one another registry or a private registry may serve, stays on the device.

Destructive and persistence command rules can be limited to agents in a given state: agents with a named MCP server, skill or plugin, agents using a component nobody has reviewed, or agents whose owner is unknown or inactive. When Guard can't establish that state, the rule's on_unknown decision applies, and the finding says why.

Hooks don't see commands that programs run on their own, such as a package's install script.

What each harness supports

Prompt checks in this table apply with the human-to-AI sharing opt-in on.

Harness Prompts Tool calls Tool output ask rules Limits
Claude Code Blocked Denied Replaced for MCP tools; reported for others, after Claude has seen it Asks If Claude cannot launch a hook or it times out, the action may proceed. Tool hooks ran live in 2.1.302 on Windows and in WSL2.
Codex Blocked Denied Replaced; the command has already run Warns Untrusted or disabled hooks don't run. A hook launch failure may let the action proceed.
Cursor Blocked (editor) Editor: denied reads, writes, shell, MCP. CLI: only shell is claimed Editor: replaced for MCP tools; reported for others. CLI: not claimed Asks for shell and MCP; write tools are allowed silently Cursor CLI never fired beforeSubmitPrompt, so CLI prompts aren't checked. The editor and the MCP, write and ask paths have not been tested live.
Cline Blocked (VS Code); the CLI can't block prompts Cancelled: the task stops In VS Code 4.1.23, output arrives as [object Object], so secrets in it reach the model Warns Attachments aren't checked in 4.1.23. Hooks that fail or time out are ignored and the action proceeds.
Continue Not available Observe only Not available None No hook Guard can use is dispatched, so nothing is installed. guard harness status continue reports its configuration. Not tested in a live session.
Copilot CLI / VS Code Copilot Session Target Rewritten, not rejected; the original may stay in Copilot's local timeline Denied Replaced Implemented and unit-tested, not run live; denied in autopilot mode; warn rules show nothing Retained live runs cover the CLI only. The editor's shared runtime has fixture tests; Legacy Local is unsupported. A timeout or invalid reply can run the action. Attachments aren't inspected. Copilot names MCP tools SERVER-TOOL and server names can contain hyphens, so MCP tool access rules and Console MCP blocks don't apply; Guard Cloud reports those blocks as harness_without_hooks. Use the MCP gateway for them.
Kimi Code Opted-in submitted text checked; attachments aren't read Denied by the reviewed protocol Reported from an asynchronous preview of at most 2,000 characters; cannot withhold Required approval is denied Current Node runtime and its VS Code SDK path have source and fixture tests only. Older Python clients are outside this adapter. A payload Guard can't inspect is denied or blocked for its event. Timeouts and errors can let the action proceed.
Qwen Code Only explicit submitted text is inspected with the opt-in; generated continuation text is not a substitute Denied by the reviewed protocol Withheld on the reviewed classic and ACP paths using continue: false; a Qwen build that follows Qwen's documentation may end the turn there Required approval is denied CLI and companion runtime have source and fixture tests only. Code-mode inner tools and paths that bypass hooks aren't qualified. A payload Guard can't inspect is denied, blocked or withheld for its event. Timeouts and errors can let the action proceed.
Gemini CLI Blocked Denied Replaced Warns A hook timeout or invalid reply runs the action. Guard can't edit a settings.json that has comments.
Windsurf Blocked Blocked: reads, writes, commands, MCP Not checked: post-hooks can't change it Warns Not validated in a live Windsurf session. The JetBrains plugin reads ~/.codeium/hooks.json, which guard hooks doesn't manage.

Where entries go

Harness Name for install User-level location
Claude Code claude_code ~/.claude/settings.json
Codex codex ~/.codex/hooks.json
Cursor cursor ~/.cursor/hooks.json
Cline cline ~/Documents/Cline/Hooks/, one script per event
Copilot CLI copilot_cli ~/.copilot/hooks/runeward-guard.json
VS Code Copilot Session Target vscode_copilot (alias of copilot_cli) The same Copilot user file; reports remain copilot_cli
Kimi Code kimi_code ~/.kimi-code/config.toml
Qwen Code qwen_code ~/.qwen/settings.json
Gemini CLI gemini_cli ~/.gemini/settings.json
Windsurf windsurf ~/.codeium/windsurf/hooks.json
  • Claude Code: to cover one project only, add the same entries to its .claude/settings.json by hand.
  • Cline: Guard won't replace a script it didn't write. On Linux, if xdg-user-dir DOCUMENTS isn't ~/Documents, copy the scripts there. For one project, use .clinerules/hooks/.
  • Windsurf: organizations can put the same entries in the system-level file (/Library/Application Support/Windsurf/hooks.json on macOS, /etc/windsurf/hooks.json on Linux), which users can't edit. guard hooks manages only the user-level file.
  • VS Code: check the session target and the host that executes the agent. An extension manifest or a default-path status is not proof that hooks ran. Remote SSH, WSL, containers, custom profiles and extension directories need their own setup and qualification. Continue remains observe-only; other extensions do not inherit Copilot's adapter.
  • Kimi and Qwen: a custom KIMI_CODE_HOME or QWEN_HOME that disagrees with the catalog's paths is refused rather than silently installing into the default home. These native adapters do not supply Guard's exact-call Cloud approval, quarantine or Linux managed-endpoint routing. Status checks configuration, not delivery; neither vendor provides a fail-closed guarantee.

Hook checks inspect delivered tool actions outside model inference. Selecting DeepSeek, Kimi, Qwen, a local runtime or another hosted backend does not by itself qualify a client, model or extension. The new native-client tests use synthetic payloads and contact no model provider.

Test with synthetic secrets only, never real credentials.

Written from docs/hooks.md, docs/claude-code.md, docs/codex.md, docs/cursor.md, docs/cline.md, docs/continue.md, docs/copilot-cli.md, docs/gemini-cli.md, docs/windsurf.md, docs/vscode-copilot.md, docs/native-model-clients.md, docs/detection-catalog.md at commit fb79778d02f0. Rune Guard is in early access.