|
| 1 | +# Copilot Instructions for rtk |
| 2 | + |
| 3 | +**rtk (Rust Token Killer)** is a CLI proxy that filters and compresses command outputs before they reach an LLM context, saving 60–90% of tokens. It wraps common tools (`git`, `cargo`, `grep`, `pnpm`, `go`, etc.) and outputs condensed summaries instead of raw output. |
| 4 | + |
| 5 | +## Using rtk in this session |
| 6 | + |
| 7 | +**Always prefix commands with `rtk` when running shell commands** — this is the entire point of the project and reduces token consumption for every operation you perform. |
| 8 | + |
| 9 | +```bash |
| 10 | +# Instead of: Use: |
| 11 | +git status rtk git status |
| 12 | +git log -10 rtk git log -10 |
| 13 | +cargo test rtk cargo test |
| 14 | +cargo clippy --all-targets rtk cargo clippy --all-targets |
| 15 | +grep -r "pattern" src/ rtk grep -r "pattern" src/ |
| 16 | +``` |
| 17 | + |
| 18 | +**rtk meta-commands** (always use these directly, no prefix needed): |
| 19 | +```bash |
| 20 | +rtk gain # Show token savings analytics for this session |
| 21 | +rtk gain --history # Full command history with per-command savings |
| 22 | +rtk discover # Scan session history for missed rtk opportunities |
| 23 | +rtk proxy <cmd> # Run a command raw (no filtering) but still track it |
| 24 | +``` |
| 25 | + |
| 26 | +**Verify rtk is installed before starting:** |
| 27 | +```bash |
| 28 | +rtk --version # Should print: rtk X.Y.Z |
| 29 | +rtk gain # Should show a dashboard (not "command not found") |
| 30 | +``` |
| 31 | + |
| 32 | +> ⚠️ **Name collision**: `rtk gain` failing means you have `reachingforthejack/rtk` (Rust Type Kit) installed instead of this project. Run `which rtk` and check the binary source. |
| 33 | +
|
| 34 | +## Build, Test & Lint |
| 35 | + |
| 36 | +```bash |
| 37 | +# Development build |
| 38 | +cargo build |
| 39 | + |
| 40 | +# Run all tests |
| 41 | +cargo test |
| 42 | + |
| 43 | +# Run a single test by name |
| 44 | +cargo test test_filter_git_log |
| 45 | + |
| 46 | +# Run all tests in a module |
| 47 | +cargo test git::tests:: |
| 48 | + |
| 49 | +# Run tests with stdout |
| 50 | +cargo test -- --nocapture |
| 51 | + |
| 52 | +# Pre-commit gate (must all pass before any PR) |
| 53 | +cargo fmt --all --check && cargo clippy --all-targets && cargo test |
| 54 | + |
| 55 | +# Smoke tests (requires installed binary) |
| 56 | +bash scripts/test-all.sh |
| 57 | +``` |
| 58 | + |
| 59 | +PRs target the **`develop`** branch, not `main`. All commits require a DCO sign-off (`git commit -s`). |
| 60 | + |
| 61 | +## Architecture |
| 62 | + |
| 63 | +``` |
| 64 | +main.rs ← Clap Commands enum → specialized module (git.rs, *_cmd.rs, etc.) |
| 65 | + ↓ |
| 66 | + execute subprocess |
| 67 | + ↓ |
| 68 | + filter/compress output |
| 69 | + ↓ |
| 70 | + tracking::TimedExecution → SQLite (~/.local/share/rtk/tracking.db) |
| 71 | +``` |
| 72 | + |
| 73 | +Key modules: |
| 74 | +- **`main.rs`** — Clap `Commands` enum routes every subcommand to its module. Each arm calls `tracking::TimedExecution::start()` before running, then `.track(...)` after. |
| 75 | +- **`filter.rs`** — Language-aware filtering with `FilterLevel` (`none` / `minimal` / `aggressive`) and `Language` enum. Used by `read` and `smart` commands. |
| 76 | +- **`tracking.rs`** — SQLite persistence for token savings, scoped per project path. Powers `rtk gain`. |
| 77 | +- **`tee.rs`** — On filter failure, saves raw output to `~/.local/share/rtk/tee/` and prints a one-line hint so the LLM can re-read without re-running the command. |
| 78 | +- **`utils.rs`** — Shared helpers: `truncate`, `strip_ansi`, `execute_command`, package-manager auto-detection (pnpm/yarn/npm/npx). |
| 79 | + |
| 80 | +New commands follow this structure: one file `src/<cmd>_cmd.rs` with a `pub fn run(...)` entry point, registered in the `Commands` enum in `main.rs`. |
| 81 | + |
| 82 | +## Key Conventions |
| 83 | + |
| 84 | +### Error handling |
| 85 | +- Use `anyhow::Result` throughout (this is a binary, not a library). |
| 86 | +- Always attach context: `operation.context("description")?` — never bare `?` without context. |
| 87 | +- No `unwrap()` in production code; `expect("reason")` is acceptable only in tests. |
| 88 | +- Every filter must fall back to raw command execution on error — never break the user's workflow. |
| 89 | + |
| 90 | +### Regex |
| 91 | +- Compile once with `lazy_static!`, never inside a function body: |
| 92 | + ```rust |
| 93 | + lazy_static! { |
| 94 | + static ref RE: Regex = Regex::new(r"pattern").unwrap(); |
| 95 | + } |
| 96 | + ``` |
| 97 | + |
| 98 | +### Testing |
| 99 | +- Unit tests live **inside the module file** in `#[cfg(test)] mod tests { ... }` — not in `tests/`. |
| 100 | +- Fixtures are real captured command output in `tests/fixtures/<cmd>_raw.txt`, loaded with `include_str!("../tests/fixtures/...")`. |
| 101 | +- Each test module defines its own local `fn count_tokens(text: &str) -> usize` (word-split approximation) — there is no shared utility for this. |
| 102 | +- Token savings assertions use `assert!(savings >= 60.0, ...)`. |
| 103 | +- Snapshot tests use `assert_snapshot!()` from the `insta` crate; review with `cargo insta review`. |
| 104 | + |
| 105 | +### Adding a new command |
| 106 | +1. Create `src/<cmd>_cmd.rs` with `pub fn run(...)`. |
| 107 | +2. Add `mod <cmd>_cmd;` at the top of `main.rs`. |
| 108 | +3. Add a variant to the `Commands` enum with `#[arg(trailing_var_arg = true, allow_hyphen_values = true)]` for pass-through flags. |
| 109 | +4. Route the variant in the `match` block, wrapping execution with `tracking::TimedExecution`. |
| 110 | +5. Write a fixture from real output, then unit tests in the module file. |
| 111 | +6. Update `README.md` (command list + savings %) and `CHANGELOG.md`. |
| 112 | + |
| 113 | +### Exit codes |
| 114 | +Preserve the underlying command's exit code. Use `std::process::exit(code)` when the child process exits non-zero. |
| 115 | + |
| 116 | +### Performance constraints |
| 117 | +- Startup must stay under 10ms — no async runtime (no `tokio`/`async-std`). |
| 118 | +- No blocking I/O at startup; config is loaded on-demand. |
| 119 | +- Binary size target: <5 MB stripped. |
| 120 | + |
| 121 | +### Branch naming |
| 122 | +``` |
| 123 | +fix(scope): short-description |
| 124 | +feat(scope): short-description |
| 125 | +chore(scope): short-description |
| 126 | +``` |
| 127 | +`scope` is the affected component (e.g. `git`, `filter`, `tracking`). |
0 commit comments