Coding agents
What itr connect installs for Claude Code, Cursor, Codex CLI, Copilot CLI and OpenCode, who answers an ask, and what each host guarantees.
How a hook decides
itr connect installs a pre-tool hook in each coding agent. Before a tool runs, the hook sends the call to POST /v1/actions/authorize with this device's runtime key for that tool. Intertrace decides it like any SDK or MCP call: the agent's policy, role, tiers, approvals and built-in floors all apply. A call that needs a person waits for the central approval and runs again with it once approved.
Each tool is one Intertrace agent per organization ("Claude Code", "Cursor", ...), created the first time anyone in the organization connects it. Each device holds its own runtime key for the tool, minted in the same browser approval as sign-in. The key records the device and the person who approved it, so approvals name the developer, and revoking a laptop revokes its keys.
Set up
curl -fsSL https://platform.intertrace.ai/install.sh | sh # macOS / Linux
irm https://platform.intertrace.ai/install.ps1 | iex # Windows (PowerShell)
npm install -g intertrace # any OS with Node 18+- 1
itr connect
Signs in through the browser: itr shows a code and opens the activation page, an admin approves it, and the CLI receives its keys once. Codes expire after 10 minutes. Nobody copies keys. Name a tool (
itr connect claude-code) or connect every agent found on the machine. - 2
Hooks installed and verified
itr installs the decision and outcome hooks, runs the allow/deny probe, and prints PROTECTED or NOT protected. Restart the tools you connected.
- 3
Role and learning
The agent starts with the Coding agent role and a learning period. Change it on the agent's page.
- 4
itr doctor
Re-checks keys, the hook path end to end and each tool's setup any time.
itr disconnectremoves only itr's own entries.
Capability matrix
"Fail-closed (host)" is what the host does when the hook process itself cannot start, crashes or times out. Inside itr, every failure it can see is a deny on every host (see Failure contract below).
| Host | Pre-tool hook | Ask in the editor | Post-tool evidence | Fail-closed (host) |
|---|---|---|---|---|
| Claude Code | PreToolUse, matcher *, in ~/.claude/settings.json (or managed settings with --managed) | Yes, for developer-level asks in an interactive session (any permission mode but dontAsk). Print mode and the SDKs keep the central approval. | PostToolUse / PostToolUseFailure (succeeded or failed) | Yes ("onFailure": "block") |
| Cursor | beforeShellExecution, beforeMCPExecution, beforeReadFile in ~/.cursor/hooks.json | Shell and MCP: as Claude Code. File reads: allow or deny only. | afterShellExecution / afterMCPExecution / afterFileEdit (executed, no exit status) | Yes ("failClosed": true) |
| Codex CLI | PreToolUse, matcher *, in $CODEX_HOME/hooks.json (default ~/.codex). Runs only after you trust it in Codex's /hooks | No: an ask is a deny. | PostToolUse (executed; needs its own trust) | No: Codex lets a call run on a timeout, a hook that cannot start, or an exit code other than 2. itr denies with exit 2 and answers before the timeout. |
| GitHub Copilot CLI | preToolUse in its own file, $COPILOT_HOME/hooks/intertrace.json (default ~/.copilot) | No: an ask is a deny. | None installed yet | Partly: a crash or non-zero exit denies; a timeout lets the call run. itr denies with exit 2 and answers before the timeout. |
| OpenCode | An itr plugin, ~/.config/opencode/plugins/intertrace.js (or under $XDG_CONFIG_HOME), on tool.execute.before for every tool | No: an ask is a deny. | tool.execute.after (executed) | Yes: the plugin blocks unless itr answers allow. A plugin from the project runs after itr's and can change the arguments. |
Every deciding hook gets a 600 s host timeout, and itr answers by 540 s from the moment the hook starts, so an undecided call is denied before the host gives up.
Who answers an ask
A host's own prompt never stands in for a central approval. The hook answers allow or deny, and answers ask only when every cause of the ask is developer-level (the learning period, download-and-run, a role's privileged ask on a developer-judgeable call such as reading a project's .env), outside production, and the host can show the prompt (interactive Claude Code, Cursor shell and MCP). Before that, an intent check reads the person's latest request and lets a call they plainly asked for run. A yes is remembered for the same call in the same session.
Organization-level asks (approval rules, guardrails, the ask list, connections, payments and admin changes, outbound messages, production) always wait for a person in Intertrace. An organization can turn editor asks off in Policies → Approvals.
While a call waits, itr shows a desktop notification with the approval's link (set INTERTRACE_HOOK_NOTIFY=off to turn it off). If nobody decides in time, the deny names the same link; running the call again in the session waits on that same approval instead of opening another.
Prompt hooks
itr also installs a prompt hook on each host (Claude Code and Codex UserPromptSubmit, Cursor beforeSubmitPrompt, Copilot userPromptSubmitted, OpenCode chat.message). It keeps the person's latest request in an owner-only file on the device for the intent check. It never holds a prompt and prints nothing (except the answer Cursor requires). Intertrace stores the intent verdict, never the request text.
Codex trust and itr doctor
Codex runs a hook only after the user trusts it in /hooks, and itr never writes trust. Doctor reads Codex's config.toml:
- Untrusted, turned off (
enabled = false) or all hooks off ([features] hooks = false): NOT protected. - Trusted: shown as "trust not verifiable" and the tool as NOT verified, never PROTECTED, because itr cannot recompute Codex's trust hash. Open
/hooksin Codex to confirm.
Doctor runs Codex hooks through $SHELL -lc, as Codex does, so a login profile that prints, exits or redirects shows up. It also fails on a stale, edited or narrowed entry, a missing binary, a missing onFailure / failClosed, an OpenCode plugin that differs from the one itr wrote, and disableAllHooks (Claude Code, Copilot CLI).
In the dashboard, the Estate coding agents card shows one of three states:
- Protected · verified: the latest verified run.
- Not protected · check failed: with the reason.
- Connected · not verified: hook traffic exists but no verification has run.
Failure contract
- Intertrace unreachable, a revoked or expired key, a server error or an unreadable answer: deny, except workspace reads (never credential paths such as ~/.ssh, .env or .aws/credentials).
- No runtime key for the tool on this device: deny, except workspace reads. Run
itr connect <tool>. - An approval not decided by itr's deadline, or expired: deny, with the approval's link.
- Offline policy
deny(INTERTRACE_HOOK_OFFLINE=deny): deny everything. - Failures are written to a local hook failure log that itr doctor shows.
A rule that requires the agent's reason blocks on every host with approval.justification_required, because native hooks carry no per-call reason.
The boundary: managed settings
Intertrace blocks an agent that edits its own hook settings, sets disableAllHooks, runs itr disconnect, or starts another agent with hooks or permission checks off. These checks read commands, so they are defense in depth, not a boundary: code can always build a path some other way.
The boundary is the host's managed location, which a user cannot edit: Claude Code managed settings (sudo itr connect claude-code --managed), Codex managed hooks in requirements.toml, Copilot CLI policy hooks, OpenCode managed config, or Cursor's hooks.json deployed through MDM. OS file permissions that make the user's hook files read-only to the agent also work.
If someone removes a hook, the post-tool hook reports tools that ran with no decision, which opens a high-severity Work finding. A tool that ran although Intertrace denied it opens one too.
Per host: Claude Code · Cursor · Codex · OpenCode · Control plane.