Skip to main content

Overview

RTK provides comprehensive Python development tool support with 70-90% token savings through:
  • JSON parsing: Structured output from Ruff and pip
  • State machine parsing: Text-based pytest output
  • Error grouping: Group by file, rule, or error code
  • Auto-detection: Detects uv for faster pip operations

Supported Tools

Ruff

Fast linter/formatter (80% savings)

Pytest

Test runner with failures only (90% savings)

pip/uv

Package manager with JSON parsing (70-85% savings)

Mypy

Type checker with error grouping (80% savings)

rtk ruff

Ruff linter and formatter with JSON parsing.

Usage

rtk ruff check [options] [path]
rtk ruff format [options] [path]

Examples

$ ruff check .
src/utils.py:12:5: F401 [*] `os` imported but unused
src/utils.py:18:1: E302 [*] Expected 2 blank lines, found 1
src/api/client.py:42:80: E501 Line too long (95 > 88 characters)
src/api/client.py:55:10: F841 [*] Local variable `result` is assigned to but never used
src/models/user.py:23:5: D103 Missing docstring in public function
Found 5 errors (4 fixable with --fix)
# 7+ lines, ~300 tokens

Features

  • JSON parsing: Uses --output-format=json automatically
  • Rule grouping: Groups violations by rule code
  • Fix hints: Shows which errors are auto-fixable
  • Exit code preservation: Safe for CI/CD

Implementation

From src/ruff_cmd.rs:
// Force JSON output for check command
if is_check {
    cmd.arg("check").arg("--output-format=json");
}

// Parse JSON diagnostics
#[derive(Deserialize)]
struct RuffDiagnostic {
    code: String,
    message: String,
    location: RuffLocation,
    filename: String,
    fix: Option<RuffFix>,
}

let diagnostics: Vec<RuffDiagnostic> = serde_json::from_str(&stdout)?;

// Group by rule code
let mut by_rule: HashMap<String, Vec<_>> = HashMap::new();
for diag in diagnostics {
    by_rule.entry(diag.code).or_default().push(diag);
}

rtk ruff format

Ruff formatter with compact output.
$ ruff format .
3 files reformatted, 12 files left unchanged

rtk pytest

Pytest test runner showing failures only.

Usage

rtk pytest [options] [file::test]

Examples

$ pytest
============================= test session starts ==============================
platform linux -- Python 3.11.0, pytest-7.4.0, pluggy-1.0.0
rootdir: /path/to/project
collected 25 items

tests/test_utils.py ........                                             [ 32%]
tests/test_api.py .F...F.                                                [ 60%]
tests/test_models.py ..........                                          [100%]

=================================== FAILURES ===================================
________________________________ test_fetch_data _______________________________

    def test_fetch_data():
>       assert response.status_code == 200
E       AssertionError: assert 404 == 200

tests/test_api.py:42: AssertionError

_______________________________ test_validate_user _____________________________

    def test_validate_user():
>       assert user.is_valid()
E       AssertionError: assert False
E        +  where False = <bound method User.is_valid of <User id=123>>()

tests/test_api.py:68: AssertionError
=========================== short test summary info ============================
FAILED tests/test_api.py::test_fetch_data - AssertionError: assert 404 == 200
FAILED tests/test_api.py::test_validate_user - AssertionError: assert False
========================= 2 failed, 23 passed in 1.52s =========================
# 35+ lines, ~800 tokens

Features

  • State machine parser: Parses text output (no JSON mode needed)
  • Auto-flags: Forces --tb=short -q for compact output
  • Failure details: Preserves assertion messages and tracebacks
  • Tee recovery: Full output saved to file on failure

Implementation

From src/pytest_cmd.rs:
#[derive(Debug, PartialEq)]
enum ParseState {
    Header,       // Session start info
    TestProgress, // Running tests (dots)
    Failures,     // Failure details
    Summary,      // Final counts
}

fn filter_pytest_output(output: &str) -> String {
    let mut state = ParseState::Header;
    let mut failures = Vec::new();
    
    for line in output.lines() {
        match state {
            ParseState::TestProgress if line.starts_with("====== FAILURES") => {
                state = ParseState::Failures;
            }
            ParseState::Failures => {
                // Extract failure sections
                failures.push(line);
            }
            // ...
        }
    }
}

Supported Options

  • -v: Verbose mode (passthrough)
  • -k <pattern>: Run tests matching pattern
  • -x: Stop on first failure
  • --tb=<style>: Traceback style (short/long/no)

rtk pip

Package manager with auto-detection of uv.

Usage

rtk pip list [options]
rtk pip outdated [options]
rtk pip install <package>
rtk pip show <package>

Auto-detection

RTK automatically detects and uses uv if available:
# Checks for `uv` in PATH
which uv  # If found, uses "uv pip"
          # Otherwise, uses "pip"

Examples

$ pip list
Package           Version
----------------- ---------
requests          2.31.0
django            4.2.7
celery            5.3.4
numpy             1.24.3
pandas            2.0.3
pytest            7.4.3
...
# 20+ lines, ~400 tokens

rtk pip outdated

Show outdated packages with upgrade suggestions.
$ pip list --outdated
Package    Version   Latest    Type
---------- --------- --------- -----
requests   2.28.0    2.31.0    wheel
django     4.1.7     4.2.7     wheel
celery     5.2.7     5.3.4     wheel
# 5+ lines, ~200 tokens

Features

  • JSON parsing: Uses --format=json for structured output
  • Grouping: Groups packages by category (Core, Data, Testing, etc.)
  • Upgrade hints: Generates upgrade commands
  • uv support: Seamlessly uses uv pip when available

Implementation

From src/pip_cmd.rs:
// Auto-detect uv
let use_uv = which_command("uv").is_some();
let base_cmd = if use_uv { "uv" } else { "pip" };

// Force JSON output
cmd.arg("list").arg("--format=json");

// Parse JSON
#[derive(Deserialize)]
struct Package {
    name: String,
    version: String,
    latest_version: Option<String>,
}

let packages: Vec<Package> = serde_json::from_str(&stdout)?;

rtk mypy

Mypy type checker with error grouping.

Usage

rtk mypy [options] [files]

Examples

$ mypy .
src/utils.py:12: error: Incompatible return value type (got "int", expected "str")
src/utils.py:24: error: Argument 1 to "process" has incompatible type "str"; expected "int"
src/api/client.py:42: error: "Response" has no attribute "json_data"
src/api/client.py:55: error: Cannot call function of unknown type
src/models/user.py:18: error: Need type annotation for "data" (hint: "data: Dict[<type>, <type>] = ...")
Found 5 errors in 3 files (checked 12 source files)
# 7+ lines, ~350 tokens

Features

  • File grouping: Group errors by file
  • Line numbers: Compact :line format
  • Error messages: Preserve full error text
  • Exit codes: Safe for CI/CD

CI/CD Integration

All Python tools preserve exit codes:
# .github/workflows/ci.yml
name: Python CI

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      - name: Install dependencies
        run: pip install -r requirements.txt
      - name: Lint
        run: rtk ruff check .
      - name: Type check
        run: rtk mypy .
      - name: Test
        run: rtk pytest

Token Savings Summary

CommandStandard TokensRTK TokensSavings
ruff check (5 errors)30060-80%
pytest (2 fail, 23 pass)80080-90%
pip list (127 packages)400120-70%
pip outdated (3 packages)20030-85%
mypy (5 errors)35070-80%

Next Steps

Go

Go development tools

Testing

Cross-language test runners