Skip to content

Latest commit

 

History

History
359 lines (239 loc) · 22.5 KB

supported-agents.md

File metadata and controls

359 lines (239 loc) · 22.5 KB
title Supported Agents
description How to integrate RTK with Claude Code, Cursor, Copilot, Cline, Windsurf, Codex, OpenCode, Hermes, Kilo Code, Antigravity, Factory Droid, Mistral Vibe, and Trae
sidebar
order
3

Supported Agents

RTK supports all major AI coding agents across 3 integration tiers.

How it works

Each agent integration intercepts CLI commands before execution and rewrites them to their RTK equivalent. The agent runs rtk cargo test instead of cargo test, sees filtered output, and reads up to 90% fewer bash output bytes — without any change to your workflow.

All rewrite logic lives in the RTK binary (rtk rewrite). Agent hooks are thin delegates that parse the agent-specific JSON format and call rtk rewrite for the actual decision.

Agent runs "cargo test"
  -> Hook intercepts (PreToolUse / plugin event)
  -> Calls rtk rewrite "cargo test"
  -> Returns "rtk cargo test"
  -> Agent executes filtered command
  -> LLM reads the condensed output

Supported agents

Agent Integration tier Can rewrite transparently?
Claude Code Rust binary (PreToolUse, rtk hook claude) Yes
Trae Rust binary (PreToolUse, matcher RunCommand) Yes
VS Code Copilot Chat Rust binary (PreToolUse, rtk hook copilot) Yes
GitHub Copilot CLI Rust binary (PreToolUse, rtk hook copilot) Yes
Cursor Rust binary (preToolUse, rtk hook cursor) Yes
Gemini CLI Rust binary (BeforeTool) Yes
OpenCode TypeScript plugin (execute.before in 2.0, tool.execute.before in 1.x >= 1.18.29) Yes
OpenClaw TypeScript plugin (before_tool_call) Yes
Pi TypeScript extension (tool_call event) Yes
Oh My Pi (OMP) TypeScript extension (tool_call event, shared with Pi) Yes
Hermes Python plugin (terminal command mutation) Yes
Factory Droid Rust binary (PreToolUse, matcher Execute) Yes
Cline / Roo Code Rules file (prompt-level) N/A
Windsurf Rules file (prompt-level) N/A
Codex CLI Rust binary (PreToolUse) Yes
Kilo Code Rules file (prompt-level) N/A
Google Antigravity Rust binary (PreToolUse plugin) Yes
Mistral Vibe Rust binary (pre_tool) Yes

Agents that rewrite transparently receive the awareness file selected by awareness.level in config.toml (default says nothing about RTK). Rules-file agents cannot rewrite, so the agent must prefix rtk itself; they always receive the full awareness file and rtk init says so. See Configuration.

:::note[How much of a pipeline reaches your agent?] Command rewriting works on almost every agent here. Compressing tool output after the fact depends on whether the agent lets a hook replace it — eight do. See Agent Coverage for the per-agent table. :::

Installation by agent

Claude Code

rtk init --global    # installs hook + patches settings.json

Restart Claude Code. Verify:

rtk init --show    # shows hook status

Trae

rtk init --agent trae             # project-scoped (.trae/hooks.json)
rtk init --global --agent trae    # user-scoped (~/.trae/hooks.json)

Global installation also updates ~/.trae-cn/hooks.json when the .trae-cn directory already exists. Both modes install the native rtk hook trae command as a PreToolUse hook for RunCommand.

Configuration files and hook input may include a UTF-8 BOM. Existing rtk.exe hook trae registrations are also recognized during install and uninstall.

If a global install fails while writing a target, the error lists any targets already updated. After fixing the reported filesystem error, rerun the install; completed targets will not receive duplicate hooks.

The hook returns hookSpecificOutput.updatedInput, preserving fields such as description and timeout while replacing only command. It deliberately omits permissionDecision, leaving command approval to Trae. Commands containing command substitution, process substitution, heredocs, or file-target redirects are left unchanged so Trae evaluates the original command natively.

Uninstall:

rtk init --uninstall --agent trae
rtk init --uninstall --global --agent trae

Uninstall removes only RTK-managed hook entries; unrelated Trae hooks and configuration are preserved.

Cursor

rtk init --global --agent cursor

Restart Cursor. The hook uses preToolUse with Cursor's updated_input format.

GitHub Copilot (VS Code Chat + CLI)

rtk init --copilot            # project-scoped (.github/hooks/)
rtk init --global --copilot   # user-scoped (~/.copilot/hooks/, respects $COPILOT_HOME)

Project-scoped writes .github/hooks/rtk-rewrite.json — a single PreToolUse entry shared by both hosts, each getting transparent rewrite via updatedInput — plus the RTK block in .github/copilot-instructions.md. User-scoped writes the same hook config to ~/.copilot/hooks/rtk-rewrite.json and the RTK block to ~/.copilot/copilot-instructions.md (both respect $COPILOT_HOME if set).

Earlier rtk versions also registered a second, camelCase preToolUse entry, which made Copilot CLI run the hook twice per tool call. Re-run rtk init --copilot (or --global --copilot) to upgrade an existing install to the single-hook config.

Uninstall:

rtk init --uninstall --copilot
rtk init --uninstall --global --copilot

Removes only RTK's hook file (and, for project, the RTK block in copilot-instructions.md). Other files in .github/hooks/ or ~/.copilot/hooks/ and your own instruction content are untouched.

Gemini CLI

rtk init --global --gemini

OpenCode

rtk init --global --opencode

Installs the Claude Code setup and creates ~/.config/opencode/plugins/rtk.ts. The plugin registers both OpenCode 2.0 (execute.before) and OpenCode 1.x (tool.execute.before) hooks, in one default export carrying both entrypoints. That shape is supported from OpenCode 1.18.29, the floor OpenCode documents for it; with an older OpenCode, when it can read opencode --version, rtk init writes nothing and says so.

Pi

# Project-local (default)
rtk init --agent pi

# Global — all projects
rtk init --agent pi --global

Creates .pi/extensions/rtk.ts (local) or ~/.pi/agent/extensions/rtk.ts (global). Pi auto-discovers extensions from both paths on startup. The global path follows PI_CODING_AGENT_DIR when set; OMP uses that same variable. When the paths alias, RTK records the agent(s) it installed in an adjacent hidden .rtk-agents state file so shared-file warnings are based on ownership rather than path equality alone.

Installation updates only the current or a known historical RTK extension. If the managed path contains modified or unrelated content, RTK asks before overwriting it; use --auto-patch to approve without prompting or --no-patch to leave it unchanged. A declined protected update, including --no-patch, exits nonzero so automation can detect that no install occurred. --dry-run reports the prompt without changing files. LF and CRLF line endings are treated as the same stock extension.

Uninstall:

rtk init --uninstall --agent pi
rtk init --uninstall --agent pi --global

Removes only the current or known historical stock Pi extension. If the file contains modified RTK content, a normal uninstall aborts without deleting it, while --dry-run previews that refusal; unreadable content is left in place and causes a normal uninstall to exit nonzero, while --dry-run reports it and succeeds. Unrelated content is left in place. LF and CRLF stock files are both recognized.

Oh My Pi (OMP)

# Project-local (default)
rtk init --agent omp

# Global — all projects
rtk init --agent omp --global

Creates .omp/extensions/rtk.ts (local) or ~/.omp/agent/extensions/rtk.ts (global). OMP loads the same extension file as Pi through its legacy-pi-compat layer, so both agents share rtk.ts. The global path follows PI_CODING_AGENT_DIR, which OMP also honors for its agent directory.

When the Pi and OMP targets in either project or global scope resolve to one file, RTK records whether Pi, OMP, or both agents were installed for that alias in an adjacent hidden .rtk-agents state file. A valid sidecar is authoritative. Missing or unreadable state is treated as uncertain: RTK warns and proceeds without using a heuristic to claim sole ownership. Uninstalling a definitively shared project or global file asks before removing it, so confirm that neither agent should use it first (or pass --auto-patch to approve). An uncertain legacy or corrupt-state uninstall warns and proceeds; a declined definitive shared uninstall, including --no-patch, exits nonzero. --dry-run remains a successful preview. RTK currently targets OMP's default profile and .omp project directory; named OMP profiles and custom PI_CONFIG_DIR locations are not auto-detected.

Installation updates only the current or a known historical RTK extension. If the managed path contains modified or unrelated content, RTK asks before overwriting it; use --auto-patch to approve without prompting or --no-patch to leave it unchanged. A declined protected update, including --no-patch, exits nonzero so automation can detect that no install occurred. --dry-run reports the prompt without changing files. LF and CRLF line endings are treated as the same stock extension.

Uninstall:

rtk init --uninstall --agent omp
rtk init --uninstall --agent omp --global

Removes only the current or known historical stock OMP extension. If the file has been modified after install, a normal uninstall aborts with a message instead of removing it, while --dry-run previews that refusal; unreadable content is left in place and causes a normal uninstall to exit nonzero, while --dry-run reports it and succeeds. Unrelated content is left in place. When Pi and OMP paths in either scope resolve to the same file and a valid sidecar records both agents, uninstall asks before removing the shared file; use --auto-patch to approve or --no-patch to keep it. Missing or unreadable ownership state warns and proceeds without definitive shared-file protection. A declined definitive shared uninstall exits nonzero so scripts can detect that the file remains.

OpenClaw

openclaw plugins install ./openclaw

Plugin in the openclaw/ directory. Uses the before_tool_call hook, delegates to rtk rewrite.

Permissions. RTK keeps the deny gate; OpenClaw owns approval. The plugin runs rtk rewrite with RTK_REWRITE_HOST=openclaw, which tells RTK that this host applies its own exec policy (tools.exec.mode, security, ask) to whatever the hook returns. RTK therefore does not prompt for a command that matched no rule, instead of raising a second approval derived from Claude Code's settings.json on a runtime that never opted into it (#3908).

A command matching a permissions.deny rule in those same Claude Code settings files is still refused, and the plugin blocks the tool call — naming the host only relaxes a default ask. As in Claude Code, a deny or ask rule matches the command as written and the command behind any leading assignment or wrapper (HUSKY=0, timeout 30, nohup, command, ...), each layer in turn, but not every way of invoking the program (Bash(git push *) does not stop git -C . push or env -i git push), so a deny rule is not a security boundary. Allow rules match the command as written. A command matching a permissions.ask rule you wrote still prompts when RTK rewrites it, because RTK keeps returning exit 3 for it. Commands containing a command substitution or a redirect to a file are never rewritten, on any host.

The exec tool's own checks see the rewritten command. OpenClaw carries hook adjustments forward into the parameters passed to the exec tool, so tools.exec.mode, tools.exec.security, tools.exec.ask and the exec-approvals allowlist are all matched against rtk git push, not git push; write those rules against the rtk form. That was already true before the permission change. A trusted tool policy (api.registerTrustedToolPolicy(...)) is the exception: OpenClaw runs trusted policies before ordinary before_tool_call hooks, so one of those still sees the original command.

No minimum rtk version: an rtk that predates RTK_REWRITE_HOST ignores it and keeps its previous behaviour, which is a prompt rather than a missing gate — an older rtk prompts for more commands, since it cannot collapse the default ask.

Hermes

rtk init --agent hermes

Creates ~/.hermes/plugins/rtk-rewrite/ and enables it through plugins.enabled in the Hermes config. Hermes loads Python plugins, so the plugin entrypoint is Python, but it is only a thin adapter. It mutates the Hermes terminal tool command before execution and delegates all rewrite decisions to rtk rewrite.

The plugin fails open. If rtk is missing at load time, the hook is not registered. If rtk rewrite errors, the tool is not terminal, the payload has no string command, or the plugin raises an exception, Hermes runs the original command unchanged. The same rtk rewrite limitations apply: already-prefixed rtk commands, compound shell commands, heredocs, and commands without filters are not rewritten.

Factory Droid

rtk init -g --agent droid    # user-scoped (~/.factory/hooks.json)
rtk init --agent droid       # project-scoped (.factory/hooks.json, commit to share)

Installs a PreToolUse hook (matcher Execute) into Droid's canonical hooks.json — falling back to the hooks key of settings.json only when that file already carries live PreToolUse hooks. Respects $FACTORY_HOME_OVERRIDE.

RTK honors Droid's own permission lists, never another agent's settings. Commands matching an explicit commandDenylist or commandBlocklist entry — read from all four settings scopes (~/.factory/settings.json, ~/.factory/settings.local.json, .factory/settings.json, .factory/settings.local.json) — are left untouched so Droid's native confirmation or block fires on the original command. Every other command is rewritten via updatedInput with no permission decision: Droid's native flow (allowlist, autonomy level, other hooks) decides on the rewritten command. To auto-run rewritten read-only commands, add rtk-prefixed entries (e.g. rtk git status) to your commandAllowlist.

Uninstall:

rtk init --uninstall -g --agent droid
rtk init --uninstall --agent droid

Removes only RTK's hook entry; other hooks and settings are untouched.

Cline / Roo Code

rtk init --agent cline    # creates .clinerules in current project

Cline reads .clinerules as custom instructions. RTK adds guidance telling Cline to prefer rtk <cmd> over raw commands.

Windsurf

rtk init --global --agent windsurf    # creates .windsurfrules in current project

Codex CLI

rtk init --codex           # project-scoped (.codex/hooks.json + AGENTS.md)
rtk init --global --codex  # user-global ($CODEX_HOME or ~/.codex/)
rtk init --codex --uninstall           # remove project-scoped integration
rtk init --global --codex --uninstall  # remove user-global integration

Restart Codex after installation. Project-scoped hooks must be trusted when Codex prompts. The native rtk hook codex processor rewrites supported Bash commands through PreToolUse.updatedInput; Codex then applies its normal approval and sandbox checks to the rewritten command.

Project-scoped install writes RTK.md to the project root, a name RTK does not own there, so it marks the files it wrote. An RTK.md is RTK's when it carries that marker, when it opens with the heading RTK wrote before the marker existed, or when it is byte-for-byte one of the payloads RTK shipped in between: install replaces it and uninstall removes it. Any other RTK.md is yours — install moves it to RTK.md.bak (numbered if that name is taken) and says so, and uninstall keeps it and tells you where it is. In global scope RTK.md lives in $CODEX_HOME and is always RTK's.

Project-scoped install also refuses, without writing anything, when .codex/hooks.json or the hooks.json.bak it would write beside it resolves outside the project through a symlink, since registering a hook there would run commands from a directory you never named. Uninstall leaves such a hook registered rather than reaching outside for it, and says so. Use the global scope, with $CODEX_HOME set if you want a different directory, to configure Codex outside the project.

AGENTS.md and RTK.md are not restricted this way, and git stores symlinks, so a repository you clone can ship either as a link pointing outside the clone.

A symlinked AGENTS.md is followed and left in place: install appends its @RTK.md line to whatever the link names, wherever that is, and the file it rewrites ends up owned by you and readable only by you. That line is inert text, unlike .codex/hooks.json, which registers a hook that runs shell commands.

A symlinked RTK.md depends on what it points at. If the target is not one RTK wrote, the link itself is moved to RTK.md.bak and a fresh file takes its place, so nothing outside is touched. If the target is one RTK wrote — a shared or global RTK.md, say — install follows the link and rewrites that file in full.

If you install RTK into repositories you have not read, check what AGENTS.md and RTK.md are first.

Kilo Code

rtk init --agent kilocode    # creates .kilocode/rules/rtk-rules.md in current project

Kilo Code reads .kilocode/rules/ as custom instructions. RTK adds guidance telling Kilo Code to prefer rtk <cmd> over raw commands.

Google Antigravity (CLI, IDE & 2.0)

rtk init --agent antigravity          # workspace-scoped (<repo>/.agents/plugins/rtk/)
rtk init -g --agent antigravity       # machine-scoped (~/.gemini/config/plugins/rtk/)

Installs an Antigravity plugin bundle: hooks.json maps PreToolUse on run_command to the native rtk hook antigravity binary, and rules/AGENTS.md carries the awareness file selected by awareness.level. Before any command executes, RTK rewrites the tool call arguments in place using overwrite.CommandLine.

Antigravity checks permissions after lifecycle hooks rewrite a command. If you enforce command allowlists, ensure permitted commands include rtk (e.g. command(rtk git status) or command(rtk *)).

Uninstall:

rtk init --agent antigravity --uninstall       # workspace
rtk init -g --agent antigravity --uninstall    # global

Mistral Vibe

rtk init -g --agent vibe                # user-scoped (~/.vibe/hooks.toml)
rtk init -g --agent vibe --hook-only    # skip the ~/.vibe/prompts/rtk.md prompt file

Installs a pre_tool hook entry (match = "bash", command = "rtk hook vibe", strict = false) into ~/.vibe/hooks.toml, following the contract at docs.mistral.ai/vibe/code/cli/hooks. Vibe invokes the native rtk hook vibe binary before every bash tool call; RTK reads Vibe's stdin JSON payload and emits {"hook_specific_output": {"tool_input": {"command": "rtk ..."}}} to rewrite the command in place. The Vibe UI surfaces [rtk-rewrite] rtk: rewrote to \…`via RTK'ssystem_message` field so the rewrite is visible.

Unlike Droid, Vibe does not expose a denylist / allowlist surface in hooks.toml for RTK to honor. RTK therefore rewrites every bash command it knows how to compress and defers to Vibe's own permission prompt on the rewritten command; commands RTK doesn't handle pass through unchanged. strict = false ensures a hook crash degrades to a warning rather than blocking the tool call.

Alongside the hook, RTK drops a system prompt at ~/.vibe/prompts/rtk.md describing the RTK conventions to Vibe as a fallback. Use --hook-only to skip it.

Install is global-only (Vibe's hook registry is user-scoped). Re-running the installer is a no-op; the RTK entry is detected by its name = "rtk-rewrite" field and never duplicated.

Uninstall:

rtk init -g --agent vibe --uninstall

Strips only RTK's [[hooks]] block and the ~/.vibe/prompts/rtk.md file. Any other user-declared hooks in hooks.toml are preserved byte-for-byte. hooks.toml is removed only when the RTK entry was the sole content.

Integration tiers explained

Tier Mechanism How rewrites work
Full hook Rust binary command (or a thin wrapper around one), intercepts via agent API Transparent — agent never sees the raw command
Plugin TypeScript, JavaScript, or Python in agent's plugin system Transparent, in-place mutation when the agent allows it
Rules file Prompt-level instructions Guidance only — agent is told to prefer rtk <cmd>

Rules file integrations (Cline, Windsurf, Kilo Code) rely on the model following instructions. Full hook integrations (Claude Code, Trae, Cursor, Gemini, Codex, Factory Droid, Antigravity) apply rewrites before execution whenever RTK supports and can safely attest the command. Plugin integrations (OpenCode, Pi, Hermes) use in-place mutation via the agent's extension or plugin API.

Windows support

Since v0.37.2 the hooks for Claude Code, Cursor, Copilot, Codex, Trae, Factory Droid and Mistral Vibe are native binary commands (rtk hook <agent>), so auto-rewrite works on native Windows — no Unix shell, bash or jq required. rtk init -g installs the native hook on Windows exactly as on Linux and macOS, and adds it to Claude Code's settings.json once you answer y to the prompt (or pass --auto-patch).

The Gemini CLI hook is a small bash wrapper around rtk hook gemini, so it needs a bash available; WSL behaves identically to Linux.

Setups created before v0.37.2 used CLAUDE.md injection with no hook, or the legacy rtk-rewrite.sh shell hook. Re-run rtk init -g to migrate them to the native binary hook.

Graceful degradation

Hooks never block command execution. If RTK is missing, the hook exits cleanly and the raw command runs unchanged:

  • RTK binary not found: warning to stderr, exit 0
  • Invalid JSON input: pass through unchanged
  • RTK version too old: warning to stderr, exit 0
  • Filter logic error: fallback to raw command output

Override: disable RTK for one command

RTK_DISABLED=1 git status    # runs raw git status, no rewrite

Or exclude commands permanently in ~/.config/rtk/config.toml:

[hooks]
exclude_commands = ["git rebase", "git cherry-pick"]