Tooling gotcha — RTK silently corrupts some shell commands

RTK (the token-optimizing CLI proxy that auto-rewrites shell commands via a Claude Code hook) does not just filter output — for some commands it mutates the command itself before running it, producing wrong results with no obvious sign that RTK was the cause. Two failure modes confirmed: curl <url> gets the URL corrupted, and certain pipes/find-counts return empty or zeroed output.

This was hit while trying to fetch the actionlint binary during the FKITDEV-8239 review — curl failed, python3 urllib worked. It is the same family of hazard as rtk-git-log-hides-merge-commits (RTK output-filtering hides merge commits) and the long-standing RTK pipe-count mangling note in agent memory.

Symptoms (confirmed)

curl — malformed URL

curl: (3) URL using bad/illegal format or missing URL
# (libcurl: "Malformed input to a URL function")

RTK’s Rust proxy corrupts the URL string it passes through, so even a well-formed curl https://… fails with curl error (3). wget is also unreliable through the proxy.

Pipes / counts — empty or zeroed output

  • ls | sort returned empty.
  • find … | wc -l and … | grep -c … get zeroed (count comes back 0 even when matches exist).
  • A find … -o … expression came back empty during this same session.

The danger is that a zeroed count or empty listing looks like a legitimate “no results” answer — you can draw the wrong conclusion (e.g. “no file matches”) instead of realizing the command was mangled.

Workarounds — bypass RTK with python3

python3 is not rewritten by the hook — route the real work through it

The proxy rewrites the shell command, but a python3 one-liner runs the actual logic inside the interpreter where RTK can’t touch the URL or the pipeline.

Download a file (instead of curl/wget):

python3 -c "import urllib.request,sys; urllib.request.urlretrieve(sys.argv[1], sys.argv[2])" <url> <dest>

This is exactly how the actionlint binary was fetched after curl failed with error (3).

Run a multi-step CLI check (instead of a shell pipeline):

python3 - <<'EOF'
import subprocess
r = subprocess.run(["some-tool", "--flag", "arg"], capture_output=True, text=True)
print(r.returncode, r.stdout, r.stderr)
EOF

Use subprocess.run([...]) with an argv list (no shell=True) so the command never round-trips through the rewriting hook. This sidesteps both the URL corruption and the pipe mangling. The vault scans in this very session (find files / grep contents) were done this way after find/grep returned empty.

Counts — cross-check two independent methods: Don’t trust a single | wc -l / | grep -c. Compute the count two different ways (e.g. git ls-tree + a python len([...])) and confirm they agree before relying on the number. (See the agent-memory rtk-pipe-count-mangling note for the git-specific recipe.)

Escape hatch: rtk proxy <cmd> runs a command raw/unfiltered, but the user generally prefers agents avoid it — reach for the python bypass above first.

  • rtk-git-log-hides-merge-commits — sibling RTK gotcha: output-filtering drops merge commits from git log --graph; use %p/rev-list --parents plumbing instead.
  • RTK — the token-optimizing CLI proxy whose command rewriting causes this.
  • FKITDEV-8239 — the depcheck-CI review during which the curl-fails / python-urllib-works case was hit.