본문으로 건너뛰기
cccskills
무료GitHub에 공개

design-patterns

Choose Rust design patterns for RTK modules that process command output. Use concrete examples to structure configuration, prevent type mixups, manage parser states, and select abstractions suited to the task without adding unnecessary architectural complexity.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

원문원문 설명 보기

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.

설치 방법 보기

이럴 때 유용합니다

  • Planning the structure of a new command output filter
  • Preventing mixups between values with the same underlying type
  • Organizing configuration with many optional fields
  • Designing parsers for output with multiple sections

포함된 파일(1)

  • SKILL.md7.3 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

RTK Rust Design Patterns

Patterns that apply to RTK's filter module architecture. Focused on CLI tool patterns, not web/service patterns.

Pattern 1: Newtype (Type Safety)

Use when: wrapping primitive types to prevent misuse (command names, paths, token counts).

// Without Newtype — easy to mix up
fn track(input_tokens: usize, output_tokens: usize) { ... }
track(output_tokens, input_tokens);  // Silent bug!

// With Newtype — compile error on swap
pub struct InputTokens(pub usize);
pub struct OutputTokens(pub usize);
fn track(input: InputTokens, output: OutputTokens) { ... }
track(OutputTokens(100), InputTokens(400));  // Compile error ✅
// Practical RTK example: command name validation
pub struct CommandName(String);
impl CommandName {
    pub fn new(s: &str) -> Result<Self> {
        if s.contains(';') || s.contains('|') || s.contains('`') {
            anyhow::bail!("Invalid command name: shell metacharacters");
        }
        Ok(Self(s.to_string()))
    }
    pub fn as_str(&self) -> &str { &self.0 }
}

Pattern 2: Builder (Complex Configuration)

Use when: a struct has 4+ optional fields, many with defaults.

#[derive(Default)]
pub struct FilterConfig {
    max_lines: Option<usize>,
    strip_ansi: bool,
    show_warnings: bool,
    truncate_at: Option<usize>,
}

impl FilterConfig {
    pub fn new() -> Self { Self::default() }
    pub fn max_lines(mut self, n: usize) -> Self { self.max_lines = Some(n); self }
    pub fn strip_ansi(mut self, v: bool) -> Self { self.strip_ansi = v; self }
    pub fn show_warnings(mut self, v: bool) -> Self { self.show_warnings = v; self }
}

// Usage — readable, no positional arg confusion
let config = FilterConfig::new()
    .max_lines(50)
    .strip_ansi(true)
    .show_warnings(false);

When NOT to use Builder: if the struct has 1-3 fields with obvious meaning. Over-engineering for simple cases.

Pattern 3: State Machine (Parser/Filter Flows)

Use when: parsing multi-section output (test results, build output) where context changes behavior.

// RTK example: pytest output parsing
#[derive(Debug, PartialEq)]
enum ParseState {
    LookingForTests,
    InTestOutput,
    InFailureSummary,
    Done,
}

fn parse_pytest(input: &str) -> String {
    let mut state = ParseState::LookingForTests;
    let mut failures = Vec::new();

    for line in input.lines() {
        match state {
            ParseState::LookingForTests => {
                if line.contains("FAILED") || line.contains("ERROR") {
                    state = ParseState::InFailureSummary;
                    failures.push(line);
                }
            }
            ParseState::InFailureSummary => {
                if line.starts_with("=====") { state = ParseState::Done; }
                else { failures.push(line); }
            }
            ParseState::Done => break,
            _ => {}
        }
    }
    failures.join("\n")
}

Pattern 4: Trait Object (Command Dispatch)

Use when: different command families need the same interface. Avoids massive match arms.

// Define a common interface for filters
pub trait OutputFilter {
    fn filter(&self, input: &str) -> Result<String>;
    fn command_name(&self) -> &str;
}

pub struct GitFilter;
pub struct CargoFilter;

impl OutputFilter for GitFilter {
    fn filter(&self, input: &str) -> Result<String> { filter_git(input) }
    fn command_name(&self) -> &str { "git" }
}

// RTK currently uses match-based dispatch in main.rs (simpler, no dynamic dispatch overhead)
// Trait objects are useful if filter registry becomes dynamic (e.g., TOML-loaded plugins)

Note: RTK's current match dispatch in main.rs is intentional — static dispatch, zero overhead. Only move to trait objects if the match arm count exceeds ~20 commands.

Pattern 5: RAII (Resource Management)

Use when: managing resources that need cleanup (temp files, SQLite connections).

// RTK tee.rs — RAII for temp output files
pub struct TeeFile {
    path: PathBuf,
}

impl TeeFile {
    pub fn create(content: &str) -> Result<Self> {
        let path = tee_path()?;
        fs::write(&path, content)
            .with_context(|| format!("Failed to write tee file: {}", path.display()))?;
        Ok(Self { path })
    }

    pub fn path(&self) -> &Path { &self.path }
}

// No explicit cleanup needed — file persists intentionally (rotation handled separately)
// If cleanup were needed: impl Drop { fn drop(&mut self) { let _ = fs::remove_file(&self.path); } }

Pattern 6: Strategy (Swappable Filter Logic)

Use when: a command has multiple filtering modes (e.g., compact vs. verbose).

pub enum FilterMode {
    Compact,    // Show only failures/errors
    Summary,    // Show counts + top errors
    Full,       // Pass through unchanged
}

pub fn apply_filter(input: &str, mode: FilterMode) -> String {
    match mode {
        FilterMode::Compact => filter_compact(input),
        FilterMode::Summary => filter_summary(input),
        FilterMode::Full => input.to_string(),
    }
}

Pattern 7: Extension Trait (Add Methods to External Types)

Use when: you need to add methods to types you don't own (like &str for RTK-specific parsing).

pub trait RtkStrExt {
    fn is_error_line(&self) -> bool;
    fn is_warning_line(&self) -> bool;
    fn token_count(&self) -> usize;
}

impl RtkStrExt for str {
    fn is_error_line(&self) -> bool {
        self.starts_with("error") || self.contains("[E")
    }
    fn is_warning_line(&self) -> bool {
        self.starts_with("warning")
    }
    fn token_count(&self) -> usize {
        self.split_whitespace().count()
    }
}

// Usage
if line.is_error_line() { ... }
let tokens = output.token_count();

RTK Pattern Selection Guide

SituationPatternAvoid
New *_cmd.rs filter moduleStandard module pattern (see CLAUDE.md)Over-abstracting
4+ optional config fieldsBuilderStruct literal
Multi-phase output parsingState MachineNested if/else
Type-safe wrapper around stringNewtypeRaw String
Adding methods to &strExtension TraitFree functions
Resource with cleanupRAII / DropManual cleanup
Dynamic filter registryTrait ObjectMatch sprawl

Anti-Patterns in RTK Context

// ❌ Generic over-engineering for one command
pub trait Filterable<T: CommandArgs + Send + Sync + 'static> { ... }

// ✅ Just write the function
pub fn filter_git_log(input: &str) -> Result<String> { ... }

// ❌ Singleton registry with global state
static FILTER_REGISTRY: Mutex<HashMap<String, Box<dyn Filter>>> = ...;

// ✅ Match in main.rs — simple, zero overhead, easy to trace

// ❌ Async traits for "future-proofing"
#[async_trait]
pub trait Filter { async fn apply(&self, input: &str) -> Result<String>; }

// ✅ Synchronous — RTK is single-threaded by design
pub trait Filter { fn apply(&self, input: &str) -> Result<String>; }

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Simplify Rust code in RTK by replacing verbose loops, unnecessary copies, and excessive abstractions with common Rust patterns. Preserve behavior and project requirements, including error context, fallback handling, exit codes, and existing test modules.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Simplifying verbose loops and string construction
  • Removing unnecessary string copies
  • Reducing nested conditional and error handling code
rtk-ai/rtk8.4만2026년 10월 17일 업데이트

Organize open GitHub issues by category, risk, linked pull requests, duplicate candidates, and inactivity. Optionally analyze selected issues in depth, draft responses, and apply approved comments, labels, or closures to keep the backlog actionable.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Sorting a growing backlog of open issues
  • Checking whether suspected duplicate issues are truly duplicates
  • Prioritizing security risks and breaking changes
rtk-ai/rtk8.4만2026년 10월 17일 업데이트

pr-triage

무료

Sort open GitHub pull requests by change size, automated check results, conflicts, and inactivity. Review selected changes in detail, draft constructive feedback, and post comments after the user approves them.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Prioritizing a backlog of open pull requests
  • Finding overlapping changes and failing checks
  • Reviewing selected pull requests in detail
rtk-ai/rtk8.4만2026년 10월 17일 업데이트

rtk-tdd

무료

Guide Rust development through test-driven development: write a failing test, implement enough code to pass, then refactor. Includes practical test patterns and final checks for formatting, static analysis, and test results.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Adding Rust features with tests first
  • Reproducing bugs with failing tests before fixing them
  • Testing invalid inputs and error paths
rtk-ai/rtk8.4만2026년 10월 17일 업데이트

Review GitHub issues and pull requests together to find duplicate work, security findings without fixes, and critical bugs without linked changes. Produce action tables and a dated report to support backlog reviews and sprint planning.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Reviewing issues and pull requests before a sprint
  • Finding pull requests that duplicate the same work
  • Identifying security findings without proposed fixes
rtk-ai/rtk8.4만2026년 10월 17일 업데이트

tdd-rust

무료

Develop Rust filters for RTK through tests written before implementation. Use real command output as test inputs, check output snapshots and unexpected inputs, verify a minimum reduction target, and complete formatting, linting, and test checks before finishing.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Adding a new RTK command filter
  • Checking filtered output against saved snapshots
  • Testing empty, malformed, or ANSI-colored input
rtk-ai/rtk8.4만2026년 10월 17일 업데이트

rtk-ai의 스킬 모두 보기

이 스킬의 문제 신고