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

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 and 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 (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 (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 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 into concise relative paths such as app/models/user.rb, significantly reducing token consumption.

RSpec Output Optimization

The RSpec module in 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:

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:

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:

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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →