diff --git a/openclaw/README.md b/openclaw/README.md new file mode 100644 index 000000000..301d7c0fa --- /dev/null +++ b/openclaw/README.md @@ -0,0 +1,86 @@ +# RTK Plugin for OpenClaw + +Transparently rewrites shell commands executed via OpenClaw's `exec` tool to their RTK equivalents, achieving 60-90% LLM token savings. + +This is the OpenClaw equivalent of the Claude Code hooks in `hooks/rtk-rewrite.sh`. + +## How it works + +The plugin registers a `before_tool_call` hook that intercepts `exec` tool calls. When the agent runs a command like `git status`, the plugin delegates to `rtk rewrite` which returns the optimized command (e.g. `rtk git status`). The compressed output enters the agent's context window, saving tokens. + +All rewrite logic lives in RTK itself (`rtk rewrite`). This plugin is a thin delegate -- when new filters are added to RTK, the plugin picks them up automatically with zero changes. + +## Installation + +### Prerequisites + +RTK must be installed and available in `$PATH`: + +```bash +brew install rtk +# or +curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh +``` + +### Install the plugin + +```bash +# Copy the plugin to OpenClaw's extensions directory +mkdir -p ~/.openclaw/extensions/rtk-rewrite +cp openclaw/index.ts openclaw/openclaw.plugin.json ~/.openclaw/extensions/rtk-rewrite/ + +# Restart the gateway +openclaw gateway restart +``` + +### Or install via OpenClaw CLI + +```bash +openclaw plugins install ./openclaw +``` + +## Configuration + +In `openclaw.json`: + +```json5 +{ + plugins: { + entries: { + "rtk-rewrite": { + enabled: true, + config: { + enabled: true, // Toggle rewriting on/off + verbose: false // Log rewrites to console + } + } + } + } +} +``` + +## What gets rewritten + +Everything that `rtk rewrite` supports (30+ commands). See the [full command list](https://github.com/rtk-ai/rtk#commands). + +## What's NOT rewritten + +Handled by `rtk rewrite` guards: +- Commands already using `rtk` +- Piped commands (`|`, `&&`, `;`) +- Heredocs (`<<`) +- Commands without an RTK filter + +## Measured savings + +| Command | Token savings | +|---------|--------------| +| `git log --stat` | 87% | +| `ls -la` | 78% | +| `git status` | 66% | +| `grep` (single file) | 52% | +| `find -name` | 48% | + +## License + +MIT -- same as RTK. diff --git a/openclaw/index.ts b/openclaw/index.ts new file mode 100644 index 000000000..17ea4ec93 --- /dev/null +++ b/openclaw/index.ts @@ -0,0 +1,74 @@ +/** + * RTK Rewrite Plugin for OpenClaw + * + * Transparently rewrites exec tool commands to RTK equivalents + * before execution, achieving 60-90% LLM token savings. + * + * All rewrite logic lives in `rtk rewrite` (src/discover/registry.rs). + * This plugin is a thin delegate — to add or change rules, edit the + * Rust registry, not this file. + */ + +import { execSync } from "node:child_process"; + +let rtkAvailable: boolean | null = null; + +function checkRtk(): boolean { + if (rtkAvailable !== null) return rtkAvailable; + try { + execSync("which rtk", { stdio: "ignore" }); + rtkAvailable = true; + } catch { + rtkAvailable = false; + } + return rtkAvailable; +} + +function tryRewrite(command: string): string | null { + try { + const result = execSync(`rtk rewrite ${JSON.stringify(command)}`, { + encoding: "utf-8", + timeout: 2000, + }).trim(); + return result && result !== command ? result : null; + } catch { + return null; + } +} + +export default function register(api: any) { + const pluginConfig = api.config ?? {}; + const enabled = pluginConfig.enabled !== false; + const verbose = pluginConfig.verbose === true; + + if (!enabled) return; + + if (!checkRtk()) { + console.warn("[rtk] rtk binary not found in PATH — plugin disabled"); + return; + } + + api.on( + "before_tool_call", + (event: { toolName: string; params: Record }) => { + if (event.toolName !== "exec") return; + + const command = event.params?.command; + if (typeof command !== "string") return; + + const rewritten = tryRewrite(command); + if (!rewritten) return; + + if (verbose) { + console.log(`[rtk] ${command} -> ${rewritten}`); + } + + return { params: { ...event.params, command: rewritten } }; + }, + { priority: 10 } + ); + + if (verbose) { + console.log("[rtk] OpenClaw plugin registered"); + } +} diff --git a/openclaw/openclaw.plugin.json b/openclaw/openclaw.plugin.json new file mode 100644 index 000000000..3fce418d7 --- /dev/null +++ b/openclaw/openclaw.plugin.json @@ -0,0 +1,28 @@ +{ + "id": "rtk-rewrite", + "name": "RTK Token Optimizer", + "version": "1.0.0", + "description": "Transparently rewrites shell commands to their RTK equivalents for 60-90% LLM token savings", + "homepage": "https://github.com/rtk-ai/rtk", + "license": "MIT", + "configSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "enabled": { + "type": "boolean", + "default": true, + "description": "Enable automatic command rewriting to RTK equivalents" + }, + "verbose": { + "type": "boolean", + "default": false, + "description": "Log rewrite decisions to console for debugging" + } + } + }, + "uiHints": { + "enabled": { "label": "Enable RTK rewriting" }, + "verbose": { "label": "Verbose logging" } + } +} diff --git a/openclaw/package.json b/openclaw/package.json new file mode 100644 index 000000000..18d359ff4 --- /dev/null +++ b/openclaw/package.json @@ -0,0 +1,29 @@ +{ + "name": "@rtk-ai/rtk-rewrite", + "version": "1.0.0", + "description": "RTK plugin for OpenClaw — rewrites shell commands for 60-90% LLM token savings", + "main": "index.ts", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/rtk-ai/rtk", + "directory": "openclaw" + }, + "homepage": "https://github.com/rtk-ai/rtk", + "keywords": [ + "rtk", + "openclaw", + "openclaw-plugin", + "token-savings", + "llm", + "cli-proxy" + ], + "files": [ + "index.ts", + "openclaw.plugin.json", + "README.md" + ], + "peerDependencies": { + "rtk": ">=0.28.0" + } +}