v2.1: Linter Output Parsers
Parent: #96 (Command Coverage Expansion)
Priority: High — linters are the noisiest developer tools, highest token waste
Depends on: Nothing (v2.x track, independent of v3)
Overview
Linter output is one of the highest-value compression targets: verbose, repetitive, and heavily consumed by AI agents during code review and fix cycles. All major linters support structured JSON output, making them ideal for our three-tier degradation pattern.
Parsers to Implement
eslint (JavaScript/TypeScript)
- Structured:
eslint --format json → parse JSON array of file results
- Compression strategy:
- Group by rule (e.g., all
no-unused-vars together)
- Deduplicate identical messages
- Show: file, line, rule, message, severity
- Strip: column numbers, node types, fix suggestions (unless agent is fixing)
- Expected savings: 60-80%
- Fixture: Real eslint output from a medium project (~50 violations)
ruff (Python)
- Structured:
ruff check --output-format json → parse JSON array
- Compression strategy:
- Group by rule code (e.g., E501, F841)
- Show: file, line, code, message
- Strip: byte offsets, fix applicability metadata
- Expected savings: 60-75%
- Fixture: Real ruff output from a Python project (~30 violations)
mypy (Python)
- Structured:
mypy --output json → parse JSON lines
- Compression strategy:
- Group by error code (e.g., arg-type, name-defined)
- Deduplicate identical type errors across files
- Show: file, line, severity, message
- Strip: column numbers, internal error codes
- Expected savings: 50-70%
- Fixture: Real mypy output with type errors (~20 violations)
golangci-lint (Go)
- Structured:
golangci-lint run --out-format json → parse JSON
- Compression strategy:
- Group by linter name (e.g., govet, errcheck, staticcheck)
- Show: file, line, linter, message
- Strip: source line text (agent can read the file), column info
- Expected savings: 60-75%
- Fixture: Real golangci-lint output from a Go project
Implementation Pattern
Each parser follows the established three-tier degradation:
```rust
pub fn parse_eslint(raw: &str) -> ParseResult {
// Tier 1: Structured (JSON)
if let Ok(results) = serde_json::from_str::<Vec>(raw) {
return compress_eslint_json(results);
}
// Tier 2: Regex fallback
if let Some(compressed) = compress_eslint_regex(raw) {
return compressed;
}
// Tier 3: Passthrough (never corrupt)
ParseResult::passthrough(raw)
}
```
CLI Integration
```bash
Direct usage
eslint src/ --format json | skim lint
eslint src/ --format json | skim lint --format eslint
Via skim rewrite (hook mode)
skim rewrite "eslint src/"
→ Rewrites to: eslint src/ --format json 2>&1 | skim lint --format eslint
Auto-detection
eslint src/ | skim lint # Detects eslint from output patterns
ruff check . | skim lint # Detects ruff
mypy src/ | skim lint # Detects mypy
golangci-lint run | skim lint # Detects golangci-lint
```
Subcommand: skim lint
New subcommand alongside existing skim test, skim git, skim build:
```rust
// crates/rskim/src/commands/lint.rs
pub fn compress_lint_output(raw: &str, format: Option) -> Result {
let format = format.unwrap_or_else(|| detect_lint_format(raw));
match format {
LintFormat::Eslint => parse_eslint(raw),
LintFormat::Ruff => parse_ruff(raw),
LintFormat::Mypy => parse_mypy(raw),
LintFormat::GolangciLint => parse_golangci_lint(raw),
}
}
```
Testing
Acceptance Criteria
v2.1: Linter Output Parsers
Parent: #96 (Command Coverage Expansion)
Priority: High — linters are the noisiest developer tools, highest token waste
Depends on: Nothing (v2.x track, independent of v3)
Overview
Linter output is one of the highest-value compression targets: verbose, repetitive, and heavily consumed by AI agents during code review and fix cycles. All major linters support structured JSON output, making them ideal for our three-tier degradation pattern.
Parsers to Implement
eslint (JavaScript/TypeScript)
eslint --format json→ parse JSON array of file resultsno-unused-varstogether)ruff (Python)
ruff check --output-format json→ parse JSON arraymypy (Python)
mypy --output json→ parse JSON linesgolangci-lint (Go)
golangci-lint run --out-format json→ parse JSONImplementation Pattern
Each parser follows the established three-tier degradation:
```rust
pub fn parse_eslint(raw: &str) -> ParseResult {
// Tier 1: Structured (JSON)
if let Ok(results) = serde_json::from_str::<Vec>(raw) {
return compress_eslint_json(results);
}
}
```
CLI Integration
```bash
Direct usage
eslint src/ --format json | skim lint
eslint src/ --format json | skim lint --format eslint
Via skim rewrite (hook mode)
skim rewrite "eslint src/"
→ Rewrites to: eslint src/ --format json 2>&1 | skim lint --format eslint
Auto-detection
eslint src/ | skim lint # Detects eslint from output patterns
ruff check . | skim lint # Detects ruff
mypy src/ | skim lint # Detects mypy
golangci-lint run | skim lint # Detects golangci-lint
```
Subcommand:
skim lintNew subcommand alongside existing
skim test,skim git,skim build:```rust
// crates/rskim/src/commands/lint.rs
pub fn compress_lint_output(raw: &str, format: Option) -> Result {
let format = format.unwrap_or_else(|| detect_lint_format(raw));
match format {
LintFormat::Eslint => parse_eslint(raw),
LintFormat::Ruff => parse_ruff(raw),
LintFormat::Mypy => parse_mypy(raw),
LintFormat::GolangciLint => parse_golangci_lint(raw),
}
}
```
Testing
skim initadds lint command hooksskim rewritegenerates correct lint commandsAcceptance Criteria
skim lintsubcommand with auto-detectionskim initupdated to hook lint commands for supported agentsskim rewritegenerates correct rewrite rules