Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
21a069a
feat(init): add --dry-run flag to preview changes without writing
hed0rah Apr 19, 2026
518b196
merge: resolve conflicts with develop (drop Windows cfg stubs)
hed0rah Apr 19, 2026
add1464
fix(tests): update init.rs test calls for dry_run parameter
hed0rah Apr 21, 2026
8b4a146
chore(init): suppress semgrep filesystem-deletion on dry-run-wrapped …
hed0rah Apr 25, 2026
98fe82d
refactor(init): introduce InitContext and centralize dry-run footer
hed0rah Apr 26, 2026
2f185a4
docs(init): document --dry-run in quick-start guide
hed0rah Apr 26, 2026
71d285f
feat(gradlew): add Gradle/gradlew support with streaming filters
kherembourg May 5, 2026
36ec02d
fix(gradlew): satisfy semgrep dynamic-command-execution rule
kherembourg May 6, 2026
024c4a6
refactor(gradlew): align with shared runner pattern
kherembourg May 6, 2026
9e3a5ae
fix(gradlew): use resolved_command for system gradle fallback
kherembourg May 6, 2026
833026b
Merge pull request #312 from kherembourg/feat/gradlew-android-support
aeppling May 6, 2026
f0136af
Update telemetry documentation link to use 'master' branch
sadikkuzu May 7, 2026
ed161b0
fix(dotnet): move build/test/restore status line to the bottom
F0rty-Tw0 Apr 28, 2026
106305b
fix(dotnet): 🐛 format build/test/restore output sections
F0rty-Tw0 May 4, 2026
271bc53
fix(dotnet): 🐛 format build/test/restore output summaries
F0rty-Tw0 May 5, 2026
c5245d7
fix(dotnet): 🐛 format warnings section in build/test/restore outputs
F0rty-Tw0 May 5, 2026
f2da381
fix: correct ARCHITECTURE.md path in README links
swseverance May 7, 2026
998f1ee
feat(hooks): add transparent_prefixes config for wrapper commands
vsumner Apr 23, 2026
b234bc6
fix(hooks): compose env and transparent prefixes
vsumner Apr 26, 2026
fdf0ed0
fix(hooks): address transparent prefix review
vsumner May 3, 2026
041de2b
fix(hooks): address transparent prefix review comments
vsumner May 5, 2026
20cac8a
fix: minor code cleanup, avoid duplicating logic
KuSh May 7, 2026
5cfb8e1
fix: new rewite_command test call after rebase
KuSh May 7, 2026
b058c96
fix: don't inject -json for go test -bench runs
mykaul Apr 29, 2026
fa7020b
refactor(warn): src/core/utils.rs has an unused error warning at comp…
xdm67x May 8, 2026
380a7c9
Merge pull request #1610 from mykaul/fix/go-bench-no-json
aeppling May 8, 2026
4ebda52
fix(cicd): pr-target clean msg + git app token
aeppling May 8, 2026
e4c3ed7
Merge pull request #1792 from rtk-ai/fix/cicd/pr-target-enhance
aeppling May 8, 2026
f00977a
fix(hooks): make Cursor preToolUse rewrites work and stay visible
kamilkaczmareksolutions May 5, 2026
96aeb69
Merge branch 'develop' into feat/init-dry-run
aeppling May 9, 2026
4830d50
fix: resolve merge conflict artifacts in init.rs
aeppling May 9, 2026
172ec54
Merge pull request #1032 from hed0rah/feat/init-dry-run
aeppling May 9, 2026
2a41e03
Merge pull request #1767 from swseverance/fix/links
pszymkowiak May 10, 2026
0a55201
Merge pull request #1791 from xdm67x/refactor/unused-error-warning-fix
pszymkowiak May 10, 2026
858d0d9
Merge pull request #1764 from sadikkuzu/update-telemetry-docs-link
pszymkowiak May 10, 2026
f005dbf
chore: fix clippy 0.1.95 warnings
KuSh May 7, 2026
70b9f38
chore(ci): deny warnings and make clippy pass mandatory in ci
KuSh May 10, 2026
107b3d3
Merge pull request #1776 from KuSh/fix-clippy-0.1.95
aeppling May 10, 2026
2d6e10a
Merge pull request #1718 from kamilkaczmareksolutions/fix/cursor-hook…
pszymkowiak May 10, 2026
9d3b99d
feat(hermes): add rtk integration
Kayphoon May 7, 2026
f7c4bf6
style(hooks): format BOM helper assertion
Kayphoon May 11, 2026
55f998d
Merge pull request #1614 from Kayphoon/feat/hermes-integration
aeppling May 11, 2026
cd6ac2f
fix(security): replace insecure tmp, lock git workflow perm
aeppling May 13, 2026
26b96ec
fix(security): pin workflow actions to SHA, clean up tempfile on failure
aeppling May 13, 2026
54d1f87
Merge pull request #1871 from rtk-ai/fix/cicd-runners/insecure-tmp-lo…
aeppling May 13, 2026
7e418fd
Update pr-target-check.yml
aeppling May 13, 2026
fef1ba5
Merge pull request #1874 from rtk-ai/fix/cicd/spelling-branch-fr-en
aeppling May 13, 2026
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
2 changes: 1 addition & 1 deletion .claude/agents/rust-rtk.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ docker run --rm -v $(pwd):/rtk -w /rtk rust:latest cargo test # Linux via Docke
✅ **DO** compile regex once with `lazy_static!`
✅ **DO** verify token savings claims in tests (≥60%)
✅ **DO** test on macOS + Linux + Windows (via CI or manual)
✅ **DO** run `cargo fmt && cargo clippy && cargo test` before commit
✅ **DO** run `cargo fmt && cargo clippy --all-targets && cargo test` before commit
✅ **DO** benchmark startup time with `hyperfine` (<10ms target)
✅ **DO** use `anyhow::Result` with `.context()` for all error propagation

Expand Down
12 changes: 6 additions & 6 deletions .claude/commands/tech/codereview.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,12 +230,12 @@ Glob tests/fixtures/<cmd>_raw.txt
└────────┬────────┘
──────────────────────┐
│ 3. Quality gate
│ cargo fmt --all │
│ cargo clippy
│ cargo test
└─────────────────────┘
┌─────────────────────────────┐
│ 3. Quality gate
│ cargo fmt --all
│ cargo clippy --all-targets
│ cargo test
└──────────────┬──────────────┘
Loop ←┘ (max N iterations)
```
Expand Down
15 changes: 7 additions & 8 deletions .github/workflows/CICD.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,16 @@ Trigger: pull_request to develop or master
└────────┬─────────┘
┌────────▼─────────┐
fmt
│ fmt --all
└────────┬─────────┘
┌────────▼─────────┐
│ clippy │
│ -D unsafe_code │
└┬───┬───┬───┬───┬─┘
┌───────────▼──────────┐
│ clippy --all-targets │
└───┬───┬───┬───┬───┬──┘
│ │ │ │ │
┌───────────────┘ │ │ │ └───────────────┐
│ ┌───────────┘ │ └──────────┐ │
▼ ▼ ▼ ▼
┌───────────────┘ │ │ │ └───────────────
│ ┌───────────┘ │ └──────────┐ │
▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌───────────┐ ┌─────────┐ ┌──────────┐
│ test │ │ security │ │ semgrep │ │benchmark│ │ doc │
│ ubuntu │ │ cargo │ │ AST-aware │ │ >=80% │ │ review │
Expand Down
5 changes: 2 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
with:
components: clippy
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --all-targets -- -D unsafe_code
- run: cargo clippy --all-targets

# ─── Parallel gates (all need code to compile) ───

Expand Down Expand Up @@ -220,15 +220,14 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: 'stable'
go-version: "stable"

- name: Install Go tools
run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest

- name: Run benchmark
run: ./scripts/benchmark.sh


# ─── AI Doc Review: develop PRs only ───

doc-review:
Expand Down
21 changes: 13 additions & 8 deletions .github/workflows/pr-target-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,23 @@ on:
jobs:
check-target:
runs-on: ubuntu-latest
permissions: {}
# Skip develop→master PRs (maintainer releases)
if: >-
github.event.pull_request.base.ref == 'master' &&
github.event.pull_request.head.ref != 'develop'
steps:
- name: Add wrong-base label
uses: actions/github-script@v7
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
id: app-token
with:
client-id: ${{ secrets.APP_CLIENT_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
permission-pull-requests: write

- name: Add wrong-base label and comment
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
const pr = context.payload.pull_request;

Expand All @@ -27,13 +36,9 @@ jobs:
});

// Post comment
const body = `👋 Thanks for the PR! It looks like this targets \`master\`, but all PRs should target the **\`develop\`** branch.

Please update the base branch:
1. Click **Edit** at the top right of this PR
2. Change the base branch from \`master\` to \`develop\`
const body = `Automatic message from CI checks : It seems like this branch is targeting the wrong branch, any contribution should target develop branch.

See [CONTRIBUTING.md](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/master/CONTRIBUTING.md) for details.`;
See [CONTRIBUTING.md](https://github.com/rtk-ai/rtk/blob/master/CONTRIBUTING.md) for details.`;

await github.rest.issues.createComment({
owner: context.repo.owner,
Expand Down
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,7 @@ assets = [
assets = [
{ source = "target/release/rtk", dest = "/usr/bin/rtk", mode = "755" },
]

[lints.rust]
unsafe_code = "deny"
warnings = "deny"
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<a href="https://www.rtk-ai.app">Website</a> &bull;
<a href="#installation">Install</a> &bull;
<a href="https://www.rtk-ai.app/guide/troubleshooting">Troubleshooting</a> &bull;
<a href="ARCHITECTURE.md">Architecture</a> &bull;
<a href="docs/contributing/ARCHITECTURE.md">Architecture</a> &bull;
<a href="https://discord.gg/RySmvNF5kF">Discord</a>
</p>

Expand Down Expand Up @@ -110,12 +110,13 @@ rtk init --agent windsurf # Windsurf
rtk init --agent cline # Cline / Roo Code
rtk init --agent kilocode # Kilo Code
rtk init --agent antigravity # Google Antigravity
rtk init --agent hermes # Hermes

# 2. Restart your AI tool, then test
git status # Automatically rewritten to rtk git status
```

The hook transparently rewrites Bash commands (e.g., `git status` -> `rtk git status`) before execution. Claude never sees the rewrite, it just gets compressed output.
Hook-based agents rewrite Bash commands (e.g., `git status` -> `rtk git status`) before execution. Plugin-based agents, including Hermes, use their plugin API to rewrite commands before execution. The agent receives compact output without needing to call `rtk` explicitly.

**Important:** the hook only runs on Bash tool calls. Claude Code built-in tools like `Read`, `Grep`, and `Glob` do not pass through the Bash hook, so they are not auto-rewritten. To get RTK's compact output for those workflows, use shell commands (`cat`/`head`/`tail`, `rg`/`grep`, `find`) or call `rtk read`, `rtk grep`, or `rtk find` directly.

Expand Down Expand Up @@ -350,7 +351,7 @@ rtk git status

## Supported AI Tools

RTK supports 12 AI coding tools. Each integration transparently rewrites shell commands to `rtk` equivalents for 60-90% token savings.
RTK supports 13 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 @@ -364,11 +365,12 @@ RTK supports 12 AI coding tools. Each integration transparently rewrites shell c
| **Cline / Roo Code** | `rtk init --agent cline` | .clinerules (project-scoped) |
| **OpenCode** | `rtk init -g --opencode` | Plugin TS (tool.execute.before) |
| **OpenClaw** | `openclaw plugins install ./openclaw` | Plugin TS (before_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 |
| **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) |

For per-agent setup details, override controls, and graceful degradation, see the [Supported Agents guide](https://www.rtk-ai.app/guide/getting-started/supported-agents).
For per-agent setup details, override controls, and graceful degradation, see the [Supported Agents guide](https://www.rtk-ai.app/guide/getting-started/supported-agents). The Hermes plugin source and tests live in `hooks/hermes/`; installed Hermes runtime files still live under `~/.hermes/plugins/rtk-rewrite/`.

## Configuration

Expand Down Expand Up @@ -404,7 +406,7 @@ brew uninstall rtk # If installed via Homebrew

- **[rtk-ai.app/guide](https://www.rtk-ai.app/guide)** — full user guide (installation, supported agents, what gets optimized, analytics, configuration, troubleshooting)
- **[INSTALL.md](INSTALL.md)** — detailed installation reference
- **[ARCHITECTURE.md](ARCHITECTURE.md)** — system design and technical decisions
- **[ARCHITECTURE.md](docs/contributing/ARCHITECTURE.md)** — system design and technical decisions
- **[CONTRIBUTING.md](CONTRIBUTING.md)** — contribution guide
- **[SECURITY.md](SECURITY.md)** — security policy

Expand Down
16 changes: 16 additions & 0 deletions docs/guide/getting-started/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ cd /your/project && rtk init

This installs the hook that automatically rewrites commands. Restart your AI assistant after this step.

### Preview without writing: `--dry-run`

To see exactly what `init` would change before it touches anything, add `--dry-run`:

```bash
rtk init --global --dry-run
```

Every would-be file create/update/patch is printed with a `[dry-run] would ...` prefix, then a `[dry-run] Nothing written.` footer. Nothing on disk is modified, no settings.json is patched, and the telemetry consent prompt is skipped. Combine with `-v` to also print the full content RTK would write:

```bash
rtk init --global --dry-run -v
```

`--dry-run` works for every init flavour (`--agent cursor`, `--gemini`, `--codex`, `--copilot`, `--uninstall`, ...). It cannot be combined with `--show`.

## Step 2: Use your tools normally

Once the hook is installed, nothing changes in how you work. Your AI assistant runs commands as usual — the hook intercepts them transparently and rewrites them before execution.
Expand Down
15 changes: 13 additions & 2 deletions docs/guide/getting-started/supported-agents.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Supported Agents
description: How to integrate RTK with Claude Code, Cursor, Copilot, Cline, Windsurf, Codex, OpenCode, Kilo Code, and Antigravity
description: How to integrate RTK with Claude Code, Cursor, Copilot, Cline, Windsurf, Codex, OpenCode, Hermes, Kilo Code, and Antigravity
sidebar:
order: 3
---
Expand Down Expand Up @@ -35,6 +35,7 @@ Agent runs "cargo test"
| Gemini CLI | Rust binary (`BeforeTool`) | Yes |
| OpenCode | TypeScript plugin (`tool.execute.before`) | Yes |
| OpenClaw | TypeScript plugin (`before_tool_call`) | Yes |
| Hermes | Python plugin (`terminal` command mutation) | Yes |
| Cline / Roo Code | Rules file (prompt-level) | N/A |
| Windsurf | Rules file (prompt-level) | N/A |
| Codex CLI | AGENTS.md instructions | N/A |
Expand Down Expand Up @@ -92,6 +93,16 @@ openclaw plugins install ./openclaw

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

### Hermes

```bash
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 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.

### Cline / Roo Code

```bash
Expand Down Expand Up @@ -137,7 +148,7 @@ Support is blocked on upstream `BeforeToolCallback` ([mistral-vibe#531](https://
| 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/JS in agent's plugin system | Transparentin-place mutation |
| **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, Codex, Kilo Code, Antigravity) rely on the model following instructions. Full hook integrations (Claude Code, Cursor, Gemini) are guaranteed — the command is rewritten before the agent sees it.
Expand Down
18 changes: 15 additions & 3 deletions hooks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

**Deployed hook artifacts** — the actual files installed on user machines by `rtk init`. These are shell scripts, TypeScript plugins, and rules files that run outside the Rust binary. They are **thin delegates**: parse agent-specific JSON, call `rtk rewrite` as a subprocess, format agent-specific response. Zero filtering logic lives here.

Owns: per-agent hook scripts and configuration files for 7 supported agents (Claude Code, Copilot, Cursor, Cline, Windsurf, Codex, OpenCode).
Owns: per-agent hook scripts and configuration files for 8 supported agents (Claude Code, Copilot, Cursor, Cline, Windsurf, Codex, OpenCode, Hermes).

Does **not** own: hook installation/uninstallation (that's `src/hooks/init.rs`), the rewrite pattern registry (that's `discover/registry`), or integrity verification (that's `src/hooks/integrity.rs`).

Expand Down Expand Up @@ -40,6 +40,7 @@ Each agent subdirectory has its own README with hook-specific details:
- **[`windsurf/`](windsurf/README.md)** — Rules file (prompt-level), `.windsurfrules` workspace-scoped
- **[`codex/`](codex/README.md)** — Awareness document, `AGENTS.md` integration, `$CODEX_HOME` or `~/.codex/` location
- **[`opencode/`](opencode/README.md)** — TypeScript plugin, `zx` library, `tool.execute.before` event, in-place mutation
- **[`hermes/`](hermes/README.md)** — Python plugin, `pre_tool_call` hook, in-place terminal command mutation

## Supported Agents

Expand All @@ -54,6 +55,7 @@ Each agent subdirectory has its own README with hook-specific details:
| Windsurf | Custom instructions (rules file) | Prompt-level guidance | N/A |
| Codex CLI | AGENTS.md / instructions | Prompt-level guidance | N/A |
| OpenCode | TypeScript plugin (`tool.execute.before`) | In-place mutation | Yes |
| Hermes | Python plugin (`pre_tool_call`) | In-place mutation | Yes |

## JSON Formats by Agent

Expand Down Expand Up @@ -156,6 +158,17 @@ if (rewritten && rewritten !== command) {
}
```

### Hermes (Python Plugin)

Mutates `args["command"]` in-place via the `pre_tool_call` hook:

```python
result = subprocess.run(["rtk", "rewrite", command], capture_output=True, text=True, timeout=2)
rewritten = result.stdout.strip()
if result.returncode in {0, 3} and rewritten and rewritten != command:
args["command"] = rewritten
```

## Command Rewrite Registry

The registry (`src/discover/registry.rs`) handles command patterns across these categories:
Expand Down Expand Up @@ -217,7 +230,7 @@ New integrations must follow the [Exit Code Contract](#exit-code-contract) and [
| Tier | Mechanism | Maintenance | Examples |
|------|-----------|-------------|----------|
| **Full hook** | Shell script or Rust binary, intercepts commands via agent's hook API | High — must track agent API changes | Claude Code, Cursor, Copilot, Gemini |
| **Plugin** | TypeScript/JS plugin in agent's plugin system | Medium — agent manages loading | OpenCode |
| **Plugin** | TypeScript/JS/Python plugin in agent's plugin system | Medium — agent manages loading | OpenCode, Hermes |
| **Rules file** | Prompt-level instructions the agent reads | Low — no code to break | Cline, Windsurf, Codex |

### Eligibility
Expand All @@ -232,4 +245,3 @@ RTK supports AI coding assistants that developers actually use day-to-day. To ad
### Maintenance

If an agent's API changes and the hook breaks, the integration should be updated promptly. If the agent becomes unmaintained or the hook can't be fixed, the integration may be deprecated with a release note.

43 changes: 43 additions & 0 deletions hooks/hermes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# RTK Plugin for Hermes

Rewrites Hermes `terminal` tool commands to RTK equivalents before execution, so Hermes receives compact command output without changing your workflow.

## Installation

```bash
rtk init --agent hermes
```

The installer writes the plugin to `~/.hermes/plugins/rtk-rewrite/` and enables it through `plugins.enabled` in the Hermes config. The repository copy lives in `hooks/hermes/`; don't use that repo path as the runtime install path.

## Development

Run the Hermes plugin tests from the repository root:

```bash
python3 -m unittest discover -s hooks/hermes
```

## How it works

Hermes loads plugins from Python, so the plugin entrypoint is Python. The Python code is only a thin Hermes adapter. It reads the Hermes terminal tool payload, calls `rtk rewrite` for the actual command decision, then mutates the terminal tool `command` before Hermes executes it.

All rewrite rules stay in Rust inside `rtk rewrite`. When RTK adds or changes command rewrite behavior, the Hermes plugin picks up that behavior by delegating to the RTK binary.

## Fail-open behavior

The plugin does not block command execution. If anything goes wrong, Hermes runs the original command unchanged.

If rtk is not available in PATH when Hermes loads the plugin, the plugin prints a warning and skips hook registration.

- `rtk` is missing from `PATH`
- `rtk rewrite` exits with an error
- Hermes sends a non-terminal tool call
- The tool payload has no string `command`
- The plugin raises an unexpected exception

## Limitations

- Only Hermes `terminal` tool calls are rewritten.
- Commands skipped by `rtk rewrite` stay unchanged, including commands already prefixed with `rtk`, compound shell commands, heredocs, and commands without an RTK filter.
- Shell hooks are not used for Hermes command rewriting. The integration depends on Hermes loading Python plugins and passing a mutable terminal tool payload.
Loading
Loading