Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ rtk init --agent kilocode # Kilo Code
rtk init --agent antigravity # Google Antigravity
rtk init -g --agent pi # Pi
rtk init --agent hermes # Hermes
rtk init -g --agent vibe # Mistral Vibe (requires Vibe >= 2.15.0)

# 2. Restart your AI tool, then test
git status # Automatically rewritten to rtk git status
Expand Down Expand Up @@ -353,7 +354,7 @@ rtk git status

## Supported AI Tools

RTK supports 14 AI coding tools. Each integration rewrites shell commands to `rtk` equivalents for 60-90% token savings where the agent supports command interception.
RTK supports 15 AI coding tools. Each integration rewrites shell commands to `rtk` equivalents for 60-90% token savings where the agent supports command interception.

| Tool | Install | Method |
|------|---------|--------|
Expand All @@ -369,7 +370,7 @@ RTK supports 14 AI coding tools. Each integration rewrites shell commands to `rt
| **OpenClaw** | `openclaw plugins install ./openclaw` | Plugin TS (before_tool_call) |
| **Pi** | `rtk init -g --agent pi` (global) | TypeScript extension (tool_call) |
| **Hermes** | `rtk init --agent hermes` | Python plugin adapter (terminal command mutation via `rtk rewrite`) |
| **Mistral Vibe** | Planned ([#800](https://github.com/rtk-ai/rtk/issues/800)) | Blocked on upstream |
| **Mistral Vibe** | `rtk init -g --agent vibe` | before_tool hook (experimental, requires Vibe >= 2.15.0) |
| **Kilo Code** | `rtk init --agent kilocode` | .kilocode/rules/rtk-rules.md (project-scoped) |
| **Google Antigravity** | `rtk init --agent antigravity` | .agents/rules/antigravity-rtk-rules.md (project-scoped) |

Expand Down
32 changes: 27 additions & 5 deletions docs/guide/getting-started/supported-agents.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
---
title: Supported Agents
description: How to integrate RTK with Claude Code, Cursor, Copilot, Cline, Windsurf, Codex, OpenCode, Hermes, Kilo Code, and Antigravity
description: How to integrate RTK with Claude Code, Cursor, Copilot, Cline, Windsurf, Codex, OpenCode, Hermes, Pi, Mistral Vibe, Kilo Code, and Antigravity
sidebar:
order: 3
---

# Supported Agents

RTK supports all major AI coding agents across 3 integration tiers. Mistral Vibe support is planned.
RTK supports all major AI coding agents across 3 integration tiers.

## How it works

Expand Down Expand Up @@ -37,12 +37,12 @@ Agent runs "cargo test"
| OpenClaw | TypeScript plugin (`before_tool_call`) | Yes |
| Pi | TypeScript extension (`tool_call` event) | Yes |
| Hermes | Python plugin (`terminal` command mutation) | Yes |
| Mistral Vibe | Shell hook (`before_tool`) | Yes |
| Cline / Roo Code | Rules file (prompt-level) | N/A |
| Windsurf | Rules file (prompt-level) | N/A |
| Codex CLI | AGENTS.md instructions | N/A |
| Kilo Code | Rules file (prompt-level) | N/A |
| Google Antigravity | Rules file (prompt-level) | N/A |
| Mistral Vibe | Planned ([#800](https://github.com/rtk-ai/rtk/issues/800)) | Pending upstream |

## Installation by agent

Expand Down Expand Up @@ -174,9 +174,31 @@ rtk init --agent antigravity # creates .agents/rules/antigravity-rtk-rules.md

Antigravity reads `.agents/rules/` as custom instructions. RTK adds guidance telling Antigravity to prefer `rtk <cmd>` over raw commands.

### Mistral Vibe (planned)
### Mistral Vibe

Support is blocked on upstream `BeforeToolCallback` ([mistral-vibe#531](https://github.com/mistralai/mistral-vibe/issues/531)). Tracked in [#800](https://github.com/rtk-ai/rtk/issues/800).
**Installation:**
```bash
rtk init -g --agent vibe
```

**Requirements:**
- Mistral Vibe >= 2.15.0 (when `before_tool` hooks were introduced)
- Enable experimental hooks in your Vibe config:
```toml
# ~/.vibe/config.toml or .vibe/config.toml
enable_experimental_hooks = true
```

**How it works:** Uses Vibe's experimental `before_tool` hook system. The hook intercepts `bash` and `run_shell_command` tool calls, delegates to `rtk rewrite` for command decisions, and returns rewritten commands via JSON stdout.

**Files installed:**
- `~/.vibe/hooks/rtk-hook-vibe.sh` — Shell script hook
- `~/.vibe/hooks/hooks.toml` — Hook configuration

**Uninstall:**
```bash
rtk init -g --uninstall --agent vibe
```

## Integration tiers explained

Expand Down
32 changes: 32 additions & 0 deletions hooks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Each agent subdirectory has its own README with hook-specific details:
- **[`opencode/`](opencode/README.md)** — TypeScript plugin, `zx` library, `tool.execute.before` event, in-place mutation
- **[`pi/`](pi/README.md)** — TypeScript extension, `tool_call` event, `isToolCallEventType` guard, in-place mutation, `~/.pi/agent/extensions/`
- **[`hermes/`](hermes/README.md)** — Python plugin, `pre_tool_call` hook, in-place terminal command mutation
- **[`vibe/`](vibe/README.md)** — Shell hook, `before_tool` hook, Mistral Vibe experimental hooks (requires Vibe >= 2.15.0)

## Supported Agents

Expand All @@ -58,6 +59,7 @@ Each agent subdirectory has its own README with hook-specific details:
| OpenCode | TypeScript plugin (`tool.execute.before`) | In-place mutation | Yes |
| Pi | TypeScript extension (`tool_call` event) | In-place mutation | Yes |
| Hermes | Python plugin (`pre_tool_call`) | In-place mutation | Yes |
| Mistral Vibe | Shell hook (`before_tool`) | Transparent rewrite | Yes (`hook_specific_output.tool_input`) |

## JSON Formats by Agent

Expand Down Expand Up @@ -180,6 +182,36 @@ if result.returncode in {0, 3} and rewritten and rewritten != command:
args["command"] = rewritten
```

### Mistral Vibe (Shell Hook)

**Input** (stdin):

```json
{
"session_id": "abc123",
"parent_session_id": null,
"transcript_path": "/path/to/transcript.jsonl",
"cwd": "/path/to/project",
"hook_event_name": "before_tool",
"tool_name": "bash",
"tool_call_id": "def456",
"tool_input": { "command": "git status" }
}
```

**Output** (stdout, when rewritten):

```json
{
"decision": "allow",
"hook_specific_output": {
"tool_input": { "command": "rtk git status" }
}
}
```

**No rewrite**: Empty stdout, exit code 0.

## Command Rewrite Registry

The registry (`src/discover/registry.rs`) handles command patterns across these categories:
Expand Down
105 changes: 105 additions & 0 deletions hooks/vibe/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# RTK Hook for Mistral Vibe

> Part of [`hooks/`](../README.md) — see also [`src/hooks/`](../../src/hooks/README.md) for installation code

## Design Intent

RTK's Mistral Vibe hook is a **rewrite-only token optimizer**. It intercepts Vibe tool calls (specifically `bash`/`run_shell_command`) and rewrites them to use RTK for 60-90% token savings.

**Permission gating is intentionally out of scope.** RTK does not block, confirm, or audit commands — that concern belongs to dedicated permission hooks. This separation keeps RTK's hook fast, predictable, and composable with other Vibe hooks.

## Specifics

- Shell script hook using Mistral Vibe's experimental `before_tool` hook system
- Requires `enable_experimental_hooks = true` in Vibe's `config.toml`
- Intercepts `bash` and `run_shell_command` tool calls
- Calls `rtk rewrite` as a subprocess; returns rewritten command via JSON stdout
- All rewrite logic lives in RTK's Rust `rtk rewrite` command (single source of truth)
- Installed via `rtk init --agent vibe` which creates `.vibe/hooks.toml`

## Installation

```bash
rtk init --agent vibe
```

This creates or updates `~/.vibe/hooks.toml` with the RTK hook configuration. The hook script itself lives at `~/.vibe/hooks/rtk-hook-vibe.sh`.

After installation, ensure your Vibe config has:

```toml
# ~/.vibe/config.toml or .vibe/config.toml
enable_experimental_hooks = true
```

Then restart Vibe.

## Uninstall

```bash
rtk init --uninstall --agent vibe
```

This removes the RTK hook entry from `~/.vibe/hooks.toml` and the hook script.

## How it works

Vibe's `before_tool` hook receives JSON on stdin describing the tool call, including `tool_name` and `tool_input`. The RTK hook:

1. Checks if the tool is `bash` or `run_shell_command`
2. Extracts the command from `tool_input.command`
3. Calls `rtk rewrite <command>` to check for RTK equivalents
4. Returns JSON with either:
- No output (exit 0) — pass through unchanged
- JSON with `hook_specific_output.tool_input` — rewritten command

All error paths exit 0 with no output (fail-open), ensuring commands always execute.

## Fail-open behavior

The hook does not block command execution. If anything goes wrong, Vibe runs the original command unchanged:

- `jq` not installed: warning to stderr, exit 0
- `rtk` not available in PATH: warning to stderr, exit 0
- `rtk` version too old (< 0.23.0): warning to stderr, exit 0
- Invalid JSON input: pass through unchanged
- `rtk rewrite` crashes: hook exits 0 (subprocess error ignored)

## Limitations

- Only `bash` and `run_shell_command` tool calls are rewritten
- Commands skipped by `rtk rewrite` stay unchanged (already prefixed with `rtk`, compound shell commands, heredocs, etc.)
- Requires Vibe 2.15.0+ (when `before_tool` hooks were introduced)
- Requires `enable_experimental_hooks = true` in Vibe config

## JSON Format

### Input (stdin)

```json
{
"session_id": "abc123",
"parent_session_id": null,
"transcript_path": "/path/to/transcript.jsonl",
"cwd": "/path/to/project",
"hook_event_name": "before_tool",
"tool_name": "bash",
"tool_call_id": "def456",
"tool_input": { "command": "git status" }
}
```

### Output (stdout, when rewritten)

```json
{
"decision": "allow",
"hook_specific_output": {
"tool_input": { "command": "rtk git status" }
}
}
```

### Output (no rewrite)

Empty stdout, exit code 0.
24 changes: 24 additions & 0 deletions hooks/vibe/hooks.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# RTK hook configuration for Mistral Vibe
# Place this file in ~/.vibe/hooks.toml or .vibe/hooks.toml
# Requires enable_experimental_hooks = true in config.toml
#
# This file is installed by: rtk init --agent vibe
# To uninstall: rtk init --uninstall --agent vibe

[[hooks]]
name = "rtk-rewrite"
type = "before_tool"
match = "bash" # Match bash tool calls
command = "rtk-hook-vibe.sh" # Path relative to hooks directory or absolute
timeout = 60.0 # seconds; default 60 for all hooks
strict = false # tool hooks only: turn failures into denials
description = "Rewrite bash commands to use RTK for 60-90% token savings"

[[hooks]]
name = "rtk-rewrite-shell"
type = "before_tool"
match = "run_shell_command" # Match run_shell_command tool calls (alternative name)
command = "rtk-hook-vibe.sh" # Path relative to hooks directory or absolute
timeout = 60.0
strict = false
description = "Rewrite shell commands to use RTK for 60-90% token savings"
122 changes: 122 additions & 0 deletions hooks/vibe/rtk-hook-vibe.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/usr/bin/env bash
# rtk-hook-version: 1
# RTK Mistral Vibe hook — rewrites bash commands to use rtk for token savings.
# Requires: rtk >= 0.23.0, jq, Mistral Vibe >= 2.15.0
#
# This is a thin delegating hook: all rewrite logic lives in `rtk rewrite`,
# which is the single source of truth (src/discover/registry.rs).
# To add or change rewrite rules, edit the Rust registry — not this file.
#
# Exit code protocol:
# 0 + empty stdout Pass through unchanged
# 0 + JSON stdout Structured response (rewrite/deny)
# Any non-zero Treated as hook failure (fail-open by Vibe)
#
# Vibe before_tool hook contract:
# - Receives JSON on stdin with tool_name, tool_input, etc.
# - Returns JSON on stdout with decision and hook_specific_output
# - Exit 0 means success, non-zero means hook failure

set -euo pipefail

# Fail-open: if jq is missing, warn and exit 0 (pass through)
if ! command -v jq &>/dev/null; then
echo "[rtk] WARNING: jq is not installed. Hook cannot rewrite commands. Install jq: https://jqlang.github.io/jq/download/" >&2
exit 0
fi

# Fail-open: if rtk is missing, warn and exit 0 (pass through)
if ! command -v rtk &>/dev/null; then
echo "[rtk] WARNING: rtk is not installed or not in PATH. Hook cannot rewrite commands. Install: https://github.com/rtk-ai/rtk#installation" >&2
exit 0
fi

# Version guard: rtk rewrite was added in 0.23.0.
# Cache the version check to avoid spawning multiple processes on every hook call.
CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}"
CACHE_FILE="$CACHE_DIR/rtk-hook-vibe-version-ok"
if [ ! -f "$CACHE_FILE" ]; then
RTK_VERSION_RAW=$(rtk --version 2>/dev/null || true)
RTK_VERSION=${RTK_VERSION_RAW#rtk }
RTK_VERSION=${RTK_VERSION%% *}
if [ -n "$RTK_VERSION" ]; then
IFS=. read -r MAJOR MINOR PATCH <<<"$RTK_VERSION"
# Require >= 0.23.0
if [ "$MAJOR" -eq 0 ] && [ "$MINOR" -lt 23 ]; then
echo "[rtk] WARNING: rtk $RTK_VERSION is too old (need >= 0.23.0). Upgrade: cargo install --git https://github.com/rtk-ai/rtk" >&2
exit 0
fi
fi
mkdir -p "$CACHE_DIR" 2>/dev/null || true
touch "$CACHE_FILE" 2>/dev/null || true
fi

# Read all stdin
INPUT=$(cat)

# Extract tool_name and tool_input.command
TOOL_NAME=$(jq -r '.tool_name // empty' <<<"$INPUT")
TOOL_INPUT=$(jq -c '.tool_input // empty' <<<"$INPUT")

# Only process bash and run_shell_command tools
# Vibe uses "bash" for the bash tool and "run_shell_command" for shell commands
if [ "$TOOL_NAME" != "bash" ] && [ "$TOOL_NAME" != "run_shell_command" ]; then
exit 0
fi

# Extract command from tool_input
CMD=$(jq -r '.command // empty' <<<"$TOOL_INPUT")

if [ -z "$CMD" ]; then
exit 0
fi

# Check for RTK_DISABLED override
if [ "${RTK_DISABLED:-0}" = "1" ]; then
exit 0
fi

# Delegate all rewrite logic to the Rust binary.
# rtk rewrite exits:
# 0 - rewrite found
# 1 - no RTK equivalent (pass through)
# 2 - deny rule matched (not used by RTK, pass through)
# 3 - ask rule matched (rewrite but ask user)
REWRITTEN=$(rtk rewrite "$CMD" 2>/dev/null || true)
EXIT_CODE=$?

# Handle exit codes
case $EXIT_CODE in
0)
# Rewrite found - use it
;;
1)
# No RTK equivalent - pass through
exit 0
;;
2)
# Deny rule matched - pass through (RTK doesn't use deny rules)
exit 0
;;
3)
# Ask rule matched - rewrite but we'll allow it (Vibe handles permission separately)
;;
*)
# Unexpected error - pass through
exit 0
;;
esac

# If rewritten is empty or same as original, pass through
if [ -z "$REWRITTEN" ] || [ "$REWRITTEN" = "$CMD" ]; then
exit 0
fi

# Return JSON response with rewritten command
# Vibe expects: decision (allow/deny), hook_specific_output.tool_input
jq -n --arg cmd "$REWRITTEN" '{
"decision": "allow",
"hook_specific_output": {
"tool_input": { "command": $cmd }
}
}'
1 change: 1 addition & 0 deletions hooks/vibe/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Test files for Vibe hook
Loading