/tdd-rust
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.
$ npx -y skills add rtk-ai/rtk --skill tdd-rust --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/tdd-rust
Context preview
The summary Claude sees to decide when to auto-load this skill.
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.
SKILL.md
tdd-rust.SKILL.mdname: 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 ≥60% token reduction
5. SNAPSHOT — Lock output format with insta
Step 1: Real Fixture First
Never write synthetic test data. Capture real command output:
# 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)
#[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 ≥60%
#[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 >= 60.0,
"Expected ≥60% 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)
// 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
# 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)
// src/main.rs
mod mycmd_cmd;
#[derive(Subcommand)]
pub enum Commands {
// ... existing commands ...
Mycmd(MycmdArgs),
}
// In match:
Commands::Mycmd(args) => mycmd_cmd::run(args),// 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
cargo fmt --all && cargo clippy --all-targets && cargo test
All 3 must pass. Zero clippy warnings.
Arrange-Act-Assert Pattern
#[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
#[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
#[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 s
Read more
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 ≥60% token reduction 5. SNAPSHOT — Lock output format with insta
Step 1: Real Fixture First
Never write synthetic test data. Capture real command output:
# 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)
#[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 ≥60%
#[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 >= 60.0,
"Expected ≥60% 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)
// 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
# 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)
// src/main.rs
mod mycmd_cmd;
#[derive(Subcommand)]
pub enum Commands {
// ... existing commands ...
Mycmd(MycmdArgs),
}
// In match:
Commands::Mycmd(args) => mycmd_cmd::run(args),// 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
cargo fmt --all && cargo clippy --all-targets && cargo test
All 3 must pass. Zero clippy warnings.
Arrange-Act-Assert Pattern
#[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
#[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
#[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 s
CLI proxy that reduces LLM token consumption by 60-90% on common dev commands. Single Rust binary, zero dependencies
Repo: rtk-ai/rtk
Other skills on rtk.
- /code-simplifier
Review RTK Rust code for idiomatic simplification. Detects over-engineering, unnecessary allocations, verbose patterns. Applies Rust idioms without changing behavior.
Open skill - /design-patterns
Rust design patterns for RTK. Newtype, Builder, RAII, Trait Objects, State Machine. Applied to CLI filter modules. Use when designing new modules or refactoring existing ones.
Open skill - /issue-triage
Issue triage: audit open issues, categorize, detect duplicates, cross-ref PRs, risk assessment, post comments. Args: "all" for deep analysis of all, issue numbers to focus (e.g. "42 57"), "en"/"fr" for language, no arg = audit only in French.
Open skill - /performance
CLI performance optimization - startup time, memory usage, token savings benchmarking
Open skill - /pr-review
Batch review des PRs RTK par ordre de complexité croissante (XS → S → M → L). Pour chaque PR : vérifie l'état (conflits, CLA, reviews), lit le diff complet, analyse le code en contexte, présente un résumé avec lien + taille + recommandation. Attend validation explicite avant
Open skill - /pr-triage
PR triage: audit open PRs, deep review selected ones, draft and post review comments. Args: "all" to review all, PR numbers to focus (e.g. "42 57"), "en"/"fr" for language, no arg = audit only in French.
Open skill

