Supported Agents
Supported Agents
Section titled “Supported Agents”RTK supports all major AI coding agents across 3 integration tiers.
How it works
Section titled “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 up to 90% fewer bash output bytesSupported agents
Section titled “Supported agents”| Agent | Integration tier | Can rewrite transparently? |
|---|---|---|
| Claude Code | Shell hook (PreToolUse) | Yes |
| Trae | Rust binary (PreToolUse, matcher RunCommand) | Yes |
| VS Code Copilot Chat | Shell hook (PreToolUse) | Yes |
| GitHub Copilot CLI | Shell hook (PreToolUse) | Yes |
| Cursor | Shell hook (preToolUse) | Yes |
| Gemini CLI | Rust binary (BeforeTool) | Yes |
| OpenCode | TypeScript plugin (tool.execute.before) | 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 | Shell hook (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 | Rules file (prompt-level) | N/A |
| 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.
Installation by agent
Section titled “Installation by agent”Claude Code
Section titled “Claude Code”rtk init --global # installs hook + patches settings.jsonRestart Claude Code. Verify:
rtk init --show # shows hook statusrtk 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 traertk init --uninstall --global --agent traeUninstall removes only RTK-managed hook entries; unrelated Trae hooks and configuration are preserved.
Cursor
Section titled “Cursor”rtk init --global --agent cursorRestart Cursor. The hook uses preToolUse with Cursor’s updated_input format.
GitHub Copilot (VS Code Chat + CLI)
Section titled “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 for Copilot CLI’s native schema. Copilot CLI treats PreToolUse/preToolUse as independent hooks and runs both sequentially for the same tool call — a redundant process spawn with no behavioral benefit, since Copilot CLI honors the single PreToolUse schema on its own. Re-run rtk init --copilot (or --global --copilot) to upgrade an existing install to the single-hook config.
Uninstall:
rtk init --uninstall --copilotrtk init --uninstall --global --copilotRemoves 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
Section titled “Gemini CLI”rtk init --global --geminiOpenCode
Section titled “OpenCode”rtk init --global --opencodeCreates ~/.config/opencode/plugins/rtk.ts. Uses the tool.execute.before hook.
# Project-local (default)rtk init --agent pi
# Global — all projectsrtk init --agent pi --globalCreates .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 pirtk init --uninstall --agent pi --globalRemoves 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)
Section titled “Oh My Pi (OMP)”# Project-local (default)rtk init --agent omp
# Global — all projectsrtk init --agent omp --globalCreates .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 omprtk init --uninstall --agent omp --globalRemoves 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
Section titled “OpenClaw”openclaw plugins install ./openclawPlugin in the openclaw/ directory. Uses the before_tool_call hook, delegates to rtk rewrite.
Hermes
Section titled “Hermes”rtk init --agent hermesCreates ~/.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 Rust through rtk rewrite. The repository source and tests for that adapter live in hooks/hermes/; only installed runtime files use the ~/.hermes/plugins/rtk-rewrite/ path.
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
Section titled “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 droidrtk init --uninstall --agent droidRemoves only RTK’s hook entry; other hooks and settings are untouched.
Cline / Roo Code
Section titled “Cline / Roo Code”rtk init --agent cline # creates .clinerules in current projectCline reads .clinerules as custom instructions. RTK adds guidance telling Cline to prefer rtk <cmd> over raw commands.
Windsurf
Section titled “Windsurf”rtk init --global --agent windsurf # creates .windsurfrules in current projectCodex CLI
Section titled “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 integrationrtk init --global --codex --uninstall # remove user-global integrationRestart 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
Section titled “Kilo Code”rtk init --agent kilocode # creates .kilocode/rules/rtk-rules.md in current projectKilo Code reads .kilocode/rules/ as custom instructions. RTK adds guidance telling Kilo Code to prefer rtk <cmd> over raw commands.
Google Antigravity
Section titled “Google Antigravity”rtk init --agent antigravity # creates .agents/rules/antigravity-rtk-rules.md in current projectAntigravity reads .agents/rules/ as custom instructions. RTK adds guidance telling Antigravity to prefer rtk <cmd> over raw commands.
Mistral Vibe
Section titled “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 fileInstalls 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 yet 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 belt-and-suspenders 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 --uninstallStrips 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
Section titled “Integration tiers explained”| Tier | Mechanism | How rewrites work |
|---|---|---|
| Full hook | Shell script or Rust binary, 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, Antigravity) rely on the model following instructions. Full hook integrations (Claude Code, Trae, Cursor, Gemini, Codex, Factory Droid) 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
Section titled “Windows support”The shell hook (rtk-rewrite.sh) requires a Unix shell. On native Windows:
rtk init -gautomatically falls back to CLAUDE.md injection mode (prompt-level instructions)- Filters work normally (
rtk cargo test,rtk git status) - Auto-rewrite does not work — the AI assistant is instructed to use RTK but commands are not intercepted
For full shell-hook support on Windows, use WSL. Inside WSL, agents with shell hook integration (Claude Code, Cursor, Gemini) work identically to Linux. Native Rust hook integrations such as Trae do not depend on rtk-rewrite.sh.
Graceful degradation
Section titled “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
Section titled “Override: disable RTK for one command”RTK_DISABLED=1 git status # runs raw git status, no rewriteOr exclude commands permanently in ~/.config/rtk/config.toml:
[hooks]exclude_commands = ["git rebase", "git cherry-pick"]