Skip to content

GTST-20 feat: add compact TOON-inspired output format for agent token efficiency#17

Merged
MonteYin merged 2 commits intomainfrom
GTST-20.feat/toon-compact-output
Mar 26, 2026
Merged

GTST-20 feat: add compact TOON-inspired output format for agent token efficiency#17
MonteYin merged 2 commits intomainfrom
GTST-20.feat/toon-compact-output

Conversation

@MonteYin
Copy link
Copy Markdown
Owner

Summary

  • Add self-implemented compact output format inspired by TOON — no external dependencies
  • Default format is now toon (compact), json available via --format json
  • Remove human format and Auto detection — gitsift is agent-only
  • Remove similar crate dependency (was only used for human output)
  • ~40% token savings vs JSON on real-world diffs (38KB → 23KB)

Key optimizations

  • Tabular rows for hunk lines: {tag,content,old,new}: header + CSV-like rows
  • Context lines (unchanged) stripped — agents only need change lines for staging
  • Redundant file_path removed from hunks (already on parent file entry)

Test plan

  • cargo fmt --check passes
  • cargo clippy --all-targets — zero warnings
  • cargo test — all 96 tests pass
  • cargo build --release — binary works: diff, stage, status, protocol
  • Manual stage test on real repo verified
  • Size comparison: JSON 38,187 bytes vs toon 22,558 bytes (40.9% reduction)

… efficiency

- Add toon.rs: self-implemented compact formatter inspired by TOON format
  - Tabular rows for hunk lines: schema header {tag,content,old,new} + CSV rows
  - Strip context lines (equal) — agents don't need them for staging
  - Remove redundant file_path from hunks (already in parent FileChange)
  - ~40% token savings vs JSON on real-world diffs
- Default output format is now toon (compact), JSON available via --format json
- Remove human output format and Auto detection — tool is agent-only
- Remove `similar` dependency (was only used for human output)
- Update README and skill documentation
@MonteYin
Copy link
Copy Markdown
Owner Author

Review -- Opus 4.6

Review Result

Overall Verdict: HAS_ISSUES


1. Correctness

Verdict: HAS_ISSUES

Issues

Important
  • FileStatus casing inconsistency between toon and JSON formats (src/toon.rs:28): The toon format uses {:?} (Rust Debug trait) to render FileStatus, producing PascalCase values like Modified, Added, Deleted, Renamed. The JSON format uses #[serde(rename_all = "snake_case")] producing modified, added, deleted, renamed. An agent that parses both formats will see different status values depending on --format. This will break any agent code that checks status == "modified" against toon output.
Minor
  • Unused Response wrapper in format_stage_result (src/toon.rs:76): Response::success(result) is constructed only to read resp.version, which is always PROTOCOL_VERSION. The other two formatters (format_diff, format_status) use crate::models::PROTOCOL_VERSION directly. This allocates an unnecessary Response struct. Not a bug, but inconsistent with the sibling functions.

Fix Instructions

  • For the FileStatus casing: Replace {:?} with an explicit match or implement Display for FileStatus that matches serde's snake_case output. Simplest fix at src/toon.rs:28:
    let status_str = match file.status {
        FileStatus::Modified => "modified",
        FileStatus::Added => "added",
        FileStatus::Deleted => "deleted",
        FileStatus::Renamed => "renamed",
    };
    writeln!(buf, "    status: {}", status_str).unwrap();
  • For the unused Response wrapper: Replace line 76-79 with writeln!(buf, "version: {}", crate::models::PROTOCOL_VERSION).unwrap(); and remove Response from the import if no longer needed.

2. Architecture

Verdict: HAS_ISSUES

Issues

Important
  • CLAUDE.md not updated (CLAUDE.md:28,36,46,51,56): CLAUDE.md is the primary guidance file for AI agents working on this codebase. It still references GlobalArgs, human format, Auto detection, IsTerminal, and --format json|human|auto. Since this PR removes all of those, CLAUDE.md will actively mislead agents into using nonexistent CLI options. Specific stale lines:
    • Line 28: GlobalArgs (struct no longer exists, was renamed/removed)
    • Line 36: output.rs described as "JSON (default when piped) vs human-readable"
    • Line 46: "auto-detect terminal via IsTerminal; JSON by default when piped"
    • Line 51: "list unstaged hunks (JSON or human)"
    • Line 56: --format json|human|auto
  • Skill doc not updated (skills/gitsift-staging/SKILL.md:32-35): The skill doc still recommends gitsift diff --format human which will now fail with a clap parse error. This will cause agent tool invocations to fail.
Minor
  • No toon format error response: The toon formatter only handles success cases (ok: true). Error responses from the CLI (e.g., invalid repo path) go through anyhow and print to stderr via main(), so this isn't a bug -- but it's worth noting that the toon format has no ok: false representation. If error formatting through toon is ever needed (e.g., for stage partial failures), the current format_stage_result does handle the errors array, so the main gap is only for top-level command failures, which correctly use stderr + exit code.

Fix Instructions

  • Update CLAUDE.md to reflect the new format options: --format toon|json, default is toon, no auto-detection, no human format, toon.rs in the architecture diagram, and remove IsTerminal from design decisions.
  • Update skills/gitsift-staging/SKILL.md lines 32-35: Remove the --format human section entirely, or replace with gitsift diff (default compact format). Also consider mentioning the toon format in the "See what changed" section since it's now the default.

3. Security

Verdict: PASS

No security concerns. The toon format is output-only, no new input parsing is introduced. The escape function properly handles the relevant special characters for the CSV-like row format.


4. Performance

Verdict: PASS

The implementation is straightforward String building with write! macros. Filtering context lines with iter().filter().collect() is fine for the expected hunk sizes. The removal of the similar crate dependency is a positive change -- less code to compile, smaller binary.


5. Simplicity

Verdict: PASS

The new code is clean and well-organized. The toon.rs module is self-contained with clear formatting functions. The removal of the Auto variant and resolve_format() indirection simplifies output.rs significantly. Test coverage is thorough with both unit tests in toon.rs and integration tests in tests/cli.rs.

The escape function is minimal and correct for the use case. The tabular row format is a reasonable design choice for token efficiency.


Summary

The core toon formatter implementation is solid -- clean code, good test coverage, and a meaningful token reduction. However, there are two issues that should be addressed before merging. First, FileStatus renders as PascalCase in toon output (Modified) but snake_case in JSON (modified) due to using Rust's Debug trait instead of matching serde's rename_all convention -- this will trip up agents that parse both formats. Second, CLAUDE.md and the skill doc (skills/gitsift-staging/SKILL.md) still reference the now-removed --format human and Auto detection, which will actively mislead AI agents working on or using this tool. Both are straightforward fixes.

- Add Display impl for FileStatus to output snake_case in toon format
  (consistent with JSON's serde rename_all = "snake_case")
@MonteYin MonteYin merged commit ff7fbd9 into main Mar 26, 2026
4 checks passed
@MonteYin MonteYin deleted the GTST-20.feat/toon-compact-output branch March 26, 2026 03:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant