docs: comprehensive v0.15.1 documentation for Python/Go support#102
docs: comprehensive v0.15.1 documentation for Python/Go support#102FlorianBruniaux wants to merge 9 commits intortk-ai:masterfrom
Conversation
Problem: `cargo test` shows 24+ summary lines even when all pass. An LLM only needs to know IF something failed, not 24x "ok". Before (24 lines): ``` ✓ test result: ok. 2 passed; 0 failed; ... ✓ test result: ok. 0 passed; 0 failed; ... ... (x24) ``` After (1 line): ``` ✓ cargo test: 137 passed (24 suites, 1.45s) ``` Changes: - Add AggregatedTestResult struct with regex parsing - Merge multiple test summaries when all pass - Format: "N passed, M ignored, P filtered out (X suites, Ys)" - Fallback to original behavior if parsing fails - Failures still show full details (no aggregation) Tests: 6 new + 1 modified, covering all cases: - Multi-suite aggregation - Single suite (singular "suite") - Zero tests - With ignored/filtered out - Failures → no aggregation (detail preserved) - Regex fallback Closes rtk-ai#83 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat(cargo): aggregate test output into single line (rtk-ai#83) Problem: `cargo test` shows 24+ summary lines even when all pass. An LLM only needs to know IF something failed, not 24x "ok". Before (24 lines): ``` ✓ test result: ok. 2 passed; 0 failed; ... ✓ test result: ok. 0 passed; 0 failed; ... ... (x24) ``` After (1 line): ``` ✓ cargo test: 137 passed (24 suites, 1.45s) ``` Changes: - Add AggregatedTestResult struct with regex parsing - Merge multiple test summaries when all pass - Format: "N passed, M ignored, P filtered out (X suites, Ys)" - Fallback to original behavior if parsing fails - Failures still show full details (no aggregation) Tests: 6 new + 1 modified, covering all cases: - Multi-suite aggregation - Single suite (singular "suite") - Zero tests - With ignored/filtered out - Failures → no aggregation (detail preserved) - Regex fallback Closes rtk-ai#83 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * feat: add Python and Go language support Implements comprehensive support for Python and Go development tooling with 70-90% token reduction across all commands. Python commands (3): - rtk ruff: Linter/formatter with JSON (check) and text (format) parsing (80%+) - rtk pytest: Test runner with state machine text parser (90%+) - rtk pip: Package manager with auto-detect uv (70-85%) Go commands (4): - rtk go test: NDJSON streaming parser for interleaved test events (90%+) - rtk go build: Text filter showing errors only (80%) - rtk go vet: Text filter for issues (75%) - rtk golangci-lint: JSON parser grouped by rule (85%) Architecture: - Standalone Python commands (mirror lint/prettier pattern) - Go sub-enum (mirror git/cargo pattern) - 5 new modules: ruff_cmd, pytest_cmd, pip_cmd, go_cmd, golangci_cmd - Hook integration in rtk-rewrite.sh for transparent rewrites - Comprehensive tests (47 new tests, all passing) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * feat(benchmark): add Python and Go commands Add benchmark sections for Python (ruff, pytest, pip) and Go (go test/build/vet, golangci-lint) to validate >80% token savings in CI pipeline. Sections conditionally execute based on project markers (pyproject.toml, go.mod) and tool availability. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
- Build from source automatically instead of requiring a pre-built binary - Default install dir to ~/.cargo/bin - Skip rebuild when binary is up to date - Warn if install dir is not in PATH
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix(vitest): robust JSON extraction for pnpm/dotenv prefixes
Problem: RTK's vitest parser forces --reporter=json but pnpm/dotenv prepend
non-JSON text to stdout (banners, env messages), causing 100% Tier 1 failure
and useless 500-char passthrough.
Solution:
- Add extract_json_object() to parser/mod.rs (shared utility)
- Algorithm: find "numTotalTests" or first standalone {, brace-balance forward
- VitestParser now tries direct parse → extract+parse → regex → passthrough
- Replace hardcoded Command::new("pnpm") with package_manager_exec("vitest")
- Delete orphan doc comment on line 203
Impact:
- Before: 100% Tier 3 passthrough with pnpm workflows
- After: Tier 1 success with prefixes, maintains 99.5% token savings
Tests:
- 6 tests for extract_json_object (clean, pnpm, dotenv, nested, no-json, strings)
- 3 tests for VitestParser with prefixes
- All 277 tests pass
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* chore(benchmark): add vitest, pnpm, and gh commands
Add benchmarks for recently implemented commands:
- vitest run (PR rtk-ai#92 - JSON extraction fix)
- pnpm list/outdated (PR rtk-ai#6)
- gh pr list/run list (existing gh support)
These commands are now tested in CI to ensure token savings are maintained.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat(cargo): aggregate test output into single line (rtk-ai#83) Problem: `cargo test` shows 24+ summary lines even when all pass. An LLM only needs to know IF something failed, not 24x "ok". Before (24 lines): ``` ✓ test result: ok. 2 passed; 0 failed; ... ✓ test result: ok. 0 passed; 0 failed; ... ... (x24) ``` After (1 line): ``` ✓ cargo test: 137 passed (24 suites, 1.45s) ``` Changes: - Add AggregatedTestResult struct with regex parsing - Merge multiple test summaries when all pass - Format: "N passed, M ignored, P filtered out (X suites, Ys)" - Fallback to original behavior if parsing fails - Failures still show full details (no aggregation) Tests: 6 new + 1 modified, covering all cases: - Multi-suite aggregation - Single suite (singular "suite") - Zero tests - With ignored/filtered out - Failures → no aggregation (detail preserved) - Regex fallback Closes rtk-ai#83 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix(ci): prevent Python/Go benchmark sections from being silently skipped **Problem:** Python and Go benchmark sections were silently skipped in CI because the RTK repository doesn't contain pyproject.toml or go.mod files. The sections only ran when these project files existed. **Solution:** 1. Create temporary fixtures with minimal project structure: - Python: pyproject.toml + sample.py + test_sample.py - Go: go.mod + main.go + main_test.go 2. Resolve RTK to absolute path to work after cd into temp dirs 3. Install required tools in CI workflow: - Python: ruff, pytest - Go: stable version + golangci-lint **Impact:** - Python/Go sections now appear in CI benchmark output - Self-contained fixtures ensure consistent benchmarking - No dependency on RTK project structure Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(hooks): add missing RTK command rewrites Add 8 missing command rewrites to rtk-rewrite.sh and rtk-suggest.sh: - cargo check/install/fmt - tree, find, diff - head → rtk read (with --max-lines transformation) - wget Fixes BSD sed compatibility for head transformation by using literal spaces instead of \s+ (which doesn't work on macOS). Impact: ~18.2K tokens saved on previously missed commands discovered by `rtk discover`. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Complete documentation overhaul for RTK v0.15.1 Python and Go support across all user-facing and technical documentation. ## Changes ### Critical (P0) - **CLAUDE.md**: Added maintenance warning, CHANGELOG reference, hook coverage section, corrected module count (46 modules) - **Hooks**: Added Python/Go rewrites (ruff, pytest, pip, go, golangci-lint) - **CI Validation**: New workflow validates doc consistency on every PR ### User Documentation (P1) - **README.md**: Added Python/Go Stack section, updated command tables, added benchmarks, explicit v0.15.1 mention ### Technical Documentation (P2) - **ARCHITECTURE.md**: Updated metadata (v0.15.1, 2026-02-12), added Python/Go modules to organization table, 3 new filtering strategies (JSON/TEXT Dual, State Machine, NDJSON), complete Python & Go Module Architecture section ## Validation - ✅ All docs mention version 0.15.1 - ✅ Module count consistent (46 across all docs) - ✅ All Python/Go commands documented - ✅ Hook rewrites present and tested - ✅ scripts/validate-docs.sh passes ## Impact - Prevents documentation drift (CI validation) - Claude Code immediately uses Python/Go via hooks - Clear architecture guidance for contributors - 375 lines added across 6 files Closes #[issue-number-if-any] Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR updates RTK to v0.15.1 and expands/aligns documentation and tooling around the newly added Python and Go command support, including parsers, CLI wiring, hooks, CI validation, and benchmarks.
Changes:
- Add new CLI commands/modules for Python (ruff/pytest/pip) and Go (go subcommands + golangci-lint), plus improved vitest JSON robustness.
- Update docs (README/CLAUDE/ARCHITECTURE/CHANGELOG) and bump version metadata to 0.15.1.
- Add/extend scripts and CI workflows for doc validation, installation, benchmarks, and help/coverage checks.
Reviewed changes
Copilot reviewed 24 out of 25 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| src/vitest_cmd.rs | Makes vitest parsing more robust (JSON extraction fallback) and uses package_manager_exec for invocation. |
| src/parser/mod.rs | Adds JSON object extraction helper used by vitest. |
| src/main.rs | Wires new Python/Go commands into the CLI. |
| src/ruff_cmd.rs | New ruff command wrapper with JSON/text filtering. |
| src/pytest_cmd.rs | New pytest wrapper with state-machine parsing. |
| src/pip_cmd.rs | New pip/uv wrapper with JSON parsing and compact output. |
| src/go_cmd.rs | New go test/build/vet wrappers; NDJSON parsing for go test -json. |
| src/golangci_cmd.rs | New golangci-lint wrapper and JSON grouping formatter. |
| src/cargo_cmd.rs | Aggregates multi-suite cargo test “ok” summaries into a single compact line. |
| scripts/validate-docs.sh | Adds a docs consistency validator used in CI. |
| .github/workflows/validate-docs.yml | New CI workflow to block merges on doc drift. |
| scripts/test-all.sh | Extends help checks to Python/Go commands when tools are installed. |
| scripts/install-local.sh | Adds local install helper for release builds. |
| scripts/benchmark.sh | Adds benchmark coverage for vitest/pnpm and Python/Go fixture benches. |
| hooks/rtk-rewrite.sh | Extends command rewrite coverage for Python/Go. |
| .claude/hooks/rtk-rewrite.sh | Extends rewrite coverage (including more core commands). |
| .claude/hooks/rtk-suggest.sh | Extends suggestion coverage for additional commands. |
| README.md | Documents Python/Go stack usage and updates metrics/examples for v0.15.1. |
| CLAUDE.md | Updates Claude guidance, module list/count, and hook coverage notes. |
| ARCHITECTURE.md | Adds Python/Go architecture sections and updates module count/version metadata. |
| CHANGELOG.md | Adds v0.15.1 notes and references. |
| Cargo.toml / Cargo.lock | Bumps crate version to 0.15.1. |
| .release-please-manifest.json | Updates release-please version manifest. |
| .github/workflows/benchmark.yml | Installs Python/Go tools in CI before running benchmarks. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| static RE: OnceLock<regex::Regex> = OnceLock::new(); | ||
| let re = RE.get_or_init(|| { | ||
| regex::Regex::new( | ||
| r"test result: (\w+)\.\s+(\d+) passed;\s+(\d+) failed;\s+(\d+) ignored;\s+(\d+) measured;\s+(\d+) filtered out(?:;\s+finished in ([\d.]+)s)?" | ||
| ).unwrap() | ||
| }); |
There was a problem hiding this comment.
This file uses regex::Regex via fully-qualified paths (e.g., OnceLock<regex::Regex> / regex::Regex::new) instead of importing use regex::Regex;, which is the prevailing convention in this repo (e.g., src/utils.rs:9, src/runner.rs:3). Consider switching to an explicit import and using OnceLock<Regex> for consistency/readability.
|
|
||
| /// Ruff linter/formatter with compact output | ||
| Ruff { | ||
| /// Ruff arguments (e.g., check, format --check) | ||
| #[arg(trailing_var_arg = true, allow_hyphen_values = true)] | ||
| args: Vec<String>, | ||
| }, | ||
|
|
||
| /// Pytest test runner with compact output | ||
| Pytest { | ||
| /// Pytest arguments | ||
| #[arg(trailing_var_arg = true, allow_hyphen_values = true)] | ||
| args: Vec<String>, | ||
| }, | ||
|
|
||
| /// Pip package manager with compact output (auto-detects uv) | ||
| Pip { | ||
| /// Pip arguments (e.g., list, outdated, install) | ||
| #[arg(trailing_var_arg = true, allow_hyphen_values = true)] | ||
| args: Vec<String>, | ||
| }, | ||
|
|
||
| /// Go commands with compact output | ||
| Go { | ||
| #[command(subcommand)] | ||
| command: GoCommands, | ||
| }, | ||
|
|
||
| /// golangci-lint with compact output | ||
| #[command(name = "golangci-lint")] | ||
| GolangciLint { | ||
| /// golangci-lint arguments | ||
| #[arg(trailing_var_arg = true, allow_hyphen_values = true)] | ||
| args: Vec<String>, | ||
| }, |
There was a problem hiding this comment.
PR title/description frame this primarily as a documentation update for existing Python/Go support, but this diff also introduces substantial new runtime functionality (new Rust modules/commands for ruff/pytest/pip/go/golangci-lint, parser changes, version bump). If that’s intended, consider updating the PR title/description to reflect that it’s a feature release as well (or split docs vs. behavior changes to ease review/risk).
| // golangci-lint returns exit code 1 when issues found (expected behavior) | ||
| // Don't exit with error code in that case | ||
| Ok(()) | ||
| } |
There was a problem hiding this comment.
golangci-lint exit code is currently ignored: run() always returns Ok(()) even when golangci-lint exits non-zero for reasons other than “issues found” (e.g., config errors, internal errors). This can cause CI to pass while linting actually failed. Consider explicitly checking output.status: treat exit code 1 as “issues found” (print filtered output but return Ok), but for any other non-success exit code propagate it (exit with code or return Err) and surface stderr regardless of verbosity.
| let package = event.package.unwrap_or_else(|| "unknown".to_string()); | ||
| let pkg_result = packages.entry(package.clone()).or_default(); | ||
|
|
||
| match event.action.as_str() { | ||
| "pass" => { | ||
| if event.test.is_some() { | ||
| pkg_result.pass += 1; | ||
| } | ||
| } | ||
| "fail" => { | ||
| if let Some(test) = &event.test { | ||
| pkg_result.fail += 1; | ||
|
|
||
| // Collect output for failed test | ||
| let key = (package.clone(), test.clone()); | ||
| let outputs = current_test_output.remove(&key).unwrap_or_default(); | ||
| pkg_result.failed_tests.push((test.clone(), outputs)); | ||
| } | ||
| } |
There was a problem hiding this comment.
filter_go_test_json only treats Action=="fail" as a failure when event.Test is present. In real go test -json output, build/package failures (and some package-level failures) are emitted as Action=="fail" events with no Test plus associated Output events with no Test. With the current logic those failures are ignored, so the summary can incorrectly print a success/no-tests message even though go test failed (run_test then exits non-zero, but the printed summary is misleading). Handle package-level fail events and non-test Output lines (e.g., track a package_failed flag and include build/output snippets in the failure summary).
| "output" => { | ||
| // Collect output for current test | ||
| if let (Some(test), Some(output_text)) = (&event.test, &event.output) { | ||
| let key = (package.clone(), test.clone()); | ||
| current_test_output | ||
| .entry(key) | ||
| .or_default() | ||
| .push(output_text.trim_end().to_string()); | ||
| } |
There was a problem hiding this comment.
current_test_output accumulates per-test output lines but entries are only removed on failed tests. For passing tests, collected output is never cleared, which can grow memory usage significantly on large test suites (especially with verbose output) even though that data is never displayed. Consider removing the buffer on Action=="pass" for a test, and/or only buffering output after seeing a failure marker.
|
|
||
| timer.track( | ||
| &format!("{} {}", base_cmd, args.join(" ")), | ||
| &format!("rtk {} {}", base_cmd, args.join(" ")), |
There was a problem hiding this comment.
In pip_cmd::run(), timer.track() uses base_cmd ("pip" vs "uv") to build the rtk command label: rtk {base_cmd} .... When uv is detected this will record the filtered invocation as rtk uv ..., but the user-facing command is still rtk pip .... Consider using a constant rtk pip ... label (and, if desired, include uv pip in the raw-command label only).
| &format!("rtk {} {}", base_cmd, args.join(" ")), | |
| &format!("rtk pip {}", args.join(" ")), |
| let chars: Vec<char> = input[start_pos..].chars().collect(); | ||
|
|
||
| for (i, &ch) in chars.iter().enumerate() { |
There was a problem hiding this comment.
extract_json_object allocates a full Vec of the remaining input (input[start_pos..].chars().collect()), duplicating potentially large outputs in memory. This can be expensive for large JSON blobs (e.g., vitest testResults). Consider iterating over the slice with char_indices() (or bytes with careful string/escape handling) to brace-balance without allocating, and compute the end byte offset directly.
| let chars: Vec<char> = input[start_pos..].chars().collect(); | |
| for (i, &ch) in chars.iter().enumerate() { | |
| for (i, ch) in input[start_pos..].char_indices() { |
| // Force JSON output for check command | ||
| if !args.contains(&"--output-format".to_string()) { | ||
| cmd.arg("check").arg("--output-format=json"); | ||
| } else { | ||
| cmd.arg("check"); | ||
| } |
There was a problem hiding this comment.
Ruff JSON output flag detection only checks for an argument equal to "--output-format". If the user passes "--output-format=json" (or any "--output-format=..." form), this code will still inject another "--output-format=json", which can lead to duplicated/conflicting flags. Consider checking both the separate-arg and equals forms (e.g., a == "--output-format" || a.starts_with("--output-format=")).
|
need a rebase for conflicts |
|
review conflicts please |
Resolve 9 conflicts: - Versions: take master (0.16.0) - Hooks: take master (POSIX character classes + ENV_PREFIX) - CHANGELOG/CLAUDE.md: take master entries - parser/mod.rs: add multibyte/emoji tests from master - ruff_cmd.rs: take pub fn visibility from master Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Complete documentation update for RTK v0.15.1 Python and Go support across all documentation files.
Why: v0.15.0 added Python/Go commands but documentation was incomplete/outdated, causing confusion for Claude Code and users.
What: Comprehensive 4-phase update following strict validation checklist.
Changes by Priority
🔴 P0 - Critical (Claude Code reads every session)
✅ CLAUDE.md
✅ Hooks (
.claude/hooks/rtk-rewrite.sh)ruff,pytest,pipgo test/build/vet,golangci-lint✅ CI Validation (
.github/workflows/validate-docs.yml)🟡 P1 - Important (User-facing)
🟢 P2 - Recommended (Technical contributors)
Validation ✅
All checks pass via
scripts/validate-docs.sh:Commands Documented
ruff check/formatpytestpip list/install/outdatedgo test/build/vetgolangci-lint runFiles Changed (6)
.claude/hooks/rtk-rewrite.sh(+14 lines)CLAUDE.md(+23 lines)README.md(+34 lines)ARCHITECTURE.md(+304 lines).github/workflows/validate-docs.yml(new, 61 lines)scripts/validate-docs.sh(new, 73 lines)Total: +508 insertions, -9 deletions
Impact
Testing
scripts/validate-docs.shpasses locallyMaintenance Note
Going forward, the CI validation workflow will catch documentation drift automatically. Contributors must update all 4 docs when adding modules/commands.
🤖 Generated with Claude Code