Skip to content

fix(hooks): rewrite producer stage of producer | cat pipelines - #3724

Closed
javython999 wants to merge 1 commit into
rtk-ai:developfrom
javython999:fix/pipe-rewrite-transparent-cat-sink
Closed

javython999 wants to merge 1 commit into
rtk-ai:developfrom
javython999:fix/pipe-rewrite-transparent-cat-sink

Conversation

@javython999

Copy link
Copy Markdown

A bare cat (no flags, no files) is byte-transparent: it copies stdin to stdout unchanged. producer | cat and producer are therefore equivalent on stdout, so the producer segment can be rewritten the same way a standalone command would be, without risking a change to what a downstream consumer reads.

Previously the hook left pipelines entirely raw except for an allowlisted final-stage rewrite (grep/rg), so git status | cat never got the rtk rewrite even though nothing consumes the pipe's output structurally.

The exception is scoped to a single stdout pipe with no further pipe stages, so pipelines with real intermediate processing (a | b | cat) keep the existing raw-producer contract.

Fixes #3722

Summary

  • Rewrite the producer stage of a producer | cat pipeline (e.g. git status | cat -> rtk git status | cat) since a bare cat sink is byte-transparent
  • Added is_transparent_cat_sink / rewrite_producer_before_transparent_sink in src/discover/registry.rs, wired as a fallback when the existing final-stage rewrite finds nothing
  • Scoped narrowly: only a single stdout pipe with no further pipe stages qualifies; a | b | cat, cat -n, and |& stderr pipes are unaffected

Test plan

  • cargo fmt --all && cargo clippy --all-targets && cargo test
  • Added 5 new unit tests in src/discover/registry.rs covering the happy path, && continuation after the pipe, cat -n (non-transparent), a real intermediate stage before cat, and the stderr-pipe case
  • Manual testing: echo '{"tool_name":"Bash","tool_input":{"command":"git status | cat"}}' | rtk hook claude now rewrites to rtk git status | cat

Important: All PRs must target the develop branch (not master).
See CONTRIBUTING.md for details.

@CLAassistant

CLAassistant commented Aug 27, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

A bare `cat` (no flags, no files) is byte-transparent: it copies stdin
to stdout unchanged. `producer | cat` and `producer` are therefore
equivalent on stdout, so the producer segment can be rewritten the same
way a standalone command would be, without risking a change to what a
downstream consumer reads.

Previously the hook left pipelines entirely raw except for an
allowlisted final-stage rewrite (grep/rg), so `git status | cat`
never got the rtk rewrite even though nothing consumes the pipe's
output structurally.

The exception is scoped to a single stdout pipe with no further pipe
stages, so pipelines with real intermediate processing (`a | b | cat`)
keep the existing raw-producer contract.

Fixes rtk-ai#3722
@javython999
javython999 force-pushed the fix/pipe-rewrite-transparent-cat-sink branch from f668689 to 16ddc78 Compare August 27, 2026 02:11
@KuSh

KuSh commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the tight scoping and for the tests that came with it. #3343, merged on 2026-09-07, made the hook rewrite the producer stage whenever the consumer is safe, so git status | cat already becomes rtk git status | cat on develop, and it goes further than this PR by also accepting cat -n while still leaving a | b | cat and stderr pipes alone. I checked each of those cases against a current develop build. The helpers here, is_transparent_cat_sink and rewrite_producer_before_transparent_sink, sit on the pipeline shape that #3343 and #3704 replaced, so there is nothing left to carry over. Please comment here or reopen if a case you had in mind is still not rewritten.

@KuSh KuSh closed this Sep 19, 2026
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.

Hook rewrite (rtk hook claude) skips commands containing a pipe (|)

3 participants