К основному содержанию
скилл Claude Code CX Codex Cursor GitHub Copilot

tdd-rust — скилл для Claude Code: Red-Green-Refactor с Rust

Скилл для разработки RTK-фильтров по методу TDD. Пишешь тест на реальных данных, реализуешь минимум кода, проверяешь экономию токенов — и фиксируешь формат вывода снимком через insta.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add rtk-ai/rtk --skill tdd-rust -a claude-code
Открыть на GitHub

Что делает tdd-rust

tdd-rust автоматизирует цикл Red-Green-Refactor для новых фильтров. Ты начинаешь с реального вывода команды (git log, cargo test, gh pr view), пишешь тест, который должен упасть, затем добавляешь минимум кода, чтобы он прошёл. На каждом этапе скилл проверяет, что сокращение достигло 20% по токенам и что края (пустой ввод, сломанные данные) не ломают фильтр.

Внутри — инструменты: Read, Write, Edit и Bash. Скилл работает с реальными фиксчурами в tests/fixtures/, снимками через insta и паттерном Arrange-Act-Assert. Ты пишешь две обязательные проверки: на формат вывода (snapshot) и на сбережение токенов. Тесты для пустого ввода и некорректных данных гарантируют, что фильтр не упадёт.

Чтобы фильтр попал в RTK, нужно зарегистрировать его в main.rs и пройти cargo fmt, cargo clippy и cargo test без ошибок. Скилл срабатывает на триггеры: «новый фильтр», «реализовать фильтр», «написать тесты».

Какие задачи решает

  • Захватить реальный вывод команды без синтетических данных
  • Гарантировать сокращение минимум на 20% токенов для каждого фильтра
  • Заблокировать формат вывода снимком, чтобы не деградировал
  • Обработать граничные случаи без паник
  • Пройти все проверки качества и интегрировать в основной код

Примеры запросов агенту

  • Напиши тест и реализацию для нового фильтра git log
  • Добавь проверку token savings для фильтра cargo clippy
  • Запусти Red-Green-Refactor для фильтра gh pr view

Как установить tdd-rust

1Через Skills CLI (Vercel)

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

2Вручную: положить файлы

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

Папка скилла целиком; для одного проекта — .claude/skills/tdd-rust/

Из того же набора4

Весь набор →

Похожие

bmad-eval bmad-code-org Тестирует и бенчмаркает скиллы в изолированной среде: сравнивает вывод с чистой моделью, проверяет точность триггеров и оценивает качество по рубрике. Claude Code CX Codex Cursor +1 4 500установок add-lang colbymchenry Добавляет поддержку нового языка в codegraph через tree-sitter, покрывает её тестами и проверяет извлечение на реальных репозиториях. Claude Code CX Codex Cursor +1 1 200установок laravel-specialist https://github.com/Jeffallan Настраивает агента на разработку бэкенда на Laravel 10+ и PHP 8.2+. Помогает писать модели Eloquent, очереди Horizon, API resources и тесты Pest. Claude Code CX Codex Cursor +1 23 300установок dotnet-backend-patterns Seth Hobson Скилл для разработки на C# и .NET: паттерны асинхронного кода, внедрение зависимостей, Entity Framework Core, кэширование и тестирование. Нужен, если вы пишете backend API, MCP-серверы или рецензируете код на C#. Claude Code CX Codex Cursor 19 076установок flutter-add-widget-test flutter Скилл помогает писать компонентные тесты Flutter с помощью WidgetTester. Проверяет, как виджет отображается и реагирует на касания, скролл и ввод текста. Claude Code CX Codex Cursor +1 39 000установок flutter-add-integration-test flutter Скилл настраивает интеграционные тесты во Flutter через пакет integration_test. Он переносит действия из MCP-сервера в готовые тестовые сценарии. Claude Code CX Codex Cursor +1 38 000установок improve-codebase-architecture Matt Pocock Скилл ищет архитектурные узкие места в кодовой базе и показывает варианты углубления модулей в HTML-отчёте. Подойдёт для ревью перед рефакторингом. Claude Code 1 163 035установок design-taste-frontend Leonxlnx Скилл задаёт арт-дирекцию для публичных страниц и рабочих экранов, а затем проверяет результат в браузере по скриншотам. Нужен, когда интерфейс выглядит шаблонным или недоработанным. Claude Code CX Codex Cursor +1 673 100установок

Вопросы о tdd-rust

Как установить tdd-rust в Claude Code?

Запусти npx skills add rtk-ai/rtk --skill tdd-rust -a claude-code, затем открой ~/.claude/skills/tdd-rust/SKILL.md для проверки. Для других платформ замени флаг: -a codex для Codex, -a cursor для Cursor, -a gemini-cli для Gemini CLI или используй gh skill install rtk-ai/rtk tdd-rust для GitHub Copilot.

Что делает tdd-rust?

Скилл проводит тебя через Red-Green-Refactor для фильтров RTK. Пишешь тест на реальных данных, реализуешь фильтр, проверяешь, что он сокращает вывод минимум на 20% токенов, и фиксируешь формат снимком через insta.

Почему нужна проверка на 20% экономии токенов?

Фильтр имеет смысл только если существенно сокращает вывод. 20% — минимальный порог, который имеет практическую ценность. Скилл гарантирует это через тест test_token_savings, который не даст пройти фильтру слабее.

Исходный текст

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

Смотрите также

Спонсоры проекта

Компании, которые помогают держать аналитику открытой