# Cursor

Cursor and chock: install methods and steps, what it can enforce, and the evidence behind it.

Install methods: plugin, sync. Agentseam tier block+rewrite, grade enforceable before a tool runs.

> Ask the user before running any command on this page: each one changes how their agent or repository behaves.

## Install methods

- Plugin: `chock install --client cursor` (ask the user before running it)
- Repo hooks: `chock sync --repo . --agents cursor` writes `.cursor/hooks.json` (ask the user before running it)

## Install steps

### Cursor (cursor)

State: tested.

The command (ask the user before running it: it builds a plugin of hooks that change how their agent behaves):

    chock install --selection <code> --client cursor --apply

With --apply, chock runs these steps for Cursor:

Cursor loads ~/.cursor/plugins/local/chock-guardrails as a local plugin: run "Developer: Reload Window" (or restart Cursor), then check it under Customize. There is no command to run.

## What it can enforce

- Tier: block+rewrite
- Grade before a tool runs: enforceable
- Fail mode before a tool runs: configurable
- Basis: live-run-partial
- Recorded: 2026-09-23

## Events

| Event | Can block | Can rewrite | Fail mode |
| --- | --- | --- | --- |
| pre_tool | yes | yes | configurable |
| post_tool | no | no | open |
| tool_failure | no | no | open |
| prompt_submit | yes | no | configurable |
| session_start | no | no | open |
| session_end | no | no | open |
| subagent_start | no | no | open |
| subagent_stop | no | no | open |
| stop | yes | no | open |
| pre_compact | no | no | open |
| file_changed | no | no | open |

## Ask support

Answers an ask with: ask. Honours ask: yes. Evidence: tested (tests/test_guard_fail_to_ask.py::test_a_crashed_guard_asks_rather_than_allowing).

## Hook timeout

The engine records no timeout for this agent.

## Test status

- Plugin (cursor): tested.
- Repo hooks: untested. A test of the plugin says nothing about repo hooks.
- Through the plugin install, at hook point plugin-hook: Cursor, 2026-08-24. live probe: a stdout deny blocked a matched command, a benign one still ran (chock 6b4d400)

## Known limits

Fails OPEN by default; failClosed:true per hook definition makes it fail closed, and agentseam sets it on every gate it installs. `ask` is accepted by the preToolUse schema but not enforced today, so the adapter denies instead of returning a prompt that would behave as a pass; beforeShellExecution and beforeMCPExecution do honour ask. Separate Tab hooks (beforeTabFileRead, afterTabFileEdit) gate inline completions, and workspaceOpen fires outside any session with no canonical event here. Cursor also loads Claude Code-format hooks -- confirmed live (2026-08-27): with both `.cursor/hooks.json` and `.claude/settings.json` carrying the same probe, every event fired twice, once per config. SETTLED live (3.17.8, Windows, 2026-08-28) by a two-trial experiment differing in one key: a beforeShellExecution hook that exited 0 in SILENCE let `echo hello` run without failClosed, and BLOCKED it with failClosed:true. Silence here is a hook ERROR -- not a refusal, not an abstention. That retires the earlier note's flat 'an empty response is not an allow': the 2026-08-27 rejection it rested on was real, but the hook carried failClosed:true, which hook_config() set on every gate with no way to opt out. Its `matcher` also does not mean the same thing at every event: under beforeShellExecution it is a regex over the COMMAND TEXT, not a tool name, so the "Bash" a caller would reasonably pass matches almost nothing and quietly disables the guard -- the one hook field whose wrong value fails silently, since the install still reports success. What preToolUse's matcher matches was not established here, so hook_config writes NO matcher until one is: no matcher gates every call, which over-gates rather than under-gates, and is the conclusion a sibling guardrail reached independently after shipping this format. A hook agentseam wires here must still answer in-dialect, and now for a proven reason -- these gates install fail-closed by DEFAULT, so a silent adapter would refuse every allowed tool call. The same run recorded two facts nothing here had: the gate fires TWICE for one command (sandbox:true, then sandbox:false on Cursor's own retry), so a policy with side effects double-counts and a deny must hold on both passes; and beforeShellExecution DOES fire when it is wired. Across three capture sessions in which shell commands ran, beforeShellExecution never fired while tool_input.command arrived under preToolUse instead. RESOLVED 2026-08-28, and the cause was our own wiring: REVERSE_EVENT_MAP sends pre_tool to preToolUse, so beforeShellExecution was never installed in those captures. A consumer should still gate shell on pre_tool -- it covers every tool and is the only one that can rewrite -- but not because the dedicated event is absent. WITNESSED 2026-09-23 (3.21.18, Windows): the generic preToolUse gate DOES honour deny for a file write -- `Write` arrives with file_path and the full content, a `{permission: deny}` left the file unwritten -- so the write path is gateable here after all, and `Write` is recorded as the write vocabulary. The stop hook honours `{followup_message}`: the message is posted as the next turn and the agent acts on it, so a refusal at stop is delivered the way Claude Code's Stop block is; silence there ends the turn, so stop fails open. afterFileEdit still accepts nothing back, and the chat reply is not a tool call.


---

Built from engine [5a4b6287a46e](https://github.com/open-coder-ai/chock/commit/5a4b6287a46e07f9f856d9bbe10622bd1ff2e021) and catalog [1e60d211c1bb](https://github.com/open-coder-ai/chock-catalog/commit/1e60d211c1bb767152c6ab0167932da06ab3a10f).
