ruvnet / ruvnet/ruflo

feat: ruflo-rtk plugin — integrate RTK token compression without hook conflicts

Open
#1,900 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
72.7k
Forks
8.6k
Avg merge
3d 3h
Merged PRs (30d)
85

Description

## Problem

[RTK (Rust Token Killer)](https://github.com/rtk-ai/rtk) reduces LLM token consumption by **60–90%** by intercepting Bash tool calls and compressing shell output (git, ls, grep, test runners) before it reaches the LLM context.

RTK installs its own `PreToolUse/Bash` hook via `rtk init -g`, writing to `.claude/settings.json`. Ruflo also manages `settings.json` (PreToolUse, PostToolUse, hooks pipeline). **Conflict**: when either tool updates, it can clobber the other's hooks entry.

Ruflo's own Token Optimizer achieves 30–50% savings at the context/caching level. RTK operates at the shell output level (60–90%). Together they stack — but only if the integration is conflict-free.

## Proposed Solution: `ruflo-rtk` plugin

A thin adapter plugin that:

1. Places the RTK hook script under `.claude/plugins/ruflo-rtk/` — a directory Ruflo's updater never touches
2. Registers the hook in `settings.local.json` — which Ruflo never writes to (`settings.json` only)
3. Chains cleanly: RTK compresses stdout first, then Ruflo's post-bash hook records the result

### Architecture

```
PreToolUse/Bash pipeline:
1. settings.local.json → .claude/plugins/ruflo-rtk/rtk-pre-bash.sh (RTK rewrite)
2. settings.json → .claude/helpers/hook-handler.cjs pre-bash (Ruflo safety check)

PostToolUse/Bash:
→ hook-handler.cjs post-bash (Ruflo learning + metrics, already compressed input)
```

### Combined savings

| Layer | Savings | Mechanism |
|---|---|---|
| RTK (shell output) | 60–90% | stdout filter per Bash call |
| Ruflo Token Optimizer | 30–50% | context caching + smart routing |
| Combined (typical session) | ~85–90% | stack multiplicatively |

## Implementation

### `.claude/plugins/ruflo-rtk/rtk-pre-bash.sh`

Thin delegating hook — all rewrite logic lives in `rtk rewrite` (Rust binary). Hook uses the `hookSpecificOutput` protocol to transparently rewrite commands:

```bash
INPUT=$(cat)
CMD=$(jq -r '.tool_input.command // empty' <<<"$INPUT")
[ -z "$CMD" ] && exit 0

REWRITTEN=$(rtk rewrite "$CMD" 2>/dev/null)
case $? in
0) jq -c --arg cmd "$REWRITTEN" '.tool_input.command = $cmd | {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",permissionDecisionReason:"RTK auto-rewrite",updatedInput:.tool_input}}' <<<"$INPUT" ;;
3) jq -c --arg cmd "$REWRITTEN" '.tool_input.command = $cmd | {hookSpecificOutput:{hookEventName:"PreToolUse",updatedInput:.tool_input}}' <<<"$INPUT" ;;
*) exit 0 ;;
esac
```

### `settings.local.json` registration

```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "sh -c '~/.claude/plugins/ruflo-rtk/rtk-pre-bash.sh'", "timeout": 3000 }]
}
]
},
"permissions": { "allow": ["Bash(rtk *)"] }
}
```

## Why `settings.local.json`?

- Ruflo's `init` and plugin installer write only to `settings.json`
- Claude Code merges both files — hooks from `settings.local.json` run alongside those in `settings.json`
- `settings.local.json` is user-local and not committed (no merge conflicts on team repos)
- Plugin files under `.claude/plugins/ruflo-rtk/` are in a path Ruflo's updater skips

## Acceptance Criteria

- [ ] `/plugin install ruflo-rtk@ruflo` registers the hook in `settings.local.json`
- [ ] `rtk gain` shows savings accumulating through Ruflo sessions
- [ ] Ruflo update (`npx ruflo@latest update`) does not remove the RTK hook
- [ ] `ruflo doctor` reports RTK version and hook status
- [ ] If RTK is not installed, hook exits 0 silently (no disruption)

Contributor guide

Open the contributing guide

Research direction

Trace Ruflo's init, plugin installer, updater, and doctor entry points, then inspect how settings.json and hook pipelines are managed. Use the proposed .claude/plugins/ruflo-rtk/rtk-pre-bash.sh and settings.local.json layout as the integration boundary. Done means the acceptance criteria pass, including silent behavior without RTK and preservation across updates.

Written by the indexing model from the issue text.

Assessment

Tech stack
bash, typescript
Domain
cli, tooling
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.