# How RTK Processes and Optimizes Ruby Tool Output for RuboCop and RSpec

> RTK optimizes Ruby tool output like RuboCop and RSpec by capturing logs, parsing JSON, and generating concise summaries for efficient processing.

- Repository: [rtk-ai/rtk](https://github.com/rtk-ai/rtk)
- Tags: how-to-guide
- Published: 2026-04-24

---

**RTK treats RuboCop and RSpec as filter modules that execute commands, capture raw output, and replace verbose logs with concise, token-efficient summaries using JSON parsing and intelligent truncation.**

The `rtk-ai/rtk` repository implements a specialized pipeline for Ruby ecosystem tools that transforms sprawling command-line output into LLM-friendly diagnostics. By intercepting execution at the source code level, RTK applies intelligent filtering to **RuboCop** and **RSpec** results before they reach your terminal. This article examines the internal machinery that makes this optimization possible.

## The Filter Module Pipeline

Every Ruby command in RTK follows a standardized execution flow defined in [`src/core/runner.rs`](https://github.com/rtk-ai/rtk/blob/main/src/core/runner.rs) and [`src/core/utils.rs`](https://github.com/rtk-ai/rtk/blob/main/src/core/utils.rs). The system automatically detects project context and handles output transformation through three distinct phases.

### Automatic Bundler Detection

The `ruby_exec()` function in [`src/core/utils.rs`](https://github.com/rtk-ai/rtk/blob/main/src/core/utils.rs) (lines 43-53) inspects the working directory for a `Gemfile`. When present, RTK prefixes every Ruby command with `bundle exec`, ensuring tools run with the exact versions specified in your project lockfile. This eliminates version mismatch errors before filtering begins.

### Execution and Capture

The `runner::run_filtered()` function in [`src/core/runner.rs`](https://github.com/rtk-ai/rtk/blob/main/src/core/runner.rs) (lines 62-100) spawns the subprocess and captures stdout. Rather than streaming raw bytes to your terminal, this runner invokes a specialized filter closure unique to each Ruby tool. The closure receives the complete output buffer and returns a transformed string optimized for readability and token efficiency.

## RuboCop Processing Strategies

The RuboCop implementation in [`src/cmds/ruby/rubocop_cmd.rs`](https://github.com/rtk-ai/rtk/blob/main/src/cmds/ruby/rubocop_cmd.rs) handles both structured JSON output and legacy text formats through dual parsing paths.

### JSON Parsing and Severity Ranking

When you run `rtk rubocop`, the `run()` function (lines 53-87) automatically injects `--format json` unless you've specified a custom formatter. The `filter_rubocop_json()` function (lines 91-200) deserializes this structured data and sorts files by offense severity. It displays only the **top 10 files** and **5 offenses per file**, appending an overflow indicator when additional issues exist.

### Text Fallback and Path Compaction

If JSON parsing fails or you provide a format flag like `-f progress`, RTK falls back to `filter_rubocop_text()` (lines 210-264). This state machine extracts summary lines and autocorrect counts while truncating verbose error blocks. Both paths utilize `compact_ruby_path()` (lines 287-318) to rewrite absolute paths like [`/Users/dev/project/app/models/user.rb`](https://github.com/rtk-ai/rtk/blob/main//Users/dev/project/app/models/user.rb) into concise relative paths such as [`app/models/user.rb`](https://github.com/rtk-ai/rtk/blob/main/app/models/user.rb), significantly reducing token consumption.

## RSpec Output Optimization

The RSpec module in [`src/cmds/ruby/rspec_cmd.rs`](https://github.com/rtk-ai/rtk/blob/main/src/cmds/ruby/rspec_cmd.rs) applies similar principles to test output, with additional logic for handling noisy Ruby environments.

### Structured Test Summaries

The `run()` method (lines 65-89) adds `--format json` to RSpec invocations when no user format is detected. The `filter_rspc_output()` function (lines 74-84) attempts deserialization into an `RspecOutput` struct, then calls `build_rspec_summary()` (lines 101-159) to generate a compressed report showing passed/failed/pending counts, duration, and up to **5 failure entries**. Each failure trims stack traces to a single line containing file and line information.

### Noise Reduction and Fallback Parsing

When JSON parsing fails, the `strip_noise()` function (lines 102-152) removes Spring preloader messages, SimpleCov output, and deprecation warnings. The `filter_rspec_text()` state machine (lines 166-236) then extracts failure details and summary statistics, truncating backtraces at the first non-gem line. Like RuboCop, RSpec output includes overflow hints (e.g., "... +2 more") when failures exceed the display limit.

## Token Optimization Techniques

Both Ruby modules implement specific strategies to minimize LLM token usage while preserving diagnostic value:

- **JSON-First Processing**: Machine-readable formats provide structured data without decorative ASCII borders or progress bars.
- **Quantitative Limits**: Hard caps on displayed files, offenses, and failures prevent context window overflow.
- **Path Compression**: `compact_ruby_path()` eliminates redundant absolute path prefixes common in Rails applications.
- **Smart Truncation**: Helper functions remove backtrace noise while keeping the first relevant application frame.

## Practical Usage Examples

Execute RuboCop through RTK to receive a condensed offense summary:

```bash
rtk rubocop src/

```

Example output:

```

rubocop: 12 offenses (8 files)

app/models/user.rb
  :10 Layout/TrailingWhitespace — Trailing whitespace
  :25 Lint/UselessAssignment — Useless assignment
  ... +2 more

... +2 more files

(3 correctable, run `rubocop -A`)

```

Run RSpec with automatic noise filtering:

```bash
rtk rspec spec/models

```

Example output:

```

RSpec: 9 passed, 2 failed (0.12s)
═══════════════════════════════════════

Failures:

1. ❌ User validates email format
   spec/models/user_spec.rb:42
   ExpectationNotMetError: expected true but got false

2. ❌ Post validates title
   spec/models/post_spec.rb:27
   ExpectationNotMetError: expected "Hello" to eq "World"

... +1 more failures

```

Force text mode when using custom formatters:

```bash
rtk rubocop -f progress src/

```

RTK detects the `-f` flag and invokes `filter_rubocop_text()`, preserving your formatter's output while still applying length limits and path compression.

## Summary

- RTK processes Ruby tools through **filter modules** that intercept output before terminal display.
- The `ruby_exec()` function auto-detects Bundler environments to ensure consistent gem versions.
- RuboCop output undergoes **JSON parsing** with severity sorting and path compaction via `compact_rub path()`.
- RSpec results are stripped of Spring/SimpleCov noise and limited to 5 failures with clean backtraces.
- Both tools implement **fallback text parsers** when JSON is unavailable or user formatting is specified.
- Token reduction strategies include limiting displayed items, compressing paths, and removing stacktrace noise.

## Frequently Asked Questions

### How does RTK detect when to use Bundler?

The `ruby_exec()` function in [`src/core/utils.rs`](https://github.com/rtk-ai/rtk/blob/main/src/core/utils.rs) checks for a `Gemfile` in the working directory. When found, it automatically prefixes commands with `bundle exec`, ensuring RuboCop and RSpec execute with the exact versions locked in your project.

### What happens if JSON parsing fails during output processing?

Both Ruby modules include robust fallback mechanisms. If `filter_rubocop_json()` or `filter_rspc_output()` encounters malformed JSON, control passes to `filter_rubocop_text()` or `filter_rspec_text()` respectively. These state machines parse the raw text output, extract critical error summaries, and truncate verbose sections while preserving essential diagnostic information.

### How does RTK optimize output for LLM token limits?

RTK employs several compression strategies: requesting machine-readable **JSON formats** over decorative text, limiting displayed offenses to 10 files and 5 per file (RuboCop) or 5 failures (RSpec), and rewriting absolute paths to relative equivalents via `compact_ruby_path()`. The system also strips Spring preloader noise and truncates backtraces to the first application frame.

### Can I use custom RSpec or RuboCop formatters with RTK?

Yes. When RTK detects user-provided format flags (like `-f progress` or `--format documentation`), it skips JSON injection and processes the raw formatted output through its text fallback filters. This preserves your custom formatter's appearance while still applying path compaction and length limits to prevent token overflow.