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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ All notable changes to rtk (Rust Token Killer) will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Features

* **init:** add Cursor support (`rtk init --cursor`) ([#213](https://github.com/rtk-ai/rtk/issues/213))
* Hook script supports both Claude Code and Cursor preToolUse (auto-detect payload)
* Installs hook + rules (rtk.mdc) + hooks.json for global (~/.cursor) or project (.cursor)
* `rtk init --cursor --show` and `rtk init --cursor -g --uninstall`
* **init:** refactor for multi-agent: `InitTarget` enum, shared `patch_json_registry`, `ensure_agent_hook_installed` (enables adding Codex, OpenCode, etc.)

## [0.22.2](https://github.com/rtk-ai/rtk/compare/v0.22.1...v0.22.2) (2026-02-20)


Expand Down
5 changes: 3 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,10 @@ main.rs (CLI entry)
- Priority: env var > config file > default location

**4. Configuration System** (src/config.rs, src/init.rs)
- Manages CLAUDE.md initialization (global vs local)
- Manages CLAUDE.md initialization (global vs local) and Cursor (hooks + rules)
- Reads ~/.config/rtk/config.toml for user preferences
- `rtk init` command bootstraps LLM integration
- `rtk init` bootstraps Claude Code; `rtk init --cursor` bootstraps Cursor (hooks.json + rtk.mdc)
- **Adding a new agent (Codex, OpenCode, etc.)**: Add an `InitTarget` variant in init.rs, implement `run_<agent>_mode` (reuse `ensure_agent_hook_installed`, `patch_json_registry` with agent-specific is_present/insert), and branch in `show_config`/`uninstall`. See doc comment on `InitTarget` in src/init.rs.
- **New**: `tracking.database_path` field for custom DB location

**5. Tee Output Recovery** (src/tee.rs)
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,8 @@ Four strategies applied per command type:
| `rtk init -g --claude-md` | Global | ❌ | ❌ | Full (137 lines) | ~2000 | Legacy compatibility |
| `rtk init -g --hook-only` | Global | ✅ | ❌ | Nothing | 0 | Minimal setup, hook-only |
| `rtk init` | Local | ❌ | ❌ | Full (137 lines) | ~2000 | Single project, no hook |
| `rtk init --cursor` | Project | Cursor hook | rtk.mdc | .cursor/hooks.json | 0 | Cursor Agent (preToolUse) |
| `rtk init --cursor -g` | Global | Cursor hook | rtk.mdc | ~/.cursor/hooks.json | 0 | Cursor Agent, all projects |

```bash
rtk init --show # Show current configuration
Expand Down Expand Up @@ -401,6 +403,15 @@ rtk init -g --hook-only # Hook only, no RTK.md
rtk init -g --uninstall # Remove all RTK artifacts
```

**Cursor** (Agent / Cmd+K):
```bash
rtk init --cursor # Project: .cursor/hooks + .cursor/rules/rtk.mdc + .cursor/hooks.json
rtk init --cursor -g # Global: ~/.cursor/ (same layout)
rtk init --cursor --show # Show Cursor RTK status (global + project)
rtk init --cursor -g --uninstall # Remove global Cursor RTK
```
Uses the same rewrite hook (preToolUse for Shell); Cursor runs it via `hooks.json` and gets rules from `rtk.mdc`. Restart Cursor after init.

**What is settings.json?**
Claude Code configuration file that registers the RTK hook. The hook transparently rewrites commands (e.g., `git status` → `rtk git status`) before execution. Without this registration, Claude won't use the hook.

Expand Down
39 changes: 39 additions & 0 deletions hooks/rtk-cursor-rules.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
description: Use rtk (Rust Token Killer) to wrap CLI commands for token-optimized output (60-90% savings)
globs: ["**/*"]
alwaysApply: true
---

# RTK Command Proxy

When running shell commands, prefer `rtk <cmd>` over raw commands for token-optimized output. rtk is a CLI proxy that reduces LLM token consumption by 60-90% through smart filtering.

Leading env var assignments should be preserved (e.g., `FOO=bar cargo test` → `FOO=bar rtk cargo test`).

## Custom Rules (rtk err — errors-only wrapper)

These commands have no native rtk filter. Wrap with `rtk err` to show only stderr/errors:

- `pre-commit ...` → `rtk err pre-commit ...`
- `make ...` → `rtk err make ...`
- `go generate ...` → `rtk err go generate ...`
- `pnpm run <script>` → `rtk err pnpm run <script>`

## Native RTK Rewrites

- **Git**: `git <subcmd>` → `rtk git <subcmd>` (all subcommands)
- **GitHub CLI**: `gh pr|issue|run|api|release ...` → `rtk gh ...`
- **Cargo**: `cargo test|build|clippy|check|install|fmt` → `rtk cargo ...`
- **File ops**: `cat` → `rtk read`, `rg|grep` → `rtk grep`, `ls` → `rtk ls`, `tree` → `rtk tree`, `find|diff` → `rtk find|diff`
- **JS/TS**: `vitest|tsc|eslint|prettier|playwright|prisma|pnpm list|outdated` → `rtk vitest|tsc|lint|prettier|playwright|prisma|pnpm ...`
- **Python**: `pytest|ruff check|format|pip|uv pip` → `rtk pytest|ruff|pip ...`
- **Go**: `go test|build|vet` → `rtk go ...`, `golangci-lint` → `rtk golangci-lint`
- **Containers**: `docker compose|docker ps|images|logs|...` → `rtk docker ...`, `kubectl get|logs|...` → `rtk kubectl ...`
- **Network**: `curl|wget` → `rtk curl|wget`

## Exceptions — Do NOT wrap with rtk

- Commands already prefixed with `rtk`
- Commands with heredocs (`<<`)
- Interactive commands (e.g., `git rebase -i`)
- Commands that must produce exact raw output for parsing by other tools
47 changes: 34 additions & 13 deletions hooks/rtk-rewrite.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash
# RTK auto-rewrite hook for Claude Code PreToolUse:Bash
# RTK auto-rewrite hook for Claude Code PreToolUse:Bash and Cursor preToolUse (Shell).
# Transparently rewrites raw commands to their rtk equivalents.
# Outputs JSON with updatedInput to modify the command before execution.
# Outputs JSON: Claude = hookSpecificOutput.updatedInput; Cursor = decision + updated_input.

# Guards: skip silently if dependencies missing
if ! command -v rtk &>/dev/null || ! command -v jq &>/dev/null; then
Expand All @@ -11,6 +11,19 @@ fi
set -euo pipefail

INPUT=$(cat)
# Detect Cursor vs Claude Code from payload shape.
# Cursor payloads include "hook_event_name" or "cursor_version" as top-level strings.
# Claude Code payloads have none of these; they nest event info inside hookSpecificOutput.
# If both agents add overlapping fields in the future, set RTK_HOOK_MODE=cursor|claude to override.
CURSOR_MODE=
if [ "${RTK_HOOK_MODE:-}" = "cursor" ]; then
CURSOR_MODE=1
elif [ "${RTK_HOOK_MODE:-}" = "claude" ]; then
CURSOR_MODE=
elif echo "$INPUT" | jq -e '.hook_event_name // .cursor_version | type == "string"' &>/dev/null; then
CURSOR_MODE=1
fi

CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

if [ -z "$CMD" ]; then
Expand Down Expand Up @@ -196,14 +209,22 @@ fi
ORIGINAL_INPUT=$(echo "$INPUT" | jq -c '.tool_input')
UPDATED_INPUT=$(echo "$ORIGINAL_INPUT" | jq --arg cmd "$REWRITTEN" '.command = $cmd')

# Output the rewrite instruction
jq -n \
--argjson updated "$UPDATED_INPUT" \
'{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"permissionDecisionReason": "RTK auto-rewrite",
"updatedInput": $updated
}
}'
# Output the rewrite instruction (format depends on host)
if [ -n "$CURSOR_MODE" ]; then
# Cursor preToolUse: https://cursor.com/docs/agent/hooks
jq -n \
--argjson updated "$UPDATED_INPUT" \
'{ "decision": "allow", "updated_input": $updated }'
else
# Claude Code PreToolUse
jq -n \
--argjson updated "$UPDATED_INPUT" \
'{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"permissionDecisionReason": "RTK auto-rewrite",
"updatedInput": $updated
}
}'
fi
Loading