Skip to main content
skill Claude Code CX Codex Cursor GitHub Copilot

tdd-rust — Claude Code skill: Red-Green-Refactor in Rust

Skill for RTK filter development using TDD. Write a test with real data, implement minimum code, verify token savings, lock the output format with insta snapshots.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add rtk-ai/rtk --skill tdd-rust -a claude-code
Open on GitHub

What tdd-rust does

tdd-rust automates the Red-Green-Refactor loop for new filters. Start with real command output (git log, cargo test, gh pr view), write a failing test, add minimum code to pass it, then verify the filter saves at least 20% of tokens and handles edge cases without panicking.

The skill uses Read, Write, Edit and Bash tools. It works with real fixtures in tests/fixtures/, snapshots via insta, and the Arrange-Act-Assert pattern. You write two required checks: snapshot test for output format and token savings validation. Tests for empty input and malformed data ensure the filter won't crash.

Before a filter lands in RTK, register it in main.rs and pass cargo fmt, cargo clippy and cargo test with no errors. The skill triggers on "new filter", "implement filter", "write tests for" and similar phrases.

What it helps with

  • Capture real command output without synthetic test data
  • Guarantee at least 20% token reduction for every filter
  • Lock output format with snapshots to prevent degradation
  • Handle edge cases without panics
  • Pass all quality checks and integrate into main codebase

Example prompts for the agent

  • Write test and implementation for a new git log filter
  • Add token savings check for cargo clippy filter
  • Run Red-Green-Refactor for gh pr view filter

How to install tdd-rust

1Skills CLI (Vercel)

npx skills add rtk-ai/rtk --skill tdd-rust -a claude-code

2Manually: put the files in place

~/.claude/skills/tdd-rust/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/tdd-rust/

From the same set4

The whole set →

Similar

bmad-eval bmad-code-org Runs automated benchmarks and evaluations for agent skills across four modes, checking trigger accuracy and grading quality in a clean workspace. Claude Code CX Codex Cursor +1 4,500installs add-lang colbymchenry Adds a new language to codegraph through tree-sitter, tests the extractor, and measures extraction and retrieval on real repositories. Claude Code CX Codex Cursor +1 1,200installs laravel-specialist https://github.com/Jeffallan Configures the agent for Laravel 10+ and PHP 8.2+ development. It guides Eloquent modeling, Horizon queues, API resources, and Pest testing. Claude Code CX Codex Cursor +1 23,300installs dotnet-backend-patterns Seth Hobson Skill for C# and .NET development: patterns for async code, dependency injection, Entity Framework Core, caching, and testing. Use when building backend APIs, MCP servers, or reviewing C# code. Claude Code CX Codex Cursor 19,076installs flutter-add-widget-test flutter A skill that teaches AI coders to write component-level Flutter tests using WidgetTester. Verifies how widgets render and respond to taps, scrolling, and text input. Claude Code CX Codex Cursor +1 39,000installs flutter-add-integration-test flutter Sets up the integration_test package for Flutter and turns MCP session interactions into repeatable end-to-end tests. Claude Code CX Codex Cursor +1 38,000installs improve-codebase-architecture Matt Pocock This skill scans a codebase for architectural friction, then builds a visual HTML report with refactoring candidates. Use it before a deeper architecture review. Claude Code 1,163,035installs design-taste-frontend Leonxlnx This skill directs the design of public pages and work screens, then checks the result in a browser through screenshots. Use it when an interface feels generic or unfinished. Claude Code CX Codex Cursor +1 673,100installs

Questions about tdd-rust

How do I install tdd-rust in Claude Code?

Run npx skills add rtk-ai/rtk --skill tdd-rust -a claude-code, then open ~/.claude/skills/tdd-rust/SKILL.md to verify. For other platforms use -a codex for Codex, -a cursor for Cursor, -a gemini-cli for Gemini CLI, or gh skill install rtk-ai/rtk tdd-rust for GitHub Copilot.

What does tdd-rust do?

The skill walks you through Red-Green-Refactor for RTK filters. You write a test against real data, implement the filter, verify it cuts output by at least 20% tokens, and lock the format with insta snapshots.

Why require 20% token savings?

A filter is only worth adding if it meaningfully cuts output. 20% is the practical minimum threshold. The skill enforces this through test_token_savings so weak filters cannot pass.

Source text

SKILL.md · Apache-2.0
---
name: tdd-rust
description: TDD workflow for RTK filter development. Red-Green-Refactor with Rust idioms. Real fixtures, token savings assertions, snapshot tests with insta. Auto-triggers on new filter implementation.
triggers:
  - "new filter"
  - "implement filter"
  - "add command"
  - "write tests for"
  - "test coverage"
  - "fix failing test"
allowed-tools:
  - Read
  - Write
  - Edit
  - Bash
effort: medium
tags: [tdd, testing, rust, filters, snapshots, token-savings, rtk]
---

# RTK TDD Workflow

Enforce Red-Green-Refactor for all RTK filter development.

## The Loop

```
1. RED   — Write failing test with real fixture
2. GREEN — Implement minimum code to pass
3. REFACTOR — Clean up, verify still passing
4. SAVINGS — Verify ≥20% token reduction
5. SNAPSHOT — Lock output format with insta
```

## Step 1: Real Fixture First

Never write synthetic test data. Capture real command output:

```bash
# Capture real output from the actual command
git log -20 > tests/fixtures/git_log_raw.txt
cargo test 2>&1 > tests/fixtures/cargo_test_raw.txt
cargo clippy 2>&1 > tests/fixtures/cargo_clippy_raw.txt
gh pr view 42 > tests/fixtures/gh_pr_view_raw.txt

# For commands with ANSI codes — capture as-is
script -q /dev/null cargo test 2>&1 > tests/fixtures/cargo_test_ansi_raw.txt
```

Fixture naming: `tests/fixtures/<command>_raw.txt`

## Step 2: Write the Test (Red)

```rust
#[cfg(test)]
mod tests {
    use super::*;
    use insta::assert_snapshot;

    fn count_tokens(s: &str) -> usize {
        s.split_whitespace().count()
    }

    // Test 1: Output format (snapshot)
    #[test]
    fn test_filter_output_format() {
        let input = include_str!("../tests/fixtures/mycmd_raw.txt");
        let output = filter_mycmd(input).expect("filter should not fail");
        assert_snapshot!(output);
    }

    // Test 2: Token savings ≥20%
    #[test]
    fn test_token_savings() {
        let input = include_str!("../tests/fixtures/mycmd_raw.txt");
        let output = filter_mycmd(input).expect("filter should not fail");

        let input_tokens = count_tokens(input);
        let output_tokens = count_tokens(&output);
        let savings = 100.0 * (1.0 - output_tokens as f64 / input_tokens as f64);

        assert!(
            savings >= 20.0,
            "Expected ≥20% token savings, got {:.1}% ({} → {} tokens)",
            savings, input_tokens, output_tokens
        );
    }

    // Test 3: Edge cases
    #[test]
    fn test_empty_input() {
        let result = filter_mycmd("");
        assert!(result.is_ok());
        // Empty input = empty output OR passthrough, never panic
    }

    #[test]
    fn test_malformed_input() {
        let result = filter_mycmd("not valid command output\nrandom text\n");
        // Must not panic — either filter best-effort or return input unchanged
        assert!(result.is_ok());
    }
}
```

Run: `cargo test` → should fail (function doesn't exist yet).

## Step 3: Minimum Implementation (Green)

```rust
// src/mycmd_cmd.rs

use anyhow::{Context, Result};
use regex::Regex;
use std::sync::LazyLock;

static ERROR_RE: LazyLock<Regex> =
    LazyLock::new(|| Regex::new(r"^error").unwrap());

pub fn filter_mycmd(input: &str) -> Result<String> {
    if input.is_empty() {
        return Ok(String::new());
    }

    let filtered: Vec<&str> = input.lines()
        .filter(|line| ERROR_RE.is_match(line))
        .collect();

    Ok(filtered.join("\n"))
}
```

Run: `cargo test` → green.

## Step 4: Accept Snapshot

```bash
# First run creates the snapshot
cargo test test_filter_output_format

# Review what was captured
cargo insta review
# Press 'a' to accept

# Snapshot saved to src/snapshots/mycmd_cmd__tests__test_filter_output_format.snap
```

## Step 5: Wire to main.rs (Integration)

```rust
// src/main.rs
mod mycmd_cmd;

#[derive(Subcommand)]
pub enum Commands {
    // ... existing commands ...
    Mycmd(MycmdArgs),
}

// In match:
Commands::Mycmd(args) => mycmd_cmd::run(args),
```

```rust
// src/mycmd_cmd.rs — add run() function
pub fn run(args: MycmdArgs) -> Result<()> {
    let output = execute_command("mycmd", &args.to_vec())
        .context("Failed to execute mycmd")?;

    let filtered = filter_mycmd(&output.stdout)
        .unwrap_or_else(|e| {
            eprintln!("rtk: filter warning: {}", e);
            output.stdout.clone()
        });

    tracking::record("mycmd", &output.stdout, &filtered)?;
    print!("{}", filtered);

    if !output.status.success() {
        std::process::exit(output.status.code().unwrap_or(1));
    }
    Ok(())
}
```

## Step 6: Quality Gate

```bash
cargo fmt --all && cargo clippy --all-targets && cargo test
```

All 3 must pass. Zero clippy warnings.

## Arrange-Act-Assert Pattern

```rust
#[test]
fn test_filters_only_errors() {
    // Arrange
    let input = "info: starting build\nerror[E0001]: undefined\nwarning: unused\n";

    // Act
    let output = filter_mycmd(input).expect("should succeed");

    // Assert
    assert!(output.contains("error[E0001]"), "Should keep error lines");
    assert!(!output.contains("info:"), "Should drop info lines");
    assert!(!output.contains("warning:"), "Should drop warning lines");
}
```

## RTK-Specific Test Patterns

### Test ANSI stripping

```rust
#[test]
fn test_strips_ansi_codes() {
    let input = "\x1b[32mSuccess\x1b[0m\n\x1b[31merror: failed\x1b[0m\n";
    let output = filter_mycmd(input).expect("should succeed");
    assert!(!output.contains("\x1b["), "ANSI codes should be stripped");
    assert!(output.contains("error: failed"), "Content should be preserved");
}
```

### Test fallback behavior

```rust
#[test]
fn test_filter_handles_unexpected_format() {
    // Give it something completely unexpected
    let input = "completely unexpected\x00binary\xff data";
    // Should not panic — returns Ok() with either empty or passthrough
    let result = filter_mycmd(input);
    assert!(result.is_ok(), "Filter must not panic on unexpected input");
}
```

### Test savings at multiple sizes

```rust
#[test]
fn test_savings_large_output() {
    // 1000-line fixture → must still hit ≥20%
    let large_input: String = (0..1000)
        .map(|i| format!("info: processing item {}\n", i))
        .collect();
    let output = filter_mycmd(&large_input).expect("should succeed");

    let savings = 100.0 * (1.0 - count_tokens(&output) as f64 / count_tokens(&large_input) as f64);
    assert!(savings >= 20.0, "Large output savings: {:.1}%", savings);
}
```

## What "Done" Looks Like

Checklist before moving on:

- [ ] `tests/fixtures/<cmd>_raw.txt` — real command output
- [ ] `filter_<cmd>()` function returns `Result<String>`
- [ ] Snapshot test passes and accepted via `cargo insta review`
- [ ] Token savings test: ≥20% verified
- [ ] Empty input test: no panic
- [ ] Malformed input test: no panic
- [ ] `run()` function with fallback pattern
- [ ] Registered in `main.rs` Commands enum
- [ ] `cargo fmt --all && cargo clippy --all-targets && cargo test` — all green

## Never Do This

```rust
// ❌ Synthetic fixture data
let input = "fake error: something went wrong";  // Not real cargo output

// ❌ Missing savings test
#[test]
fn test_filter() {
    let output = filter_mycmd(input);
    assert!(!output.is_empty());  // No savings verification
}

// ❌ unwrap() in production code
let filtered = filter_mycmd(input).unwrap();  // Panic in prod

// ❌ Regex inside the filter function
fn filter_mycmd(input: &str) -> Result<String> {
    let re = Regex::new(r"^error").unwrap();  // Recompiles every call
    ...
}
```

© rtk-ai · Apache-2.0 · rtk-ai/rtk

See also

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor